Search in sources :

Example 1 with KeyCacheKey

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;
}
Also used : FileDataInput(org.apache.cassandra.io.util.FileDataInput) KeyCacheKey(org.apache.cassandra.cache.KeyCacheKey) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer)

Example 2 with KeyCacheKey

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);
}
Also used : CachingParams(org.apache.cassandra.schema.CachingParams) KeyCacheKey(org.apache.cassandra.cache.KeyCacheKey)

Example 3 with KeyCacheKey

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));
    }
}
Also used : CacheMetrics(org.apache.cassandra.metrics.CacheMetrics) TableMetadataRef(org.apache.cassandra.schema.TableMetadataRef) KeyCacheKey(org.apache.cassandra.cache.KeyCacheKey)

Example 4 with KeyCacheKey

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);
        }
    });
}
Also used : HashMap(java.util.HashMap) KeyCacheKey(org.apache.cassandra.cache.KeyCacheKey) IOException(java.io.IOException) SSTableReader(org.apache.cassandra.io.sstable.format.SSTableReader) HashMap(java.util.HashMap) Map(java.util.Map)

Example 5 with KeyCacheKey

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);
}
Also used : KeyCacheKey(org.apache.cassandra.cache.KeyCacheKey)

Aggregations

KeyCacheKey (org.apache.cassandra.cache.KeyCacheKey)10 IOException (java.io.IOException)2 HashMap (java.util.HashMap)2 ColumnFamilyStore (org.apache.cassandra.db.ColumnFamilyStore)2 SSTableReader (org.apache.cassandra.io.sstable.format.SSTableReader)2 ByteBuffer (java.nio.ByteBuffer)1 ArrayList (java.util.ArrayList)1 Map (java.util.Map)1 MBeanServer (javax.management.MBeanServer)1 MalformedObjectNameException (javax.management.MalformedObjectNameException)1 ObjectName (javax.management.ObjectName)1 RowCacheKey (org.apache.cassandra.cache.RowCacheKey)1 JMXEnabledThreadPoolExecutorMBean (org.apache.cassandra.concurrent.JMXEnabledThreadPoolExecutorMBean)1 CFMetaData (org.apache.cassandra.config.CFMetaData)1 ColumnFamily (org.apache.cassandra.db.ColumnFamily)1 RowIndexEntry (org.apache.cassandra.db.RowIndexEntry)1 RowUpdateBuilder (org.apache.cassandra.db.RowUpdateBuilder)1 FileDataInput (org.apache.cassandra.io.util.FileDataInput)1 CacheMetrics (org.apache.cassandra.metrics.CacheMetrics)1 CachingParams (org.apache.cassandra.schema.CachingParams)1