package org.apache.cassandra.db.commitlog;
/*
* pgaref's Master Thesis is not as easy as expected
* Please use at you own risk! Be patient and optimistic
*
*/
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.cassandra.concurrent.Stage;
import org.apache.cassandra.concurrent.StageManager;
import org.apache.cassandra.config.Schema;
import org.apache.cassandra.db.ColumnFamily;
import org.apache.cassandra.db.ColumnFamilyStore;
import org.apache.cassandra.db.DefsTables;
import org.apache.cassandra.db.Keyspace;
import org.apache.cassandra.db.RowMutation;
import org.apache.cassandra.db.SystemKeyspace;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.Pair;
import org.apache.cassandra.utils.WrappedRunnable;
import org.cliffc.high_scale_lib.NonBlockingHashSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Ordering;
public class MyRowMutationReplayer {
private static final Logger logger = LoggerFactory
.getLogger(MyRowMutationReplayer.class);
private static final int MAX_OUTSTANDING_REPLAY_COUNT = 1024;
private final Set<Keyspace> keyspacesRecovered;
private final List<Future<?>> futures;
public MyRowMutationReplayer() {
this.keyspacesRecovered = new NonBlockingHashSet<Keyspace>();
this.futures = new ArrayList<Future<?>>();
}
public int blockForWrites() {
FBUtilities.waitOnFutures(futures);
logger.debug("Finished waiting on mutations from recovery");
futures.clear();
for (Keyspace keyspace : keyspacesRecovered)
futures.addAll(keyspace.flush());
FBUtilities.waitOnFutures(futures);
return futures.size();
}
public void recover(RowMutation rm) throws IOException {
logger.info("pgaref - Replaying {}", rm.toString());
final RowMutation frm = rm;
Runnable runnable = new WrappedRunnable() {
public void runMayThrow() throws IOException {
final Keyspace keyspace = Keyspace.open(frm.getKeyspaceName());
if (Schema.instance.getKSMetaData(frm.getKeyspaceName()) == null)
return;
// Rebuild the row mutation, omitting column families that
// a) have already been flushed,
// b) are part of a cf that was dropped. Keep in mind that the
// cf.name() is suspect. do every thing based on the cfid
// instead.
RowMutation newRm = null;
for (ColumnFamily columnFamily : frm.getColumnFamilies()) {
if (Schema.instance.getCF(columnFamily.id()) == null){
// null means the cf has been dropped
continue;
}
// replay if current segment is newer than last flushed one
// or,
// if it is the last known segment, if we are after the
// replay position
if (newRm == null)
newRm = new RowMutation(frm.getKeyspaceName(),
frm.key());
newRm.add(columnFamily);
}
if (newRm != null) {
logger.debug("pgaref - MyRowMutaion Final Case");
assert !newRm.isEmpty();
try {
DefsTables.mergeSchema(Arrays.asList(frm));
} catch (ConfigurationException e) {
logger.error("pgaref - Failed to Merge Schem for new RowMutation");
}
keyspacesRecovered.add(keyspace);
}
}
};
futures.add(StageManager.getStage(Stage.MUTATION).submit(runnable));
if (futures.size() > MAX_OUTSTANDING_REPLAY_COUNT) {
FBUtilities.waitOnFutures(futures);
futures.clear();
}
}
}