mirror of https://github.com/apache/cassandra
Merge branch 'cassandra-2.1' into cassandra-2.2
This commit is contained in:
commit
e487553575
|
|
@ -10,6 +10,7 @@
|
||||||
* Deprecate Pig support (CASSANDRA-10542)
|
* Deprecate Pig support (CASSANDRA-10542)
|
||||||
* Reduce contention getting instances of CompositeType (CASSANDRA-10433)
|
* Reduce contention getting instances of CompositeType (CASSANDRA-10433)
|
||||||
Merged from 2.1:
|
Merged from 2.1:
|
||||||
|
* Invalidate cache after stream receive task is completed (CASSANDRA-10341)
|
||||||
* Reject counter writes in CQLSSTableWriter (CASSANDRA-10258)
|
* Reject counter writes in CQLSSTableWriter (CASSANDRA-10258)
|
||||||
* Remove superfluous COUNTER_MUTATION stage mapping (CASSANDRA-10605)
|
* Remove superfluous COUNTER_MUTATION stage mapping (CASSANDRA-10605)
|
||||||
* Improve json2sstable error reporting on nonexistent columns (CASSANDRA-10401)
|
* Improve json2sstable error reporting on nonexistent columns (CASSANDRA-10401)
|
||||||
|
|
|
||||||
|
|
@ -2519,6 +2519,41 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean
|
||||||
CacheService.instance.invalidateCounterCacheForCf(metadata.ksAndCFName);
|
CacheService.instance.invalidateCounterCacheForCf(metadata.ksAndCFName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int invalidateRowCache(Collection<Bounds<Token>> boundsToInvalidate)
|
||||||
|
{
|
||||||
|
int invalidatedKeys = 0;
|
||||||
|
for (Iterator<RowCacheKey> keyIter = CacheService.instance.rowCache.keyIterator();
|
||||||
|
keyIter.hasNext(); )
|
||||||
|
{
|
||||||
|
RowCacheKey key = keyIter.next();
|
||||||
|
DecoratedKey dk = partitioner.decorateKey(ByteBuffer.wrap(key.key));
|
||||||
|
if (key.ksAndCFName.equals(metadata.ksAndCFName) && Bounds.isInBounds(dk.getToken(), boundsToInvalidate))
|
||||||
|
{
|
||||||
|
invalidateCachedRow(dk);
|
||||||
|
invalidatedKeys++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return invalidatedKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int invalidateCounterCache(Collection<Bounds<Token>> boundsToInvalidate)
|
||||||
|
{
|
||||||
|
int invalidatedKeys = 0;
|
||||||
|
for (Iterator<CounterCacheKey> keyIter = CacheService.instance.counterCache.keyIterator();
|
||||||
|
keyIter.hasNext(); )
|
||||||
|
{
|
||||||
|
CounterCacheKey key = keyIter.next();
|
||||||
|
DecoratedKey dk = partitioner.decorateKey(ByteBuffer.wrap(key.partitionKey));
|
||||||
|
if (key.ksAndCFName.equals(metadata.ksAndCFName) && Bounds.isInBounds(dk.getToken(), boundsToInvalidate))
|
||||||
|
{
|
||||||
|
CacheService.instance.counterCache.remove(key);
|
||||||
|
invalidatedKeys++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return invalidatedKeys;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if @param key is contained in the row cache
|
* @return true if @param key is contained in the row cache
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -189,11 +189,6 @@ public class CompactionController implements AutoCloseable
|
||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void invalidateCachedRow(DecoratedKey key)
|
|
||||||
{
|
|
||||||
cfs.invalidateCachedRow(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close()
|
public void close()
|
||||||
{
|
{
|
||||||
overlappingSSTables.release();
|
overlappingSSTables.release();
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,17 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.cassandra.dht;
|
package org.apache.cassandra.dht;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterators;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.PeekingIterator;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import org.apache.cassandra.db.RowPosition;
|
import org.apache.cassandra.db.RowPosition;
|
||||||
import org.apache.cassandra.utils.Pair;
|
import org.apache.cassandra.utils.Pair;
|
||||||
|
|
@ -102,6 +111,20 @@ public class Bounds<T extends RingPosition<T>> extends AbstractBounds<T>
|
||||||
return "]";
|
return "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T extends RingPosition<T>> boolean isInBounds(T token, Iterable<Bounds<T>> bounds)
|
||||||
|
{
|
||||||
|
assert bounds != null;
|
||||||
|
|
||||||
|
for (Bounds<T> bound : bounds)
|
||||||
|
{
|
||||||
|
if (bound.contains(token))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute a bounds of keys corresponding to a given bounds of token.
|
* Compute a bounds of keys corresponding to a given bounds of token.
|
||||||
*/
|
*/
|
||||||
|
|
@ -114,4 +137,43 @@ public class Bounds<T extends RingPosition<T>> extends AbstractBounds<T>
|
||||||
{
|
{
|
||||||
return new Bounds<T>(left, newRight);
|
return new Bounds<T>(left, newRight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves non-overlapping bounds for the list of input bounds
|
||||||
|
*
|
||||||
|
* Assume we have the following bounds
|
||||||
|
* (brackets representing left/right bound):
|
||||||
|
* [ ] [ ] [ ] [ ]
|
||||||
|
* [ ] [ ]
|
||||||
|
* This method will return the following bounds:
|
||||||
|
* [ ] [ ]
|
||||||
|
*
|
||||||
|
* @param bounds unsorted bounds to find overlaps
|
||||||
|
* @return the non-overlapping bounds
|
||||||
|
*/
|
||||||
|
public static <T extends RingPosition<T>> Set<Bounds<T>> getNonOverlappingBounds(Iterable<Bounds<T>> bounds)
|
||||||
|
{
|
||||||
|
ArrayList<Bounds<T>> sortedBounds = Lists.newArrayList(bounds);
|
||||||
|
Collections.sort(sortedBounds, new Comparator<Bounds<T>>()
|
||||||
|
{
|
||||||
|
public int compare(Bounds<T> o1, Bounds<T> o2)
|
||||||
|
{
|
||||||
|
return o1.left.compareTo(o2.left);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Set<Bounds<T>> nonOverlappingBounds = Sets.newHashSet();
|
||||||
|
|
||||||
|
PeekingIterator<Bounds<T>> it = Iterators.peekingIterator(sortedBounds.iterator());
|
||||||
|
while (it.hasNext())
|
||||||
|
{
|
||||||
|
Bounds<T> beginBound = it.next();
|
||||||
|
Bounds<T> endBound = beginBound;
|
||||||
|
while (it.hasNext() && endBound.right.compareTo(it.peek().left) >= 0)
|
||||||
|
endBound = it.next();
|
||||||
|
nonOverlappingBounds.add(new Bounds<>(beginBound.left, endBound.right));
|
||||||
|
}
|
||||||
|
|
||||||
|
return nonOverlappingBounds;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ package org.apache.cassandra.io.sstable;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.util.concurrent.Runnables;
|
|
||||||
|
|
||||||
import org.apache.cassandra.cache.InstrumentingCache;
|
import org.apache.cassandra.cache.InstrumentingCache;
|
||||||
import org.apache.cassandra.cache.KeyCacheKey;
|
import org.apache.cassandra.cache.KeyCacheKey;
|
||||||
|
|
|
||||||
|
|
@ -171,6 +171,5 @@ public class StreamReader
|
||||||
{
|
{
|
||||||
DecoratedKey key = StorageService.getPartitioner().decorateKey(ByteBufferUtil.readWithShortLength(in));
|
DecoratedKey key = StorageService.getPartitioner().decorateKey(ByteBufferUtil.readWithShortLength(in));
|
||||||
writer.appendFromStream(key, cfs.metadata, in, inputVersion);
|
writer.appendFromStream(key, cfs.metadata, in, inputVersion);
|
||||||
cfs.invalidateCachedRow(key);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,20 @@ import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import org.apache.cassandra.concurrent.NamedThreadFactory;
|
import org.apache.cassandra.concurrent.NamedThreadFactory;
|
||||||
import org.apache.cassandra.config.Schema;
|
import org.apache.cassandra.config.Schema;
|
||||||
import org.apache.cassandra.db.ColumnFamilyStore;
|
import org.apache.cassandra.db.ColumnFamilyStore;
|
||||||
import org.apache.cassandra.db.Keyspace;
|
import org.apache.cassandra.db.Keyspace;
|
||||||
|
import org.apache.cassandra.dht.Bounds;
|
||||||
|
import org.apache.cassandra.dht.Token;
|
||||||
import org.apache.cassandra.io.sstable.format.SSTableReader;
|
import org.apache.cassandra.io.sstable.format.SSTableReader;
|
||||||
import org.apache.cassandra.io.sstable.format.SSTableWriter;
|
import org.apache.cassandra.io.sstable.format.SSTableWriter;
|
||||||
import org.apache.cassandra.utils.Pair;
|
import org.apache.cassandra.utils.Pair;
|
||||||
|
|
@ -43,6 +49,7 @@ import org.apache.cassandra.utils.concurrent.Refs;
|
||||||
public class StreamReceiveTask extends StreamTask
|
public class StreamReceiveTask extends StreamTask
|
||||||
{
|
{
|
||||||
private static final ExecutorService executor = Executors.newCachedThreadPool(new NamedThreadFactory("StreamReceiveTask"));
|
private static final ExecutorService executor = Executors.newCachedThreadPool(new NamedThreadFactory("StreamReceiveTask"));
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(StreamReceiveTask.class);
|
||||||
|
|
||||||
// number of files to receive
|
// number of files to receive
|
||||||
private final int totalFiles;
|
private final int totalFiles;
|
||||||
|
|
@ -76,6 +83,7 @@ public class StreamReceiveTask extends StreamTask
|
||||||
assert cfId.equals(sstable.metadata.cfId);
|
assert cfId.equals(sstable.metadata.cfId);
|
||||||
|
|
||||||
sstables.add(sstable);
|
sstables.add(sstable);
|
||||||
|
|
||||||
if (sstables.size() == totalFiles)
|
if (sstables.size() == totalFiles)
|
||||||
{
|
{
|
||||||
done = true;
|
done = true;
|
||||||
|
|
@ -131,6 +139,33 @@ public class StreamReceiveTask extends StreamTask
|
||||||
// add sstables and build secondary indexes
|
// add sstables and build secondary indexes
|
||||||
cfs.addSSTables(readers);
|
cfs.addSSTables(readers);
|
||||||
cfs.indexManager.maybeBuildSecondaryIndexes(readers, cfs.indexManager.allIndexesNames());
|
cfs.indexManager.maybeBuildSecondaryIndexes(readers, cfs.indexManager.allIndexesNames());
|
||||||
|
|
||||||
|
//invalidate row and counter cache
|
||||||
|
if (cfs.isRowCacheEnabled() || cfs.metadata.isCounter())
|
||||||
|
{
|
||||||
|
List<Bounds<Token>> boundsToInvalidate = new ArrayList<>(readers.size());
|
||||||
|
for (SSTableReader sstable : readers)
|
||||||
|
boundsToInvalidate.add(new Bounds<Token>(sstable.first.getToken(), sstable.last.getToken()));
|
||||||
|
Set<Bounds<Token>> nonOverlappingBounds = Bounds.getNonOverlappingBounds(boundsToInvalidate);
|
||||||
|
|
||||||
|
if (cfs.isRowCacheEnabled())
|
||||||
|
{
|
||||||
|
int invalidatedKeys = cfs.invalidateRowCache(nonOverlappingBounds);
|
||||||
|
if (invalidatedKeys > 0)
|
||||||
|
logger.debug("[Stream #{}] Invalidated {} row cache entries on table {}.{} after stream " +
|
||||||
|
"receive task completed.", task.session.planId(), invalidatedKeys,
|
||||||
|
cfs.keyspace.getName(), cfs.getColumnFamilyName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfs.metadata.isCounter())
|
||||||
|
{
|
||||||
|
int invalidatedKeys = cfs.invalidateCounterCache(nonOverlappingBounds);
|
||||||
|
if (invalidatedKeys > 0)
|
||||||
|
logger.debug("[Stream #{}] Invalidated {} counter cache entries on table {}.{} after stream " +
|
||||||
|
"receive task completed.", task.session.planId(), invalidatedKeys,
|
||||||
|
cfs.keyspace.getName(), cfs.getColumnFamilyName());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task.session.taskCompleted(task);
|
task.session.taskCompleted(task);
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.cassandra.db;
|
package org.apache.cassandra.db;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
|
|
@ -26,6 +27,8 @@ import org.junit.Test;
|
||||||
import org.apache.cassandra.SchemaLoader;
|
import org.apache.cassandra.SchemaLoader;
|
||||||
import org.apache.cassandra.config.KSMetaData;
|
import org.apache.cassandra.config.KSMetaData;
|
||||||
import org.apache.cassandra.db.marshal.CounterColumnType;
|
import org.apache.cassandra.db.marshal.CounterColumnType;
|
||||||
|
import org.apache.cassandra.dht.Bounds;
|
||||||
|
import org.apache.cassandra.dht.Token;
|
||||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||||
import org.apache.cassandra.config.Schema;
|
import org.apache.cassandra.config.Schema;
|
||||||
import org.apache.cassandra.exceptions.WriteTimeoutException;
|
import org.apache.cassandra.exceptions.WriteTimeoutException;
|
||||||
|
|
@ -85,6 +88,48 @@ public class CounterCacheTest
|
||||||
assertEquals(ClockAndCount.create(2L, 2L), cfs.getCachedCounter(bytes(2), cellname(2)));
|
assertEquals(ClockAndCount.create(2L, 2L), cfs.getCachedCounter(bytes(2), cellname(2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCounterCacheInvalidate()
|
||||||
|
{
|
||||||
|
ColumnFamilyStore cfs = Keyspace.open(KEYSPACE1).getColumnFamilyStore(CF);
|
||||||
|
cfs.truncateBlocking();
|
||||||
|
CacheService.instance.invalidateCounterCache();
|
||||||
|
|
||||||
|
assertEquals(0, CacheService.instance.counterCache.size());
|
||||||
|
assertNull(cfs.getCachedCounter(bytes(1), cellname(1)));
|
||||||
|
assertNull(cfs.getCachedCounter(bytes(1), cellname(2)));
|
||||||
|
assertNull(cfs.getCachedCounter(bytes(2), cellname(1)));
|
||||||
|
assertNull(cfs.getCachedCounter(bytes(2), cellname(2)));
|
||||||
|
assertNull(cfs.getCachedCounter(bytes(3), cellname(1)));
|
||||||
|
assertNull(cfs.getCachedCounter(bytes(3), cellname(2)));
|
||||||
|
|
||||||
|
cfs.putCachedCounter(bytes(1), cellname(1), ClockAndCount.create(1L, 1L));
|
||||||
|
cfs.putCachedCounter(bytes(1), cellname(2), ClockAndCount.create(1L, 2L));
|
||||||
|
cfs.putCachedCounter(bytes(2), cellname(1), ClockAndCount.create(2L, 1L));
|
||||||
|
cfs.putCachedCounter(bytes(2), cellname(2), ClockAndCount.create(2L, 2L));
|
||||||
|
cfs.putCachedCounter(bytes(3), cellname(1), ClockAndCount.create(3L, 1L));
|
||||||
|
cfs.putCachedCounter(bytes(3), cellname(2), ClockAndCount.create(3L, 2L));
|
||||||
|
|
||||||
|
assertEquals(6, CacheService.instance.counterCache.size());
|
||||||
|
assertEquals(ClockAndCount.create(1L, 1L), cfs.getCachedCounter(bytes(1), cellname(1)));
|
||||||
|
assertEquals(ClockAndCount.create(1L, 2L), cfs.getCachedCounter(bytes(1), cellname(2)));
|
||||||
|
assertEquals(ClockAndCount.create(2L, 1L), cfs.getCachedCounter(bytes(2), cellname(1)));
|
||||||
|
assertEquals(ClockAndCount.create(2L, 2L), cfs.getCachedCounter(bytes(2), cellname(2)));
|
||||||
|
assertEquals(ClockAndCount.create(3L, 1L), cfs.getCachedCounter(bytes(3), cellname(1)));
|
||||||
|
assertEquals(ClockAndCount.create(3L, 2L), cfs.getCachedCounter(bytes(3), cellname(2)));
|
||||||
|
|
||||||
|
cfs.invalidateCounterCache(Collections.singleton(new Bounds<Token>(cfs.partitioner.decorateKey(bytes(1)).getToken(),
|
||||||
|
cfs.partitioner.decorateKey(bytes(2)).getToken())));
|
||||||
|
|
||||||
|
assertEquals(2, CacheService.instance.counterCache.size());
|
||||||
|
assertNull(cfs.getCachedCounter(bytes(1), cellname(1)));
|
||||||
|
assertNull(cfs.getCachedCounter(bytes(1), cellname(2)));
|
||||||
|
assertNull(cfs.getCachedCounter(bytes(2), cellname(1)));
|
||||||
|
assertNull(cfs.getCachedCounter(bytes(2), cellname(2)));
|
||||||
|
assertEquals(ClockAndCount.create(3L, 1L), cfs.getCachedCounter(bytes(3), cellname(1)));
|
||||||
|
assertEquals(ClockAndCount.create(3L, 2L), cfs.getCachedCounter(bytes(3), cellname(2)));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSaveLoad() throws ExecutionException, InterruptedException, WriteTimeoutException
|
public void testSaveLoad() throws ExecutionException, InterruptedException, WriteTimeoutException
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,12 @@ package org.apache.cassandra.db;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
@ -36,6 +40,8 @@ import org.apache.cassandra.db.composites.*;
|
||||||
import org.apache.cassandra.db.compaction.CompactionManager;
|
import org.apache.cassandra.db.compaction.CompactionManager;
|
||||||
import org.apache.cassandra.db.filter.QueryFilter;
|
import org.apache.cassandra.db.filter.QueryFilter;
|
||||||
import org.apache.cassandra.db.marshal.IntegerType;
|
import org.apache.cassandra.db.marshal.IntegerType;
|
||||||
|
import org.apache.cassandra.dht.Bounds;
|
||||||
|
import org.apache.cassandra.dht.Token;
|
||||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||||
import org.apache.cassandra.dht.ByteOrderedPartitioner.BytesToken;
|
import org.apache.cassandra.dht.ByteOrderedPartitioner.BytesToken;
|
||||||
import org.apache.cassandra.locator.TokenMetadata;
|
import org.apache.cassandra.locator.TokenMetadata;
|
||||||
|
|
@ -171,6 +177,51 @@ public class RowCacheTest
|
||||||
CacheService.instance.setRowCacheCapacityInMB(0);
|
CacheService.instance.setRowCacheCapacityInMB(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvalidateRowCache() throws Exception
|
||||||
|
{
|
||||||
|
StorageService.instance.initServer(0);
|
||||||
|
CacheService.instance.setRowCacheCapacityInMB(1);
|
||||||
|
rowCacheLoad(100, Integer.MAX_VALUE, 1000);
|
||||||
|
|
||||||
|
ColumnFamilyStore store = Keyspace.open(KEYSPACE_CACHED).getColumnFamilyStore(CF_CACHED);
|
||||||
|
assertEquals(CacheService.instance.rowCache.size(), 100);
|
||||||
|
|
||||||
|
//construct 5 ranges of 20 elements each
|
||||||
|
ArrayList<Bounds<Token>> subranges = getBounds(20);
|
||||||
|
|
||||||
|
//invalidate 3 of the 5 ranges
|
||||||
|
ArrayList<Bounds<Token>> boundsToInvalidate = Lists.newArrayList(subranges.get(0), subranges.get(2), subranges.get(4));
|
||||||
|
int invalidatedKeys = store.invalidateRowCache(boundsToInvalidate);
|
||||||
|
assertEquals(60, invalidatedKeys);
|
||||||
|
|
||||||
|
//now there should be only 40 cached entries left
|
||||||
|
assertEquals(CacheService.instance.rowCache.size(), 40);
|
||||||
|
CacheService.instance.setRowCacheCapacityInMB(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<Bounds<Token>> getBounds(int nElements)
|
||||||
|
{
|
||||||
|
ColumnFamilyStore store = Keyspace.open(KEYSPACE_CACHED).getColumnFamilyStore(CF_CACHED);
|
||||||
|
TreeSet<DecoratedKey> orderedKeys = new TreeSet<>();
|
||||||
|
|
||||||
|
for(Iterator<RowCacheKey> it = CacheService.instance.rowCache.keyIterator();it.hasNext();)
|
||||||
|
orderedKeys.add(store.partitioner.decorateKey(ByteBuffer.wrap(it.next().key)));
|
||||||
|
|
||||||
|
ArrayList<Bounds<Token>> boundsToInvalidate = new ArrayList<>();
|
||||||
|
Iterator<DecoratedKey> iterator = orderedKeys.iterator();
|
||||||
|
|
||||||
|
while (iterator.hasNext())
|
||||||
|
{
|
||||||
|
Token startRange = iterator.next().getToken();
|
||||||
|
for (int i = 0; i < nElements-2; i++)
|
||||||
|
iterator.next();
|
||||||
|
Token endRange = iterator.next().getToken();
|
||||||
|
boundsToInvalidate.add(new Bounds<>(startRange, endRange));
|
||||||
|
}
|
||||||
|
return boundsToInvalidate;
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRowCachePartialLoad() throws Exception
|
public void testRowCachePartialLoad() throws Exception
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* 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.dht;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class BoundsTest
|
||||||
|
{
|
||||||
|
|
||||||
|
private Bounds<Token> bounds(long left, long right)
|
||||||
|
{
|
||||||
|
return new Bounds<Token>(new Murmur3Partitioner.LongToken(left), new Murmur3Partitioner.LongToken(right));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
/**
|
||||||
|
* [0,1],[0,5],[1,8],[4,10] = [0, 10]
|
||||||
|
* [15,19][19,20] = [15,20]
|
||||||
|
* [21, 22] = [21,22]
|
||||||
|
*/
|
||||||
|
public void testGetNonOverlappingBounds()
|
||||||
|
{
|
||||||
|
List<Bounds<Token>> bounds = new LinkedList<>();
|
||||||
|
bounds.add(bounds(19, 20));
|
||||||
|
bounds.add(bounds(0, 1));
|
||||||
|
bounds.add(bounds(4, 10));
|
||||||
|
bounds.add(bounds(15, 19));
|
||||||
|
bounds.add(bounds(0, 5));
|
||||||
|
bounds.add(bounds(21, 22));
|
||||||
|
bounds.add(bounds(1, 8));
|
||||||
|
|
||||||
|
Set<Bounds<Token>> nonOverlappingBounds = Bounds.getNonOverlappingBounds(bounds);
|
||||||
|
assertEquals(3, nonOverlappingBounds.size());
|
||||||
|
assertTrue(nonOverlappingBounds.contains(bounds(0, 10)));
|
||||||
|
assertTrue(nonOverlappingBounds.contains(bounds(15,20)));
|
||||||
|
assertTrue(nonOverlappingBounds.contains(bounds(21,22)));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue