在cassandra1.2版本删除以前,删除基本上只有整个Column的删除,整个SuperColumn的删除,整个Rowkey的删除。
在cassandra1.0.6版本中,DeletionInfo只有两个属性:1、markedForDeleteAt,删除的毫秒数,用于判断记录是否有效的;2、localDeletionTime,删除时间的秒数,用于记录是否需要物理删除。
protected static class DeletionInfo
{
public final long markedForDeleteAt;
public final int localDeletionTime;
public DeletionInfo()
{
this(Long.MIN_VALUE, Integer.MIN_VALUE);
}
public DeletionInfo(long markedForDeleteAt, int localDeletionTime)
{
this.markedForDeleteAt = markedForDeleteAt;
this.localDeletionTime = localDeletionTime;
}
}
无论是在memtable中保存整个内存数据中的map,map为rowkey对应columnfamily的key-value结构,在columnfamily中有一个ISortedColumn用于存放rowkey下的记录(superCF则是SuperColumn的集合,standCF则是StandCF的集合)。每一条记录都会有自己有效的时间戳timestamp,在ColumnFamily中还有一个DeletionInfo用于标记,这个rowkey何时做过delete,是对于整个rowkey而言的,ISortedColumn中任何一个IColumn的时间戳小于DeletionInfo中的markedForDeleteAt的时候,就可以判断IColumn已经被删除了。supercolumn中集合和DeletionInfo,也是相同的作用,用于处理supername级的删除。
在cassandra1.2中,DeletionInfo已经做出了很大的改动了,将整体记录(无论是row还是superColumn)的删除,都增强为范围删除。
1、DeletionInfo的属性已经改变为:
(1)topLevel是DeletionTime相当于以前版本的DeletionInfo,DeletionTime中也有markedForDeleteAt和localDeletionTime。
(2)ranges是IntervalTree
private static final Serializer serializer = new Serializer();
// We don't have way to represent the full interval of keys (Interval don't support the minimum token as the right bound),
// so we keep the topLevel deletion info separatly. This also slightly optimize the case of full row deletion which is rather common.
private final DeletionTime topLevel;
private final IntervalTree ranges;
public static final DeletionInfo LIVE = new DeletionInfo(DeletionTime.LIVE, IntervalTree.emptyTree());
删除需要考虑多种情况:
(1)第一次范围删除,就可以直接生成删除标记DeletionInfo
(2)直接进行整条记录的删除,那么这个时候DeletionInfo中只有topLevel,可以比较删除时间,然后保留最新的记录
(3)多次范围删除,topLvel保留最新的删除时间,而将范围删除的树进行hashSet的合并以后重新生成。
/**
* Returns a new DeletionInfo containing of this plus the provided {@code
* newInfo}.
*/
public DeletionInfo add(DeletionInfo newInfo)
{
if (ranges.isEmpty())
{
return topLevel.markedForDeleteAt < newInfo.topLevel.markedForDeleteAt
? newInfo
: newInfo.ranges.isEmpty() ? this : new DeletionInfo(topLevel, newInfo.ranges);
}
else
{
if (newInfo.ranges.isEmpty())
{
return topLevel.markedForDeleteAt < newInfo.topLevel.markedForDeleteAt
? new DeletionInfo(newInfo.topLevel, ranges)
: this;
}
else
{
// Need to merge both ranges
Set merged = new HashSet();
Iterables.addAll(merged, Iterables.concat(ranges, newInfo.ranges));
return new DeletionInfo(topLevel.markedForDeleteAt < newInfo.topLevel.markedForDeleteAt ? newInfo.topLevel : topLevel,
IntervalTree.build(merged, ranges.comparator()));
}
}
}
3、记录有效性的判断。如果记录时间小于整条记录的删除标记,则此记录已经被删除。或者可以找到范围删除标记,判断记录是否被删除
public boolean isDeleted(ByteBuffer name, long timestamp)
{
if (isLive())
return false;
if (timestamp <= topLevel.markedForDeleteAt)
return true;
for (DeletionTime d : ranges.search(name))
{
if (timestamp <= d.markedForDeleteAt)
return true;
}
return false;
}
测试一下DeletionInfo的各种表现
public class TestDeletionInfo {
/**
* @param args
*/
public static void main(String[] args) {
RangeTombstone stone1 = new RangeTombstone(ByteBufferUtil.bytes(0),ByteBufferUtil.bytes(5),new DeletionTime(1L,1));
DeletionInfo info1 = new DeletionInfo(stone1,BytesType.instance);
RangeTombstone stone2 = new RangeTombstone(ByteBufferUtil.bytes(3),ByteBufferUtil.bytes(5),new DeletionTime(3L,3));
DeletionInfo info2 = new DeletionInfo(stone2,BytesType.instance);
DeletionInfo info3 = info1.add(info2);
System.out.println(info3.isDeleted(ByteBufferUtil.bytes(2), 1L));
System.out.println(info3.isDeleted(ByteBufferUtil.bytes(2), 2L));
System.out.println(info3.isDeleted(ByteBufferUtil.bytes(3), 2L));
System.out.println(info3.isDeleted(ByteBufferUtil.bytes(4), 2L));
System.out.println(info3.isDeleted(ByteBufferUtil.bytes(5), 2L));
}
}
true
false
true
true
true