You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

btree_impl.tpp 20 kB

5 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. /* Copyright 2019 Huawei Technologies Co., Ltd.All Rights Reserved.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. #ifndef DATASET_UTIL_BTREE_H_
  16. #define DATASET_UTIL_BTREE_H_
  17. #include "btree.h"
  18. namespace mindspore {
  19. namespace dataset {
  20. template <typename K, typename V, typename A, typename C, typename T>
  21. typename BPlusTree<K, V, A, C, T>::IndexRc BPlusTree<K, V, A, C, T>::InnerNode::Sort() {
  22. // Build an inverse map. Basically it means keys[i] should be relocated to keys[inverse[i]];
  23. slot_allocator alloc(this->alloc_);
  24. try {
  25. // We use a unique_ptr will custom deleter to ensure the memory will be released when this
  26. // function returns.
  27. std::unique_ptr<slot_type[], std::function<void(slot_type *)>> memGuard(
  28. alloc.allocate(traits::kInnerSlots), [&alloc](slot_type *p) { alloc.deallocate(p, traits::kInnerSlots); });
  29. slot_type *inverse = memGuard.get();
  30. for (slot_type i = 0; i < slotuse_; i++) {
  31. inverse[slot_dir_[i]] = i;
  32. }
  33. for (slot_type i = 0; i < slotuse_; i++) {
  34. while (inverse[i] != i) {
  35. slot_type j = inverse[i];
  36. slot_type k = inverse[j];
  37. // Swap the key
  38. std::swap(keys_[j], keys_[i]);
  39. // Swap the pointers.
  40. if ((j + 1) >= traits::kInnerSlots + 1 || (i + 1) >= traits::kInnerSlots + 1) {
  41. return IndexRc::kUnexpectedError;
  42. }
  43. std::swap(data_[j + 1], data_[i + 1]);
  44. // one key in order.
  45. inverse[j] = j;
  46. // continue to move
  47. inverse[i] = k;
  48. }
  49. slot_dir_[i] = i;
  50. }
  51. return IndexRc::kOk;
  52. } catch (std::bad_alloc &e) {
  53. return IndexRc::kOutOfMemory;
  54. } catch (std::exception &e) {
  55. return IndexRc::kUnexpectedError;
  56. }
  57. }
  58. template <typename K, typename V, typename A, typename C, typename T>
  59. typename BPlusTree<K, V, A, C, T>::IndexRc BPlusTree<K, V, A, C, T>::InnerNode::Split(
  60. BPlusTree<K, V, A, C, T>::InnerNode *to, key_type *split_key) {
  61. MS_ASSERT(to);
  62. MS_ASSERT(to->slotuse_ == 0);
  63. // It is simpler to sort first, then split. Other alternative is to move key by key to the
  64. // new node. Also we need to deal with the 'holes' after a key is moved.
  65. RETURN_IF_BAD_RC(this->Sort());
  66. slot_type mid = slotuse_ >> 1;
  67. slot_type num_keys_to_move = slotuse_ - (mid + 1);
  68. *split_key = keys_[mid];
  69. errno_t err = memmove_s(to->keys_, sizeof(to->keys_), keys_ + mid + 1, num_keys_to_move * sizeof(key_type));
  70. if (err != EOK) {
  71. return IndexRc::kUnexpectedError;
  72. }
  73. err = memcpy_s(to->data_, sizeof(to->data_), data_ + mid + 1, (num_keys_to_move + 1) * sizeof(BaseNode *));
  74. if (err != EOK) {
  75. return IndexRc::kUnexpectedError;
  76. }
  77. for (slot_type i = 0; i < num_keys_to_move; i++) {
  78. to->slot_dir_[i] = i;
  79. }
  80. slotuse_ -= (num_keys_to_move + 1); // the split key is moved up. So one less
  81. to->slotuse_ += num_keys_to_move;
  82. return IndexRc::kOk;
  83. }
  84. template <typename K, typename V, typename A, typename C, typename T>
  85. typename BPlusTree<K, V, A, C, T>::IndexRc BPlusTree<K, V, A, C, T>::InnerNode::InsertIntoSlot(
  86. slot_type slot, const key_type &key, BPlusTree<K, V, A, C, T>::BaseNode *ptr) {
  87. if (is_full()) {
  88. return IndexRc::kSlotFull;
  89. }
  90. // Shift the slot entries to the right and make room for the new comer.
  91. // We don't sort the key and/or the data array until node split
  92. auto num_keys_to_move = slotuse_ - slot;
  93. if (num_keys_to_move > 0) {
  94. auto *src = &slot_dir_[slot];
  95. auto *dest = &slot_dir_[slot + 1];
  96. auto destMax = sizeof(slot_dir_) - sizeof(slot_type) * (slot + 1);
  97. auto amt = sizeof(slot_type) * num_keys_to_move;
  98. errno_t err = memmove_s(dest, destMax, src, amt);
  99. if (err) {
  100. return IndexRc::kUnexpectedError;
  101. }
  102. }
  103. slot_dir_[slot] = slotuse_;
  104. keys_[slotuse_] = key;
  105. data_[slotuse_ + 1] = ptr;
  106. ++slotuse_;
  107. return IndexRc::kOk;
  108. }
  109. template <typename K, typename V, typename A, typename C, typename T>
  110. typename BPlusTree<K, V, A, C, T>::IndexRc BPlusTree<K, V, A, C, T>::LeafNode::Sort() {
  111. // Build an inverse map. Basically it means keys[i] should be relocated to keys[inverse[i]];
  112. slot_allocator alloc(this->alloc_);
  113. try {
  114. // We use a unique_ptr will custom deleter to ensure the memory will be released when this
  115. // function returns.
  116. std::unique_ptr<slot_type[], std::function<void(slot_type *)>> memGuard(
  117. alloc.allocate(traits::kLeafSlots), [&alloc](slot_type *p) { alloc.deallocate(p, traits::kLeafSlots); });
  118. slot_type *inverse = memGuard.get();
  119. for (slot_type i = 0; i < slotuse_; i++) {
  120. inverse[slot_dir_[i]] = i;
  121. }
  122. for (slot_type i = 0; i < slotuse_; i++) {
  123. while (inverse[i] != i) {
  124. slot_type j = inverse[i];
  125. slot_type k = inverse[j];
  126. // Swap the key
  127. if (j >= traits::kLeafSlots || i >= traits::kLeafSlots) {
  128. return IndexRc::kUnexpectedError;
  129. }
  130. std::swap(keys_[j], keys_[i]);
  131. // Swap the shared pointers
  132. std::swap(data_[j], data_[i]);
  133. // one key in order.
  134. inverse[j] = j;
  135. // continue to move
  136. inverse[i] = k;
  137. }
  138. slot_dir_[i] = i;
  139. }
  140. return IndexRc::kOk;
  141. } catch (std::bad_alloc &e) {
  142. return IndexRc::kOutOfMemory;
  143. } catch (std::exception &e) {
  144. return IndexRc::kUnexpectedError;
  145. }
  146. }
  147. template <typename K, typename V, typename A, typename C, typename T>
  148. typename BPlusTree<K, V, A, C, T>::IndexRc BPlusTree<K, V, A, C, T>::LeafNode::Split(
  149. BPlusTree<K, V, A, C, T>::LeafNode *to) {
  150. MS_ASSERT(to);
  151. MS_ASSERT(to->slotuse_ == 0);
  152. // It is simpler to sort first, then split. Other alternative is to move key by key to the
  153. // new node. Also we need to deal with the 'holes' after a key is moved.
  154. RETURN_IF_BAD_RC(this->Sort());
  155. slot_type mid = slotuse_ >> 1;
  156. slot_type num_keys_to_move = slotuse_ - mid;
  157. errno_t err = memmove_s(to->keys_, sizeof(to->keys_), keys_ + mid, num_keys_to_move * sizeof(key_type));
  158. if (err) {
  159. return IndexRc::kUnexpectedError;
  160. }
  161. for (slot_type i = 0; i < num_keys_to_move; i++) {
  162. to->data_[i] = std::move(data_[i + mid]);
  163. to->slot_dir_[i] = i;
  164. }
  165. slotuse_ -= num_keys_to_move;
  166. to->slotuse_ += num_keys_to_move;
  167. return IndexRc::kOk;
  168. }
  169. template <typename K, typename V, typename A, typename C, typename T>
  170. typename BPlusTree<K, V, A, C, T>::IndexRc BPlusTree<K, V, A, C, T>::LeafNode::InsertIntoSlot(
  171. BPlusTree<K, V, A, C, T>::LockPathCB *insCB, slot_type slot, const key_type &key,
  172. std::unique_ptr<value_type> &&value) {
  173. if (is_full()) {
  174. // If we need to do node split, we need to ensure all the intermediate nodes are locked exclusive.
  175. // Otherwise we need to do a retry.
  176. if (insCB == nullptr || !insCB->latch_shared_) {
  177. return IndexRc::kSlotFull;
  178. } else {
  179. return IndexRc::kRetry;
  180. }
  181. }
  182. // We can now let go all the locks of the parent. Nothing we do from now on will change the
  183. // structure of the tree.
  184. if (insCB) {
  185. insCB->UnlockMyParents(this);
  186. }
  187. // Shift the slot entries to the right and make room for the new comer.
  188. // We don't sort the key and/or the data array until node split
  189. auto num_keys_to_move = slotuse_ - slot;
  190. if (num_keys_to_move > 0) {
  191. auto *src = &slot_dir_[slot];
  192. auto *dest = &slot_dir_[slot + 1];
  193. auto destMax = sizeof(slot_dir_) - sizeof(slot_type) * (slot + 1);
  194. auto amt = sizeof(slot_type) * num_keys_to_move;
  195. errno_t err = memmove_s(dest, destMax, src, amt);
  196. if (err) {
  197. return IndexRc::kUnexpectedError;
  198. }
  199. }
  200. slot_dir_[slot] = slotuse_;
  201. keys_[slotuse_] = key;
  202. data_[slotuse_] = std::move(value);
  203. ++slotuse_;
  204. return IndexRc::kOk;
  205. }
  206. template <typename K, typename V, typename A, typename C, typename T>
  207. typename BPlusTree<K, V, A, C, T>::IndexRc BPlusTree<K, V, A, C, T>::AllocateInner(
  208. BPlusTree<K, V, A, C, T>::InnerNode **p) {
  209. if (p == nullptr) {
  210. return IndexRc::kNullPointer;
  211. }
  212. typename InnerNode::alloc_type alloc(alloc_);
  213. InnerNode *ptr = nullptr;
  214. try {
  215. ptr = alloc.allocate(1);
  216. } catch (std::bad_alloc &e) {
  217. return IndexRc::kOutOfMemory;
  218. } catch (std::exception &e) {
  219. return IndexRc::kUnexpectedError;
  220. }
  221. *p = new (ptr) InnerNode(alloc_);
  222. all_.Prepend(ptr);
  223. stats_.inner_nodes_++;
  224. return IndexRc::kOk;
  225. }
  226. template <typename K, typename V, typename A, typename C, typename T>
  227. typename BPlusTree<K, V, A, C, T>::IndexRc BPlusTree<K, V, A, C, T>::AllocateLeaf(
  228. BPlusTree<K, V, A, C, T>::LeafNode **p) {
  229. if (p == nullptr) {
  230. return IndexRc::kNullPointer;
  231. }
  232. typename LeafNode::alloc_type alloc(this->alloc_);
  233. LeafNode *ptr = nullptr;
  234. try {
  235. ptr = alloc.allocate(1);
  236. } catch (std::bad_alloc &e) {
  237. return IndexRc::kOutOfMemory;
  238. } catch (std::exception &e) {
  239. return IndexRc::kUnexpectedError;
  240. }
  241. *p = new (ptr) LeafNode(alloc_);
  242. all_.Prepend(ptr);
  243. stats_.leaves_++;
  244. return IndexRc::kOk;
  245. }
  246. template <typename K, typename V, typename A, typename C, typename T>
  247. typename BPlusTree<K, V, A, C, T>::IndexRc BPlusTree<K, V, A, C, T>::LeafInsertKeyValue(
  248. BPlusTree<K, V, A, C, T>::LockPathCB *ins_cb, BPlusTree<K, V, A, C, T>::LeafNode *node, const key_type &key,
  249. std::unique_ptr<value_type> &&value, key_type *split_key, BPlusTree<K, V, A, C, T>::LeafNode **split_node) {
  250. bool duplicate;
  251. slot_type slot = FindSlot(node, key, &duplicate);
  252. if (duplicate) {
  253. return IndexRc::kDuplicateKey;
  254. }
  255. IndexRc rc = node->InsertIntoSlot(ins_cb, slot, key, std::move(value));
  256. if (rc == IndexRc::kSlotFull) {
  257. LeafNode *new_leaf = nullptr;
  258. rc = AllocateLeaf(&new_leaf);
  259. RETURN_IF_BAD_RC(rc);
  260. leaf_nodes_.InsertAfter(node, new_leaf);
  261. *split_node = new_leaf;
  262. // 50/50 split
  263. rc = node->Split(new_leaf);
  264. RETURN_IF_BAD_RC(rc);
  265. *split_key = new_leaf->keys_[0];
  266. if (LessThan(key, *split_key)) {
  267. rc = node->InsertIntoSlot(nullptr, slot, key, std::move(value));
  268. RETURN_IF_BAD_RC(rc);
  269. } else {
  270. slot -= node->slotuse_;
  271. rc = new_leaf->InsertIntoSlot(nullptr, slot, key, std::move(value));
  272. RETURN_IF_BAD_RC(rc);
  273. }
  274. }
  275. return rc;
  276. }
  277. template <typename K, typename V, typename A, typename C, typename T>
  278. typename BPlusTree<K, V, A, C, T>::IndexRc BPlusTree<K, V, A, C, T>::InnerInsertKeyChild(
  279. BPlusTree<K, V, A, C, T>::InnerNode *node, const key_type &key, BPlusTree<K, V, A, C, T>::BaseNode *ptr,
  280. key_type *split_key, BPlusTree<K, V, A, C, T>::InnerNode **split_node) {
  281. bool duplicate;
  282. slot_type slot = FindSlot(node, key, &duplicate);
  283. if (duplicate) {
  284. return IndexRc::kDuplicateKey;
  285. }
  286. IndexRc rc = node->InsertIntoSlot(slot, key, ptr);
  287. if (rc == IndexRc::kSlotFull) {
  288. InnerNode *new_inner = nullptr;
  289. rc = AllocateInner(&new_inner);
  290. RETURN_IF_BAD_RC(rc);
  291. *split_node = new_inner;
  292. rc = node->Split(new_inner, split_key);
  293. RETURN_IF_BAD_RC(rc);
  294. if (LessThan(key, *split_key)) {
  295. // Need to readjust the slot position since the split key is no longer in the two children.
  296. slot = FindSlot(node, key);
  297. rc = node->InsertIntoSlot(slot, key, ptr);
  298. RETURN_IF_BAD_RC(rc);
  299. } else {
  300. // Same reasoning as above
  301. slot = FindSlot(new_inner, key);
  302. rc = new_inner->InsertIntoSlot(slot, key, ptr);
  303. RETURN_IF_BAD_RC(rc);
  304. }
  305. }
  306. return rc;
  307. }
  308. template <typename K, typename V, typename A, typename C, typename T>
  309. typename BPlusTree<K, V, A, C, T>::IndexRc BPlusTree<K, V, A, C, T>::InsertKeyValue(
  310. BPlusTree<K, V, A, C, T>::LockPathCB *ins_cb, BPlusTree<K, V, A, C, T>::BaseNode *n, const key_type &key,
  311. std::unique_ptr<value_type> &&value, key_type *split_key, BPlusTree<K, V, A, C, T>::BaseNode **split_node) {
  312. if (split_key == nullptr || split_node == nullptr) {
  313. return IndexRc::kUnexpectedError;
  314. }
  315. if (n->is_leafnode()) {
  316. if (ins_cb) {
  317. // Always lock the leaf in X.
  318. ins_cb->LockNode(n, LockPathCB::LockMode::kExclusive);
  319. }
  320. auto *leaf = static_cast<LeafNode *>(n);
  321. LeafNode *new_leaf = nullptr;
  322. RETURN_IF_BAD_RC(LeafInsertKeyValue(ins_cb, leaf, key, std::move(value), split_key, &new_leaf));
  323. if (new_leaf) {
  324. *split_node = new_leaf;
  325. }
  326. } else {
  327. if (ins_cb) {
  328. // For internal node, lock in S unless we are doing retry.
  329. if (ins_cb->latch_shared_) {
  330. ins_cb->LockNode(n, LockPathCB::LockMode::kShared);
  331. } else {
  332. ins_cb->LockNode(n, LockPathCB::LockMode::kExclusive);
  333. }
  334. }
  335. auto *inner = static_cast<InnerNode *>(n);
  336. slot_type slot = FindSlot(inner, key);
  337. BaseNode *new_child = nullptr;
  338. key_type new_key = key_type();
  339. RETURN_IF_BAD_RC(InsertKeyValue(ins_cb, FindBranch(inner, slot), key, std::move(value), &new_key, &new_child));
  340. if (new_child) {
  341. InnerNode *new_inner = nullptr;
  342. RETURN_IF_BAD_RC(InnerInsertKeyChild(inner, new_key, new_child, split_key, &new_inner));
  343. if (new_inner) {
  344. *split_node = new_inner;
  345. }
  346. }
  347. }
  348. return IndexRc::kOk;
  349. }
  350. template <typename K, typename V, typename A, typename C, typename T>
  351. typename BPlusTree<K, V, A, C, T>::IndexRc BPlusTree<K, V, A, C, T>::Locate(RWLock *parent_lock, bool forUpdate,
  352. BPlusTree<K, V, A, C, T>::BaseNode *top,
  353. const key_type &key,
  354. BPlusTree<K, V, A, C, T>::LeafNode **ln,
  355. slot_type *s) const {
  356. if (ln == nullptr || s == nullptr) {
  357. return IndexRc::kNullPointer;
  358. }
  359. if (top == nullptr) {
  360. return IndexRc::kKeyNotFound;
  361. }
  362. RWLock *myLock = nullptr;
  363. if (parent_lock != nullptr) {
  364. // Crabbing. Lock this node first, then unlock the parent.
  365. myLock = &top->rw_lock_;
  366. if (top->is_leafnode()) {
  367. if (forUpdate) {
  368. // We are holding the parent lock in S and try to lock this node with X. It is not possible to run
  369. // into deadlock because no one will hold the child in X and trying to lock the parent in that order.
  370. myLock->LockExclusive();
  371. } else {
  372. myLock->LockShared();
  373. }
  374. } else {
  375. myLock->LockShared();
  376. }
  377. parent_lock->Unlock();
  378. }
  379. if (top->is_leafnode()) {
  380. bool duplicate;
  381. auto *leaf = static_cast<LeafNode *>(top);
  382. slot_type slot = FindSlot(leaf, key, &duplicate);
  383. // Need exact match.
  384. if (duplicate) {
  385. *ln = leaf;
  386. *s = slot;
  387. } else {
  388. if (myLock != nullptr) {
  389. myLock->Unlock();
  390. }
  391. return IndexRc::kKeyNotFound;
  392. }
  393. } else {
  394. auto *inner = static_cast<InnerNode *>(top);
  395. slot_type slot = FindSlot(inner, key);
  396. return Locate(myLock, forUpdate, FindBranch(inner, slot), key, ln, s);
  397. }
  398. // We still have a S lock on the leaf node. Leave it there. The iterator will unlock it for us.
  399. return IndexRc::kOk;
  400. }
  401. template <typename K, typename V, typename A, typename C, typename T>
  402. BPlusTree<K, V, A, C, T>::BPlusTree()
  403. : leaf_nodes_(&LeafNode::link_), all_(&BaseNode::lru_), root_(nullptr), acquire_lock_(true) {
  404. Init();
  405. }
  406. template <typename K, typename V, typename A, typename C, typename T>
  407. BPlusTree<K, V, A, C, T>::BPlusTree(const Allocator<V> &alloc)
  408. : alloc_(alloc), leaf_nodes_(&LeafNode::link_), all_(&BaseNode::lru_), root_(nullptr), acquire_lock_(true) {
  409. Init();
  410. }
  411. template <typename K, typename V, typename A, typename C, typename T>
  412. BPlusTree<K, V, A, C, T>::~BPlusTree() noexcept {
  413. // We have a list of all the nodes allocated. Traverse them and free all the memory
  414. BaseNode *n = all_.head;
  415. BaseNode *t = nullptr;
  416. while (n) {
  417. t = n->lru_.next;
  418. all_.Remove(n);
  419. if (n->is_leafnode()) {
  420. auto *leaf = static_cast<LeafNode *>(n);
  421. typename LeafNode::alloc_type alloc(alloc_);
  422. leaf->~LeafNode();
  423. alloc.deallocate(leaf, 1);
  424. } else {
  425. auto *in = static_cast<InnerNode *>(n);
  426. typename InnerNode::alloc_type alloc(alloc_);
  427. in->~InnerNode();
  428. alloc.deallocate(in, 1);
  429. }
  430. n = t;
  431. }
  432. root_ = nullptr;
  433. }
  434. template <typename K, typename V, typename A, typename C, typename T>
  435. Status BPlusTree<K, V, A, C, T>::DoInsert(const key_type &key, std::unique_ptr<value_type> &&value) {
  436. IndexRc rc;
  437. bool retry = false;
  438. do {
  439. // Track all the paths to the target and lock each internal node in S.
  440. LockPathCB InsCB(this, retry);
  441. // Initially we lock path in S unless we need to do node split.
  442. retry = false;
  443. BaseNode *new_child = nullptr;
  444. key_type new_key = key_type();
  445. rc = InsertKeyValue(acquire_lock_ ? &InsCB : nullptr, root_, key, std::move(value), &new_key, &new_child);
  446. if (rc == IndexRc::kRetry) {
  447. retry = true;
  448. } else if (rc != IndexRc::kOk) {
  449. return IndexRc2Status(rc);
  450. } else if (new_child != nullptr) {
  451. // root is full
  452. InnerNode *new_root = nullptr;
  453. rc = AllocateInner(&new_root);
  454. if (rc == IndexRc::kOk) {
  455. rc = new_root->InsertIntoSlot(0, new_key, new_child);
  456. if (rc != IndexRc::kOk) {
  457. return IndexRc2Status(rc);
  458. }
  459. new_root->data_[0] = root_;
  460. root_ = new_root;
  461. stats_.level_++;
  462. } else {
  463. return IndexRc2Status(rc);
  464. }
  465. }
  466. } while (retry);
  467. (void)stats_.size_++;
  468. return Status::OK();
  469. }
  470. template <typename K, typename V, typename A, typename C, typename T>
  471. Status BPlusTree<K, V, A, C, T>::DoInsert(const key_type &key, const value_type &value) {
  472. // We don't store the value directly into the leaf node as it is expensive to move it during node split.
  473. // Rather we store a pointer instead.
  474. return DoInsert(key, std::make_unique<value_type>(value));
  475. }
  476. template <typename K, typename V, typename A, typename C, typename T>
  477. std::unique_ptr<V> BPlusTree<K, V, A, C, T>::DoUpdate(const key_type &key, const value_type &new_value) {
  478. return DoUpdate(key, std::make_unique<value_type>(new_value));
  479. }
  480. template <typename K, typename V, typename A, typename C, typename T>
  481. std::unique_ptr<V> BPlusTree<K, V, A, C, T>::DoUpdate(const key_type &key, std::unique_ptr<value_type> &&new_value) {
  482. if (root_ != nullptr) {
  483. LeafNode *leaf = nullptr;
  484. slot_type slot;
  485. RWLock *myLock = nullptr;
  486. if (acquire_lock_) {
  487. myLock = &this->rw_lock_;
  488. // Lock the tree in S, pass the lock to Locate which will unlock it for us underneath.
  489. myLock->LockShared();
  490. }
  491. IndexRc rc = Locate(myLock, true, root_, key, &leaf, &slot);
  492. if (rc == IndexRc::kOk) {
  493. // All locks from the tree to the parent of leaf are all gone. We still have a X lock
  494. // on the leaf.
  495. // Swap out the old value and replace it with new value.
  496. std::unique_ptr<value_type> old = std::move(leaf->data_[leaf->slot_dir_[slot]]);
  497. leaf->data_[leaf->slot_dir_[slot]] = std::move(new_value);
  498. if (acquire_lock_) {
  499. leaf->rw_lock_.Unlock();
  500. }
  501. return old;
  502. } else {
  503. MS_LOG(DEBUG) << "Key not found. rc = " << static_cast<int>(rc) << ".";
  504. return nullptr;
  505. }
  506. } else {
  507. return nullptr;
  508. }
  509. }
  510. } // namespace dataset
  511. } // namespace mindspore
  512. #endif