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));
}
}