| 162 | } |
| 163 | |
| 164 | Status RecordReader::ReadRecord(uint64* offset, string* record) { |
| 165 | // Position the input stream. |
| 166 | int64 curr_pos = input_stream_->Tell(); |
| 167 | int64 desired_pos = static_cast<int64>(*offset); |
| 168 | if (curr_pos > desired_pos || curr_pos < 0 /* EOF */ || |
| 169 | (curr_pos == desired_pos && last_read_failed_)) { |
| 170 | last_read_failed_ = false; |
| 171 | TF_RETURN_IF_ERROR(input_stream_->Reset()); |
| 172 | TF_RETURN_IF_ERROR(input_stream_->SkipNBytes(desired_pos)); |
| 173 | } else if (curr_pos < desired_pos) { |
| 174 | TF_RETURN_IF_ERROR(input_stream_->SkipNBytes(desired_pos - curr_pos)); |
| 175 | } |
| 176 | DCHECK_EQ(desired_pos, input_stream_->Tell()); |
| 177 | |
| 178 | // Read header data. |
| 179 | Status s = ReadChecksummed(*offset, sizeof(uint64), record); |
| 180 | if (!s.ok()) { |
| 181 | last_read_failed_ = true; |
| 182 | return s; |
| 183 | } |
| 184 | const uint64 length = core::DecodeFixed64(record->data()); |
| 185 | |
| 186 | // Read data |
| 187 | s = ReadChecksummed(*offset + kHeaderSize, length, record); |
| 188 | if (!s.ok()) { |
| 189 | last_read_failed_ = true; |
| 190 | if (errors::IsOutOfRange(s)) { |
| 191 | s = errors::DataLoss("truncated record at ", *offset); |
| 192 | } |
| 193 | return s; |
| 194 | } |
| 195 | |
| 196 | *offset += kHeaderSize + length + kFooterSize; |
| 197 | DCHECK_EQ(*offset, input_stream_->Tell()); |
| 198 | return Status::OK(); |
| 199 | } |
| 200 | |
| 201 | SequentialRecordReader::SequentialRecordReader( |
| 202 | RandomAccessFile* file, const RecordReaderOptions& options) |