diff --git a/CHANGES.txt b/CHANGES.txt index cc6478e3f1..99a5d51f84 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.0 + * Serializing Row cache alternative, fully off heap (CASSANDRA-7438) * Duplicate rows returned when in clause has repeated values (CASSANDRA-6707) * Make CassandraException unchecked, extend RuntimeException (CASSANDRA-8560) * Support direct buffer decompression for reads (CASSANDRA-8464) diff --git a/NOTICE.txt b/NOTICE.txt index 2fe15f5f61..43d45141be 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -66,3 +66,8 @@ Javassist SIGAR http://sigar.hyperic.com/ + +OHC +(https://github.com/snazy/ohc) +Java Off-Heap-Cache, licensed under APLv2 +Copyright 2014-2015 Robert Stupp, Germany. diff --git a/build.xml b/build.xml index baf6a77e70..fccd009299 100644 --- a/build.xml +++ b/build.xml @@ -375,6 +375,7 @@ + @@ -424,10 +425,10 @@ + - extends InstrumentingCache saveTask; protected final CacheService.CacheType cacheType; - private CacheSerializer cacheLoader; + private final CacheSerializer cacheLoader; private static final String CURRENT_VERSION = "b"; private static volatile IStreamFactory streamFactory = new IStreamFactory() @@ -177,16 +177,24 @@ public class AutoSavingCache extends InstrumentingCache keys; + private final Iterator keyIterator; private final CompactionInfo info; private long keysWritten; + private final long keysEstimate; protected Writer(int keysToSave) { - if (keysToSave >= getKeySet().size()) - keys = getKeySet(); + int size = size(); + if (keysToSave >= size || keysToSave == 0) + { + keyIterator = keyIterator(); + keysEstimate = size; + } else - keys = hotKeySet(keysToSave); + { + keyIterator = hotKeyIterator(keysToSave); + keysEstimate = keysToSave; + } OperationType type; if (cacheType == CacheService.CacheType.KEY_CACHE) @@ -201,7 +209,7 @@ public class AutoSavingCache extends InstrumentingCache extends InstrumentingCache extends InstrumentingCache extends InstrumentingCache extends InstrumentingCache= keysEstimate) + break; } } finally { + if (keyIterator instanceof Closeable) + try + { + ((Closeable)keyIterator).close(); + } + catch (IOException ignored) + { + // not thrown (by OHC) + } + for (OutputStream writer : streams.values()) FileUtils.closeQuietly(writer); } @@ -290,7 +312,7 @@ public class AutoSavingCache extends InstrumentingCache +{ + ICache create(); +} diff --git a/src/java/org/apache/cassandra/cache/ConcurrentLinkedHashCache.java b/src/java/org/apache/cassandra/cache/ConcurrentLinkedHashCache.java index 81824477b7..bb14055fca 100644 --- a/src/java/org/apache/cassandra/cache/ConcurrentLinkedHashCache.java +++ b/src/java/org/apache/cassandra/cache/ConcurrentLinkedHashCache.java @@ -17,7 +17,7 @@ */ package org.apache.cassandra.cache; -import java.util.Set; +import java.util.Iterator; import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap; import com.googlecode.concurrentlinkedhashmap.EntryWeigher; @@ -45,7 +45,7 @@ public class ConcurrentLinkedHashCache(map); + return new ConcurrentLinkedHashCache<>(map); } public static ConcurrentLinkedHashCache create(long weightedCapacity) @@ -116,14 +116,14 @@ public class ConcurrentLinkedHashCache keySet() + public Iterator keyIterator() { - return map.keySet(); + return map.keySet().iterator(); } - public Set hotKeySet(int n) + public Iterator hotKeyIterator(int n) { - return map.descendingKeySetWithLimit(n); + return map.descendingKeySetWithLimit(n).iterator(); } public boolean containsKey(K key) diff --git a/src/java/org/apache/cassandra/cache/ICache.java b/src/java/org/apache/cassandra/cache/ICache.java index 22dbb16a1e..37b55cd0e7 100644 --- a/src/java/org/apache/cassandra/cache/ICache.java +++ b/src/java/org/apache/cassandra/cache/ICache.java @@ -17,7 +17,7 @@ */ package org.apache.cassandra.cache; -import java.util.Set; +import java.util.Iterator; /** * This is similar to the Map interface, but requires maintaining a given capacity @@ -46,9 +46,9 @@ public interface ICache public void clear(); - public Set keySet(); + public Iterator keyIterator(); - public Set hotKeySet(int n); + public Iterator hotKeyIterator(int n); public boolean containsKey(K key); } diff --git a/src/java/org/apache/cassandra/cache/InstrumentingCache.java b/src/java/org/apache/cassandra/cache/InstrumentingCache.java index 311b373379..c8728fd243 100644 --- a/src/java/org/apache/cassandra/cache/InstrumentingCache.java +++ b/src/java/org/apache/cassandra/cache/InstrumentingCache.java @@ -17,7 +17,7 @@ */ package org.apache.cassandra.cache; -import java.util.Set; +import java.util.Iterator; import org.apache.cassandra.metrics.CacheMetrics; @@ -26,7 +26,6 @@ import org.apache.cassandra.metrics.CacheMetrics; */ public class InstrumentingCache { - private volatile boolean capacitySetManually; private final ICache map; private final String type; @@ -78,20 +77,9 @@ public class InstrumentingCache return map.capacity(); } - public boolean isCapacitySetManually() - { - return capacitySetManually; - } - - public void updateCapacity(long capacity) - { - map.setCapacity(capacity); - } - public void setCapacity(long capacity) { - updateCapacity(capacity); - capacitySetManually = true; + map.setCapacity(capacity); } public int size() @@ -110,14 +98,14 @@ public class InstrumentingCache metrics = new CacheMetrics(type, map); } - public Set getKeySet() + public Iterator keyIterator() { - return map.keySet(); + return map.keyIterator(); } - public Set hotKeySet(int n) + public Iterator hotKeyIterator(int n) { - return map.hotKeySet(n); + return map.hotKeyIterator(n); } public boolean containsKey(K key) diff --git a/src/java/org/apache/cassandra/cache/NopCacheProvider.java b/src/java/org/apache/cassandra/cache/NopCacheProvider.java new file mode 100644 index 0000000000..20f837a506 --- /dev/null +++ b/src/java/org/apache/cassandra/cache/NopCacheProvider.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cassandra.cache; + +import java.util.Collections; +import java.util.Iterator; + +public class NopCacheProvider implements CacheProvider +{ + public ICache create() + { + return new NopCache(); + } + + private static class NopCache implements ICache + { + public long capacity() + { + return 0; + } + + public void setCapacity(long capacity) + { + } + + public void put(RowCacheKey key, IRowCacheEntry value) + { + } + + public boolean putIfAbsent(RowCacheKey key, IRowCacheEntry value) + { + return false; + } + + public boolean replace(RowCacheKey key, IRowCacheEntry old, IRowCacheEntry value) + { + return false; + } + + public IRowCacheEntry get(RowCacheKey key) + { + return null; + } + + public void remove(RowCacheKey key) + { + } + + public int size() + { + return 0; + } + + public long weightedSize() + { + return 0; + } + + public void clear() + { + } + + public Iterator hotKeyIterator(int n) + { + return Collections.emptyIterator(); + } + + public Iterator keyIterator() + { + return Collections.emptyIterator(); + } + + public boolean containsKey(RowCacheKey key) + { + return false; + } + } +} diff --git a/src/java/org/apache/cassandra/cache/OHCProvider.java b/src/java/org/apache/cassandra/cache/OHCProvider.java new file mode 100644 index 0000000000..365ca41bb5 --- /dev/null +++ b/src/java/org/apache/cassandra/cache/OHCProvider.java @@ -0,0 +1,274 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cassandra.cache; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Iterator; +import java.util.UUID; + +import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.db.ColumnFamily; +import org.apache.cassandra.db.TypeSizes; +import org.apache.cassandra.io.util.DataOutputPlus; +import org.apache.cassandra.io.util.Memory; +import org.apache.cassandra.net.MessagingService; +import org.caffinitas.ohc.OHCache; +import org.caffinitas.ohc.OHCacheBuilder; + +public class OHCProvider implements CacheProvider +{ + public ICache create() + { + OHCacheBuilder builder = OHCacheBuilder.newBuilder(); + builder.capacity(DatabaseDescriptor.getRowCacheSizeInMB() * 1024 * 1024) + .keySerializer(new KeySerializer()) + .valueSerializer(new ValueSerializer()) + .throwOOME(true); + + return new OHCacheAdapter(builder.build()); + } + + private static class OHCacheAdapter implements ICache + { + private final OHCache ohCache; + + public OHCacheAdapter(OHCache ohCache) + { + this.ohCache = ohCache; + } + + public long capacity() + { + return ohCache.capacity(); + } + + public void setCapacity(long capacity) + { + ohCache.setCapacity(capacity); + } + + public void put(RowCacheKey key, IRowCacheEntry value) + { + ohCache.put(key, value); + } + + public boolean putIfAbsent(RowCacheKey key, IRowCacheEntry value) + { + return ohCache.putIfAbsent(key, value); + } + + public boolean replace(RowCacheKey key, IRowCacheEntry old, IRowCacheEntry value) + { + return ohCache.addOrReplace(key, old, value); + } + + public IRowCacheEntry get(RowCacheKey key) + { + return ohCache.get(key); + } + + public void remove(RowCacheKey key) + { + ohCache.remove(key); + } + + public int size() + { + return (int) ohCache.size(); + } + + public long weightedSize() + { + return ohCache.size(); + } + + public void clear() + { + ohCache.clear(); + } + + public Iterator hotKeyIterator(int n) + { + return ohCache.hotKeyIterator(n); + } + + public Iterator keyIterator() + { + return ohCache.keyIterator(); + } + + public boolean containsKey(RowCacheKey key) + { + return ohCache.containsKey(key); + } + } + + private static class KeySerializer implements org.caffinitas.ohc.CacheSerializer + { + public void serialize(RowCacheKey rowCacheKey, DataOutput dataOutput) throws IOException + { + dataOutput.writeLong(rowCacheKey.cfId.getMostSignificantBits()); + dataOutput.writeLong(rowCacheKey.cfId.getLeastSignificantBits()); + dataOutput.writeInt(rowCacheKey.key.length); + dataOutput.write(rowCacheKey.key); + } + + public RowCacheKey deserialize(DataInput dataInput) throws IOException + { + long msb = dataInput.readLong(); + long lsb = dataInput.readLong(); + byte[] key = new byte[dataInput.readInt()]; + dataInput.readFully(key); + return new RowCacheKey(new UUID(msb, lsb), key); + } + + public int serializedSize(RowCacheKey rowCacheKey) + { + return 20 + rowCacheKey.key.length; + } + } + + private static class ValueSerializer implements org.caffinitas.ohc.CacheSerializer + { + public void serialize(IRowCacheEntry entry, DataOutput out) throws IOException + { + assert entry != null; // unlike CFS we don't support nulls, since there is no need for that in the cache + boolean isSentinel = entry instanceof RowCacheSentinel; + out.writeBoolean(isSentinel); + if (isSentinel) + out.writeLong(((RowCacheSentinel) entry).sentinelId); + else + ColumnFamily.serializer.serialize((ColumnFamily) entry, new DataOutputPlusAdapter(out), MessagingService.current_version); + } + + public IRowCacheEntry deserialize(DataInput in) throws IOException + { + boolean isSentinel = in.readBoolean(); + if (isSentinel) + return new RowCacheSentinel(in.readLong()); + return ColumnFamily.serializer.deserialize(in, MessagingService.current_version); + } + + public int serializedSize(IRowCacheEntry entry) + { + TypeSizes typeSizes = TypeSizes.NATIVE; + int size = typeSizes.sizeof(true); + if (entry instanceof RowCacheSentinel) + size += typeSizes.sizeof(((RowCacheSentinel) entry).sentinelId); + else + size += ColumnFamily.serializer.serializedSize((ColumnFamily) entry, typeSizes, MessagingService.current_version); + return size; + } + } + + static class DataOutputPlusAdapter implements DataOutputPlus + { + private final DataOutput out; + + public void write(byte[] b) throws IOException + { + out.write(b); + } + + public void write(byte[] b, int off, int len) throws IOException + { + out.write(b, off, len); + } + + public void write(int b) throws IOException + { + out.write(b); + } + + public void writeBoolean(boolean v) throws IOException + { + out.writeBoolean(v); + } + + public void writeByte(int v) throws IOException + { + out.writeByte(v); + } + + public void writeBytes(String s) throws IOException + { + out.writeBytes(s); + } + + public void writeChar(int v) throws IOException + { + out.writeChar(v); + } + + public void writeChars(String s) throws IOException + { + out.writeChars(s); + } + + public void writeDouble(double v) throws IOException + { + out.writeDouble(v); + } + + public void writeFloat(float v) throws IOException + { + out.writeFloat(v); + } + + public void writeInt(int v) throws IOException + { + out.writeInt(v); + } + + public void writeLong(long v) throws IOException + { + out.writeLong(v); + } + + public void writeShort(int v) throws IOException + { + out.writeShort(v); + } + + public void writeUTF(String s) throws IOException + { + out.writeUTF(s); + } + + public DataOutputPlusAdapter(DataOutput out) + { + this.out = out; + } + + public void write(ByteBuffer buffer) throws IOException + { + if (buffer.hasArray()) + out.write(buffer.array(), buffer.arrayOffset(), buffer.remaining()); + else + throw new UnsupportedOperationException("IMPLEMENT ME"); + } + + public void write(Memory memory) throws IOException + { + throw new UnsupportedOperationException("IMPLEMENT ME"); + } + } +} diff --git a/src/java/org/apache/cassandra/cache/RowCacheKey.java b/src/java/org/apache/cassandra/cache/RowCacheKey.java index af2d4d4ee1..ccb85d85e0 100644 --- a/src/java/org/apache/cassandra/cache/RowCacheKey.java +++ b/src/java/org/apache/cassandra/cache/RowCacheKey.java @@ -33,6 +33,12 @@ public class RowCacheKey implements CacheKey, Comparable private static final long EMPTY_SIZE = ObjectSizes.measure(new RowCacheKey(null, ByteBufferUtil.EMPTY_BYTE_BUFFER)); + public RowCacheKey(UUID cfId, byte[] key) + { + this.cfId = cfId; + this.key = key; + } + public RowCacheKey(UUID cfId, DecoratedKey key) { this(cfId, key.getKey()); diff --git a/src/java/org/apache/cassandra/cache/SerializingCache.java b/src/java/org/apache/cassandra/cache/SerializingCache.java index ca65fccd3b..911b5007d2 100644 --- a/src/java/org/apache/cassandra/cache/SerializingCache.java +++ b/src/java/org/apache/cassandra/cache/SerializingCache.java @@ -18,7 +18,7 @@ package org.apache.cassandra.cache; import java.io.IOException; -import java.util.Set; +import java.util.Iterator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -264,14 +264,14 @@ public class SerializingCache implements ICache mem.unreference(); } - public Set keySet() + public Iterator keyIterator() { - return map.keySet(); + return map.keySet().iterator(); } - public Set hotKeySet(int n) + public Iterator hotKeyIterator(int n) { - return map.descendingKeySetWithLimit(n); + return map.descendingKeySetWithLimit(n).iterator(); } public boolean containsKey(K key) diff --git a/src/java/org/apache/cassandra/cache/SerializingCacheProvider.java b/src/java/org/apache/cassandra/cache/SerializingCacheProvider.java index a058872610..f540322917 100644 --- a/src/java/org/apache/cassandra/cache/SerializingCacheProvider.java +++ b/src/java/org/apache/cassandra/cache/SerializingCacheProvider.java @@ -20,17 +20,18 @@ package org.apache.cassandra.cache; import java.io.DataInput; import java.io.IOException; +import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.db.ColumnFamily; import org.apache.cassandra.db.TypeSizes; import org.apache.cassandra.io.ISerializer; import org.apache.cassandra.io.util.DataOutputPlus; import org.apache.cassandra.net.MessagingService; -public class SerializingCacheProvider +public class SerializingCacheProvider implements CacheProvider { - public ICache create(long capacity) + public ICache create() { - return SerializingCache.create(capacity, new RowCacheSerializer()); + return SerializingCache.create(DatabaseDescriptor.getRowCacheSizeInMB() * 1024 * 1024, new RowCacheSerializer()); } // Package protected for tests diff --git a/src/java/org/apache/cassandra/config/Config.java b/src/java/org/apache/cassandra/config/Config.java index 33d2bb2644..f42c980850 100644 --- a/src/java/org/apache/cassandra/config/Config.java +++ b/src/java/org/apache/cassandra/config/Config.java @@ -192,6 +192,7 @@ public class Config public volatile int key_cache_save_period = 14400; public volatile int key_cache_keys_to_save = Integer.MAX_VALUE; + public String row_cache_class_name = "org.apache.cassandra.cache.OHCProvider"; public long row_cache_size_in_mb = 0; public volatile int row_cache_save_period = 0; public volatile int row_cache_keys_to_save = Integer.MAX_VALUE; diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java index 6d626da361..8cc2da46c9 100644 --- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java +++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java @@ -1423,6 +1423,11 @@ public class DatabaseDescriptor conf.key_cache_keys_to_save = keyCacheKeysToSave; } + public static String getRowCacheClassName() + { + return conf.row_cache_class_name; + } + public static long getRowCacheSizeInMB() { return conf.row_cache_size_in_mb; @@ -1448,6 +1453,11 @@ public class DatabaseDescriptor return counterCacheSizeInMB; } + public static void setRowCacheKeysToSave(int rowCacheKeysToSave) + { + conf.row_cache_keys_to_save = rowCacheKeysToSave; + } + public static int getCounterCacheSavePeriod() { return conf.counter_cache_save_period; @@ -1473,11 +1483,6 @@ public class DatabaseDescriptor return memoryAllocator; } - public static void setRowCacheKeysToSave(int rowCacheKeysToSave) - { - conf.row_cache_keys_to_save = rowCacheKeysToSave; - } - public static int getStreamingSocketTimeout() { return conf.streaming_socket_timeout_in_ms; diff --git a/src/java/org/apache/cassandra/config/YamlConfigurationLoader.java b/src/java/org/apache/cassandra/config/YamlConfigurationLoader.java index 50991f2392..82c8151ffa 100644 --- a/src/java/org/apache/cassandra/config/YamlConfigurationLoader.java +++ b/src/java/org/apache/cassandra/config/YamlConfigurationLoader.java @@ -102,7 +102,7 @@ public class YamlConfigurationLoader implements ConfigurationLoader } logConfig(configBytes); - + org.yaml.snakeyaml.constructor.Constructor constructor = new org.yaml.snakeyaml.constructor.Constructor(Config.class); TypeDescription seedDesc = new TypeDescription(SeedProviderDef.class); seedDesc.putMapPropertyType("parameters", String.class, String.class); diff --git a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java index 002238c93b..c2ee0aca4d 100644 --- a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java +++ b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java @@ -1961,19 +1961,23 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean { Collection> ranges = StorageService.instance.getLocalRanges(keyspace.getName()); - for (RowCacheKey key : CacheService.instance.rowCache.getKeySet()) + for (Iterator keyIter = CacheService.instance.rowCache.keyIterator(); + keyIter.hasNext(); ) { + RowCacheKey key = keyIter.next(); DecoratedKey dk = partitioner.decorateKey(ByteBuffer.wrap(key.key)); - if (key.cfId == metadata.cfId && !Range.isInRanges(dk.getToken(), ranges)) + if (key.cfId.equals(metadata.cfId) && !Range.isInRanges(dk.getToken(), ranges)) invalidateCachedRow(dk); } if (metadata.isCounter()) { - for (CounterCacheKey key : CacheService.instance.counterCache.getKeySet()) + for (Iterator keyIter = CacheService.instance.counterCache.keyIterator(); + keyIter.hasNext(); ) { + CounterCacheKey key = keyIter.next(); DecoratedKey dk = partitioner.decorateKey(ByteBuffer.wrap(key.partitionKey)); - if (key.cfId == metadata.cfId && !Range.isInRanges(dk.getToken(), ranges)) + if (key.cfId.equals(metadata.cfId) && !Range.isInRanges(dk.getToken(), ranges)) CacheService.instance.counterCache.remove(key); } } diff --git a/src/java/org/apache/cassandra/service/CacheService.java b/src/java/org/apache/cassandra/service/CacheService.java index 2ffd954d42..fb8153c2f5 100644 --- a/src/java/org/apache/cassandra/service/CacheService.java +++ b/src/java/org/apache/cassandra/service/CacheService.java @@ -33,6 +33,7 @@ import javax.management.MBeanServer; import javax.management.ObjectName; import com.google.common.util.concurrent.Futures; + import org.apache.cassandra.io.sstable.format.SSTableReader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -132,10 +133,22 @@ public class CacheService implements CacheServiceMBean { logger.info("Initializing row cache with capacity of {} MBs", DatabaseDescriptor.getRowCacheSizeInMB()); - long rowCacheInMemoryCapacity = DatabaseDescriptor.getRowCacheSizeInMB() * 1024 * 1024; + CacheProvider cacheProvider; + String cacheProviderClassName = DatabaseDescriptor.getRowCacheSizeInMB() > 0 + ? DatabaseDescriptor.getRowCacheClassName() : "org.apache.cassandra.cache.NopCacheProvider"; + try + { + Class> cacheProviderClass = + (Class>) Class.forName(cacheProviderClassName); + cacheProvider = cacheProviderClass.newInstance(); + } + catch (Exception e) + { + throw new RuntimeException("Cannot find configured row cache provider class " + DatabaseDescriptor.getRowCacheClassName()); + } // cache object - ICache rc = new SerializingCacheProvider().create(rowCacheInMemoryCapacity); + ICache rc = cacheProvider.create(); AutoSavingCache rowCache = new AutoSavingCache<>(rc, CacheType.ROW_CACHE, new RowCacheSerializer()); int rowCacheKeysToSave = DatabaseDescriptor.getRowCacheKeysToSave(); @@ -285,7 +298,7 @@ public class CacheService implements CacheServiceMBean public void invalidateKeyCacheForCf(UUID cfId) { - Iterator keyCacheIterator = keyCache.getKeySet().iterator(); + Iterator keyCacheIterator = keyCache.keyIterator(); while (keyCacheIterator.hasNext()) { KeyCacheKey key = keyCacheIterator.next(); @@ -301,7 +314,7 @@ public class CacheService implements CacheServiceMBean public void invalidateRowCacheForCf(UUID cfId) { - Iterator rowCacheIterator = rowCache.getKeySet().iterator(); + Iterator rowCacheIterator = rowCache.keyIterator(); while (rowCacheIterator.hasNext()) { RowCacheKey rowCacheKey = rowCacheIterator.next(); @@ -312,7 +325,7 @@ public class CacheService implements CacheServiceMBean public void invalidateCounterCacheForCf(UUID cfId) { - Iterator counterCacheIterator = counterCache.getKeySet().iterator(); + Iterator counterCacheIterator = counterCache.keyIterator(); while (counterCacheIterator.hasNext()) { CounterCacheKey counterCacheKey = counterCacheIterator.next(); diff --git a/test/conf/cassandra.yaml b/test/conf/cassandra.yaml index ec988e299f..307ca8cf10 100644 --- a/test/conf/cassandra.yaml +++ b/test/conf/cassandra.yaml @@ -36,3 +36,5 @@ server_encryption_options: incremental_backups: true concurrent_compactors: 4 compaction_throughput_mb_per_sec: 0 +row_cache_class_name: org.apache.cassandra.cache.OHCProvider +row_cache_size_in_mb: 16 diff --git a/test/unit/org/apache/cassandra/db/KeyCacheTest.java b/test/unit/org/apache/cassandra/db/KeyCacheTest.java index e31b4398cd..c370e4f8d1 100644 --- a/test/unit/org/apache/cassandra/db/KeyCacheTest.java +++ b/test/unit/org/apache/cassandra/db/KeyCacheTest.java @@ -18,6 +18,7 @@ package org.apache.cassandra.db; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -88,8 +89,10 @@ public class KeyCacheTest // really? our caches don't implement the map interface? (hence no .addAll) Map savedMap = new HashMap(); - for (KeyCacheKey k : CacheService.instance.keyCache.getKeySet()) + for (Iterator iter = CacheService.instance.keyCache.keyIterator(); + iter.hasNext();) { + KeyCacheKey k = iter.next(); if (k.desc.ksname.equals(KEYSPACE1) && k.desc.cfname.equals(COLUMN_FAMILY2)) savedMap.put(k, CacheService.instance.keyCache.get(k)); } @@ -207,8 +210,10 @@ public class KeyCacheTest private void assertKeyCacheSize(int expected, String keyspace, String columnFamily) { int size = 0; - for (KeyCacheKey k : CacheService.instance.keyCache.getKeySet()) + for (Iterator iter = CacheService.instance.keyCache.keyIterator(); + iter.hasNext();) { + KeyCacheKey k = iter.next(); if (k.desc.ksname.equals(keyspace) && k.desc.cfname.equals(columnFamily)) size++; } diff --git a/test/unit/org/apache/cassandra/db/RowCacheTest.java b/test/unit/org/apache/cassandra/db/RowCacheTest.java index 7d5799a7cd..3d5617fabb 100644 --- a/test/unit/org/apache/cassandra/db/RowCacheTest.java +++ b/test/unit/org/apache/cassandra/db/RowCacheTest.java @@ -156,9 +156,9 @@ public class RowCacheTest rowCacheLoad(100, Integer.MAX_VALUE, 1000); ColumnFamilyStore store = Keyspace.open(KEYSPACE_CACHED).getColumnFamilyStore(CF_CACHED); - assertEquals(CacheService.instance.rowCache.getKeySet().size(), 100); + assertEquals(CacheService.instance.rowCache.size(), 100); store.cleanupCache(); - assertEquals(CacheService.instance.rowCache.getKeySet().size(), 100); + assertEquals(CacheService.instance.rowCache.size(), 100); TokenMetadata tmd = StorageService.instance.getTokenMetadata(); byte[] tk1, tk2; tk1 = "key1000".getBytes(); @@ -166,7 +166,7 @@ public class RowCacheTest tmd.updateNormalToken(new BytesToken(tk1), InetAddress.getByName("127.0.0.1")); tmd.updateNormalToken(new BytesToken(tk2), InetAddress.getByName("127.0.0.2")); store.cleanupCache(); - assertEquals(CacheService.instance.rowCache.getKeySet().size(), 50); + assertEquals(50, CacheService.instance.rowCache.size()); CacheService.instance.setRowCacheCapacityInMB(0); } @@ -259,19 +259,19 @@ public class RowCacheTest // empty the cache CacheService.instance.invalidateRowCache(); - assert CacheService.instance.rowCache.size() == 0; + assertEquals(0, CacheService.instance.rowCache.size()); // insert data and fill the cache SchemaLoader.insertData(KEYSPACE_CACHED, CF_CACHED, offset, totalKeys); SchemaLoader.readData(KEYSPACE_CACHED, CF_CACHED, offset, totalKeys); - assert CacheService.instance.rowCache.size() == totalKeys; + assertEquals(totalKeys, CacheService.instance.rowCache.size()); // force the cache to disk CacheService.instance.rowCache.submitWrite(keysToSave).get(); // empty the cache again to make sure values came from disk CacheService.instance.invalidateRowCache(); - assert CacheService.instance.rowCache.size() == 0; - assert CacheService.instance.rowCache.loadSaved(store) == (keysToSave == Integer.MAX_VALUE ? totalKeys : keysToSave); + assertEquals(0, CacheService.instance.rowCache.size()); + assertEquals(keysToSave == Integer.MAX_VALUE ? totalKeys : keysToSave, CacheService.instance.rowCache.loadSaved(store)); } }