]>
Commit | Line | Data |
---|---|---|
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> | |
12 | #include "port/port.h" | |
13 | ||
14 | namespace rocksdb { | |
15 | ||
16 | inline size_t TruncateToPageBoundary(size_t page_size, size_t s) { | |
17 | s -= (s & (page_size - 1)); | |
18 | assert((s % page_size) == 0); | |
19 | return s; | |
20 | } | |
21 | ||
22 | inline size_t Roundup(size_t x, size_t y) { | |
23 | return ((x + y - 1) / y) * y; | |
24 | } | |
25 | ||
11fdf7f2 TL |
26 | inline size_t Rounddown(size_t x, size_t y) { return (x / y) * y; } |
27 | ||
7c673cae FG |
28 | // This class is to manage an aligned user |
29 | // allocated buffer for direct I/O purposes | |
30 | // though can be used for any purpose. | |
31 | class AlignedBuffer { | |
32 | size_t alignment_; | |
33 | std::unique_ptr<char[]> buf_; | |
34 | size_t capacity_; | |
35 | size_t cursize_; | |
36 | char* bufstart_; | |
37 | ||
38 | public: | |
39 | AlignedBuffer() | |
40 | : alignment_(), | |
41 | capacity_(0), | |
42 | cursize_(0), | |
43 | bufstart_(nullptr) { | |
44 | } | |
45 | ||
46 | AlignedBuffer(AlignedBuffer&& o) ROCKSDB_NOEXCEPT { | |
47 | *this = std::move(o); | |
48 | } | |
49 | ||
50 | AlignedBuffer& operator=(AlignedBuffer&& o) ROCKSDB_NOEXCEPT { | |
51 | alignment_ = std::move(o.alignment_); | |
52 | buf_ = std::move(o.buf_); | |
53 | capacity_ = std::move(o.capacity_); | |
54 | cursize_ = std::move(o.cursize_); | |
55 | bufstart_ = std::move(o.bufstart_); | |
56 | return *this; | |
57 | } | |
58 | ||
59 | AlignedBuffer(const AlignedBuffer&) = delete; | |
60 | ||
61 | AlignedBuffer& operator=(const AlignedBuffer&) = delete; | |
62 | ||
63 | static bool isAligned(const void* ptr, size_t alignment) { | |
64 | return reinterpret_cast<uintptr_t>(ptr) % alignment == 0; | |
65 | } | |
66 | ||
67 | static bool isAligned(size_t n, size_t alignment) { | |
68 | return n % alignment == 0; | |
69 | } | |
70 | ||
71 | size_t Alignment() const { | |
72 | return alignment_; | |
73 | } | |
74 | ||
75 | size_t Capacity() const { | |
76 | return capacity_; | |
77 | } | |
78 | ||
79 | size_t CurrentSize() const { | |
80 | return cursize_; | |
81 | } | |
82 | ||
83 | const char* BufferStart() const { | |
84 | return bufstart_; | |
85 | } | |
86 | ||
87 | char* BufferStart() { return bufstart_; } | |
88 | ||
89 | void Clear() { | |
90 | cursize_ = 0; | |
91 | } | |
92 | ||
93 | void Alignment(size_t alignment) { | |
94 | assert(alignment > 0); | |
95 | assert((alignment & (alignment - 1)) == 0); | |
96 | alignment_ = alignment; | |
97 | } | |
98 | ||
11fdf7f2 TL |
99 | // Allocates a new buffer and sets bufstart_ to the aligned first byte. |
100 | // requested_capacity: requested new buffer capacity. This capacity will be | |
101 | // rounded up based on alignment. | |
102 | // copy_data: Copy data from old buffer to new buffer. | |
103 | // copy_offset: Copy data from this offset in old buffer. | |
104 | // copy_len: Number of bytes to copy. | |
105 | void AllocateNewBuffer(size_t requested_capacity, bool copy_data = false, | |
106 | uint64_t copy_offset = 0, size_t copy_len = 0) { | |
7c673cae FG |
107 | assert(alignment_ > 0); |
108 | assert((alignment_ & (alignment_ - 1)) == 0); | |
109 | ||
11fdf7f2 TL |
110 | copy_len = copy_len > 0 ? copy_len : cursize_; |
111 | if (copy_data && requested_capacity < copy_len) { | |
112 | // If we are downsizing to a capacity that is smaller than the current | |
113 | // data in the buffer. Ignore the request. | |
114 | return; | |
115 | } | |
7c673cae | 116 | |
11fdf7f2 TL |
117 | size_t new_capacity = Roundup(requested_capacity, alignment_); |
118 | char* new_buf = new char[new_capacity + alignment_]; | |
119 | char* new_bufstart = reinterpret_cast<char*>( | |
120 | (reinterpret_cast<uintptr_t>(new_buf) + (alignment_ - 1)) & | |
121 | ~static_cast<uintptr_t>(alignment_ - 1)); | |
122 | ||
123 | if (copy_data) { | |
124 | assert(bufstart_ + copy_offset + copy_len <= bufstart_ + cursize_); | |
125 | memcpy(new_bufstart, bufstart_ + copy_offset, copy_len); | |
126 | cursize_ = copy_len; | |
127 | } else { | |
128 | cursize_ = 0; | |
129 | } | |
130 | ||
131 | bufstart_ = new_bufstart; | |
132 | capacity_ = new_capacity; | |
133 | buf_.reset(new_buf); | |
7c673cae FG |
134 | } |
135 | // Used for write | |
136 | // Returns the number of bytes appended | |
137 | size_t Append(const char* src, size_t append_size) { | |
138 | size_t buffer_remaining = capacity_ - cursize_; | |
139 | size_t to_copy = std::min(append_size, buffer_remaining); | |
140 | ||
141 | if (to_copy > 0) { | |
142 | memcpy(bufstart_ + cursize_, src, to_copy); | |
143 | cursize_ += to_copy; | |
144 | } | |
145 | return to_copy; | |
146 | } | |
147 | ||
148 | size_t Read(char* dest, size_t offset, size_t read_size) const { | |
149 | assert(offset < cursize_); | |
11fdf7f2 TL |
150 | |
151 | size_t to_read = 0; | |
152 | if(offset < cursize_) { | |
153 | to_read = std::min(cursize_ - offset, read_size); | |
154 | } | |
7c673cae FG |
155 | if (to_read > 0) { |
156 | memcpy(dest, bufstart_ + offset, to_read); | |
157 | } | |
158 | return to_read; | |
159 | } | |
160 | ||
161 | /// Pad to alignment | |
162 | void PadToAlignmentWith(int padding) { | |
163 | size_t total_size = Roundup(cursize_, alignment_); | |
164 | size_t pad_size = total_size - cursize_; | |
165 | ||
166 | if (pad_size > 0) { | |
167 | assert((pad_size + cursize_) <= capacity_); | |
168 | memset(bufstart_ + cursize_, padding, pad_size); | |
169 | cursize_ += pad_size; | |
170 | } | |
171 | } | |
172 | ||
11fdf7f2 TL |
173 | void PadWith(size_t pad_size, int padding) { |
174 | assert((pad_size + cursize_) <= capacity_); | |
175 | memset(bufstart_ + cursize_, padding, pad_size); | |
176 | cursize_ += pad_size; | |
177 | } | |
178 | ||
7c673cae FG |
179 | // After a partial flush move the tail to the beginning of the buffer |
180 | void RefitTail(size_t tail_offset, size_t tail_size) { | |
181 | if (tail_size > 0) { | |
182 | memmove(bufstart_, bufstart_ + tail_offset, tail_size); | |
183 | } | |
184 | cursize_ = tail_size; | |
185 | } | |
186 | ||
187 | // Returns place to start writing | |
188 | char* Destination() { | |
189 | return bufstart_ + cursize_; | |
190 | } | |
191 | ||
192 | void Size(size_t cursize) { | |
193 | cursize_ = cursize; | |
194 | } | |
195 | }; | |
196 | } |