1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4: 3 #ident "$Id$" 4 /*====== 5 This file is part of PerconaFT. 6 7 8 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. 9 10 PerconaFT is free software: you can redistribute it and/or modify 11 it under the terms of the GNU General Public License, version 2, 12 as published by the Free Software Foundation. 13 14 PerconaFT is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. 21 22 ---------------------------------------- 23 24 PerconaFT is free software: you can redistribute it and/or modify 25 it under the terms of the GNU Affero General Public License, version 3, 26 as published by the Free Software Foundation. 27 28 PerconaFT is distributed in the hope that it will be useful, 29 but WITHOUT ANY WARRANTY; without even the implied warranty of 30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31 GNU Affero General Public License for more details. 32 33 You should have received a copy of the GNU Affero General Public License 34 along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. 35 36 ---------------------------------------- 37 38 Licensed under the Apache License, Version 2.0 (the "License"); 39 you may not use this file except in compliance with the License. 40 You may obtain a copy of the License at 41 42 http://www.apache.org/licenses/LICENSE-2.0 43 44 Unless required by applicable law or agreed to in writing, software 45 distributed under the License is distributed on an "AS IS" BASIS, 46 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 47 See the License for the specific language governing permissions and 48 limitations under the License. 49 ======= */ 50 51 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved." 52 53 #pragma once 54 55 #include <stdint.h> 56 #include <memory.h> 57 #include <toku_portability.h> 58 #include <toku_race_tools.h> 59 #include "growable_array.h" 60 61 namespace toku { 62 63 /** 64 * Order Maintenance Tree (OMT) 65 * 66 * Maintains a collection of totally ordered values, where each value has an integer weight. 67 * The OMT is a mutable datatype. 68 * 69 * The Abstraction: 70 * 71 * An OMT is a vector of values, $V$, where $|V|$ is the length of the vector. 72 * The vector is numbered from $0$ to $|V|-1$. 73 * Each value has a weight. The weight of the $i$th element is denoted $w(V_i)$. 74 * 75 * We can create a new OMT, which is the empty vector. 76 * 77 * We can insert a new element $x$ into slot $i$, changing $V$ into $V'$ where 78 * $|V'|=1+|V|$ and 79 * 80 * V'_j = V_j if $j<i$ 81 * x if $j=i$ 82 * V_{j-1} if $j>i$. 83 * 84 * We can specify $i$ using a kind of function instead of as an integer. 85 * Let $b$ be a function mapping from values to nonzero integers, such that 86 * the signum of $b$ is monotically increasing. 87 * We can specify $i$ as the minimum integer such that $b(V_i)>0$. 88 * 89 * We look up a value using its index, or using a Heaviside function. 90 * For lookups, we allow $b$ to be zero for some values, and again the signum of $b$ must be monotonically increasing. 91 * When lookup up values, we can look up 92 * $V_i$ where $i$ is the minimum integer such that $b(V_i)=0$. (With a special return code if no such value exists.) 93 * (Rationale: Ordinarily we want $i$ to be unique. But for various reasons we want to allow multiple zeros, and we want the smallest $i$ in that case.) 94 * $V_i$ where $i$ is the minimum integer such that $b(V_i)>0$. (Or an indication that no such value exists.) 95 * $V_i$ where $i$ is the maximum integer such that $b(V_i)<0$. (Or an indication that no such value exists.) 96 * 97 * When looking up a value using a Heaviside function, we get the value and its index. 98 * 99 * We can also split an OMT into two OMTs, splitting the weight of the values evenly. 100 * Find a value $j$ such that the values to the left of $j$ have about the same total weight as the values to the right of $j$. 101 * The resulting two OMTs contain the values to the left of $j$ and the values to the right of $j$ respectively. 102 * All of the values from the original OMT go into one of the new OMTs. 103 * If the weights of the values don't split exactly evenly, then the implementation has the freedom to choose whether 104 * the new left OMT or the new right OMT is larger. 105 * 106 * Performance: 107 * Insertion and deletion should run with $O(\log |V|)$ time and $O(\log |V|)$ calls to the Heaviside function. 108 * The memory required is O(|V|). 109 * 110 * Usage: 111 * The omt is templated by two parameters: 112 * - omtdata_t is what will be stored within the omt. These could be pointers or real data types (ints, structs). 113 * - omtdataout_t is what will be returned by find and related functions. By default, it is the same as omtdata_t, but you can set it to (omtdata_t *). 114 * To create an omt which will store "TXNID"s, for example, it is a good idea to typedef the template: 115 * typedef omt<TXNID> txnid_omt_t; 116 * If you are storing structs, you may want to be able to get a pointer to the data actually stored in the omt (see find_zero). To do this, use the second template parameter: 117 * typedef omt<struct foo, struct foo *> foo_omt_t; 118 */ 119 120 namespace omt_internal { 121 122 template<bool subtree_supports_marks> 123 class subtree_templated { 124 private: 125 uint32_t m_index; 126 public: 127 static const uint32_t NODE_NULL = UINT32_MAX; set_to_null(void)128 inline void set_to_null(void) { 129 m_index = NODE_NULL; 130 } 131 is_null(void)132 inline bool is_null(void) const { 133 return NODE_NULL == this->get_index(); 134 } 135 get_index(void)136 inline uint32_t get_index(void) const { 137 return m_index; 138 } 139 set_index(uint32_t index)140 inline void set_index(uint32_t index) { 141 paranoid_invariant(index != NODE_NULL); 142 m_index = index; 143 } 144 } ; 145 146 template<> 147 class subtree_templated<true> { 148 private: 149 uint32_t m_bitfield; 150 static const uint32_t MASK_INDEX = ~(((uint32_t)1) << 31); 151 static const uint32_t MASK_BIT = ((uint32_t)1) << 31; 152 set_index_internal(uint32_t new_index)153 inline void set_index_internal(uint32_t new_index) { 154 m_bitfield = (m_bitfield & MASK_BIT) | new_index; 155 } 156 public: 157 static const uint32_t NODE_NULL = INT32_MAX; set_to_null(void)158 inline void set_to_null(void) { 159 this->set_index_internal(NODE_NULL); 160 } 161 is_null(void)162 inline bool is_null(void) const { 163 return NODE_NULL == this->get_index(); 164 } 165 get_index(void)166 inline uint32_t get_index(void) const { 167 TOKU_DRD_IGNORE_VAR(m_bitfield); 168 const uint32_t bits = m_bitfield; 169 TOKU_DRD_STOP_IGNORING_VAR(m_bitfield); 170 return bits & MASK_INDEX; 171 } 172 set_index(uint32_t index)173 inline void set_index(uint32_t index) { 174 paranoid_invariant(index < NODE_NULL); 175 this->set_index_internal(index); 176 } 177 get_bit(void)178 inline bool get_bit(void) const { 179 TOKU_DRD_IGNORE_VAR(m_bitfield); 180 const uint32_t bits = m_bitfield; 181 TOKU_DRD_STOP_IGNORING_VAR(m_bitfield); 182 return (bits & MASK_BIT) != 0; 183 } 184 enable_bit(void)185 inline void enable_bit(void) { 186 // These bits may be set by a thread with a write lock on some 187 // leaf, and the index can be read by another thread with a (read 188 // or write) lock on another thread. Also, the has_marks_below 189 // bit can be set by two threads simultaneously. Neither of these 190 // are real races, so if we are using DRD we should tell it to 191 // ignore these bits just while we set this bit. If there were a 192 // race in setting the index, that would be a real race. 193 TOKU_DRD_IGNORE_VAR(m_bitfield); 194 m_bitfield |= MASK_BIT; 195 TOKU_DRD_STOP_IGNORING_VAR(m_bitfield); 196 } 197 disable_bit(void)198 inline void disable_bit(void) { 199 m_bitfield &= MASK_INDEX; 200 } 201 } ; 202 203 template<typename omtdata_t, bool subtree_supports_marks> 204 class omt_node_templated { 205 public: 206 uint32_t weight; 207 subtree_templated<subtree_supports_marks> left; 208 subtree_templated<subtree_supports_marks> right; 209 omtdata_t value; 210 211 // this needs to be in both implementations because we don't have 212 // a "static if" the caller can use clear_stolen_bits(void)213 inline void clear_stolen_bits(void) {} 214 } ; 215 216 template<typename omtdata_t> 217 class omt_node_templated<omtdata_t, true> { 218 public: 219 uint32_t weight; 220 subtree_templated<true> left; 221 subtree_templated<true> right; 222 omtdata_t value; get_marked(void)223 inline bool get_marked(void) const { 224 return left.get_bit(); 225 } set_marked_bit(void)226 inline void set_marked_bit(void) { 227 return left.enable_bit(); 228 } unset_marked_bit(void)229 inline void unset_marked_bit(void) { 230 return left.disable_bit(); 231 } 232 get_marks_below(void)233 inline bool get_marks_below(void) const { 234 return right.get_bit(); 235 } set_marks_below_bit(void)236 inline void set_marks_below_bit(void) { 237 // This function can be called by multiple threads. 238 // Checking first reduces cache invalidation. 239 if (!this->get_marks_below()) { 240 right.enable_bit(); 241 } 242 } unset_marks_below_bit(void)243 inline void unset_marks_below_bit(void) { 244 right.disable_bit(); 245 } 246 clear_stolen_bits(void)247 inline void clear_stolen_bits(void) { 248 this->unset_marked_bit(); 249 this->unset_marks_below_bit(); 250 } 251 } ; 252 253 } 254 255 template<typename omtdata_t, 256 typename omtdataout_t=omtdata_t, 257 bool supports_marks=false> 258 class omt { 259 public: 260 /** 261 * Effect: Create an empty OMT. 262 * Performance: constant time. 263 */ 264 void create(void); 265 266 /** 267 * Effect: Create an empty OMT with no internal allocated space. 268 * Performance: constant time. 269 * Rationale: In some cases we need a valid omt but don't want to malloc. 270 */ 271 void create_no_array(void); 272 273 /** 274 * Effect: Create a OMT containing values. The number of values is in numvalues. 275 * Stores the new OMT in *omtp. 276 * Requires: this has not been created yet 277 * Requires: values != NULL 278 * Requires: values is sorted 279 * Performance: time=O(numvalues) 280 * Rationale: Normally to insert N values takes O(N lg N) amortized time. 281 * If the N values are known in advance, are sorted, and 282 * the structure is empty, we can batch insert them much faster. 283 */ 284 __attribute__((nonnull)) 285 void create_from_sorted_array(const omtdata_t *const values, const uint32_t numvalues); 286 287 /** 288 * Effect: Create an OMT containing values. The number of values is in numvalues. 289 * On success the OMT takes ownership of *values array, and sets values=NULL. 290 * Requires: this has not been created yet 291 * Requires: values != NULL 292 * Requires: *values is sorted 293 * Requires: *values was allocated with toku_malloc 294 * Requires: Capacity of the *values array is <= new_capacity 295 * Requires: On success, *values may not be accessed again by the caller. 296 * Performance: time=O(1) 297 * Rational: create_from_sorted_array takes O(numvalues) time. 298 * By taking ownership of the array, we save a malloc and memcpy, 299 * and possibly a free (if the caller is done with the array). 300 */ 301 void create_steal_sorted_array(omtdata_t **const values, const uint32_t numvalues, const uint32_t new_capacity); 302 303 /** 304 * Effect: Create a new OMT, storing it in *newomt. 305 * The values to the right of index (starting at index) are moved to *newomt. 306 * Requires: newomt != NULL 307 * Returns 308 * 0 success, 309 * EINVAL if index > toku_omt_size(omt) 310 * On nonzero return, omt and *newomt are unmodified. 311 * Performance: time=O(n) 312 * Rationale: We don't need a split-evenly operation. We need to split items so that their total sizes 313 * are even, and other similar splitting criteria. It's easy to split evenly by calling size(), and dividing by two. 314 */ 315 __attribute__((nonnull)) 316 int split_at(omt *const newomt, const uint32_t idx); 317 318 /** 319 * Effect: Appends leftomt and rightomt to produce a new omt. 320 * Creates this as the new omt. 321 * leftomt and rightomt are destroyed. 322 * Performance: time=O(n) is acceptable, but one can imagine implementations that are O(\log n) worst-case. 323 */ 324 __attribute__((nonnull)) 325 void merge(omt *const leftomt, omt *const rightomt); 326 327 /** 328 * Effect: Creates a copy of an omt. 329 * Creates this as the clone. 330 * Each element is copied directly. If they are pointers, the underlying data is not duplicated. 331 * Performance: O(n) or the running time of fill_array_with_subtree_values() 332 */ 333 void clone(const omt &src); 334 335 /** 336 * Effect: Set the tree to be empty. 337 * Note: Will not reallocate or resize any memory. 338 * Performance: time=O(1) 339 */ 340 void clear(void); 341 342 /** 343 * Effect: Destroy an OMT, freeing all its memory. 344 * If the values being stored are pointers, their underlying data is not freed. See free_items() 345 * Those values may be freed before or after calling toku_omt_destroy. 346 * Rationale: Returns no values since free() cannot fail. 347 * Rationale: Does not free the underlying pointers to reduce complexity. 348 * Performance: time=O(1) 349 */ 350 void destroy(void); 351 352 /** 353 * Effect: return |this|. 354 * Performance: time=O(1) 355 */ 356 uint32_t size(void) const; 357 358 359 /** 360 * Effect: Insert value into the OMT. 361 * If there is some i such that $h(V_i, v)=0$ then returns DB_KEYEXIST. 362 * Otherwise, let i be the minimum value such that $h(V_i, v)>0$. 363 * If no such i exists, then let i be |V| 364 * Then this has the same effect as 365 * insert_at(tree, value, i); 366 * If idx!=NULL then i is stored in *idx 367 * Requires: The signum of h must be monotonically increasing. 368 * Returns: 369 * 0 success 370 * DB_KEYEXIST the key is present (h was equal to zero for some value) 371 * On nonzero return, omt is unchanged. 372 * Performance: time=O(\log N) amortized. 373 * Rationale: Some future implementation may be O(\log N) worst-case time, but O(\log N) amortized is good enough for now. 374 */ 375 template<typename omtcmp_t, int (*h)(const omtdata_t &, const omtcmp_t &)> 376 int insert(const omtdata_t &value, const omtcmp_t &v, uint32_t *const idx); 377 378 /** 379 * Effect: Increases indexes of all items at slot >= idx by 1. 380 * Insert value into the position at idx. 381 * Returns: 382 * 0 success 383 * EINVAL if idx > this->size() 384 * On error, omt is unchanged. 385 * Performance: time=O(\log N) amortized time. 386 * Rationale: Some future implementation may be O(\log N) worst-case time, but O(\log N) amortized is good enough for now. 387 */ 388 int insert_at(const omtdata_t &value, const uint32_t idx); 389 390 /** 391 * Effect: Replaces the item at idx with value. 392 * Returns: 393 * 0 success 394 * EINVAL if idx>=this->size() 395 * On error, omt is unchanged. 396 * Performance: time=O(\log N) 397 * Rationale: The FT needs to be able to replace a value with another copy of the same value (allocated in a different location) 398 * 399 */ 400 int set_at(const omtdata_t &value, const uint32_t idx); 401 402 /** 403 * Effect: Delete the item in slot idx. 404 * Decreases indexes of all items at slot > idx by 1. 405 * Returns 406 * 0 success 407 * EINVAL if idx>=this->size() 408 * On error, omt is unchanged. 409 * Rationale: To delete an item, first find its index using find or find_zero, then delete it. 410 * Performance: time=O(\log N) amortized. 411 */ 412 int delete_at(const uint32_t idx); 413 414 /** 415 * Effect: Iterate over the values of the omt, from left to right, calling f on each value. 416 * The first argument passed to f is a ref-to-const of the value stored in the omt. 417 * The second argument passed to f is the index of the value. 418 * The third argument passed to f is iterate_extra. 419 * The indices run from 0 (inclusive) to this->size() (exclusive). 420 * Requires: f != NULL 421 * Returns: 422 * If f ever returns nonzero, then the iteration stops, and the value returned by f is returned by iterate. 423 * If f always returns zero, then iterate returns 0. 424 * Requires: Don't modify the omt while running. (E.g., f may not insert or delete values from the omt.) 425 * Performance: time=O(i+\log N) where i is the number of times f is called, and N is the number of elements in the omt. 426 * Rationale: Although the functional iterator requires defining another function (as opposed to C++ style iterator), it is much easier to read. 427 * Rationale: We may at some point use functors, but for now this is a smaller change from the old OMT. 428 */ 429 template<typename iterate_extra_t, 430 int (*f)(const omtdata_t &, const uint32_t, iterate_extra_t *const)> 431 int iterate(iterate_extra_t *const iterate_extra) const; 432 433 /** 434 * Effect: Iterate over the values of the omt, from left to right, calling f on each value. 435 * The first argument passed to f is a ref-to-const of the value stored in the omt. 436 * The second argument passed to f is the index of the value. 437 * The third argument passed to f is iterate_extra. 438 * The indices run from 0 (inclusive) to this->size() (exclusive). 439 * We will iterate only over [left,right) 440 * 441 * Requires: left <= right 442 * Requires: f != NULL 443 * Returns: 444 * EINVAL if right > this->size() 445 * If f ever returns nonzero, then the iteration stops, and the value returned by f is returned by iterate_on_range. 446 * If f always returns zero, then iterate_on_range returns 0. 447 * Requires: Don't modify the omt while running. (E.g., f may not insert or delete values from the omt.) 448 * Performance: time=O(i+\log N) where i is the number of times f is called, and N is the number of elements in the omt. 449 * Rational: Although the functional iterator requires defining another function (as opposed to C++ style iterator), it is much easier to read. 450 */ 451 template<typename iterate_extra_t, 452 int (*f)(const omtdata_t &, const uint32_t, iterate_extra_t *const)> 453 int iterate_on_range(const uint32_t left, const uint32_t right, iterate_extra_t *const iterate_extra) const; 454 455 /** 456 * Effect: Iterate over the values of the omt, and mark the nodes that are visited. 457 * Other than the marks, this behaves the same as iterate_on_range. 458 * Requires: supports_marks == true 459 * Performance: time=O(i+\log N) where i is the number of times f is called, and N is the number of elements in the omt. 460 * Notes: 461 * This function MAY be called concurrently by multiple threads, but 462 * not concurrently with any other non-const function. 463 */ 464 template<typename iterate_extra_t, 465 int (*f)(const omtdata_t &, const uint32_t, iterate_extra_t *const)> 466 int iterate_and_mark_range(const uint32_t left, const uint32_t right, iterate_extra_t *const iterate_extra); 467 468 /** 469 * Effect: Iterate over the values of the omt, from left to right, calling f on each value whose node has been marked. 470 * Other than the marks, this behaves the same as iterate. 471 * Requires: supports_marks == true 472 * Performance: time=O(i+\log N) where i is the number of times f is called, and N is the number of elements in the omt. 473 */ 474 template<typename iterate_extra_t, 475 int (*f)(const omtdata_t &, const uint32_t, iterate_extra_t *const)> 476 int iterate_over_marked(iterate_extra_t *const iterate_extra) const; 477 478 /** 479 * Effect: Delete all elements from the omt, whose nodes have been marked. 480 * Requires: supports_marks == true 481 * Performance: time=O(N + i\log N) where i is the number of marked elements, {c,sh}ould be faster 482 */ 483 void delete_all_marked(void); 484 485 /** 486 * Effect: Verify that the internal state of the marks in the tree are self-consistent. 487 * Crashes the system if the marks are in a bad state. 488 * Requires: supports_marks == true 489 * Performance: time=O(N) 490 * Notes: 491 * Even though this is a const function, it requires exclusive access. 492 * Rationale: 493 * The current implementation of the marks relies on a sort of 494 * "cache" bit representing the state of bits below it in the tree. 495 * This allows glass-box testing that these bits are correct. 496 */ 497 void verify_marks_consistent(void) const; 498 499 /** 500 * Effect: None 501 * Returns whether there are any marks in the tree. 502 */ 503 bool has_marks(void) const; 504 505 /** 506 * Effect: Iterate over the values of the omt, from left to right, calling f on each value. 507 * The first argument passed to f is a pointer to the value stored in the omt. 508 * The second argument passed to f is the index of the value. 509 * The third argument passed to f is iterate_extra. 510 * The indices run from 0 (inclusive) to this->size() (exclusive). 511 * Requires: same as for iterate() 512 * Returns: same as for iterate() 513 * Performance: same as for iterate() 514 * Rationale: In general, most iterators should use iterate() since they should not modify the data stored in the omt. This function is for iterators which need to modify values (for example, free_items). 515 * Rationale: We assume if you are transforming the data in place, you want to do it to everything at once, so there is not yet an iterate_on_range_ptr (but there could be). 516 */ 517 template<typename iterate_extra_t, 518 int (*f)(omtdata_t *, const uint32_t, iterate_extra_t *const)> 519 void iterate_ptr(iterate_extra_t *const iterate_extra); 520 521 /** 522 * Effect: Set *value=V_idx 523 * Returns 524 * 0 success 525 * EINVAL if index>=toku_omt_size(omt) 526 * On nonzero return, *value is unchanged 527 * Performance: time=O(\log N) 528 */ 529 int fetch(const uint32_t idx, omtdataout_t *const value) const; 530 531 /** 532 * Effect: Find the smallest i such that h(V_i, extra)>=0 533 * If there is such an i and h(V_i,extra)==0 then set *idxp=i, set *value = V_i, and return 0. 534 * If there is such an i and h(V_i,extra)>0 then set *idxp=i and return DB_NOTFOUND. 535 * If there is no such i then set *idx=this->size() and return DB_NOTFOUND. 536 * Note: value is of type omtdataout_t, which may be of type (omtdata_t) or (omtdata_t *) but is fixed by the instantiation. 537 * If it is the value type, then the value is copied out (even if the value type is a pointer to something else) 538 * If it is the pointer type, then *value is set to a pointer to the data within the omt. 539 * This is determined by the type of the omt as initially declared. 540 * If the omt is declared as omt<foo_t>, then foo_t's will be stored and foo_t's will be returned by find and related functions. 541 * If the omt is declared as omt<foo_t, foo_t *>, then foo_t's will be stored, and pointers to the stored items will be returned by find and related functions. 542 * Rationale: 543 * Structs too small for malloc should be stored directly in the omt. 544 * These structs may need to be edited as they exist inside the omt, so we need a way to get a pointer within the omt. 545 * Using separate functions for returning pointers and values increases code duplication and reduces type-checking. 546 * That also reduces the ability of the creator of a data structure to give advice to its future users. 547 * Slight overloading in this case seemed to provide a better API and better type checking. 548 */ 549 template<typename omtcmp_t, 550 int (*h)(const omtdata_t &, const omtcmp_t &)> 551 int find_zero(const omtcmp_t &extra, omtdataout_t *const value, uint32_t *const idxp) const; 552 553 /** 554 * Effect: 555 * If direction >0 then find the smallest i such that h(V_i,extra)>0. 556 * If direction <0 then find the largest i such that h(V_i,extra)<0. 557 * (Direction may not be equal to zero.) 558 * If value!=NULL then store V_i in *value 559 * If idxp!=NULL then store i in *idxp. 560 * Requires: The signum of h is monotically increasing. 561 * Returns 562 * 0 success 563 * DB_NOTFOUND no such value is found. 564 * On nonzero return, *value and *idxp are unchanged 565 * Performance: time=O(\log N) 566 * Rationale: 567 * Here's how to use the find function to find various things 568 * Cases for find: 569 * find first value: ( h(v)=+1, direction=+1 ) 570 * find last value ( h(v)=-1, direction=-1 ) 571 * find first X ( h(v)=(v< x) ? -1 : 1 direction=+1 ) 572 * find last X ( h(v)=(v<=x) ? -1 : 1 direction=-1 ) 573 * find X or successor to X ( same as find first X. ) 574 * 575 * Rationale: To help understand heaviside functions and behavor of find: 576 * There are 7 kinds of heaviside functions. 577 * The signus of the h must be monotonically increasing. 578 * Given a function of the following form, A is the element 579 * returned for direction>0, B is the element returned 580 * for direction<0, C is the element returned for 581 * direction==0 (see find_zero) (with a return of 0), and D is the element 582 * returned for direction==0 (see find_zero) with a return of DB_NOTFOUND. 583 * If any of A, B, or C are not found, then asking for the 584 * associated direction will return DB_NOTFOUND. 585 * See find_zero for more information. 586 * 587 * Let the following represent the signus of the heaviside function. 588 * 589 * -...- 590 * A 591 * D 592 * 593 * +...+ 594 * B 595 * D 596 * 597 * 0...0 598 * C 599 * 600 * -...-0...0 601 * AC 602 * 603 * 0...0+...+ 604 * C B 605 * 606 * -...-+...+ 607 * AB 608 * D 609 * 610 * -...-0...0+...+ 611 * AC B 612 */ 613 template<typename omtcmp_t, 614 int (*h)(const omtdata_t &, const omtcmp_t &)> 615 int find(const omtcmp_t &extra, int direction, omtdataout_t *const value, uint32_t *const idxp) const; 616 617 /** 618 * Effect: Return the size (in bytes) of the omt, as it resides in main memory. If the data stored are pointers, don't include the size of what they all point to. 619 */ 620 size_t memory_size(void); 621 622 private: 623 typedef uint32_t node_idx; 624 typedef omt_internal::subtree_templated<supports_marks> subtree; 625 typedef omt_internal::omt_node_templated<omtdata_t, supports_marks> omt_node; 626 ENSURE_POD(subtree); 627 628 struct omt_array { 629 uint32_t start_idx; 630 uint32_t num_values; 631 omtdata_t *values; 632 }; 633 634 struct omt_tree { 635 subtree root; 636 uint32_t free_idx; 637 omt_node *nodes; 638 }; 639 640 bool is_array; 641 uint32_t capacity; 642 union { 643 struct omt_array a; 644 struct omt_tree t; 645 } d; 646 647 __attribute__((nonnull)) 648 void unmark(const subtree &subtree, const uint32_t index, GrowableArray<node_idx> *const indexes); 649 650 void create_internal_no_array(const uint32_t new_capacity); 651 652 void create_internal(const uint32_t new_capacity); 653 654 uint32_t nweight(const subtree &subtree) const; 655 656 node_idx node_malloc(void); 657 658 void node_free(const node_idx idx); 659 660 void maybe_resize_array(const uint32_t n); 661 662 __attribute__((nonnull)) 663 void fill_array_with_subtree_values(omtdata_t *const array, const subtree &subtree) const; 664 665 void convert_to_array(void); 666 667 __attribute__((nonnull)) 668 void rebuild_from_sorted_array(subtree *const subtree, const omtdata_t *const values, const uint32_t numvalues); 669 670 void convert_to_tree(void); 671 672 void maybe_resize_or_convert(const uint32_t n); 673 674 bool will_need_rebalance(const subtree &subtree, const int leftmod, const int rightmod) const; 675 676 __attribute__((nonnull)) 677 void insert_internal(subtree *const subtreep, const omtdata_t &value, const uint32_t idx, subtree **const rebalance_subtree); 678 679 void set_at_internal_array(const omtdata_t &value, const uint32_t idx); 680 681 void set_at_internal(const subtree &subtree, const omtdata_t &value, const uint32_t idx); 682 683 void delete_internal(subtree *const subtreep, const uint32_t idx, omt_node *const copyn, subtree **const rebalance_subtree); 684 685 template<typename iterate_extra_t, 686 int (*f)(const omtdata_t &, const uint32_t, iterate_extra_t *const)> 687 int iterate_internal_array(const uint32_t left, const uint32_t right, 688 iterate_extra_t *const iterate_extra) const; 689 690 template<typename iterate_extra_t, 691 int (*f)(omtdata_t *, const uint32_t, iterate_extra_t *const)> 692 void iterate_ptr_internal(const uint32_t left, const uint32_t right, 693 const subtree &subtree, const uint32_t idx, 694 iterate_extra_t *const iterate_extra); 695 696 template<typename iterate_extra_t, 697 int (*f)(omtdata_t *, const uint32_t, iterate_extra_t *const)> 698 void iterate_ptr_internal_array(const uint32_t left, const uint32_t right, 699 iterate_extra_t *const iterate_extra); 700 701 template<typename iterate_extra_t, 702 int (*f)(const omtdata_t &, const uint32_t, iterate_extra_t *const)> 703 int iterate_internal(const uint32_t left, const uint32_t right, 704 const subtree &subtree, const uint32_t idx, 705 iterate_extra_t *const iterate_extra) const; 706 707 template<typename iterate_extra_t, 708 int (*f)(const omtdata_t &, const uint32_t, iterate_extra_t *const)> 709 int iterate_and_mark_range_internal(const uint32_t left, const uint32_t right, 710 const subtree &subtree, const uint32_t idx, 711 iterate_extra_t *const iterate_extra); 712 713 template<typename iterate_extra_t, 714 int (*f)(const omtdata_t &, const uint32_t, iterate_extra_t *const)> 715 int iterate_over_marked_internal(const subtree &subtree, const uint32_t idx, 716 iterate_extra_t *const iterate_extra) const; 717 718 uint32_t verify_marks_consistent_internal(const subtree &subtree, const bool allow_marks) const; 719 720 void fetch_internal_array(const uint32_t i, omtdataout_t *const value) const; 721 722 void fetch_internal(const subtree &subtree, const uint32_t i, omtdataout_t *const value) const; 723 724 __attribute__((nonnull)) 725 void fill_array_with_subtree_idxs(node_idx *const array, const subtree &subtree) const; 726 727 __attribute__((nonnull)) 728 void rebuild_subtree_from_idxs(subtree *const subtree, const node_idx *const idxs, const uint32_t numvalues); 729 730 __attribute__((nonnull)) 731 void rebalance(subtree *const subtree); 732 733 __attribute__((nonnull)) 734 static void copyout(omtdata_t *const out, const omt_node *const n); 735 736 __attribute__((nonnull)) 737 static void copyout(omtdata_t **const out, omt_node *const n); 738 739 __attribute__((nonnull)) 740 static void copyout(omtdata_t *const out, const omtdata_t *const stored_value_ptr); 741 742 __attribute__((nonnull)) 743 static void copyout(omtdata_t **const out, omtdata_t *const stored_value_ptr); 744 745 template<typename omtcmp_t, 746 int (*h)(const omtdata_t &, const omtcmp_t &)> 747 int find_internal_zero_array(const omtcmp_t &extra, omtdataout_t *const value, uint32_t *const idxp) const; 748 749 template<typename omtcmp_t, 750 int (*h)(const omtdata_t &, const omtcmp_t &)> 751 int find_internal_zero(const subtree &subtree, const omtcmp_t &extra, omtdataout_t *const value, uint32_t *const idxp) const; 752 753 template<typename omtcmp_t, 754 int (*h)(const omtdata_t &, const omtcmp_t &)> 755 int find_internal_plus_array(const omtcmp_t &extra, omtdataout_t *const value, uint32_t *const idxp) const; 756 757 template<typename omtcmp_t, 758 int (*h)(const omtdata_t &, const omtcmp_t &)> 759 int find_internal_plus(const subtree &subtree, const omtcmp_t &extra, omtdataout_t *const value, uint32_t *const idxp) const; 760 761 template<typename omtcmp_t, 762 int (*h)(const omtdata_t &, const omtcmp_t &)> 763 int find_internal_minus_array(const omtcmp_t &extra, omtdataout_t *const value, uint32_t *const idxp) const; 764 765 template<typename omtcmp_t, 766 int (*h)(const omtdata_t &, const omtcmp_t &)> 767 int find_internal_minus(const subtree &subtree, const omtcmp_t &extra, omtdataout_t *const value, uint32_t *const idxp) const; 768 }; 769 770 } // namespace toku 771 772 // include the implementation here 773 #include "omt.cc" 774