]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/utilities/transactions/lock/range/range_tree/lib/locktree/range_buffer.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rocksdb / utilities / transactions / lock / range / range_tree / lib / locktree / range_buffer.cc
CommitLineData
1e59de90
TL
1/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3#ifndef ROCKSDB_LITE
4#ifndef OS_WIN
5#ident "$Id$"
6/*======
7This file is part of PerconaFT.
8
9
10Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
11
12 PerconaFT is free software: you can redistribute it and/or modify
13 it under the terms of the GNU General Public License, version 2,
14 as published by the Free Software Foundation.
15
16 PerconaFT is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with PerconaFT. If not, see <http://www.gnu.org/licenses/>.
23
24----------------------------------------
25
26 PerconaFT is free software: you can redistribute it and/or modify
27 it under the terms of the GNU Affero General Public License, version 3,
28 as published by the Free Software Foundation.
29
30 PerconaFT is distributed in the hope that it will be useful,
31 but WITHOUT ANY WARRANTY; without even the implied warranty of
32 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 GNU Affero General Public License for more details.
34
35 You should have received a copy of the GNU Affero General Public License
36 along with PerconaFT. If not, see <http://www.gnu.org/licenses/>.
37
38----------------------------------------
39
40 Licensed under the Apache License, Version 2.0 (the "License");
41 you may not use this file except in compliance with the License.
42 You may obtain a copy of the License at
43
44 http://www.apache.org/licenses/LICENSE-2.0
45
46 Unless required by applicable law or agreed to in writing, software
47 distributed under the License is distributed on an "AS IS" BASIS,
48 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
49 See the License for the specific language governing permissions and
50 limitations under the License.
51======= */
52
53#ident \
54 "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
55
56#include "range_buffer.h"
57
58#include <string.h>
59
60#include "../portability/memory.h"
61#include "../util/dbt.h"
62
63namespace toku {
64
65bool range_buffer::record_header::left_is_infinite(void) const {
66 return left_neg_inf || left_pos_inf;
67}
68
69bool range_buffer::record_header::right_is_infinite(void) const {
70 return right_neg_inf || right_pos_inf;
71}
72
73void range_buffer::record_header::init(const DBT *left_key,
74 const DBT *right_key,
75 bool is_exclusive) {
76 is_exclusive_lock = is_exclusive;
77 left_neg_inf = left_key == toku_dbt_negative_infinity();
78 left_pos_inf = left_key == toku_dbt_positive_infinity();
79 left_key_size = toku_dbt_is_infinite(left_key) ? 0 : left_key->size;
80 if (right_key) {
81 right_neg_inf = right_key == toku_dbt_negative_infinity();
82 right_pos_inf = right_key == toku_dbt_positive_infinity();
83 right_key_size = toku_dbt_is_infinite(right_key) ? 0 : right_key->size;
84 } else {
85 right_neg_inf = left_neg_inf;
86 right_pos_inf = left_pos_inf;
87 right_key_size = 0;
88 }
89}
90
91const DBT *range_buffer::iterator::record::get_left_key(void) const {
92 if (_header.left_neg_inf) {
93 return toku_dbt_negative_infinity();
94 } else if (_header.left_pos_inf) {
95 return toku_dbt_positive_infinity();
96 } else {
97 return &_left_key;
98 }
99}
100
101const DBT *range_buffer::iterator::record::get_right_key(void) const {
102 if (_header.right_neg_inf) {
103 return toku_dbt_negative_infinity();
104 } else if (_header.right_pos_inf) {
105 return toku_dbt_positive_infinity();
106 } else {
107 return &_right_key;
108 }
109}
110
111size_t range_buffer::iterator::record::size(void) const {
112 return sizeof(record_header) + _header.left_key_size + _header.right_key_size;
113}
114
115void range_buffer::iterator::record::deserialize(const char *buf) {
116 size_t current = 0;
117
118 // deserialize the header
119 memcpy(&_header, buf, sizeof(record_header));
120 current += sizeof(record_header);
121
122 // deserialize the left key if necessary
123 if (!_header.left_is_infinite()) {
124 // point the left DBT's buffer into ours
125 toku_fill_dbt(&_left_key, buf + current, _header.left_key_size);
126 current += _header.left_key_size;
127 }
128
129 // deserialize the right key if necessary
130 if (!_header.right_is_infinite()) {
131 if (_header.right_key_size == 0) {
132 toku_copyref_dbt(&_right_key, _left_key);
133 } else {
134 toku_fill_dbt(&_right_key, buf + current, _header.right_key_size);
135 }
136 }
137}
138
139toku::range_buffer::iterator::iterator()
140 : _ma_chunk_iterator(nullptr),
141 _current_chunk_base(nullptr),
142 _current_chunk_offset(0),
143 _current_chunk_max(0),
144 _current_rec_size(0) {}
145
146toku::range_buffer::iterator::iterator(const range_buffer *buffer)
147 : _ma_chunk_iterator(&buffer->_arena),
148 _current_chunk_base(nullptr),
149 _current_chunk_offset(0),
150 _current_chunk_max(0),
151 _current_rec_size(0) {
152 reset_current_chunk();
153}
154
155void range_buffer::iterator::reset_current_chunk() {
156 _current_chunk_base = _ma_chunk_iterator.current(&_current_chunk_max);
157 _current_chunk_offset = 0;
158}
159
160bool range_buffer::iterator::current(record *rec) {
161 if (_current_chunk_offset < _current_chunk_max) {
162 const char *buf = reinterpret_cast<const char *>(_current_chunk_base);
163 rec->deserialize(buf + _current_chunk_offset);
164 _current_rec_size = rec->size();
165 return true;
166 } else {
167 return false;
168 }
169}
170
171// move the iterator to the next record in the buffer
172void range_buffer::iterator::next(void) {
173 invariant(_current_chunk_offset < _current_chunk_max);
174 invariant(_current_rec_size > 0);
175
176 // the next record is _current_rec_size bytes forward
177 _current_chunk_offset += _current_rec_size;
178 // now, we don't know how big the current is, set it to 0.
179 _current_rec_size = 0;
180
181 if (_current_chunk_offset >= _current_chunk_max) {
182 // current chunk is exhausted, try moving to the next one
183 if (_ma_chunk_iterator.more()) {
184 _ma_chunk_iterator.next();
185 reset_current_chunk();
186 }
187 }
188}
189
190void range_buffer::create(void) {
191 // allocate buffer space lazily instead of on creation. this way,
192 // no malloc/free is done if the transaction ends up taking no locks.
193 _arena.create(0);
194 _num_ranges = 0;
195}
196
197void range_buffer::append(const DBT *left_key, const DBT *right_key,
198 bool is_write_request) {
199 // if the keys are equal, then only one copy is stored.
200 if (toku_dbt_equals(left_key, right_key)) {
201 invariant(left_key->size <= MAX_KEY_SIZE);
202 append_point(left_key, is_write_request);
203 } else {
204 invariant(left_key->size <= MAX_KEY_SIZE);
205 invariant(right_key->size <= MAX_KEY_SIZE);
206 append_range(left_key, right_key, is_write_request);
207 }
208 _num_ranges++;
209}
210
211bool range_buffer::is_empty(void) const { return total_memory_size() == 0; }
212
213uint64_t range_buffer::total_memory_size(void) const {
214 return _arena.total_size_in_use();
215}
216
217int range_buffer::get_num_ranges(void) const { return _num_ranges; }
218
219void range_buffer::destroy(void) { _arena.destroy(); }
220
221void range_buffer::append_range(const DBT *left_key, const DBT *right_key,
222 bool is_exclusive) {
223 size_t record_length =
224 sizeof(record_header) + left_key->size + right_key->size;
225 char *buf = reinterpret_cast<char *>(_arena.malloc_from_arena(record_length));
226
227 record_header h;
228 h.init(left_key, right_key, is_exclusive);
229
230 // serialize the header
231 memcpy(buf, &h, sizeof(record_header));
232 buf += sizeof(record_header);
233
234 // serialize the left key if necessary
235 if (!h.left_is_infinite()) {
236 memcpy(buf, left_key->data, left_key->size);
237 buf += left_key->size;
238 }
239
240 // serialize the right key if necessary
241 if (!h.right_is_infinite()) {
242 memcpy(buf, right_key->data, right_key->size);
243 }
244}
245
246void range_buffer::append_point(const DBT *key, bool is_exclusive) {
247 size_t record_length = sizeof(record_header) + key->size;
248 char *buf = reinterpret_cast<char *>(_arena.malloc_from_arena(record_length));
249
250 record_header h;
251 h.init(key, nullptr, is_exclusive);
252
253 // serialize the header
254 memcpy(buf, &h, sizeof(record_header));
255 buf += sizeof(record_header);
256
257 // serialize the key if necessary
258 if (!h.left_is_infinite()) {
259 memcpy(buf, key->data, key->size);
260 }
261}
262
263} /* namespace toku */
264#endif // OS_WIN
265#endif // ROCKSDB_LITE