Skip to content

Commit 6e7872b

Browse files
committed
review
1 parent 0662a38 commit 6e7872b

File tree

9 files changed

+73
-51
lines changed

9 files changed

+73
-51
lines changed

Diff for: conf/logback.xml

+6-2
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,13 @@ appender reference in the root level section below.
124124
<!-- <appender name="SLOW_QUERIES_TO_VTABLE" class="org.apache.cassandra.utils.logging.SlowQueriesAppender"/> -->
125125

126126
<!-- Log slow queries to system_views.slow_queries virtual table -->
127-
<!-- <logger name="slow_queries" additivity="false" level="DEBUG">
127+
<logger name="slow_queries" additivity="false" level="DEBUG">
128+
<appender-ref ref="DEBUGLOG"/>
129+
<!-- uncomment this appender reference together with appender definition above
130+
to start to put slow queries into system_views.slow_queries virtual table
128131
<appender-ref ref="SLOW_QUERIES_TO_VTABLE"/>
129-
</logger> -->
132+
-->
133+
</logger>
130134

131135
<root level="INFO">
132136
<appender-ref ref="SYSTEMLOG" />

Diff for: src/java/org/apache/cassandra/db/monitoring/MonitoringTask.java

+26-23
Original file line numberDiff line numberDiff line change
@@ -192,14 +192,15 @@ boolean logSlowOperations(long approxCurrentTimeNanos)
192192
if (!slowOperations.isEmpty())
193193
{
194194
long approxElapsedNanos = approxCurrentTimeNanos - approxLastLogTimeNanos;
195-
noSpamLogger.info("Some operations were slow, details available at debug level (debug.log)");
195+
noSpamLogger.info("Some operations were slow, details available at debug level (debug.log) or " +
196+
"system_views.slow_queries virtual table (when enabled).");
196197

197198
if (slowOperationsLogger.isDebugEnabled())
198199
{
199200
if (slowOperationsLoggedToVirtualTable)
200201
{
201202
// This is the crux of the patch for appending to vtable.
202-
// Because we can send only String's to debug method (or objects, on which toString()
203+
// Because we can send only Strings to debug method (or objects, on which toString()
203204
// would be eventually called), we need to log a string in such a way that we can
204205
// get Operation object(s) back "on the other side" when dealing with vtables and custom appenders
205206
// as appenders work with LoggingEvent where message is just a string.
@@ -370,10 +371,10 @@ public abstract static class Operation
370371
long totalTimeNanos;
371372

372373
/** The maximum time spent by this operation */
373-
long maxTime;
374+
long maxTimeNanos;
374375

375376
/** The minimum time spent by this operation */
376-
long minTime;
377+
long minTimeNanos;
377378

378379
/** The name of the operation, i.e. the SELECT query CQL,
379380
* this is set lazily as it takes time to build the query CQL */
@@ -385,10 +386,10 @@ public abstract static class Operation
385386
* which does not follow wall clock and is useless for
386387
* reporting purposes e.g. in virtual tables
387388
*/
388-
private final long timestamp;
389+
private final long timestampMs;
389390

390391
// optional keyspace and table this operation acts on
391-
// used upon deserialisation
392+
// used upon deserialization
392393
private String keyspace;
393394
private String table;
394395
private boolean crossNode;
@@ -398,17 +399,17 @@ public abstract static class Operation
398399
this.operation = operation;
399400
numTimesReported = 1;
400401
totalTimeNanos = failedAtNanos - operation.creationTimeNanos();
401-
minTime = totalTimeNanos;
402-
maxTime = totalTimeNanos;
403-
timestamp = Clock.Global.currentTimeMillis();
402+
minTimeNanos = totalTimeNanos;
403+
maxTimeNanos = totalTimeNanos;
404+
timestampMs = Clock.Global.currentTimeMillis() - (Clock.Global.nanoTime() - operation.creationTimeNanos()) / 1_000_000;
404405
}
405406

406407
void add(Operation operation)
407408
{
408409
numTimesReported++;
409410
totalTimeNanos += operation.totalTimeNanos;
410-
maxTime = Math.max(maxTime, operation.maxTime);
411-
minTime = Math.min(minTime, operation.minTime);
411+
maxTimeNanos = Math.max(maxTimeNanos, operation.maxTimeNanos);
412+
minTimeNanos = Math.min(minTimeNanos, operation.minTimeNanos);
412413
}
413414

414415
public abstract String getLogMessage();
@@ -467,15 +468,15 @@ public long totalTimeNanos()
467468
}
468469

469470
@JsonProperty
470-
public long maxTime()
471+
public long maxTimeNanos()
471472
{
472-
return maxTime;
473+
return maxTimeNanos;
473474
}
474475

475476
@JsonProperty
476-
public long minTime()
477+
public long minTimeNanos()
477478
{
478-
return minTime;
479+
return minTimeNanos;
479480
}
480481

481482
@JsonIgnore
@@ -485,19 +486,21 @@ public long averageTime()
485486
}
486487

487488
@JsonProperty
488-
public long timestamp()
489+
public long timestampMs()
489490
{
490-
return timestamp;
491+
return timestampMs;
491492
}
492493

493494
public static String serialize(Collection<Operation> operations)
494495
{
495496
return JsonUtils.writeAsJsonString(operations);
496497
}
497498

499+
private static final TypeReference<List<Operation>> TYPE_REFERENCE = new TypeReference<>() {};
500+
498501
public static List<Operation> deserialize(String message) throws Throwable
499502
{
500-
return JsonUtils.JSON_OBJECT_MAPPER.readValue(message, new TypeReference<>() {});
503+
return JsonUtils.JSON_OBJECT_MAPPER.readValue(message, TYPE_REFERENCE);
501504
}
502505
}
503506

@@ -524,8 +527,8 @@ public String getLogMessage()
524527
name(),
525528
numTimesReported,
526529
NANOSECONDS.toMillis(totalTimeNanos / numTimesReported),
527-
NANOSECONDS.toMillis(minTime),
528-
NANOSECONDS.toMillis(maxTime),
530+
NANOSECONDS.toMillis(minTimeNanos),
531+
NANOSECONDS.toMillis(maxTimeNanos),
529532
NANOSECONDS.toMillis(operation.timeoutNanos()),
530533
operation.isCrossNode() ? "msec/cross-node" : "msec");
531534
}
@@ -537,7 +540,7 @@ public String getLogMessage()
537540
@VisibleForTesting
538541
public final static class SlowOperation extends Operation
539542
{
540-
// purely for deserialisation purposes
543+
// purely for deserialization purposes
541544
public SlowOperation()
542545
{
543546
this(Monitorable.NO_OP, 0);
@@ -562,8 +565,8 @@ public String getLogMessage()
562565
name(),
563566
numTimesReported,
564567
NANOSECONDS.toMillis(totalTimeNanos/ numTimesReported),
565-
NANOSECONDS.toMillis(minTime),
566-
NANOSECONDS.toMillis(maxTime),
568+
NANOSECONDS.toMillis(minTimeNanos),
569+
NANOSECONDS.toMillis(maxTimeNanos),
567570
NANOSECONDS.toMillis(operation.slowTimeoutNanos()),
568571
operation.isCrossNode() ? "msec/cross-node" : "msec");
569572
}

Diff for: src/java/org/apache/cassandra/db/virtual/AbstractLoggerVirtualTable.java

+8-4
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,13 @@ public abstract class AbstractLoggerVirtualTable<U> extends AbstractMutableVirtu
3838
{
3939
private static final Logger logger = LoggerFactory.getLogger(AbstractLoggerVirtualTable.class);
4040

41+
// please be sure operations on this structure are thread-safe
4142
protected final List<U> buffer;
4243

4344
@VisibleForTesting
44-
protected static int resolveBufferSize(int wantedSize, int min, int max, int defaultSize)
45+
protected static int resolveBufferSize(int wantedSize, int max, int defaultSize)
4546
{
46-
return (wantedSize < min || wantedSize > max) ? defaultSize : wantedSize;
47+
return (wantedSize < 0 || wantedSize > max) ? defaultSize : wantedSize;
4748
}
4849

4950
protected AbstractLoggerVirtualTable(TableMetadata metadata, int maxSize)
@@ -70,7 +71,10 @@ public void add(LoggingEvent event)
7071
@Override
7172
public void truncate()
7273
{
73-
buffer.clear();
74+
synchronized (buffer)
75+
{
76+
buffer.clear();
77+
}
7478
}
7579

7680
@Override
@@ -94,7 +98,7 @@ private BoundedLinkedList(int maxSize)
9498
}
9599

96100
@Override
97-
public boolean add(T t)
101+
public synchronized boolean add(T t)
98102
{
99103
if (size() == maxSize)
100104
removeLast();

Diff for: src/java/org/apache/cassandra/db/virtual/LogMessagesTable.java

-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
*/
4949
public final class LogMessagesTable extends AbstractLoggerVirtualTable<LoggingEvent>
5050
{
51-
public static final int LOGS_VIRTUAL_TABLE_MIN_ROWS = 1000;
5251
public static final int LOGS_VIRTUAL_TABLE_DEFAULT_ROWS = 50_000;
5352
public static final int LOGS_VIRTUAL_TABLE_MAX_ROWS = 100_000;
5453

@@ -64,7 +63,6 @@ public final class LogMessagesTable extends AbstractLoggerVirtualTable<LoggingEv
6463
LogMessagesTable(String keyspace)
6564
{
6665
this(keyspace, resolveBufferSize(CassandraRelevantProperties.LOGS_VIRTUAL_TABLE_MAX_ROWS.getInt(),
67-
LOGS_VIRTUAL_TABLE_MIN_ROWS,
6866
LOGS_VIRTUAL_TABLE_MAX_ROWS,
6967
LOGS_VIRTUAL_TABLE_DEFAULT_ROWS));
7068
}

Diff for: src/java/org/apache/cassandra/db/virtual/SlowQueriesTable.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ public class SlowQueriesTable extends AbstractLoggerVirtualTable<Operation>
4545
{
4646
private static final Logger logger = LoggerFactory.getLogger(SlowQueriesTable.class);
4747

48-
public static final int LOGS_VIRTUAL_TABLE_MIN_ROWS = 1000;
4948
public static final int LOGS_VIRTUAL_TABLE_DEFAULT_ROWS = 50_000;
5049
public static final int LOGS_VIRTUAL_TABLE_MAX_ROWS = 100_000;
5150

@@ -65,7 +64,6 @@ public class SlowQueriesTable extends AbstractLoggerVirtualTable<Operation>
6564
SlowQueriesTable(String keyspace)
6665
{
6766
this(keyspace, resolveBufferSize(CassandraRelevantProperties.LOGS_SLOW_QUERIES_VIRTUAL_TABLE_MAX_ROWS.getInt(),
68-
LOGS_VIRTUAL_TABLE_MIN_ROWS,
6967
LOGS_VIRTUAL_TABLE_MAX_ROWS,
7068
LOGS_VIRTUAL_TABLE_DEFAULT_ROWS));
7169
}
@@ -121,9 +119,9 @@ public DataSet data()
121119
{
122120
Operation operation = iterator.next();
123121

124-
result.row(operation.keyspace(), operation.table(), new Date(operation.timestamp()), operation.name())
125-
.column(MINIMUM_TIME_COLUMN_NAME, NANOSECONDS.toMillis(operation.minTime()))
126-
.column(MAXIMUM_TIME_COLUMN_NAME, NANOSECONDS.toMillis(operation.maxTime()))
122+
result.row(operation.keyspace(), operation.table(), new Date(operation.timestampMs()), operation.name())
123+
.column(MINIMUM_TIME_COLUMN_NAME, NANOSECONDS.toMillis(operation.minTimeNanos()))
124+
.column(MAXIMUM_TIME_COLUMN_NAME, NANOSECONDS.toMillis(operation.maxTimeNanos()))
127125
.column(AVERAGE_TIME_COLUMN_NAME, NANOSECONDS.toMillis(operation.averageTime()))
128126
.column(TIMES_REPORTED_COLUMN_NAME, operation.numTimesReported())
129127
.column(CROSS_NODE_COLUMN_NAME, operation.isCrossNode());
@@ -144,6 +142,9 @@ public List<Operation> getMessages(LoggingEvent event)
144142
String keyspace = operation.keyspace();
145143
String table = operation.table();
146144

145+
// in (improbable) case there is an operation which does not have
146+
// keyspace / table on it, we just skip this from processing
147+
// as we would have nothing to show for partition key and clustering column
147148
if (keyspace == null || table == null)
148149
continue;
149150

Diff for: src/java/org/apache/cassandra/utils/logging/AbstractVirtualTableAppender.java

+19-10
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,11 @@ protected AbstractLoggerVirtualTable<?> appendToVirtualTable(AbstractLoggerVirtu
108108
@Override
109109
public void stop()
110110
{
111-
messageBuffer.clear();
112-
super.stop();
111+
synchronized (messageBuffer)
112+
{
113+
messageBuffer.clear();
114+
super.stop();
115+
}
113116
}
114117

115118
/**
@@ -119,17 +122,23 @@ public void stop()
119122
*/
120123
public void flushBuffer(Class<? extends AbstractLoggerVirtualTable<?>> vtableClass, String tableName)
121124
{
122-
Optional.ofNullable(getVirtualTable(vtableClass, tableName)).ifPresent(vtable -> {
123-
messageBuffer.forEach(vtable::add);
124-
messageBuffer.clear();
125-
});
125+
synchronized (messageBuffer)
126+
{
127+
Optional.ofNullable(getVirtualTable(vtableClass, tableName)).ifPresent(vtable -> {
128+
messageBuffer.forEach(vtable::add);
129+
messageBuffer.clear();
130+
});
131+
}
126132
}
127133

128134
protected void addToBuffer(LoggingEvent eventObject)
129135
{
130-
// we restrict how many logging events we can put into buffer,
131-
// so we are not growing without any bound when things go south
132-
if (messageBuffer.size() < defaultRows)
133-
messageBuffer.add(eventObject);
136+
synchronized (messageBuffer)
137+
{
138+
// we restrict how many logging events we can put into buffer,
139+
// so we are not growing without any bound when things go south
140+
if (messageBuffer.size() < defaultRows)
141+
messageBuffer.add(eventObject);
142+
}
134143
}
135144
}

Diff for: src/java/org/apache/cassandra/utils/logging/SlowQueriesAppender.java

+4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ public SlowQueriesAppender()
3636
@Override
3737
protected void append(LoggingEvent eventObject)
3838
{
39+
// slowQueries will be null as long as virtual tables
40+
// are not registered, and we already try to put queries there.
41+
// As soon as vtable is registered (as part of node's startup / initialisation),
42+
// slow queries will never be null again
3943
slowQueries = appendToVirtualTable(slowQueries, eventObject, SlowQueriesTable.TABLE_NAME);
4044
}
4145
}

Diff for: test/unit/org/apache/cassandra/db/virtual/LogMessagesTableTest.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,13 @@ public void testResolvingBufferSize()
7777
assertEquals(LogMessagesTable.LOGS_VIRTUAL_TABLE_DEFAULT_ROWS, resolveBufferSize());
7878

7979
LOGS_VIRTUAL_TABLE_MAX_ROWS.setInt(0);
80-
assertEquals(LogMessagesTable.LOGS_VIRTUAL_TABLE_DEFAULT_ROWS, resolveBufferSize());
80+
assertEquals(0, resolveBufferSize());
8181

8282
LOGS_VIRTUAL_TABLE_MAX_ROWS.setInt(1000001);
8383
assertEquals(LogMessagesTable.LOGS_VIRTUAL_TABLE_DEFAULT_ROWS, resolveBufferSize());
8484

8585
LOGS_VIRTUAL_TABLE_MAX_ROWS.setInt(999);
86-
assertEquals(LogMessagesTable.LOGS_VIRTUAL_TABLE_DEFAULT_ROWS, resolveBufferSize());
86+
assertEquals(999, resolveBufferSize());
8787

8888
LOGS_VIRTUAL_TABLE_MAX_ROWS.setInt(50001);
8989
assertEquals(50001, resolveBufferSize());
@@ -92,7 +92,6 @@ public void testResolvingBufferSize()
9292
private int resolveBufferSize()
9393
{
9494
return AbstractLoggerVirtualTable.resolveBufferSize(CassandraRelevantProperties.LOGS_VIRTUAL_TABLE_MAX_ROWS.getInt(),
95-
LogMessagesTable.LOGS_VIRTUAL_TABLE_MIN_ROWS,
9695
LogMessagesTable.LOGS_VIRTUAL_TABLE_MAX_ROWS,
9796
LogMessagesTable.LOGS_VIRTUAL_TABLE_DEFAULT_ROWS);
9897
}
@@ -106,7 +105,7 @@ protected void registerTable(int maxSize)
106105
@Override
107106
protected void registerTable()
108107
{
109-
registerTable(LogMessagesTable.LOGS_VIRTUAL_TABLE_MIN_ROWS);
108+
registerTable(1000);
110109
}
111110

112111
@Override

Diff for: test/unit/org/apache/cassandra/db/virtual/SlowQueriesTableTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ protected void registerTable(int maxSize)
4848
@Override
4949
protected void registerTable()
5050
{
51-
registerTable(SlowQueriesTable.LOGS_VIRTUAL_TABLE_MIN_ROWS);
51+
registerTable(1000);
5252
}
5353

5454
@Test

0 commit comments

Comments
 (0)