diff --git a/util/aligned_buffer.h b/util/aligned_buffer.h index 2201b48777..dbff9c8109 100644 --- a/util/aligned_buffer.h +++ b/util/aligned_buffer.h @@ -13,21 +13,47 @@ namespace rocksdb { +// This file contains utilities to handle the alignment of pages and buffers. + +// Truncate to a multiple of page_size, which is also a page boundary. This +// helps to figuring out the right alignment. +// Example: +// TruncateToPageBoundary(5000, 4096) => 4096 +// TruncateToPageBoundary(10000, 4096) => 8192 inline size_t TruncateToPageBoundary(size_t page_size, size_t s) { s -= (s & (page_size - 1)); assert((s % page_size) == 0); return s; } +// Round up x to a multiple of y. +// Example: +// Roundup(13, 5) => 15 +// Roundup(201, 16) => 208 inline size_t Roundup(size_t x, size_t y) { return ((x + y - 1) / y) * y; } +// Round down x to a multiple of y. +// Example: +// Rounddown(13, 5) => 10 +// Rounddown(201, 16) => 192 inline size_t Rounddown(size_t x, size_t y) { return (x / y) * y; } -// This class is to manage an aligned user -// allocated buffer for direct I/O purposes -// though can be used for any purpose. +// AlignedBuffer manages a buffer by taking alignment into consideration, and +// aligns the buffer start and end positions. It is mainly used for direct I/O, +// though it can be used other purposes as well. +// It also supports expanding the managed buffer, and copying whole or part of +// the data from old buffer into the new expanded buffer. Such a copy especially +// helps in cases avoiding an IO to re-fetch the data from disk. +// +// Example: +// AlignedBuffer buf; +// buf.Alignment(alignment); +// buf.AllocateNewBuffer(user_requested_buf_size); +// ... +// buf.AllocateNewBuffer(2*user_requested_buf_size, /*copy_data*/ true, +// copy_offset, copy_len); class AlignedBuffer { size_t alignment_; std::unique_ptr buf_; @@ -96,12 +122,21 @@ public: alignment_ = alignment; } - // Allocates a new buffer and sets bufstart_ to the aligned first byte. + // Allocates a new buffer and sets the start position to the first aligned + // byte. + // // requested_capacity: requested new buffer capacity. This capacity will be // rounded up based on alignment. - // copy_data: Copy data from old buffer to new buffer. + // copy_data: Copy data from old buffer to new buffer. If copy_offset and + // copy_len are not passed in and the new requested capacity is bigger + // than the existing buffer's capacity, the data in the exising buffer is + // fully copied over to the new buffer. // copy_offset: Copy data from this offset in old buffer. // copy_len: Number of bytes to copy. + // + // The function does nothing if the new requested_capacity is smaller than + // the current buffer capacity and copy_data is true i.e. the old buffer is + // retained as is. void AllocateNewBuffer(size_t requested_capacity, bool copy_data = false, uint64_t copy_offset = 0, size_t copy_len = 0) { assert(alignment_ > 0); @@ -110,7 +145,7 @@ public: copy_len = copy_len > 0 ? copy_len : cursize_; if (copy_data && requested_capacity < copy_len) { // If we are downsizing to a capacity that is smaller than the current - // data in the buffer. Ignore the request. + // data in the buffer -- Ignore the request. return; } @@ -132,8 +167,15 @@ public: capacity_ = new_capacity; buf_.reset(new_buf); } - // Used for write - // Returns the number of bytes appended + + // Append to the buffer. + // + // src : source to copy the data from. + // append_size : number of bytes to copy from src. + // Returns the number of bytes appended. + // + // If append_size is more than the remaining buffer size only the + // remaining-size worth of bytes are copied. size_t Append(const char* src, size_t append_size) { size_t buffer_remaining = capacity_ - cursize_; size_t to_copy = std::min(append_size, buffer_remaining); @@ -145,6 +187,12 @@ public: return to_copy; } + // Read from the buffer. + // + // dest : destination buffer to copy the data to. + // offset : the buffer offset to start reading from. + // read_size : the number of bytes to copy from the buffer to dest. + // Returns the number of bytes read/copied to dest. size_t Read(char* dest, size_t offset, size_t read_size) const { assert(offset < cursize_); @@ -158,7 +206,7 @@ public: return to_read; } - /// Pad to alignment + // Pad to the end of alignment with "padding" void PadToAlignmentWith(int padding) { size_t total_size = Roundup(cursize_, alignment_); size_t pad_size = total_size - cursize_; @@ -176,7 +224,7 @@ public: cursize_ += pad_size; } - // After a partial flush move the tail to the beginning of the buffer + // After a partial flush move the tail to the beginning of the buffer. void RefitTail(size_t tail_offset, size_t tail_size) { if (tail_size > 0) { memmove(bufstart_, bufstart_ + tail_offset, tail_size); @@ -184,7 +232,11 @@ public: cursize_ = tail_size; } - // Returns place to start writing + // Returns a place to start appending. + // WARNING: Note that it is possible to write past the end of the buffer if + // the buffer is modified without using the write APIs or encapsulation + // offered by AlignedBuffer. It is up to the user to guard against such + // errors. char* Destination() { return bufstart_ + cursize_; }