ensure that directory is selected for compaction

patch by Aaron Morton; reviewed by Pavel Yaskevich for CASSANDRA-3985
This commit is contained in:
Pavel Yaskevich 2012-03-22 15:40:29 +03:00
parent 5a3d4c14b2
commit fbdf7b03c7
4 changed files with 64 additions and 45 deletions

View File

@ -10,6 +10,7 @@
* don't change manifest level for cleanup, scrub, and upgradesstables
operations under LeveledCompactionStrategy (CASSANDRA-3989)
* fix race leading to super columns assertion failure (CASSANDRA-3957)
* ensure that directory is selected for compaction (CASSANDRA-3985)
1.0.8

View File

@ -63,8 +63,6 @@ public class DatabaseDescriptor
private static InetAddress broadcastAddress;
private static InetAddress rpcAddress;
private static SeedProvider seedProvider;
/* Current index into the above list of directories */
private static int currentIndex = 0;
/* Hashing strategy Random or OPHF */
private static IPartitioner partitioner;
@ -741,12 +739,6 @@ public class DatabaseDescriptor
return tableLocations;
}
public synchronized static String getNextAvailableDataLocation()
{
String dataFileDirectory = conf.data_file_directories[currentIndex];
currentIndex = (currentIndex + 1) % conf.data_file_directories.length;
return dataFileDirectory;
}
public static String getCommitLogLocation()
{
@ -763,41 +755,57 @@ public class DatabaseDescriptor
return Collections.unmodifiableSet(new HashSet(seedProvider.getSeeds()));
}
public synchronized static String getDataFileLocationForTable(String table, long expectedCompactedFileSize)
{
return getDataFileLocationForTable(table, expectedCompactedFileSize, true);
}
/*
* Loop through all the disks to see which disk has the max free space
* return the disk with max free space for compactions. If the size of the expected
* compacted file is greater than the max disk space available return null, we cannot
* do compaction in this case.
*
* @param table name of the table.
* @param expectedCompactedSize expected file size in bytes.
* @param ensureFreeSpace Flag if the function should ensure enough free space exists for the expected file size.
* If False and there is not enough free space a warning is logged, and the dir with the most space is returned.
*/
public static String getDataFileLocationForTable(String table, long expectedCompactedFileSize)
public synchronized static String getDataFileLocationForTable(String table, long expectedCompactedFileSize, boolean ensureFreeSpace)
{
long maxFreeDisk = 0;
int maxDiskIndex = 0;
String dataFileDirectory = null;
String[] dataDirectoryForTable = getAllDataFileLocationsForTable(table);
long maxFreeDisk = 0;
int maxDiskIndex = 0;
String dataFileDirectory = null;
String[] dataDirectoryForTable = getAllDataFileLocationsForTable(table);
for ( int i = 0 ; i < dataDirectoryForTable.length ; i++ )
{
File f = new File(dataDirectoryForTable[i]);
if( maxFreeDisk < f.getUsableSpace())
for (int i = 0; i < dataDirectoryForTable.length; i++)
{
maxFreeDisk = f.getUsableSpace();
maxDiskIndex = i;
File f = new File(dataDirectoryForTable[i]);
if (maxFreeDisk < f.getUsableSpace())
{
maxFreeDisk = f.getUsableSpace();
maxDiskIndex = i;
}
}
}
logger.debug("expected data files size is {}; largest free partition has {} bytes free",
expectedCompactedFileSize, maxFreeDisk);
// Load factor of 0.9 we do not want to use the entire disk that is too risky.
maxFreeDisk = (long)(0.9 * maxFreeDisk);
if( expectedCompactedFileSize < maxFreeDisk )
{
dataFileDirectory = dataDirectoryForTable[maxDiskIndex];
currentIndex = (maxDiskIndex + 1 )%dataDirectoryForTable.length ;
}
else
{
currentIndex = maxDiskIndex;
}
expectedCompactedFileSize,
maxFreeDisk);
// Load factor of 0.9 we do not want to use the entire disk that is too risky.
maxFreeDisk = (long) (0.9 * maxFreeDisk);
if (!ensureFreeSpace || expectedCompactedFileSize < maxFreeDisk)
{
dataFileDirectory = dataDirectoryForTable[maxDiskIndex];
if (expectedCompactedFileSize >= maxFreeDisk)
logger.warn(String.format("Data file location %s only has %d free, expected size is %d",
dataFileDirectory,
maxFreeDisk,
expectedCompactedFileSize));
}
return dataFileDirectory;
}

View File

@ -556,7 +556,12 @@ public class Table
public String getDataFileLocation(long expectedSize)
{
String path = DatabaseDescriptor.getDataFileLocationForTable(name, expectedSize);
return getDataFileLocation(expectedSize, true);
}
public String getDataFileLocation(long expectedSize, boolean ensureFreeSpace)
{
String path = DatabaseDescriptor.getDataFileLocationForTable(name, expectedSize, ensureFreeSpace);
// Requesting GC has a chance to free space only if we're using mmap and a non SUN jvm
if (path == null
&& (DatabaseDescriptor.getDiskAccessMode() == Config.DiskAccessMode.mmap || DatabaseDescriptor.getIndexAccessMode() == Config.DiskAccessMode.mmap)
@ -574,7 +579,7 @@ public class Table
{
throw new AssertionError(e);
}
path = DatabaseDescriptor.getDataFileLocationForTable(name, expectedSize);
path = DatabaseDescriptor.getDataFileLocationForTable(name, expectedSize, ensureFreeSpace);
}
return path;
}

View File

@ -77,21 +77,20 @@ public class CompactionTask extends AbstractCompactionTask
return 0;
if (compactionFileLocation == null)
compactionFileLocation = cfs.table.getDataFileLocation(cfs.getExpectedCompactedFileSize(toCompact));
if (partialCompactionsAcceptable())
compactionFileLocation = cfs.table.getDataFileLocation(cfs.getExpectedCompactedFileSize(toCompact), ensureFreeSpace());
if (compactionFileLocation == null && partialCompactionsAcceptable())
{
// If the compaction file path is null that means we have no space left for this compaction.
// Try again w/o the largest one.
if (compactionFileLocation == null)
while (compactionFileLocation == null && toCompact.size() > 1)
{
while (compactionFileLocation == null && toCompact.size() > 1)
{
logger.warn("insufficient space to compact all requested files " + StringUtils.join(toCompact, ", "));
// Note that we have removed files that are still marked as compacting. This suboptimal but ok since the caller will unmark all
// the sstables at the end.
toCompact.remove(cfs.getMaxSizeFile(toCompact));
compactionFileLocation = cfs.table.getDataFileLocation(cfs.getExpectedCompactedFileSize(toCompact));
}
logger.warn("insufficient space to compact all requested files " + StringUtils.join(toCompact, ", "));
// Note that we have removed files that are still marked as compacting.
// This suboptimal but ok since the caller will unmark all the sstables at the end.
toCompact.remove(cfs.getMaxSizeFile(toCompact));
compactionFileLocation = cfs.table.getDataFileLocation(cfs.getExpectedCompactedFileSize(toCompact),
ensureFreeSpace());
}
if (compactionFileLocation == null)
@ -100,6 +99,7 @@ public class CompactionTask extends AbstractCompactionTask
return 0;
}
}
assert compactionFileLocation != null;
if (DatabaseDescriptor.isSnapshotBeforeCompaction())
cfs.snapshotWithoutFlush(System.currentTimeMillis() + "-" + "compact-" + cfs.columnFamily);
@ -231,6 +231,11 @@ public class CompactionTask extends AbstractCompactionTask
return !isUserDefined;
}
protected boolean ensureFreeSpace()
{
return !isUserDefined;
}
//extensibility point for other strategies that may want to limit the upper bounds of the sstable segment size
protected boolean newSSTableSegmentThresholdReached(SSTableWriter writer, long position)
{