diff options
author | jorlow@chromium.org <jorlow@chromium.org@62dab493-f737-651d-591e-8d6aee1b9529> | 2011-03-18 22:37:00 +0000 |
---|---|---|
committer | jorlow@chromium.org <jorlow@chromium.org@62dab493-f737-651d-591e-8d6aee1b9529> | 2011-03-18 22:37:00 +0000 |
commit | f67e15e50f392625b4097caf22e8be1b0fe96013 (patch) | |
tree | 1cb1764c7627f9bac27ed0e0abf27010156e5007 /db/log_writer.cc | |
parent | 54f1fd7eef101db1dfb2bb66a59083c45a38aa4a (diff) | |
download | leveldb-f67e15e50f392625b4097caf22e8be1b0fe96013.tar.gz |
Initial checkin.
git-svn-id: https://leveldb.googlecode.com/svn/trunk@2 62dab493-f737-651d-591e-8d6aee1b9529
Diffstat (limited to 'db/log_writer.cc')
-rw-r--r-- | db/log_writer.cc | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/db/log_writer.cc b/db/log_writer.cc new file mode 100644 index 0000000..465eca2 --- /dev/null +++ b/db/log_writer.cc @@ -0,0 +1,101 @@ +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#include "db/log_writer.h" + +#include <stdint.h> +#include "include/env.h" +#include "util/coding.h" +#include "util/crc32c.h" + +namespace leveldb { +namespace log { + +Writer::Writer(WritableFile* dest) + : dest_(dest), + block_offset_(0) { + for (int i = 0; i <= kMaxRecordType; i++) { + char t = static_cast<char>(i); + type_crc_[i] = crc32c::Value(&t, 1); + } +} + +Writer::~Writer() { +} + +Status Writer::AddRecord(const Slice& slice) { + const char* ptr = slice.data(); + size_t left = slice.size(); + + // Fragment the record if necessary and emit it. Note that if slice + // is empty, we still want to iterate once to emit a single + // zero-length record + Status s; + do { + const int leftover = kBlockSize - block_offset_; + assert(leftover >= 0); + if (leftover <= kHeaderSize) { + // Switch to a new block + if (leftover > 0) { + // Fill the trailer + dest_->Append(Slice("\x00\x00\x00\x00\x00\x00\x00", leftover)); + } + block_offset_ = 0; + } + + // Invariant: we never leave <= kHeaderSize bytes in a block. + const int avail = kBlockSize - block_offset_ - kHeaderSize; + assert(avail > 0); + + const size_t fragment_length = (left < avail) ? left : avail; + + RecordType type; + const bool begin = (ptr == slice.data()); + const bool end = (left == fragment_length); + if (begin && end) { + type = kFullType; + } else if (begin) { + type = kFirstType; + } else if (end) { + type = kLastType; + } else { + type = kMiddleType; + } + + s = EmitPhysicalRecord(type, ptr, fragment_length); + ptr += fragment_length; + left -= fragment_length; + } while (s.ok() && left > 0); + return s; +} + +Status Writer::EmitPhysicalRecord(RecordType t, const char* ptr, size_t n) { + assert(n <= 0xffff); // Must fit in two bytes + assert(block_offset_ + kHeaderSize + n <= kBlockSize); + + // Format the header + char buf[kHeaderSize]; + buf[4] = static_cast<char>(n & 0xff); + buf[5] = static_cast<char>(n >> 8); + buf[6] = static_cast<char>(t); + + // Compute the crc of the record type and the payload. + uint32_t crc = crc32c::Extend(type_crc_[t], ptr, n); + crc = crc32c::Mask(crc); // Adjust for storage + EncodeFixed32(buf, crc); + + // Write the header and the payload + Status s = dest_->Append(Slice(buf, kHeaderSize)); + if (s.ok()) { + s = dest_->Append(Slice(ptr, n)); + if (s.ok()) { + s = dest_->Flush(); + } + } + block_offset_ += kHeaderSize + n; + return s; +} + +} +} |