/*
* 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.util.concurrent.ExecutionException;
import org.junit.Test;
import org.apache.cassandra.CleanupHelper;
import org.apache.cassandra.db.commitlog.CommitLog;
import org.apache.cassandra.db.filter.IdentityQueryFilter;
import org.apache.cassandra.db.filter.QueryPath;
import static org.apache.cassandra.Util.column;
import static org.apache.cassandra.db.TableTest.assertColumns;
public class RecoveryManagerTest extends CleanupHelper
{
@Test
public void testNothing() throws IOException {
// TODO nothing to recover
CommitLog.recover();
}
@Test
public void testOne() throws IOException, ExecutionException, InterruptedException
{
Table table1 = Table.open("Keyspace1");
Table table2 = Table.open("Keyspace2");
RowMutation rm;
ColumnFamily cf;
rm = new RowMutation("Keyspace1", "keymulti");
cf = ColumnFamily.create("Keyspace1", "Standard1");
cf.addColumn(column("col1", "val1", 1L));
rm.add(cf);
rm.apply();
rm = new RowMutation("Keyspace2", "keymulti");
cf = ColumnFamily.create("Keyspace2", "Standard3");
cf.addColumn(column("col2", "val2", 1L));
rm.add(cf);
rm.apply();
table1.getColumnFamilyStore("Standard1").clearUnsafe();
table2.getColumnFamilyStore("Standard3").clearUnsafe();
CommitLog.recover();
assertColumns(table1.get("keymulti", "Standard1"), "col1");
assertColumns(table2.get("keymulti", "Standard3"), "col2");
}
@Test
public void testPartialReplay() throws IOException, ExecutionException, InterruptedException
{
Table table = Table.open("Keyspace1");
ColumnFamilyStore store1 = table.getColumnFamilyStore("Standard1");
ColumnFamilyStore store2 = table.getColumnFamilyStore("Standard2");
genCommits(store1, store2);
// now replaying with max timestamp = 5. only 5 mutations must be applied
CommitLog.instance().forcedRecover(5);
ColumnFamily cf1 = store1.getColumnFamily(new IdentityQueryFilter("key33", new QueryPath("Standard1")));
for (int i = 1; i < 10; i++)
{
IColumn c = cf1.getColumn(("Column33"+i).getBytes());
if (i>5)
assert c == null;
if (i<=5)
assert c.timestamp()==i;
}
ColumnFamily cf2 = store2.getColumnFamily(new IdentityQueryFilter("key33", new QueryPath("Standard2")));
assert cf2.getColumn("Column33".getBytes()).timestamp()==5;
store1 = table.getColumnFamilyStore("Standard1");
store2 = table.getColumnFamilyStore("Standard2");
genCommits(store1, store2);
// now replaying with max timestamp = 0. no mutations must be applied
CommitLog.instance().forcedRecover(0);
cf1 = store1.getColumnFamily(new IdentityQueryFilter("key33", new QueryPath("Standard1")));
for (int i = 1; i < 10; i++)
{
IColumn c = cf1.getColumn(("Column33"+i).getBytes());
assert c == null : c.toString();
}
cf2 = store2.getColumnFamily(new IdentityQueryFilter("key33", new QueryPath("Standard2")));
assert cf2.getColumn("Column33".getBytes()).timestamp() == 0l;
genCommits(store1, store2);
// now replaying with no max timestamp. all mutations must be there
CommitLog.instance().forcedRecover(Long.MAX_VALUE);
cf1 = store1.getColumnFamily(new IdentityQueryFilter("key33", new QueryPath("Standard1")));
for (int i = 1; i < 10; i++)
{
IColumn c = cf1.getColumn(("Column33"+i).getBytes());
assert c.timestamp()==i;
}
cf2 = store2.getColumnFamily(new IdentityQueryFilter("key33", new QueryPath("Standard2")));
assert cf2.getColumn("Column33".getBytes()).timestamp() == 9;
}
private void genCommits(ColumnFamilyStore store1, ColumnFamilyStore store2)
throws IOException
{
store1.clearUnsafe();
store2.clearUnsafe();
CommitLog.instance().resetUnsafe();
assert CommitLog.instance().getSegmentCount() == 1;
CommitLog.setSegmentSize(10000000);
RowMutation rm;
byte[] value = new byte[501];
// add data. use relatively large values to force quick segment creation since we have a low flush threshold in the test config.
for (int i = 0; i < 10; i++)
{
rm = new RowMutation("Keyspace1", "key33");
rm.add(new QueryPath("Standard1", null, ("Column33"+i).getBytes()), value, i);
rm.add(new QueryPath("Standard2", null, "Column33".getBytes()), value, i);
rm.apply();
}
assert CommitLog.instance().getSegmentCount() == 1;
CommitLog.instance().forceNewSegment();
store1.clearUnsafe();
store2.clearUnsafe();
}
}