Bend.SegmentBlockBasicDecoder._findRecord C# (CSharp) Method

_findRecord() private method

private _findRecord ( IComparable keytest, bool equal_is_after ) : FindRecordResult
keytest IComparable
equal_is_after bool
return FindRecordResult
        private FindRecordResult _findRecord(IComparable<RecordKey> keytest, bool equal_is_after)
        {
            // read state
            byte[] search_buffer = new byte[FIND_RECORD_BUFSIZE];
            int read_result_size, read_size;
            int restart_count = 0;

            FindRecordResult result = default(FindRecordResult);

            // cursor state
            int startpos = 0;
            int endpos = (int)this.datastream.Length;
            int midpoint_pos = 0xbeefed;  // distinct but uninitalized

            // start by decoding the first record in the block
            int eol_marker_pos = -1;
            mpss state = mpss.HAVE_START;

            switch (state) {
                case mpss.BISECT:
                    if (endpos == startpos) {
                        return result;
                    }
                    {   // find out if we need to account for an odd-size split
                        int midpoint_pos_delta = endpos - startpos;
                        int midpoint_offset = 0xbeefed;
                        if ((midpoint_pos_delta & 1) == 1) {
                            midpoint_offset = (midpoint_pos_delta - 1) / 2;
                        } else {
                            midpoint_offset = midpoint_pos_delta / 2;
                        }
                        midpoint_pos = startpos + midpoint_offset;
                    }

                    if (midpoint_pos > endpos) {
                        midpoint_pos = startpos;
                    }
                    goto case mpss.FIND_REC_FORWARD;
                case mpss.FIND_REC_FORWARD:
                    restart_count = 0;
                    goto case mpss.FIND_REC_FORWARD_RESTART; // fall through
                case mpss.FIND_REC_FORWARD_RESTART:
                    restart_count++;
                    // scan forward until we find an END_OF_LINE record boundary
                    {
                        int cur_stream_pos = midpoint_pos;
                        do {
                            int bufpos = 0;
                            this.datastream.Seek(cur_stream_pos, SeekOrigin.Begin);
                            read_size = (int)Math.Min(search_buffer.Length,endpos-cur_stream_pos);
                            read_result_size = this.datastream.Read(search_buffer,0,read_size);

                            while (bufpos < read_result_size) {
                                if (search_buffer[bufpos] == SegmentBlockBasicEncoder.END_OF_LINE) {
                                    eol_marker_pos = cur_stream_pos + bufpos;
                                    goto case mpss.HAVE_START;
                                }
                                bufpos++;
                            }
                            cur_stream_pos += read_result_size;
                        } while (cur_stream_pos < endpos);
                    }

                    if (restart_count > 1) {
                        throw new Exception("INTERNAL ERROR : SegmentBlockBasic._findRecord, restarted more than once!");
                    }
                    // ran out of datastream and didn't find END_OF_LINE!
                    // move to the beginning of the buffer and restart,
                    midpoint_pos = startpos;
                    // but don't rescan that stuff we just saw between midpoint_pos and endpos
                    endpos = midpoint_pos+1;
                    goto case mpss.FIND_REC_FORWARD_RESTART;
                    // fyi - we considered bisecting the first half, but if the records are so big relative
                    //  to our midpoint that there were none in the second half, it's because our records
                    //  are really large relative to the range we are scanning, so it's safer just to
                    //  start at the BEGINNING of the whole range.
                case mpss.HAVE_START:
                    // we have a record_start_stream_pos, so decode the record and test against the comparison
                    {
                        RecordLocator rloc;
                        int record_start_pos = eol_marker_pos + 1;
                        if (record_start_pos == endpos) {
                            // we found the end of the last record in the midpoint-region,
                            // however, we're not sure where it starts, let's
                            // decode the record at the start of the region instead.
                            record_start_pos = startpos;
                        }

                        // decode the record
                        this.datastream.Seek(record_start_pos, SeekOrigin.Begin);
                        rloc.record = SegmentBlockBasicDecoder._decodeRecordFromBlock(this.datastream);
                        rloc.start_pos = record_start_pos;
                        rloc.after_end_pos = (int)this.datastream.Position;
                        rloc.have_record = true;

                        int compare_result = keytest.CompareTo(rloc.record.Key);
                        if (compare_result == 0) {
                            if (equal_is_after) {
                                compare_result = -1; // rec==keytest should be after
                            } else {
                                compare_result = 1;  // rec==keytest should be before
                            }

                        }
                        if (compare_result < 0) {  // record is AFTER keytest
                            result.after_keytest = rloc;
                            // we know this record is after us, so scan only before it
                            endpos = rloc.start_pos;
                        } else if (compare_result > 0) { // record is BEFORE keytest
                            result.before_keytest = rloc;
                            // we know this record is before us, so scan only after it
                            startpos = rloc.after_end_pos;
                        }
                    }
                    goto case mpss.BISECT;
                default:
                    throw new Exception("unknown mpss state: " + state.ToString());
            } // end switch(mpss state)
        }