private void _prevRecord(ref RecordLocator rloc)
{
byte[] search_buffer = new byte[PREV_RECORD_SCANSIZE];
int read_result_size, read_size;
if (!rloc.have_record) {
throw new Exception("_prevRecord() called with rloc.have_record==false");
}
if (rloc.start_pos == 0) {
// we can't go back before the beginning of our block, so if we reach it, we are done
rloc.have_record = false;
rloc.start_pos = 0;
rloc.after_end_pos = 0;
rloc.record = default(KeyValuePair<RecordKey,RecordUpdate>);
return;
}
int check_up_to = rloc.start_pos - 1; // stop short, or we'll try to redecode the same record we were handed
int cur_stream_pos = Math.Max(0, rloc.start_pos - search_buffer.Length);
while (cur_stream_pos >= 0) {
this.datastream.Seek(cur_stream_pos, SeekOrigin.Begin);
read_size = (int)Math.Min(search_buffer.Length,check_up_to-cur_stream_pos);
read_result_size = this.datastream.Read(search_buffer,0,read_size);
int bufpos = read_result_size - 1;
while (bufpos >= 0) {
if (search_buffer[bufpos] == SegmentBlockBasicEncoder.END_OF_LINE) {
// decode record
int new_record_start = cur_stream_pos + bufpos + 1;
this.datastream.Seek(new_record_start, SeekOrigin.Begin);
rloc.record = SegmentBlockBasicDecoder._decodeRecordFromBlock(this.datastream);
rloc.after_end_pos = (int) this.datastream.Position;
if (rloc.after_end_pos != rloc.start_pos) {
// if this decode didn't bring us to the start of the record we were
// ..handed, then something is WRONG!
throw new Exception("_prevRecord() INTERNAL scan error");
}
rloc.have_record = true;
rloc.start_pos = new_record_start;
return;
}
bufpos--;
}
// IF we got this far with cur_stream_pos == 0, we're at the start of the block!
if (cur_stream_pos == 0) {
// TODO: use a crafty state switch to avoid the block duplicated here from above
// if we landed on the beginnng of the block, then decode the first record in the block
int new_record_start = 0;
this.datastream.Seek(new_record_start, SeekOrigin.Begin);
rloc.record = SegmentBlockBasicDecoder._decodeRecordFromBlock(this.datastream);
rloc.after_end_pos = (int)this.datastream.Position;
if (rloc.after_end_pos != rloc.start_pos) {
// if this decode didn't bring us to the start of the record we were
// ..handed, then something is WRONG!
throw new Exception("_prevRecord() INTERNAL scan error");
}
rloc.have_record = true;
rloc.start_pos = new_record_start;
return;
}
// backup to the next range
cur_stream_pos = Math.Max(0, cur_stream_pos - search_buffer.Length);
};
throw new Exception("_prevRecord() INTERNAL scan error, dropout");
}