If SizeEstimatesRecorder misses a 'onDropTable' notification, the size_estimates table will never be cleared for that table.

Patch by Joel Knighton; Reviewed by Ariel Weisberg for CASSANDRA-14905

Co-authored-by: Joel Knighton <jkni@apache.org>
Co-authored-by: Aleksandr Sorokoumov <aleksandr.sorokoumov@gmail.com>
This commit is contained in:
Joel Knighton 2017-09-12 17:48:07 -05:00 committed by Ariel Weisberg
parent ebfa280fac
commit ddbcff3363
5 changed files with 64 additions and 7 deletions

View File

@ -1,4 +1,5 @@
3.0.18
* If SizeEstimatesRecorder misses a 'onDropTable' notification, the size_estimates table will never be cleared for that table. (CASSANDRA-14905)
* Counters fail to increment in 2.1/2.2 to 3.X mixed version clusters (CASSANDRA-14958)
* Streaming needs to synchronise access to LifecycleTransaction (CASSANDRA-14554)
* Fix cassandra-stress write hang with default options (CASSANDRA-14616)

View File

@ -1236,6 +1236,32 @@ public final class SystemKeyspace
executeInternal(cql, keyspace, table);
}
/**
* Clears size estimates for a keyspace (used to manually clean when we miss a keyspace drop)
*/
public static void clearSizeEstimates(String keyspace)
{
String cql = String.format("DELETE FROM %s.%s WHERE keyspace_name = ?", NAME, SIZE_ESTIMATES);
executeInternal(cql, keyspace);
}
/**
* @return A multimap from keyspace to table for all tables with entries in size estimates
*/
public static synchronized SetMultimap<String, String> getTablesWithSizeEstimates()
{
SetMultimap<String, String> keyspaceTableMap = HashMultimap.create();
String cql = String.format("SELECT keyspace_name, table_name FROM %s.%s", NAME, SIZE_ESTIMATES);
UntypedResultSet rs = executeInternal(cql);
for (UntypedResultSet.Row row : rs)
{
keyspaceTableMap.put(row.getString("keyspace_name"), row.getString("table_name"));
}
return keyspaceTableMap;
}
public static synchronized void updateAvailableRanges(String keyspace, Collection<Range<Token>> completedRanges)
{
String cql = "UPDATE system.%s SET ranges = ranges + ? WHERE keyspace_name = ?";

View File

@ -336,9 +336,17 @@ public class CassandraDaemon
ScheduledExecutors.optionalTasks.schedule(viewRebuild, StorageService.RING_DELAY, TimeUnit.MILLISECONDS);
SystemKeyspace.finishStartup();
// Clean up system.size_estimates entries left lying around from missed keyspace drops (CASSANDRA-14905)
StorageService.instance.cleanupSizeEstimates();
// schedule periodic dumps of table size estimates into SystemKeyspace.SIZE_ESTIMATES_CF
// set cassandra.size_recorder_interval to 0 to disable
int sizeRecorderInterval = Integer.getInteger("cassandra.size_recorder_interval", 5 * 60);
if (sizeRecorderInterval > 0)
ScheduledExecutors.optionalTasks.scheduleWithFixedDelay(SizeEstimatesRecorder.instance, 30, sizeRecorderInterval, TimeUnit.SECONDS);
// start server internals
StorageService.instance.registerDaemon(this);
try
@ -380,12 +388,6 @@ public class CassandraDaemon
// due to scheduling errors or race conditions
ScheduledExecutors.optionalTasks.scheduleWithFixedDelay(ColumnFamilyStore.getBackgroundCompactionTaskSubmitter(), 5, 1, TimeUnit.MINUTES);
// schedule periodic dumps of table size estimates into SystemKeyspace.SIZE_ESTIMATES_CF
// set cassandra.size_recorder_interval to 0 to disable
int sizeRecorderInterval = Integer.getInteger("cassandra.size_recorder_interval", 5 * 60);
if (sizeRecorderInterval > 0)
ScheduledExecutors.optionalTasks.scheduleWithFixedDelay(SizeEstimatesRecorder.instance, 30, sizeRecorderInterval, TimeUnit.SECONDS);
// Thrift
InetAddress rpcAddr = DatabaseDescriptor.getRpcAddress();
int rpcPort = DatabaseDescriptor.getRpcPort();

View File

@ -3038,9 +3038,32 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
public void refreshSizeEstimates() throws ExecutionException
{
cleanupSizeEstimates();
FBUtilities.waitOnFuture(ScheduledExecutors.optionalTasks.submit(SizeEstimatesRecorder.instance));
}
public void cleanupSizeEstimates()
{
SetMultimap<String, String> sizeEstimates = SystemKeyspace.getTablesWithSizeEstimates();
for (Entry<String, Collection<String>> tablesByKeyspace : sizeEstimates.asMap().entrySet())
{
String keyspace = tablesByKeyspace.getKey();
if (!Schema.instance.getKeyspaces().contains(keyspace))
{
SystemKeyspace.clearSizeEstimates(keyspace);
}
else
{
for (String table : tablesByKeyspace.getValue())
{
if (!Schema.instance.hasCF(Pair.create(keyspace, table)))
SystemKeyspace.clearSizeEstimates(keyspace, table);
}
}
}
}
/**
* @param allowIndexes Allow index CF names to be passed in
* @param autoAddIndexes Automatically add secondary indexes if a CF has them

View File

@ -243,6 +243,11 @@ public interface StorageServiceMBean extends NotificationEmitter
*/
public void refreshSizeEstimates() throws ExecutionException;
/**
* Removes extraneous entries in system.size_estimates.
*/
public void cleanupSizeEstimates();
/**
* Forces major compaction of a single keyspace
*/