internal IEnumerable<KeyValuePair<RecordKey, RecordData>> fetchLogEntries(
string log_server_guid,
RecordKeyType log_start_key,
int limit = -1,
bool block = false)
{
var rk_start = new RecordKey()
.appendKeyPart("_logs")
.appendKeyPart(log_server_guid);
if (!log_start_key.Equals("")) {
rk_start.appendKeyPart(log_start_key);
}
var rk_end = new RecordKey()
.appendKeyPart("_logs")
.appendKeyPart(log_server_guid);
var scanrange = new ScanRange<RecordKey>(rk_start, RecordKey.AfterPrefix(rk_end), null);
Console.WriteLine(" fetchLogEntries (block:{3}) for ({0}): start {1} end {2}",
log_server_guid, rk_start, rk_end, block);
bool matched_first = false;
int count = 0;
retry_log_fetch:
foreach (var logrow in next_stage.scanForward(scanrange)) {
if (!matched_first) {
// the first logrow needs to match the log_start_key, or there was a gap in the log!!
var logstamp = logrow.Key.key_parts[2];
if (logstamp.CompareTo(log_start_key) != 0) {
throw new LogException(
String.Format("log start gap! guid:{0} log_start_key:{1} logstamp:{2}",
log_server_guid,log_start_key,logstamp));
}
matched_first = true;
continue;
}
yield return logrow;
count++;
// if we're limiting the number of return rows...
if (limit != -1) {
if (count > limit) {
yield break;
}
}
}
if (!matched_first) {
throw new LogException("no log entries!");
}
// if we only matched one log row, then it should be the matching first row.
if ((count == 0) && block) {
Console.WriteLine("++++++++ block on log tail");
lock (this.logWaiters) {
Monitor.Wait(this.logWaiters);
}
Console.WriteLine("++++++++ wakeup from log tail");
goto retry_log_fetch;
}
}