private void worker_fullRebuild()
{
IReplConnection srvr;
// TODO: make sure servers are only listed as seeds when they are "active".
try {
srvr = pusher.getRandomSeed();
// double check that we didn't get ourself, because that won't work
if (srvr.getServerGuid().CompareTo(this.getServerGuid()) == 0) {
Console.WriteLine("******************* ERROR: getRandomSeed() returned US when we're trying to full rebuild");
this.state = ReplState.error;
return;
}
} catch (ReplPusher.NoServersAvailableException) {
Console.WriteLine("Repl({0}): fullRebuild - no servers available... return to init",
ctx.server_guid);
this.state = ReplState.init;
return;
}
// (1) clear our keyspace
// TODO: How do we trigger a reinit on a new prefix, so we don't
// have to actually delete everything?? Maybe we can make SubsetStage
// capable of clearing by dropping the old prefix-id? Or maybe we will
// use built-in support for a range-deletion-tombstone?
// TODO: how do we verify that this isn't going to lose important information?
// TODO: probably should just delete/copy _data and _logs
// so we don't lose our seeds and config info
Console.WriteLine("Rebuild({0}): deleting our keys", ctx.server_guid);
foreach (var row in this.next_stage.scanForward(ScanRange<RecordKey>.All())) {
Console.WriteLine(" Rebuild({0}): deleting {1}", ctx.server_guid, row);
this.next_stage.setValue(row.Key, RecordUpdate.DeletionTombstone());
}
// (2) re-record our data-instance id, so we don't get confused
next_stage.setValue(new RecordKey()
.appendKeyPart("_config")
.appendKeyPart("DATA-INSTANCE-ID"),
RecordUpdate.WithPayload(this.data_instance_id));
// (3) ask for a snapshot
IStepsKVDB snapshot = srvr.getSnapshot();
// (4) then copy the snapshot
// TODO: make sure we get data keys before logs, or that we do something to
// be sure to know whether this copy completes successfully or not.
// TODO: probably want to record our copy-progress, so we can continue copy after
// restart without having to do it from scratch!!
// TODO: need to be able to see tombstones in this scan!!
foreach (var row in snapshot.scanForward(ScanRange<RecordKey>.All())) {
Console.WriteLine(" + Rebuild({0}) setValue: {1}", ctx.server_guid, row);
this.next_stage.setValue(row.Key,RecordUpdate.WithPayload(row.Value.data));
}
// (5) make sure to record our server-id correctly
next_stage.setValue(new RecordKey()
.appendKeyPart("_config")
.appendKeyPart("MY-SERVER-ID"),
RecordUpdate.WithPayload(ctx.server_guid));
// (6) if our log is empty, write our log-start
LogStatus status = this.getStatusForLog(ctx.server_guid);
if (status.log_commit_head.GetLong().CompareTo(0) == 0) {
next_stage.setValue(new RecordKey()
.appendKeyPart("_logs")
.appendKeyPart(ctx.server_guid)
.appendKeyPart(new RecordKeyType_Long(0)),
RecordUpdate.WithPayload(new byte[0]));
}
// (7) make sure there is a seed/log entry for ourselves
next_stage.setValue(new RecordKey()
.appendKeyPart("_config").appendKeyPart("seeds").appendKeyPart(ctx.server_guid),
RecordUpdate.WithPayload(""));
Console.WriteLine("Rebuild({0}): finished, sending to init", ctx.server_guid);
this.state = ReplState.init; // now we should be able to log resume!!
}