PageRenderTime 135ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/src/java/org/apache/cassandra/io/sstable/SSTableSimpleUnsortedWriter.java

https://github.com/thepaul/cassandra
Java | 202 lines | 137 code | 22 blank | 43 comment | 14 complexity | 824006771265776fdf7f325c6d450e26 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.io.sstable;
  19. import java.io.File;
  20. import java.io.IOException;
  21. import java.util.Map;
  22. import java.util.TreeMap;
  23. import java.util.concurrent.BlockingQueue;
  24. import java.util.concurrent.SynchronousQueue;
  25. import com.google.common.base.Throwables;
  26. import org.apache.cassandra.config.CFMetaData;
  27. import org.apache.cassandra.db.ColumnFamily;
  28. import org.apache.cassandra.db.ColumnFamilyType;
  29. import org.apache.cassandra.db.DecoratedKey;
  30. import org.apache.cassandra.db.TreeMapBackedSortedColumns;
  31. import org.apache.cassandra.db.marshal.AbstractType;
  32. import org.apache.cassandra.dht.IPartitioner;
  33. import org.apache.cassandra.io.compress.CompressionParameters;
  34. import org.apache.cassandra.net.MessagingService;
  35. /**
  36. * A SSTable writer that doesn't assume rows are in sorted order.
  37. * This writer buffers rows in memory and then write them all in sorted order.
  38. * To avoid loading the entire data set in memory, the amount of rows buffered
  39. * is configurable. Each time the threshold is met, one SSTable will be
  40. * created (and the buffer be reseted).
  41. *
  42. * @see AbstractSSTableSimpleWriter
  43. */
  44. public class SSTableSimpleUnsortedWriter extends AbstractSSTableSimpleWriter
  45. {
  46. private static final Buffer SENTINEL = new Buffer();
  47. private Buffer buffer = new Buffer();
  48. private final long bufferSize;
  49. private long currentSize;
  50. private final BlockingQueue<Buffer> writeQueue = new SynchronousQueue<Buffer>();
  51. private final DiskWriter diskWriter = new DiskWriter();
  52. /**
  53. * Create a new buffering writer.
  54. * @param directory the directory where to write the sstables
  55. * @param partitioner the partitioner
  56. * @param keyspace the keyspace name
  57. * @param columnFamily the column family name
  58. * @param comparator the column family comparator
  59. * @param subComparator the column family subComparator or null if not a Super column family.
  60. * @param bufferSizeInMB the data size in MB before which a sstable is written and the buffer reseted. This correspond roughly to the written
  61. * data size (i.e. the size of the create sstable). The actual size used in memory will be higher (by how much depends on the size of the
  62. * columns you add). For 1GB of heap, a 128 bufferSizeInMB is probably a reasonable choice. If you experience OOM, this value should be lowered.
  63. */
  64. public SSTableSimpleUnsortedWriter(File directory,
  65. IPartitioner partitioner,
  66. String keyspace,
  67. String columnFamily,
  68. AbstractType<?> comparator,
  69. AbstractType<?> subComparator,
  70. int bufferSizeInMB,
  71. CompressionParameters compressParameters)
  72. {
  73. super(directory, new CFMetaData(keyspace, columnFamily, subComparator == null ? ColumnFamilyType.Standard : ColumnFamilyType.Super, comparator, subComparator).compressionParameters(compressParameters), partitioner);
  74. this.bufferSize = bufferSizeInMB * 1024L * 1024L;
  75. this.diskWriter.start();
  76. }
  77. public SSTableSimpleUnsortedWriter(File directory,
  78. IPartitioner partitioner,
  79. String keyspace,
  80. String columnFamily,
  81. AbstractType<?> comparator,
  82. AbstractType<?> subComparator,
  83. int bufferSizeInMB)
  84. {
  85. this(directory, partitioner, keyspace, columnFamily, comparator, subComparator, bufferSizeInMB, new CompressionParameters(null));
  86. }
  87. protected void writeRow(DecoratedKey key, ColumnFamily columnFamily) throws IOException
  88. {
  89. currentSize += key.key.remaining() + ColumnFamily.serializer.serializedSize(columnFamily, MessagingService.current_version) * 1.2;
  90. if (currentSize > bufferSize)
  91. sync();
  92. }
  93. protected ColumnFamily getColumnFamily()
  94. {
  95. ColumnFamily previous = buffer.get(currentKey);
  96. // If the CF already exist in memory, we'll just continue adding to it
  97. if (previous == null)
  98. {
  99. previous = ColumnFamily.create(metadata, TreeMapBackedSortedColumns.factory());
  100. buffer.put(currentKey, previous);
  101. }
  102. else
  103. {
  104. // We will reuse a CF that we have counted already. But because it will be easier to add the full size
  105. // of the CF in the next writeRow call than to find out the delta, we just remove the size until that next call
  106. currentSize -= currentKey.key.remaining() + ColumnFamily.serializer.serializedSize(previous, MessagingService.current_version) * 1.2;
  107. }
  108. return previous;
  109. }
  110. public void close() throws IOException
  111. {
  112. sync();
  113. try
  114. {
  115. writeQueue.put(SENTINEL);
  116. diskWriter.join();
  117. }
  118. catch (InterruptedException e)
  119. {
  120. throw new RuntimeException(e);
  121. }
  122. checkForWriterException();
  123. }
  124. private void sync() throws IOException
  125. {
  126. if (buffer.isEmpty())
  127. return;
  128. checkForWriterException();
  129. try
  130. {
  131. writeQueue.put(buffer);
  132. }
  133. catch (InterruptedException e)
  134. {
  135. throw new RuntimeException(e);
  136. }
  137. buffer = new Buffer();
  138. currentSize = 0;
  139. }
  140. private void checkForWriterException() throws IOException
  141. {
  142. // slightly lame way to report exception from the writer, but that should be good enough
  143. if (diskWriter.exception != null)
  144. {
  145. if (diskWriter.exception instanceof IOException)
  146. throw (IOException) diskWriter.exception;
  147. else
  148. throw Throwables.propagate(diskWriter.exception);
  149. }
  150. }
  151. // typedef
  152. private static class Buffer extends TreeMap<DecoratedKey, ColumnFamily> {}
  153. private class DiskWriter extends Thread
  154. {
  155. volatile Throwable exception = null;
  156. public void run()
  157. {
  158. SSTableWriter writer = null;
  159. try
  160. {
  161. while (true)
  162. {
  163. Buffer b = writeQueue.take();
  164. if (b == SENTINEL)
  165. return;
  166. writer = getWriter();
  167. for (Map.Entry<DecoratedKey, ColumnFamily> entry : b.entrySet())
  168. writer.append(entry.getKey(), entry.getValue());
  169. writer.closeAndOpenReader();
  170. }
  171. }
  172. catch (Throwable e)
  173. {
  174. if (writer != null)
  175. writer.abort();
  176. exception = e;
  177. }
  178. }
  179. }
  180. }