use of org.apache.cassandra.cache.KeyCacheKey in project cassandra by apache.
the class BigTableReader method getPosition.
/**
* @param key The key to apply as the rhs to the given Operator. A 'fake' key is allowed to
* allow key selection by token bounds but only if op != * EQ
* @param op The Operator defining matching keys: the nearest key to the target matching the operator wins.
* @param updateCacheAndStats true if updating stats and cache
* @return The index entry corresponding to the key, or null if the key is not present
*/
protected RowIndexEntry getPosition(PartitionPosition key, Operator op, boolean updateCacheAndStats, boolean permitMatchPastLast) {
if (op == Operator.EQ) {
// EQ only make sense if the key is a valid row key
assert key instanceof DecoratedKey;
if (!bf.isPresent((DecoratedKey) key)) {
Tracing.trace("Bloom filter allows skipping sstable {}", descriptor.generation);
return null;
}
}
// next, the key cache (only make sense for valid row key)
if ((op == Operator.EQ || op == Operator.GE) && (key instanceof DecoratedKey)) {
DecoratedKey decoratedKey = (DecoratedKey) key;
KeyCacheKey cacheKey = new KeyCacheKey(metadata(), descriptor, decoratedKey.getKey());
RowIndexEntry cachedPosition = getCachedPosition(cacheKey, updateCacheAndStats);
if (cachedPosition != null) {
Tracing.trace("Key cache hit for sstable {}", descriptor.generation);
return cachedPosition;
}
}
// check the smallest and greatest keys in the sstable to see if it can't be present
boolean skip = false;
if (key.compareTo(first) < 0) {
if (op == Operator.EQ)
skip = true;
else
key = first;
op = Operator.EQ;
} else {
int l = last.compareTo(key);
// l <= 0 => we may be looking past the end of the file; we then narrow our behaviour to:
// 1) skipping if strictly greater for GE and EQ;
// 2) skipping if equal and searching GT, and we aren't permitting matching past last
skip = l <= 0 && (l < 0 || (!permitMatchPastLast && op == Operator.GT));
}
if (skip) {
if (op == Operator.EQ && updateCacheAndStats)
bloomFilterTracker.addFalsePositive();
Tracing.trace("Check against min and max keys allows skipping sstable {}", descriptor.generation);
return null;
}
int binarySearchResult = indexSummary.binarySearch(key);
long sampledPosition = getIndexScanPositionFromBinarySearchResult(binarySearchResult, indexSummary);
int sampledIndex = getIndexSummaryIndexFromBinarySearchResult(binarySearchResult);
int effectiveInterval = indexSummary.getEffectiveIndexIntervalAfterIndex(sampledIndex);
if (ifile == null)
return null;
// scan the on-disk index, starting at the nearest sampled position.
// The check against IndexInterval is to be exit the loop in the EQ case when the key looked for is not present
// (bloom filter false positive). But note that for non-EQ cases, we might need to check the first key of the
// next index position because the searched key can be greater the last key of the index interval checked if it
// is lesser than the first key of next interval (and in that case we must return the position of the first key
// of the next interval).
int i = 0;
String path = null;
try (FileDataInput in = ifile.createReader(sampledPosition)) {
path = in.getPath();
while (!in.isEOF()) {
i++;
ByteBuffer indexKey = ByteBufferUtil.readWithShortLength(in);
// did we find an appropriate position for the op requested
boolean opSatisfied;
// is the current position an exact match for the key, suitable for caching
boolean exactMatch;
// Compare raw keys if possible for performance, otherwise compare decorated keys.
if (op == Operator.EQ && i <= effectiveInterval) {
opSatisfied = exactMatch = indexKey.equals(((DecoratedKey) key).getKey());
} else {
DecoratedKey indexDecoratedKey = decorateKey(indexKey);
int comparison = indexDecoratedKey.compareTo(key);
int v = op.apply(comparison);
opSatisfied = (v == 0);
exactMatch = (comparison == 0);
if (v < 0) {
Tracing.trace("Partition index lookup allows skipping sstable {}", descriptor.generation);
return null;
}
}
if (opSatisfied) {
// read data position from index entry
RowIndexEntry indexEntry = rowIndexEntrySerializer.deserialize(in, in.getFilePointer());
if (exactMatch && updateCacheAndStats) {
// key can be == to the index key only if it's a true row key
assert key instanceof DecoratedKey;
DecoratedKey decoratedKey = (DecoratedKey) key;
if (logger.isTraceEnabled()) {
// expensive sanity check! see CASSANDRA-4687
try (FileDataInput fdi = dfile.createReader(indexEntry.position)) {
DecoratedKey keyInDisk = decorateKey(ByteBufferUtil.readWithShortLength(fdi));
if (!keyInDisk.equals(key))
throw new AssertionError(String.format("%s != %s in %s", keyInDisk, key, fdi.getPath()));
}
}
// store exact match for the key
cacheKey(decoratedKey, indexEntry);
}
if (op == Operator.EQ && updateCacheAndStats)
bloomFilterTracker.addTruePositive();
Tracing.trace("Partition index with {} entries found for sstable {}", indexEntry.columnsIndexCount(), descriptor.generation);
return indexEntry;
}
RowIndexEntry.Serializer.skip(in, descriptor.version);
}
} catch (IOException e) {
markSuspect();
throw new CorruptSSTableException(e, path);
}
if (op == SSTableReader.Operator.EQ && updateCacheAndStats)
bloomFilterTracker.addFalsePositive();
Tracing.trace("Partition index lookup complete (bloom filter false positive) for sstable {}", descriptor.generation);
return null;
}
use of org.apache.cassandra.cache.KeyCacheKey in project cassandra by apache.
the class SSTableReader method cacheKey.
public void cacheKey(DecoratedKey key, RowIndexEntry info) {
CachingParams caching = metadata().params.caching;
if (!caching.cacheKeys() || keyCache == null || keyCache.getCapacity() == 0)
return;
KeyCacheKey cacheKey = new KeyCacheKey(metadata(), descriptor, key.getKey());
logger.trace("Adding cache entry for {} -> {}", cacheKey, info);
keyCache.put(cacheKey, info);
}
use of org.apache.cassandra.cache.KeyCacheKey in project cassandra by apache.
the class KeyCacheCqlTest method test2iKeyCachePathsSaveKeysForDroppedTable.
private void test2iKeyCachePathsSaveKeysForDroppedTable() throws Throwable {
String table = createTable("CREATE TABLE %s (" + commonColumnsDef + "PRIMARY KEY ((part_key_a, part_key_b),clust_key_a,clust_key_b,clust_key_c))");
String indexName = createIndex("CREATE INDEX ON %s (col_int)");
insertData(table, indexName, true);
clearCache();
CacheMetrics metrics = CacheService.instance.keyCache.getMetrics();
long expectedNumberOfRequests = 0;
for (int i = 0; i < 10; i++) {
UntypedResultSet result = execute("SELECT part_key_a FROM %s WHERE col_int = ?", i);
assertEquals(500, result.size());
// Index requests and table requests are both added to the same metric
// We expect 10 requests on the index SSTables and 10 IN requests on the table SSTables + BF false positives
expectedNumberOfRequests += recentBloomFilterFalsePositives() + 20;
}
long hits = metrics.hits.getCount();
long requests = metrics.requests.getCount();
assertEquals(0, hits);
assertEquals(expectedNumberOfRequests, requests);
for (int i = 0; i < 10; i++) {
UntypedResultSet result = execute("SELECT part_key_a FROM %s WHERE col_int = ?", i);
// 100 part-keys * 50 clust-keys
// indexed on part-key % 10 = 10 index partitions
// (50 clust-keys * 100-part-keys / 10 possible index-values) = 500
assertEquals(500, result.size());
// Index requests and table requests are both added to the same metric
// We expect 10 requests on the index SSTables and 10 IN requests on the table SSTables + BF false positives
expectedNumberOfRequests += recentBloomFilterFalsePositives() + 20;
}
metrics = CacheService.instance.keyCache.getMetrics();
hits = metrics.hits.getCount();
requests = metrics.requests.getCount();
assertEquals(200, hits);
assertEquals(expectedNumberOfRequests, requests);
dropTable("DROP TABLE %s");
CacheService.instance.keyCache.submitWrite(Integer.MAX_VALUE).get();
CacheService.instance.keyCache.clear();
Assert.assertEquals(0, CacheService.instance.keyCache.size());
// then load saved
CacheService.instance.keyCache.loadSaved();
Iterator<KeyCacheKey> iter = CacheService.instance.keyCache.keyIterator();
while (iter.hasNext()) {
KeyCacheKey key = iter.next();
TableMetadataRef tableMetadataRef = Schema.instance.getTableMetadataRef(key.tableId);
Assert.assertFalse(tableMetadataRef.keyspace.equals("KEYSPACE_PER_TEST"));
Assert.assertFalse(tableMetadataRef.name.startsWith(table));
}
}
use of org.apache.cassandra.cache.KeyCacheKey in project cassandra by apache.
the class KeyCacheTest method testKeyCacheLoad.
private void testKeyCacheLoad(String cf) throws Exception {
CompactionManager.instance.disableAutoCompaction();
ColumnFamilyStore store = Keyspace.open(KEYSPACE1).getColumnFamilyStore(cf);
// empty the cache
CacheService.instance.invalidateKeyCache();
assertKeyCacheSize(0, KEYSPACE1, cf);
// insert data and force to disk
SchemaLoader.insertData(KEYSPACE1, cf, 0, 100);
store.forceBlockingFlush();
// populate the cache
readData(KEYSPACE1, cf, 0, 100);
assertKeyCacheSize(100, KEYSPACE1, cf);
// really? our caches don't implement the map interface? (hence no .addAll)
Map<KeyCacheKey, RowIndexEntry> savedMap = new HashMap<>();
Map<KeyCacheKey, RowIndexEntry.IndexInfoRetriever> savedInfoMap = new HashMap<>();
for (Iterator<KeyCacheKey> iter = CacheService.instance.keyCache.keyIterator(); iter.hasNext(); ) {
KeyCacheKey k = iter.next();
if (k.desc.ksname.equals(KEYSPACE1) && k.desc.cfname.equals(cf)) {
RowIndexEntry rie = CacheService.instance.keyCache.get(k);
savedMap.put(k, rie);
SSTableReader sstr = readerForKey(k);
savedInfoMap.put(k, rie.openWithIndex(sstr.getIndexFile()));
}
}
// force the cache to disk
CacheService.instance.keyCache.submitWrite(Integer.MAX_VALUE).get();
CacheService.instance.invalidateKeyCache();
assertKeyCacheSize(0, KEYSPACE1, cf);
CacheService.instance.keyCache.loadSaved();
assertKeyCacheSize(savedMap.size(), KEYSPACE1, cf);
// probably it's better to add equals/hashCode to RowIndexEntry...
for (Map.Entry<KeyCacheKey, RowIndexEntry> entry : savedMap.entrySet()) {
RowIndexEntry expected = entry.getValue();
RowIndexEntry actual = CacheService.instance.keyCache.get(entry.getKey());
assertEquals(expected.position, actual.position);
assertEquals(expected.columnsIndexCount(), actual.columnsIndexCount());
for (int i = 0; i < expected.columnsIndexCount(); i++) {
SSTableReader actualSstr = readerForKey(entry.getKey());
try (RowIndexEntry.IndexInfoRetriever actualIir = actual.openWithIndex(actualSstr.getIndexFile())) {
RowIndexEntry.IndexInfoRetriever expectedIir = savedInfoMap.get(entry.getKey());
assertEquals(expectedIir.columnsIndex(i), actualIir.columnsIndex(i));
}
}
if (expected.isIndexed()) {
assertEquals(expected.deletionTime(), actual.deletionTime());
}
}
savedInfoMap.values().forEach(iir -> {
try {
if (iir != null)
iir.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
use of org.apache.cassandra.cache.KeyCacheKey in project cassandra by apache.
the class KeyCacheTest method assertKeyCacheSize.
private void assertKeyCacheSize(int expected, String keyspace, String columnFamily) {
int size = 0;
for (Iterator<KeyCacheKey> iter = CacheService.instance.keyCache.keyIterator(); iter.hasNext(); ) {
KeyCacheKey k = iter.next();
if (k.desc.ksname.equals(keyspace) && k.desc.cfname.equals(columnFamily))
size++;
}
assertEquals(expected, size);
}
Aggregations