@Test
  public void testGetSliceFromSuperBasic() throws Throwable {
    // tests slicing against data from one row spread across two sstables
    final Table table = Table.open("Keyspace1");
    final ColumnFamilyStore cfStore = table.getColumnFamilyStore("Super1");
    final String ROW = "row2";

    RowMutation rm = new RowMutation("Keyspace1", ROW);
    ColumnFamily cf = ColumnFamily.create("Keyspace1", "Super1");
    SuperColumn sc = new SuperColumn("sc1".getBytes(), new LongType());
    sc.addColumn(new Column(getBytes(1), "val1".getBytes(), 1L));
    cf.addColumn(sc);
    rm.add(cf);
    rm.apply();

    Runnable verify =
        new WrappedRunnable() {
          public void runMayThrow() throws Exception {
            ColumnFamily cf =
                cfStore.getColumnFamily(
                    ROW,
                    new QueryPath("Super1"),
                    ArrayUtils.EMPTY_BYTE_ARRAY,
                    ArrayUtils.EMPTY_BYTE_ARRAY,
                    false,
                    10);
            assertColumns(cf, "sc1");
            assertEquals(
                new String(cf.getColumn("sc1".getBytes()).getSubColumn(getBytes(1)).value()),
                "val1");
          }
        };

    reTest(table.getColumnFamilyStore("Standard1"), verify);
  }
  @Test
  public void testGetRowSingleColumn() throws Throwable {
    final Table table = Table.open("Keyspace1");
    final ColumnFamilyStore cfStore = table.getColumnFamilyStore("Standard1");

    RowMutation rm = new RowMutation("Keyspace1", TEST_KEY);
    ColumnFamily cf = ColumnFamily.create("Keyspace1", "Standard1");
    cf.addColumn(column("col1", "val1", 1L));
    cf.addColumn(column("col2", "val2", 1L));
    cf.addColumn(column("col3", "val3", 1L));
    rm.add(cf);
    rm.apply();

    Runnable verify =
        new WrappedRunnable() {
          public void runMayThrow() throws Exception {
            ColumnFamily cf;

            cf =
                cfStore.getColumnFamily(
                    new NamesQueryFilter(TEST_KEY, new QueryPath("Standard1"), "col1".getBytes()));
            assertColumns(cf, "col1");

            cf =
                cfStore.getColumnFamily(
                    new NamesQueryFilter(TEST_KEY, new QueryPath("Standard1"), "col3".getBytes()));
            assertColumns(cf, "col3");
          }
        };
    reTest(table.getColumnFamilyStore("Standard1"), verify);
  }
  @Test
  public void testGetSliceFromAdvanced() throws Throwable {
    // tests slicing against data from one row spread across two sstables
    final Table table = Table.open("Keyspace1");
    final ColumnFamilyStore cfStore = table.getColumnFamilyStore("Standard1");
    final String ROW = "row2";

    RowMutation rm = new RowMutation("Keyspace1", ROW);
    ColumnFamily cf = ColumnFamily.create("Keyspace1", "Standard1");
    cf.addColumn(column("col1", "val1", 1L));
    cf.addColumn(column("col2", "val2", 1L));
    cf.addColumn(column("col3", "val3", 1L));
    cf.addColumn(column("col4", "val4", 1L));
    cf.addColumn(column("col5", "val5", 1L));
    cf.addColumn(column("col6", "val6", 1L));
    rm.add(cf);
    rm.apply();
    cfStore.forceBlockingFlush();

    rm = new RowMutation("Keyspace1", ROW);
    cf = ColumnFamily.create("Keyspace1", "Standard1");
    cf.addColumn(column("col1", "valx", 2L));
    cf.addColumn(column("col2", "valx", 2L));
    cf.addColumn(column("col3", "valx", 2L));
    rm.add(cf);
    rm.apply();

    Runnable verify =
        new WrappedRunnable() {
          public void runMayThrow() throws Exception {
            ColumnFamily cf;

            cf =
                cfStore.getColumnFamily(
                    ROW,
                    new QueryPath("Standard1"),
                    "col2".getBytes(),
                    ArrayUtils.EMPTY_BYTE_ARRAY,
                    false,
                    3);
            assertColumns(cf, "col2", "col3", "col4");
            assertEquals(new String(cf.getColumn("col2".getBytes()).value()), "valx");
            assertEquals(new String(cf.getColumn("col3".getBytes()).value()), "valx");
            assertEquals(new String(cf.getColumn("col4".getBytes()).value()), "val4");
          }
        };

    reTest(table.getColumnFamilyStore("Standard1"), verify);
  }
  @Test
  public void testGetSliceFromLarge() throws Throwable {
    // tests slicing against 1000 columns in an sstable
    Table table = Table.open("Keyspace1");
    ColumnFamilyStore cfStore = table.getColumnFamilyStore("Standard1");
    String key = "row3";
    RowMutation rm = new RowMutation("Keyspace1", key);
    ColumnFamily cf = ColumnFamily.create("Keyspace1", "Standard1");
    for (int i = 1000; i < 2000; i++) cf.addColumn(column("col" + i, ("v" + i), 1L));
    rm.add(cf);
    rm.apply();
    cfStore.forceBlockingFlush();

    validateSliceLarge(cfStore);
    // compact so we have a big row with more than the minimum index count
    if (cfStore.getSSTables().size() > 1) {
      CompactionManager.instance.submitMajor(cfStore).get();
    }
    SSTableReader sstable = cfStore.getSSTables().iterator().next();
    DecoratedKey decKey = sstable.getPartitioner().decorateKey(key);
    SSTable.PositionSize info = sstable.getPosition(decKey);
    BufferedRandomAccessFile file = new BufferedRandomAccessFile(sstable.getFilename(), "r");
    file.seek(info.position);
    assert file.readUTF().equals(key);
    file.readInt();
    IndexHelper.skipBloomFilter(file);
    ArrayList<IndexHelper.IndexInfo> indexes = IndexHelper.deserializeIndex(file);
    assert indexes.size() > 2;
    validateSliceLarge(cfStore);
  }
  @Test
  public void testGetRowSliceByRange() throws Throwable {
    String key = TEST_KEY + "slicerow";
    Table table = Table.open("Keyspace1");
    ColumnFamilyStore cfStore = table.getColumnFamilyStore("Standard1");
    RowMutation rm = new RowMutation("Keyspace1", key);
    ColumnFamily cf = ColumnFamily.create("Keyspace1", "Standard1");
    // First write "a", "b", "c"
    cf.addColumn(column("a", "val1", 1L));
    cf.addColumn(column("b", "val2", 1L));
    cf.addColumn(column("c", "val3", 1L));
    rm.add(cf);
    rm.apply();

    cf =
        cfStore.getColumnFamily(
            key, new QueryPath("Standard1"), "b".getBytes(), "c".getBytes(), false, 100);
    assertEquals(2, cf.getColumnCount());

    cf =
        cfStore.getColumnFamily(
            key, new QueryPath("Standard1"), "b".getBytes(), "b".getBytes(), false, 100);
    assertEquals(1, cf.getColumnCount());

    cf =
        cfStore.getColumnFamily(
            key, new QueryPath("Standard1"), "b".getBytes(), "c".getBytes(), false, 1);
    assertEquals(1, cf.getColumnCount());

    cf =
        cfStore.getColumnFamily(
            key, new QueryPath("Standard1"), "c".getBytes(), "b".getBytes(), false, 1);
    assertNull(cf);
  }
  private void validateGetSliceNoMatch(Table table) throws IOException {
    ColumnFamilyStore cfStore = table.getColumnFamilyStore("Standard2");
    ColumnFamily cf;

    // key before the rows that exists
    cf =
        cfStore.getColumnFamily(
            "a",
            new QueryPath("Standard2"),
            ArrayUtils.EMPTY_BYTE_ARRAY,
            ArrayUtils.EMPTY_BYTE_ARRAY,
            false,
            1);
    assertColumns(cf);

    // key after the rows that exist
    cf =
        cfStore.getColumnFamily(
            "z",
            new QueryPath("Standard2"),
            ArrayUtils.EMPTY_BYTE_ARRAY,
            ArrayUtils.EMPTY_BYTE_ARRAY,
            false,
            1);
    assertColumns(cf);
  }
  @Test
  public void testGetSliceNoMatch() throws Throwable {
    Table table = Table.open("Keyspace1");
    RowMutation rm = new RowMutation("Keyspace1", "row1000");
    ColumnFamily cf = ColumnFamily.create("Keyspace1", "Standard2");
    cf.addColumn(column("col1", "val1", 1));
    rm.add(cf);
    rm.apply();

    validateGetSliceNoMatch(table);
    table.getColumnFamilyStore("Standard2").forceBlockingFlush();
    validateGetSliceNoMatch(table);

    Collection<SSTableReader> ssTables = table.getColumnFamilyStore("Standard2").getSSTables();
    assertEquals(1, ssTables.size());
    ssTables.iterator().next().forceBloomFilterFailures();
    validateGetSliceNoMatch(table);
  }
  @Test
  public void simpleQueryWithRangeTombstoneTest() throws Exception {
    Table table = Table.open(KSNAME);
    ColumnFamilyStore cfs = table.getColumnFamilyStore(CFNAME);

    // Inserting data
    String key = "k1";
    RowMutation rm;
    ColumnFamily cf;

    rm = new RowMutation(KSNAME, ByteBufferUtil.bytes(key));
    for (int i = 0; i < 40; i += 2) add(rm, i, 0);
    rm.apply();
    cfs.forceBlockingFlush();

    rm = new RowMutation(KSNAME, ByteBufferUtil.bytes(key));
    cf = rm.addOrGet(CFNAME);
    delete(cf, 10, 22, 1);
    rm.apply();
    cfs.forceBlockingFlush();

    rm = new RowMutation(KSNAME, ByteBufferUtil.bytes(key));
    for (int i = 1; i < 40; i += 2) add(rm, i, 2);
    rm.apply();
    cfs.forceBlockingFlush();

    rm = new RowMutation(KSNAME, ByteBufferUtil.bytes(key));
    cf = rm.addOrGet(CFNAME);
    delete(cf, 19, 27, 3);
    rm.apply();
    // We don't flush to test with both a range tomsbtone in memtable and in sstable

    QueryPath path = new QueryPath(CFNAME);

    // Queries by name
    int[] live = new int[] {4, 9, 11, 17, 28};
    int[] dead = new int[] {12, 19, 21, 24, 27};
    SortedSet<ByteBuffer> columns = new TreeSet<ByteBuffer>(cfs.getComparator());
    for (int i : live) columns.add(b(i));
    for (int i : dead) columns.add(b(i));
    cf = cfs.getColumnFamily(QueryFilter.getNamesFilter(dk(key), path, columns));

    for (int i : live) assert isLive(cf, cf.getColumn(b(i))) : "Column " + i + " should be live";
    for (int i : dead)
      assert !isLive(cf, cf.getColumn(b(i))) : "Column " + i + " shouldn't be live";

    // Queries by slices
    cf =
        cfs.getColumnFamily(
            QueryFilter.getSliceFilter(dk(key), path, b(7), b(30), false, Integer.MAX_VALUE));

    for (int i : new int[] {7, 8, 9, 11, 13, 15, 17, 28, 29, 30})
      assert isLive(cf, cf.getColumn(b(i))) : "Column " + i + " should be live";
    for (int i : new int[] {10, 12, 14, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27})
      assert !isLive(cf, cf.getColumn(b(i))) : "Column " + i + " shouldn't be live";
  }
  @Test
  public void overlappingRangeTest() throws Exception {
    CompactionManager.instance.disableAutoCompaction();
    Table table = Table.open(KSNAME);
    ColumnFamilyStore cfs = table.getColumnFamilyStore(CFNAME);

    // Inserting data
    String key = "k2";
    RowMutation rm;
    ColumnFamily cf;

    rm = new RowMutation(KSNAME, ByteBufferUtil.bytes(key));
    for (int i = 0; i < 20; i++) add(rm, i, 0);
    rm.apply();
    cfs.forceBlockingFlush();

    rm = new RowMutation(KSNAME, ByteBufferUtil.bytes(key));
    cf = rm.addOrGet(CFNAME);
    delete(cf, 5, 15, 1);
    rm.apply();
    cfs.forceBlockingFlush();

    rm = new RowMutation(KSNAME, ByteBufferUtil.bytes(key));
    cf = rm.addOrGet(CFNAME);
    delete(cf, 5, 10, 1);
    rm.apply();
    cfs.forceBlockingFlush();

    rm = new RowMutation(KSNAME, ByteBufferUtil.bytes(key));
    cf = rm.addOrGet(CFNAME);
    delete(cf, 5, 8, 2);
    rm.apply();
    cfs.forceBlockingFlush();

    QueryPath path = new QueryPath(CFNAME);
    cf = cfs.getColumnFamily(QueryFilter.getIdentityFilter(dk(key), path));

    for (int i = 0; i < 5; i++)
      assert isLive(cf, cf.getColumn(b(i))) : "Column " + i + " should be live";
    for (int i = 16; i < 20; i++)
      assert isLive(cf, cf.getColumn(b(i))) : "Column " + i + " should be live";
    for (int i = 5; i <= 15; i++)
      assert !isLive(cf, cf.getColumn(b(i))) : "Column " + i + " shouldn't be live";

    // Compact everything and re-test
    CompactionManager.instance.performMaximal(cfs);
    cf = cfs.getColumnFamily(QueryFilter.getIdentityFilter(dk(key), path));

    for (int i = 0; i < 5; i++)
      assert isLive(cf, cf.getColumn(b(i))) : "Column " + i + " should be live";
    for (int i = 16; i < 20; i++)
      assert isLive(cf, cf.getColumn(b(i))) : "Column " + i + " should be live";
    for (int i = 5; i <= 15; i++)
      assert !isLive(cf, cf.getColumn(b(i))) : "Column " + i + " shouldn't be live";
  }
  @Test
  public void testGetRowNoColumns() throws Throwable {
    final Table table = Table.open("Keyspace2");
    final ColumnFamilyStore cfStore = table.getColumnFamilyStore("Standard3");

    RowMutation rm = new RowMutation("Keyspace2", TEST_KEY);
    ColumnFamily cf = ColumnFamily.create("Keyspace2", "Standard3");
    cf.addColumn(column("col1", "val1", 1L));
    rm.add(cf);
    rm.apply();

    Runnable verify =
        new WrappedRunnable() {
          public void runMayThrow() throws Exception {
            ColumnFamily cf;

            cf =
                cfStore.getColumnFamily(
                    new NamesQueryFilter(
                        TEST_KEY, new QueryPath("Standard3"), new TreeSet<byte[]>()));
            assertColumns(cf);

            cf =
                cfStore.getColumnFamily(
                    new SliceQueryFilter(
                        TEST_KEY,
                        new QueryPath("Standard3"),
                        ArrayUtils.EMPTY_BYTE_ARRAY,
                        ArrayUtils.EMPTY_BYTE_ARRAY,
                        false,
                        0));
            assertColumns(cf);

            cf =
                cfStore.getColumnFamily(
                    new NamesQueryFilter(TEST_KEY, new QueryPath("Standard3"), "col99".getBytes()));
            assertColumns(cf);
          }
        };
    reTest(table.getColumnFamilyStore("Standard3"), verify);
  }
  protected void testCompaction(int sstableCount, int rowsPerSSTable, int colsPerRow)
      throws Exception {
    CompactionManager.instance.disableAutoCompaction();

    Table table = Table.open(TABLE1);
    ColumnFamilyStore store = table.getColumnFamilyStore("Standard1");

    ArrayList<SSTableReader> sstables = new ArrayList<SSTableReader>();
    for (int k = 0; k < sstableCount; k++) {
      SortedMap<String, ColumnFamily> rows = new TreeMap<String, ColumnFamily>();
      for (int j = 0; j < rowsPerSSTable; j++) {
        String key = String.valueOf(j);
        IColumn[] cols = new IColumn[colsPerRow];
        for (int i = 0; i < colsPerRow; i++) {
          // last sstable has highest timestamps
          cols[i] = Util.column(String.valueOf(i), String.valueOf(i), k);
        }
        rows.put(key, SSTableUtils.createCF(Long.MIN_VALUE, Integer.MIN_VALUE, cols));
      }
      SSTableReader sstable = SSTableUtils.writeSSTable(rows);
      sstables.add(sstable);
      store.addSSTable(sstable);
    }

    // give garbage collection a bit of time to catch up
    Thread.sleep(1000);

    long start = System.currentTimeMillis();
    CompactionManager.instance.doCompaction(
        store,
        sstables,
        (int) (System.currentTimeMillis() / 1000)
            - DatabaseDescriptor.getCFMetaData(TABLE1, "Standard1").gcGraceSeconds);
    System.out.println(
        String.format(
            "%s: sstables=%d rowsper=%d colsper=%d: %d ms",
            this.getClass().getName(),
            sstableCount,
            rowsPerSSTable,
            colsPerRow,
            System.currentTimeMillis() - start));
  }
Example #12
0
  /*
   * This excercise in particular the code of #4142
   */
  @Test
  public void testValidationMultipleSSTablePerLevel() throws Exception {
    String ksname = "Keyspace1";
    String cfname = "StandardLeveled";
    Table table = Table.open(ksname);
    ColumnFamilyStore store = table.getColumnFamilyStore(cfname);

    ByteBuffer value =
        ByteBuffer.wrap(new byte[100 * 1024]); // 100 KB value, make it easy to have multiple files

    // Enough data to have a level 1 and 2
    int rows = 20;
    int columns = 10;

    // Adds enough data to trigger multiple sstable per level
    for (int r = 0; r < rows; r++) {
      DecoratedKey key = Util.dk(String.valueOf(r));
      RowMutation rm = new RowMutation(ksname, key.key);
      for (int c = 0; c < columns; c++) {
        rm.add(new QueryPath(cfname, null, ByteBufferUtil.bytes("column" + c)), value, 0);
      }
      rm.apply();
      store.forceFlush();
    }

    LeveledCompactionStrategy strat = (LeveledCompactionStrategy) store.getCompactionStrategy();

    while (strat.getLevelSize(0) > 0) {
      store.forceMajorCompaction();
      Thread.sleep(200);
    }
    // Checking we're not completely bad at math
    assert strat.getLevelSize(1) > 0;
    assert strat.getLevelSize(2) > 0;

    AntiEntropyService.CFPair p = new AntiEntropyService.CFPair(ksname, cfname);
    Range<Token> range = new Range<Token>(Util.token(""), Util.token(""));
    AntiEntropyService.TreeRequest req =
        new AntiEntropyService.TreeRequest("1", FBUtilities.getLocalAddress(), range, p);
    AntiEntropyService.Validator validator = new AntiEntropyService.Validator(req);
    CompactionManager.instance.submitValidation(store, validator).get();
  }
Example #13
0
  /**
   * Retrieves a local subBlock
   *
   * @param blockId row key
   * @param sblockId SubBlock column name
   * @param offset inside the sblock
   * @return a local sublock
   * @throws TException
   */
  private LocalBlock getLocalSubBlock(
      String subBlockCFName, ByteBuffer blockId, ByteBuffer sblockId, int offset)
      throws TException {
    DecoratedKey<Token<?>> decoratedKey =
        new DecoratedKey<Token<?>>(StorageService.getPartitioner().getToken(blockId), blockId);

    Table table = Table.open(cfsKeyspace);
    ColumnFamilyStore sblockStore = table.getColumnFamilyStore(subBlockCFName);

    Collection<SSTableReader> sstables = sblockStore.getSSTables();

    for (SSTableReader sstable : sstables) {

      long position = sstable.getPosition(decoratedKey, Operator.EQ);

      if (position == -1) continue;

      String filename = sstable.descriptor.filenameFor(Component.DATA);
      RandomAccessFile raf = null;
      int mappedLength = -1;
      MappedByteBuffer mappedData = null;
      MappedFileDataInput file = null;
      try {
        raf = new RandomAccessFile(filename, "r");
        assert position < raf.length();

        mappedLength =
            (raf.length() - position) < Integer.MAX_VALUE
                ? (int) (raf.length() - position)
                : Integer.MAX_VALUE;

        mappedData = raf.getChannel().map(FileChannel.MapMode.READ_ONLY, position, mappedLength);

        file = new MappedFileDataInput(mappedData, filename, 0);

        if (file == null) continue;

        // Verify key was found in data file
        DecoratedKey keyInDisk =
            SSTableReader.decodeKey(
                sstable.partitioner, sstable.descriptor, ByteBufferUtil.readWithShortLength(file));
        assert keyInDisk.equals(decoratedKey)
            : String.format("%s != %s in %s", keyInDisk, decoratedKey, file.getPath());

        long rowSize = SSTableReader.readRowSize(file, sstable.descriptor);

        assert rowSize > 0;
        assert rowSize < mappedLength;

        Filter bf = IndexHelper.defreezeBloomFilter(file, sstable.descriptor.usesOldBloomFilter);

        // verify this column in in this version of the row.
        if (!bf.isPresent(sblockId)) continue;

        List<IndexHelper.IndexInfo> indexList = IndexHelper.deserializeIndex(file);

        // we can stop early if bloom filter says none of the
        // columns actually exist -- but,
        // we can't stop before initializing the cf above, in
        // case there's a relevant tombstone
        ColumnFamilySerializer serializer = ColumnFamily.serializer();
        try {
          ColumnFamily cf =
              serializer.deserializeFromSSTableNoColumns(
                  ColumnFamily.create(sstable.metadata), file);

          if (cf.isMarkedForDelete()) continue;

        } catch (Exception e) {
          e.printStackTrace();

          throw new IOException(
              serializer
                  + " failed to deserialize "
                  + sstable.getColumnFamilyName()
                  + " with "
                  + sstable.metadata
                  + " from "
                  + file,
              e);
        }

        Integer sblockLength = null;

        if (indexList == null) sblockLength = seekToSubColumn(sstable.metadata, file, sblockId);
        else sblockLength = seekToSubColumn(sstable.metadata, file, sblockId, indexList);

        if (sblockLength == null || sblockLength < 0) continue;

        int bytesReadFromStart = mappedLength - (int) file.bytesRemaining();

        if (logger.isDebugEnabled())
          logger.debug("BlockLength = " + sblockLength + " Availible " + file.bytesRemaining());

        assert offset <= sblockLength : String.format("%d > %d", offset, sblockLength);

        long dataOffset = position + bytesReadFromStart;

        if (file.bytesRemaining() == 0 || sblockLength == 0) continue;

        return new LocalBlock(file.getPath(), dataOffset + offset, sblockLength - offset);

      } catch (IOException e) {
        throw new TException(e);
      } finally {
        FileUtils.closeQuietly(raf);
      }
    }

    return null;
  }
  @Test
  public void testGetSliceFromBasic() throws Throwable {
    // tests slicing against data from one row in a memtable and then flushed to an sstable
    final Table table = Table.open("Keyspace1");
    final ColumnFamilyStore cfStore = table.getColumnFamilyStore("Standard1");
    final String ROW = "row1";

    RowMutation rm = new RowMutation("Keyspace1", ROW);
    ColumnFamily cf = ColumnFamily.create("Keyspace1", "Standard1");
    cf.addColumn(column("col1", "val1", 1L));
    cf.addColumn(column("col3", "val3", 1L));
    cf.addColumn(column("col4", "val4", 1L));
    cf.addColumn(column("col5", "val5", 1L));
    cf.addColumn(column("col7", "val7", 1L));
    cf.addColumn(column("col9", "val9", 1L));
    rm.add(cf);
    rm.apply();

    rm = new RowMutation("Keyspace1", ROW);
    rm.delete(new QueryPath("Standard1", null, "col4".getBytes()), 2L);
    rm.apply();

    Runnable verify =
        new WrappedRunnable() {
          public void runMayThrow() throws Exception {
            ColumnFamily cf;

            cf =
                cfStore.getColumnFamily(
                    ROW,
                    new QueryPath("Standard1"),
                    "col5".getBytes(),
                    ArrayUtils.EMPTY_BYTE_ARRAY,
                    false,
                    2);
            assertColumns(cf, "col5", "col7");

            cf =
                cfStore.getColumnFamily(
                    ROW,
                    new QueryPath("Standard1"),
                    "col4".getBytes(),
                    ArrayUtils.EMPTY_BYTE_ARRAY,
                    false,
                    2);
            assertColumns(cf, "col4", "col5", "col7");
            assertColumns(ColumnFamilyStore.removeDeleted(cf, Integer.MAX_VALUE), "col5", "col7");

            cf =
                cfStore.getColumnFamily(
                    ROW,
                    new QueryPath("Standard1"),
                    "col5".getBytes(),
                    ArrayUtils.EMPTY_BYTE_ARRAY,
                    true,
                    2);
            assertColumns(cf, "col3", "col4", "col5");

            cf =
                cfStore.getColumnFamily(
                    ROW,
                    new QueryPath("Standard1"),
                    "col6".getBytes(),
                    ArrayUtils.EMPTY_BYTE_ARRAY,
                    true,
                    2);
            assertColumns(cf, "col3", "col4", "col5");

            cf =
                cfStore.getColumnFamily(
                    ROW,
                    new QueryPath("Standard1"),
                    ArrayUtils.EMPTY_BYTE_ARRAY,
                    ArrayUtils.EMPTY_BYTE_ARRAY,
                    true,
                    2);
            assertColumns(cf, "col7", "col9");

            cf =
                cfStore.getColumnFamily(
                    ROW,
                    new QueryPath("Standard1"),
                    "col95".getBytes(),
                    ArrayUtils.EMPTY_BYTE_ARRAY,
                    false,
                    2);
            assertColumns(cf);

            cf =
                cfStore.getColumnFamily(
                    ROW,
                    new QueryPath("Standard1"),
                    "col0".getBytes(),
                    ArrayUtils.EMPTY_BYTE_ARRAY,
                    true,
                    2);
            assertColumns(cf);
          }
        };

    reTest(table.getColumnFamilyStore("Standard1"), verify);
  }
  @Test
  public void testGetSliceWithCutoff() throws Throwable {
    // tests slicing against data from one row in a memtable and then flushed to an sstable
    final Table table = Table.open("Keyspace1");
    final ColumnFamilyStore cfStore = table.getColumnFamilyStore("Standard1");
    final String ROW = "row4";
    final NumberFormat fmt = new DecimalFormat("000");

    RowMutation rm = new RowMutation("Keyspace1", ROW);
    ColumnFamily cf = ColumnFamily.create("Keyspace1", "Standard1");
    // at this rate, we're getting 78-79 cos/block, assuming the blocks are set to be about 4k.
    // so if we go to 300, we'll get at least 4 blocks, which is plenty for testing.
    for (int i = 0; i < 300; i++)
      cf.addColumn(column("col" + fmt.format(i), "omg!thisisthevalue!" + i, 1L));
    rm.add(cf);
    rm.apply();

    Runnable verify =
        new WrappedRunnable() {
          public void runMayThrow() throws Exception {
            ColumnFamily cf;

            // blocks are partitioned like this: 000-097, 098-193, 194-289, 290-299, assuming a 4k
            // column index size.
            assert DatabaseDescriptor.getColumnIndexSize() == 4096
                : "Unexpected column index size, block boundaries won't be where tests expect them.";

            // test forward, spanning a segment.
            cf =
                cfStore.getColumnFamily(
                    ROW,
                    new QueryPath("Standard1"),
                    "col096".getBytes(),
                    "col099".getBytes(),
                    false,
                    4);
            assertColumns(cf, "col096", "col097", "col098", "col099");

            // test reversed, spanning a segment.
            cf =
                cfStore.getColumnFamily(
                    ROW,
                    new QueryPath("Standard1"),
                    "col099".getBytes(),
                    "col096".getBytes(),
                    true,
                    4);
            assertColumns(cf, "col096", "col097", "col098", "col099");

            // test forward, within a segment.
            cf =
                cfStore.getColumnFamily(
                    ROW,
                    new QueryPath("Standard1"),
                    "col100".getBytes(),
                    "col103".getBytes(),
                    false,
                    4);
            assertColumns(cf, "col100", "col101", "col102", "col103");

            // test reversed, within a segment.
            cf =
                cfStore.getColumnFamily(
                    ROW,
                    new QueryPath("Standard1"),
                    "col103".getBytes(),
                    "col100".getBytes(),
                    true,
                    4);
            assertColumns(cf, "col100", "col101", "col102", "col103");

            // test forward from beginning, spanning a segment.
            String[] strCols = new String[100]; // col000-col099
            for (int i = 0; i < 100; i++) strCols[i] = "col" + fmt.format(i);
            cf =
                cfStore.getColumnFamily(
                    ROW,
                    new QueryPath("Standard1"),
                    "".getBytes(),
                    "col099".getBytes(),
                    false,
                    100);
            assertColumns(cf, strCols);

            // test reversed, from end, spanning a segment.
            cf =
                cfStore.getColumnFamily(
                    ROW, new QueryPath("Standard1"), "".getBytes(), "col288".getBytes(), true, 12);
            assertColumns(
                cf, "col288", "col289", "col290", "col291", "col292", "col293", "col294", "col295",
                "col296", "col297", "col298", "col299");
          }
        };

    reTest(table.getColumnFamilyStore("Standard1"), verify);
  }