]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/util/aligned_buffer.h
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rocksdb / util / aligned_buffer.h
CommitLineData
7c673cae 1// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
11fdf7f2
TL
2// This source code is licensed under both the GPLv2 (found in the
3// COPYING file in the root directory) and Apache 2.0 License
4// (found in the LICENSE.Apache file in the root directory).
7c673cae
FG
5//
6// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7// Use of this source code is governed by a BSD-style license that can be
8// found in the LICENSE file. See the AUTHORS file for names of contributors.
9#pragma once
10
11#include <algorithm>
1e59de90 12
7c673cae
FG
13#include "port/port.h"
14
f67539c2 15namespace ROCKSDB_NAMESPACE {
7c673cae 16
f67539c2
TL
17// This file contains utilities to handle the alignment of pages and buffers.
18
19// Truncate to a multiple of page_size, which is also a page boundary. This
20// helps to figuring out the right alignment.
21// Example:
20effc67
TL
22// TruncateToPageBoundary(4096, 5000) => 4096
23// TruncateToPageBoundary((4096, 10000) => 8192
7c673cae
FG
24inline size_t TruncateToPageBoundary(size_t page_size, size_t s) {
25 s -= (s & (page_size - 1));
26 assert((s % page_size) == 0);
27 return s;
28}
29
f67539c2
TL
30// Round up x to a multiple of y.
31// Example:
32// Roundup(13, 5) => 15
33// Roundup(201, 16) => 208
1e59de90 34inline size_t Roundup(size_t x, size_t y) { return ((x + y - 1) / y) * y; }
7c673cae 35
f67539c2
TL
36// Round down x to a multiple of y.
37// Example:
38// Rounddown(13, 5) => 10
39// Rounddown(201, 16) => 192
11fdf7f2
TL
40inline size_t Rounddown(size_t x, size_t y) { return (x / y) * y; }
41
f67539c2
TL
42// AlignedBuffer manages a buffer by taking alignment into consideration, and
43// aligns the buffer start and end positions. It is mainly used for direct I/O,
44// though it can be used other purposes as well.
45// It also supports expanding the managed buffer, and copying whole or part of
46// the data from old buffer into the new expanded buffer. Such a copy especially
47// helps in cases avoiding an IO to re-fetch the data from disk.
48//
49// Example:
50// AlignedBuffer buf;
51// buf.Alignment(alignment);
52// buf.AllocateNewBuffer(user_requested_buf_size);
53// ...
54// buf.AllocateNewBuffer(2*user_requested_buf_size, /*copy_data*/ true,
55// copy_offset, copy_len);
7c673cae
FG
56class AlignedBuffer {
57 size_t alignment_;
58 std::unique_ptr<char[]> buf_;
59 size_t capacity_;
60 size_t cursize_;
61 char* bufstart_;
62
1e59de90 63 public:
7c673cae 64 AlignedBuffer()
1e59de90 65 : alignment_(), capacity_(0), cursize_(0), bufstart_(nullptr) {}
7c673cae 66
1e59de90 67 AlignedBuffer(AlignedBuffer&& o) noexcept { *this = std::move(o); }
7c673cae 68
1e59de90 69 AlignedBuffer& operator=(AlignedBuffer&& o) noexcept {
7c673cae
FG
70 alignment_ = std::move(o.alignment_);
71 buf_ = std::move(o.buf_);
72 capacity_ = std::move(o.capacity_);
73 cursize_ = std::move(o.cursize_);
74 bufstart_ = std::move(o.bufstart_);
75 return *this;
76 }
77
78 AlignedBuffer(const AlignedBuffer&) = delete;
79
80 AlignedBuffer& operator=(const AlignedBuffer&) = delete;
81
82 static bool isAligned(const void* ptr, size_t alignment) {
83 return reinterpret_cast<uintptr_t>(ptr) % alignment == 0;
84 }
85
86 static bool isAligned(size_t n, size_t alignment) {
87 return n % alignment == 0;
88 }
89
1e59de90 90 size_t Alignment() const { return alignment_; }
7c673cae 91
1e59de90 92 size_t Capacity() const { return capacity_; }
7c673cae 93
1e59de90 94 size_t CurrentSize() const { return cursize_; }
7c673cae 95
1e59de90 96 const char* BufferStart() const { return bufstart_; }
7c673cae
FG
97
98 char* BufferStart() { return bufstart_; }
99
1e59de90 100 void Clear() { cursize_ = 0; }
7c673cae 101
20effc67
TL
102 char* Release() {
103 cursize_ = 0;
104 capacity_ = 0;
105 bufstart_ = nullptr;
106 return buf_.release();
107 }
108
7c673cae
FG
109 void Alignment(size_t alignment) {
110 assert(alignment > 0);
111 assert((alignment & (alignment - 1)) == 0);
112 alignment_ = alignment;
113 }
114
f67539c2
TL
115 // Allocates a new buffer and sets the start position to the first aligned
116 // byte.
117 //
11fdf7f2
TL
118 // requested_capacity: requested new buffer capacity. This capacity will be
119 // rounded up based on alignment.
f67539c2
TL
120 // copy_data: Copy data from old buffer to new buffer. If copy_offset and
121 // copy_len are not passed in and the new requested capacity is bigger
122 // than the existing buffer's capacity, the data in the exising buffer is
123 // fully copied over to the new buffer.
11fdf7f2
TL
124 // copy_offset: Copy data from this offset in old buffer.
125 // copy_len: Number of bytes to copy.
f67539c2
TL
126 //
127 // The function does nothing if the new requested_capacity is smaller than
128 // the current buffer capacity and copy_data is true i.e. the old buffer is
129 // retained as is.
11fdf7f2
TL
130 void AllocateNewBuffer(size_t requested_capacity, bool copy_data = false,
131 uint64_t copy_offset = 0, size_t copy_len = 0) {
7c673cae
FG
132 assert(alignment_ > 0);
133 assert((alignment_ & (alignment_ - 1)) == 0);
134
11fdf7f2
TL
135 copy_len = copy_len > 0 ? copy_len : cursize_;
136 if (copy_data && requested_capacity < copy_len) {
137 // If we are downsizing to a capacity that is smaller than the current
f67539c2 138 // data in the buffer -- Ignore the request.
11fdf7f2
TL
139 return;
140 }
7c673cae 141
11fdf7f2
TL
142 size_t new_capacity = Roundup(requested_capacity, alignment_);
143 char* new_buf = new char[new_capacity + alignment_];
144 char* new_bufstart = reinterpret_cast<char*>(
145 (reinterpret_cast<uintptr_t>(new_buf) + (alignment_ - 1)) &
146 ~static_cast<uintptr_t>(alignment_ - 1));
147
148 if (copy_data) {
149 assert(bufstart_ + copy_offset + copy_len <= bufstart_ + cursize_);
150 memcpy(new_bufstart, bufstart_ + copy_offset, copy_len);
151 cursize_ = copy_len;
152 } else {
153 cursize_ = 0;
154 }
155
156 bufstart_ = new_bufstart;
157 capacity_ = new_capacity;
158 buf_.reset(new_buf);
7c673cae 159 }
f67539c2
TL
160
161 // Append to the buffer.
162 //
163 // src : source to copy the data from.
164 // append_size : number of bytes to copy from src.
165 // Returns the number of bytes appended.
166 //
167 // If append_size is more than the remaining buffer size only the
168 // remaining-size worth of bytes are copied.
7c673cae
FG
169 size_t Append(const char* src, size_t append_size) {
170 size_t buffer_remaining = capacity_ - cursize_;
171 size_t to_copy = std::min(append_size, buffer_remaining);
172
173 if (to_copy > 0) {
174 memcpy(bufstart_ + cursize_, src, to_copy);
175 cursize_ += to_copy;
176 }
177 return to_copy;
178 }
179
f67539c2
TL
180 // Read from the buffer.
181 //
182 // dest : destination buffer to copy the data to.
183 // offset : the buffer offset to start reading from.
184 // read_size : the number of bytes to copy from the buffer to dest.
185 // Returns the number of bytes read/copied to dest.
7c673cae
FG
186 size_t Read(char* dest, size_t offset, size_t read_size) const {
187 assert(offset < cursize_);
11fdf7f2
TL
188
189 size_t to_read = 0;
1e59de90 190 if (offset < cursize_) {
11fdf7f2
TL
191 to_read = std::min(cursize_ - offset, read_size);
192 }
7c673cae
FG
193 if (to_read > 0) {
194 memcpy(dest, bufstart_ + offset, to_read);
195 }
196 return to_read;
197 }
198
f67539c2 199 // Pad to the end of alignment with "padding"
7c673cae
FG
200 void PadToAlignmentWith(int padding) {
201 size_t total_size = Roundup(cursize_, alignment_);
202 size_t pad_size = total_size - cursize_;
203
204 if (pad_size > 0) {
205 assert((pad_size + cursize_) <= capacity_);
206 memset(bufstart_ + cursize_, padding, pad_size);
207 cursize_ += pad_size;
208 }
209 }
210
11fdf7f2
TL
211 void PadWith(size_t pad_size, int padding) {
212 assert((pad_size + cursize_) <= capacity_);
213 memset(bufstart_ + cursize_, padding, pad_size);
214 cursize_ += pad_size;
215 }
216
f67539c2 217 // After a partial flush move the tail to the beginning of the buffer.
7c673cae
FG
218 void RefitTail(size_t tail_offset, size_t tail_size) {
219 if (tail_size > 0) {
220 memmove(bufstart_, bufstart_ + tail_offset, tail_size);
221 }
222 cursize_ = tail_size;
223 }
224
f67539c2
TL
225 // Returns a place to start appending.
226 // WARNING: Note that it is possible to write past the end of the buffer if
227 // the buffer is modified without using the write APIs or encapsulation
228 // offered by AlignedBuffer. It is up to the user to guard against such
229 // errors.
1e59de90 230 char* Destination() { return bufstart_ + cursize_; }
7c673cae 231
1e59de90 232 void Size(size_t cursize) { cursize_ = cursize; }
7c673cae 233};
f67539c2 234} // namespace ROCKSDB_NAMESPACE