PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/src/java/org/apache/cassandra/db/RangeTombstone.java

https://github.com/thepaul/cassandra
Java | 281 lines | 203 code | 30 blank | 48 comment | 24 complexity | 1798b8945f2e005cf11c58ee9f4d8087 MD5 | raw file
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. package org.apache.cassandra.db;
  19. import java.io.DataInput;
  20. import java.io.DataOutput;
  21. import java.io.IOException;
  22. import java.nio.ByteBuffer;
  23. import java.security.MessageDigest;
  24. import java.util.*;
  25. import org.apache.cassandra.config.CFMetaData;
  26. import org.apache.cassandra.db.marshal.AbstractType;
  27. import org.apache.cassandra.db.marshal.MarshalException;
  28. import org.apache.cassandra.io.ISSTableSerializer;
  29. import org.apache.cassandra.io.sstable.Descriptor;
  30. import org.apache.cassandra.io.util.DataOutputBuffer;
  31. import org.apache.cassandra.utils.ByteBufferUtil;
  32. import org.apache.cassandra.utils.Interval;
  33. public class RangeTombstone extends Interval<ByteBuffer, DeletionTime> implements OnDiskAtom
  34. {
  35. public static final Serializer serializer = new Serializer();
  36. public RangeTombstone(ByteBuffer start, ByteBuffer stop, long markedForDeleteAt, int localDeletionTime)
  37. {
  38. this(start, stop, new DeletionTime(markedForDeleteAt, localDeletionTime));
  39. }
  40. public RangeTombstone(ByteBuffer start, ByteBuffer stop, DeletionTime delTime)
  41. {
  42. super(start, stop, delTime);
  43. }
  44. public ByteBuffer name()
  45. {
  46. return min;
  47. }
  48. public int getLocalDeletionTime()
  49. {
  50. return data.localDeletionTime;
  51. }
  52. public long maxTimestamp()
  53. {
  54. return data.markedForDeleteAt;
  55. }
  56. public int serializedSize(TypeSizes typeSizes)
  57. {
  58. throw new UnsupportedOperationException();
  59. }
  60. public long serializedSizeForSSTable()
  61. {
  62. TypeSizes typeSizes = TypeSizes.NATIVE;
  63. return typeSizes.sizeof((short)min.remaining()) + min.remaining()
  64. + 1 // serialization flag
  65. + typeSizes.sizeof((short)max.remaining()) + max.remaining()
  66. + DeletionTime.serializer.serializedSize(data, typeSizes);
  67. }
  68. public void validateFields(CFMetaData metadata) throws MarshalException
  69. {
  70. AbstractType<?> nameValidator = metadata.cfType == ColumnFamilyType.Super ? metadata.subcolumnComparator : metadata.comparator;
  71. nameValidator.validate(min);
  72. nameValidator.validate(max);
  73. }
  74. public void updateDigest(MessageDigest digest)
  75. {
  76. digest.update(min.duplicate());
  77. digest.update(max.duplicate());
  78. DataOutputBuffer buffer = new DataOutputBuffer();
  79. try
  80. {
  81. buffer.writeLong(data.markedForDeleteAt);
  82. buffer.writeInt(data.localDeletionTime);
  83. }
  84. catch (IOException e)
  85. {
  86. throw new RuntimeException(e);
  87. }
  88. digest.update(buffer.getData(), 0, buffer.getLength());
  89. }
  90. /**
  91. * This tombstone supersedes another one if it is more recent and cover a
  92. * bigger range than rt.
  93. */
  94. public boolean supersedes(RangeTombstone rt, Comparator<ByteBuffer> comparator)
  95. {
  96. if (rt.data.markedForDeleteAt > data.markedForDeleteAt)
  97. return false;
  98. return comparator.compare(min, rt.min) <= 0 && comparator.compare(max, rt.max) >= 0;
  99. }
  100. public static class Tracker
  101. {
  102. private final Comparator<ByteBuffer> comparator;
  103. private final Deque<RangeTombstone> ranges = new ArrayDeque<RangeTombstone>();
  104. private final SortedSet<RangeTombstone> maxOrderingSet = new TreeSet<RangeTombstone>(new Comparator<RangeTombstone>()
  105. {
  106. public int compare(RangeTombstone t1, RangeTombstone t2)
  107. {
  108. return comparator.compare(t1.max, t2.max);
  109. }
  110. });
  111. private int atomCount;
  112. public Tracker(Comparator<ByteBuffer> comparator)
  113. {
  114. this.comparator = comparator;
  115. }
  116. /**
  117. * Compute RangeTombstone that are needed at the beginning of an index
  118. * block starting with {@code firstColumn}.
  119. * Returns the total serialized size of said tombstones and write them
  120. * to {@code out} it if isn't null.
  121. */
  122. public long writeOpenedMarker(OnDiskAtom firstColumn, DataOutput out, OnDiskAtom.Serializer atomSerializer) throws IOException
  123. {
  124. long size = 0;
  125. if (ranges.isEmpty())
  126. return size;
  127. /*
  128. * Compute the marker that needs to be written at the beginning of
  129. * this block. We need to write one if it the more recent
  130. * (opened) tombstone for at least some part of its range.
  131. */
  132. List<RangeTombstone> toWrite = new LinkedList<RangeTombstone>();
  133. outer:
  134. for (RangeTombstone tombstone : ranges)
  135. {
  136. // If ever the first column is outside the range, skip it (in
  137. // case update() hasn't been called yet)
  138. if (comparator.compare(firstColumn.name(), tombstone.max) > 0)
  139. continue;
  140. RangeTombstone updated = new RangeTombstone(firstColumn.name(), tombstone.max, tombstone.data);
  141. Iterator<RangeTombstone> iter = toWrite.iterator();
  142. while (iter.hasNext())
  143. {
  144. RangeTombstone other = iter.next();
  145. if (other.supersedes(updated, comparator))
  146. break outer;
  147. if (updated.supersedes(other, comparator))
  148. iter.remove();
  149. }
  150. toWrite.add(tombstone);
  151. }
  152. TypeSizes typeSizes = TypeSizes.NATIVE;
  153. for (RangeTombstone tombstone : toWrite)
  154. {
  155. size += tombstone.serializedSize(typeSizes);
  156. atomCount++;
  157. if (out != null)
  158. atomSerializer.serializeForSSTable(tombstone, out);
  159. }
  160. return size;
  161. }
  162. public int writtenAtom()
  163. {
  164. return atomCount;
  165. }
  166. /**
  167. * Update this tracker given an {@code atom}.
  168. * If column is a IColumn, check if any tracked range is useless and
  169. * can be removed. If it is a RangeTombstone, add it to this tracker.
  170. */
  171. public void update(OnDiskAtom atom)
  172. {
  173. if (atom instanceof RangeTombstone)
  174. {
  175. RangeTombstone t = (RangeTombstone)atom;
  176. // This could be a repeated marker already. If so, we already have a range in which it is
  177. // fully included. While keeping both would be ok functionaly, we could end up with a lot of
  178. // useless marker after a few compaction, so avoid this.
  179. for (RangeTombstone tombstone : maxOrderingSet.tailSet(t))
  180. {
  181. // We only care about tombstone have the same max than t
  182. if (comparator.compare(t.max, tombstone.max) > 0)
  183. break;
  184. // Since it is assume tombstones are passed to this method in growing min order, it's enough to
  185. // check for the data to know is the current tombstone is included in a previous one
  186. if (tombstone.data.equals(t.data))
  187. return;
  188. }
  189. ranges.addLast(t);
  190. maxOrderingSet.add(t);
  191. }
  192. else
  193. {
  194. assert atom instanceof IColumn;
  195. Iterator<RangeTombstone> iter = maxOrderingSet.iterator();
  196. while (iter.hasNext())
  197. {
  198. RangeTombstone tombstone = iter.next();
  199. if (comparator.compare(atom.name(), tombstone.max) > 0)
  200. {
  201. // That tombstone is now useless
  202. iter.remove();
  203. ranges.remove(tombstone);
  204. }
  205. else
  206. {
  207. // Since we're iterating by growing end bound, if the current range
  208. // includes the column, so does all the next ones
  209. return;
  210. }
  211. }
  212. }
  213. }
  214. public boolean isDeleted(IColumn column)
  215. {
  216. for (RangeTombstone tombstone : ranges)
  217. {
  218. if (comparator.compare(column.name(), tombstone.max) <= 0 && tombstone.data.isDeleted(column))
  219. return true;
  220. }
  221. return false;
  222. }
  223. }
  224. public static class Serializer implements ISSTableSerializer<RangeTombstone>
  225. {
  226. public void serializeForSSTable(RangeTombstone t, DataOutput dos) throws IOException
  227. {
  228. ByteBufferUtil.writeWithShortLength(t.min, dos);
  229. dos.writeByte(ColumnSerializer.RANGE_TOMBSTONE_MASK);
  230. ByteBufferUtil.writeWithShortLength(t.max, dos);
  231. DeletionTime.serializer.serialize(t.data, dos);
  232. }
  233. public RangeTombstone deserializeFromSSTable(DataInput dis, Descriptor.Version version) throws IOException
  234. {
  235. ByteBuffer min = ByteBufferUtil.readWithShortLength(dis);
  236. if (min.remaining() <= 0)
  237. throw ColumnSerializer.CorruptColumnException.create(dis, min);
  238. int b = dis.readUnsignedByte();
  239. assert (b & ColumnSerializer.RANGE_TOMBSTONE_MASK) != 0;
  240. return deserializeBody(dis, min, version);
  241. }
  242. public RangeTombstone deserializeBody(DataInput dis, ByteBuffer min, Descriptor.Version version) throws IOException
  243. {
  244. ByteBuffer max = ByteBufferUtil.readWithShortLength(dis);
  245. if (max.remaining() <= 0)
  246. throw ColumnSerializer.CorruptColumnException.create(dis, max);
  247. DeletionTime dt = DeletionTime.serializer.deserialize(dis);
  248. return new RangeTombstone(min, max, dt);
  249. }
  250. }
  251. }