/* * 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.db; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.*; import java.util.concurrent.ExecutionException; import org.apache.commons.lang.ArrayUtils; import static org.junit.Assert.assertNull; import org.junit.Test; import static junit.framework.Assert.assertEquals; import org.apache.cassandra.CleanupHelper; import org.apache.cassandra.Util; import org.apache.cassandra.dht.Token; import org.apache.cassandra.service.StorageService; import org.apache.cassandra.utils.WrappedRunnable; import java.net.InetAddress; import org.apache.cassandra.dht.Range; import org.apache.cassandra.dht.IPartitioner; import org.apache.cassandra.dht.CollatingOrderPreservingPartitioner; import org.apache.cassandra.db.filter.IdentityQueryFilter; import org.apache.cassandra.db.filter.QueryPath; import org.apache.cassandra.db.filter.SliceQueryFilter; import org.apache.cassandra.db.filter.NamesQueryFilter; import org.apache.cassandra.io.SSTableReader; public class ColumnFamilyStoreTest extends CleanupHelper { static byte[] bytes1, bytes2; static { Random random = new Random(); bytes1 = new byte[1024]; bytes2 = new byte[128]; random.nextBytes(bytes1); random.nextBytes(bytes2); } @Test public void testGetColumnWithWrongBF() throws IOException, ExecutionException, InterruptedException { List<RowMutation> rms = new LinkedList<RowMutation>(); RowMutation rm; rm = new RowMutation("Keyspace1", "key1"); rm.add(new QueryPath("Standard1", null, "Column1".getBytes()), "asdf".getBytes(), 0); rm.add(new QueryPath("Standard1", null, "Column2".getBytes()), "asdf".getBytes(), 0); rms.add(rm); ColumnFamilyStore store = Util.writeColumnFamily(rms); Table table = Table.open("Keyspace1"); List<SSTableReader> ssTables = table.getAllSSTablesOnDisk(); assertEquals(1, ssTables.size()); ssTables.get(0).forceBloomFilterFailures(); ColumnFamily cf = store.getColumnFamily(new IdentityQueryFilter("key2", new QueryPath("Standard1", null, "Column1".getBytes()))); assertNull(cf); } @Test public void testEmptyRow() throws Exception { Table table = Table.open("Keyspace1"); final ColumnFamilyStore store = table.getColumnFamilyStore("Standard2"); RowMutation rm; rm = new RowMutation("Keyspace1", "key1"); rm.delete(new QueryPath("Standard2", null, null), System.currentTimeMillis()); rm.apply(); Runnable r = new WrappedRunnable() { public void runMayThrow() throws IOException { SliceQueryFilter sliceFilter = new SliceQueryFilter("key1", new QueryPath("Standard2", null, null), ArrayUtils.EMPTY_BYTE_ARRAY, ArrayUtils.EMPTY_BYTE_ARRAY, false, 1); ColumnFamily cf = store.getColumnFamily(sliceFilter); assert cf.isMarkedForDelete(); assert cf.getColumnsMap().isEmpty(); NamesQueryFilter namesFilter = new NamesQueryFilter("key1", new QueryPath("Standard2", null, null), "a".getBytes()); cf = store.getColumnFamily(namesFilter); assert cf.isMarkedForDelete(); assert cf.getColumnsMap().isEmpty(); } }; TableTest.reTest(store, r); } /** * Writes out a bunch of keys into an SSTable, then runs anticompaction on a range. * Checks to see if anticompaction returns true. */ private void testAntiCompaction(String columnFamilyName, int insertsPerTable) throws IOException, ExecutionException, InterruptedException { List<RowMutation> rms = new ArrayList<RowMutation>(); for (int j = 0; j < insertsPerTable; j++) { String key = String.valueOf(j); RowMutation rm = new RowMutation("Keyspace1", key); rm.add(new QueryPath(columnFamilyName, null, "0".getBytes()), new byte[0], j); rms.add(rm); } ColumnFamilyStore store = Util.writeColumnFamily(rms); List<Range> ranges = new ArrayList<Range>(); IPartitioner partitioner = new CollatingOrderPreservingPartitioner(); Range r = new Range(partitioner.getToken("0"), partitioner.getToken("zzzzzzz")); ranges.add(r); List<SSTableReader> fileList = CompactionManager.instance.submitAnticompaction(store, ranges, InetAddress.getByName("127.0.0.1")).get(); assert fileList.size() >= 1; } @Test public void testAntiCompaction1() throws IOException, ExecutionException, InterruptedException { testAntiCompaction("Standard1", 100); } private RangeSliceReply getRangeSlice(ColumnFamilyStore cfs, Token start, Token end) throws IOException, ExecutionException, InterruptedException { return cfs.getRangeSlice(ArrayUtils.EMPTY_BYTE_ARRAY, new Range(start, end), 10, null, Arrays.asList("asdf".getBytes())); } private void assertKeys(List<Row> rows, List<String> keys) throws UnsupportedEncodingException { assertEquals(keys.size(), rows.size()); for (int i = 0; i < keys.size(); i++) { assertEquals(keys.get(i), rows.get(i).key); } } @Test public void testSkipStartKey() throws IOException, ExecutionException, InterruptedException { ColumnFamilyStore cfs = insert("key1", "key2"); IPartitioner p = StorageService.getPartitioner(); RangeSliceReply result = getRangeSlice(cfs, p.getToken("key1"), p.getToken("key2")); assertKeys(result.rows, Arrays.asList("key2")); } private ColumnFamilyStore insert(String... keys) throws IOException, ExecutionException, InterruptedException { List<RowMutation> rms = new LinkedList<RowMutation>(); RowMutation rm; for (String key : keys) { rm = new RowMutation("Keyspace2", key); rm.add(new QueryPath("Standard1", null, "Column1".getBytes()), "asdf".getBytes(), 0); rms.add(rm); } return Util.writeColumnFamily(rms); } }