/revolsys-core/src/main/java/com/revolsys/collection/bplus/BPlusTreeMap.java

https://github.com/revolsys/com.revolsys.open · Java · 682 lines · 592 code · 87 blank · 3 comment · 91 complexity · 2eab498977ab40c02d20d5dcac1a2b3a MD5 · raw file

  1. package com.revolsys.collection.bplus;
  2. import java.io.File;
  3. import java.util.AbstractMap;
  4. import java.util.ArrayList;
  5. import java.util.Collection;
  6. import java.util.Comparator;
  7. import java.util.List;
  8. import java.util.Map;
  9. import java.util.Set;
  10. import com.revolsys.collection.map.MapKeySetEntrySet;
  11. import com.revolsys.comparator.Comparators;
  12. import com.revolsys.io.FileUtil;
  13. import com.revolsys.io.page.FileMappedPageManager;
  14. import com.revolsys.io.page.FilePageManager;
  15. import com.revolsys.io.page.MemoryPageManager;
  16. import com.revolsys.io.page.MethodPageValueManager;
  17. import com.revolsys.io.page.Page;
  18. import com.revolsys.io.page.PageManager;
  19. import com.revolsys.io.page.PageValueManager;
  20. import com.revolsys.io.page.SerializablePageValueManager;
  21. public class BPlusTreeMap<K, V> extends AbstractMap<K, V> {
  22. private class PutResult {
  23. private boolean hasOldValue;
  24. private byte[] newKeyBytes;
  25. private byte[] newPageIndexBytes;
  26. private V oldValue;
  27. public void clear() {
  28. this.newKeyBytes = null;
  29. this.newPageIndexBytes = null;
  30. }
  31. public boolean wasSplit() {
  32. return this.newKeyBytes != null;
  33. }
  34. }
  35. private class RemoveResult {
  36. private boolean hasOldValue;
  37. private V oldValue;
  38. }
  39. public static final byte DATA = 2;
  40. public static final byte EXTENDED = -128;
  41. public static final byte INTERIOR = 0;
  42. public static final byte LEAF = 1;
  43. public static <K, V> Map<K, V> newInMemory(final Comparator<K> comparator,
  44. final PageValueManager<K> keyManager, final PageValueManager<V> valueManager) {
  45. final MemoryPageManager pages = new MemoryPageManager();
  46. return new BPlusTreeMap<>(pages, comparator, keyManager, valueManager);
  47. }
  48. public static <K extends Comparable<K>, V> Map<K, V> newInMemory(
  49. final PageValueManager<K> keyManager, final PageValueManager<V> valueManager) {
  50. final MemoryPageManager pages = new MemoryPageManager();
  51. final Comparator<K> comparator = Comparators.newComparator();
  52. return new BPlusTreeMap<>(pages, comparator, keyManager, valueManager);
  53. }
  54. public static <V> Map<Integer, V> newIntSeralizableTempDisk() {
  55. final File file = FileUtil.newTempFile("int", ".btree");
  56. final PageManager pageManager = new FilePageManager(file);
  57. final PageValueManager<Integer> keyManager = PageValueManager.INT;
  58. final SerializablePageValueManager<V> valueSerializer = new SerializablePageValueManager<>();
  59. final PageValueManager<V> valueManager = BPlusTreePageValueManager
  60. .newPageValueManager(pageManager, valueSerializer);
  61. final Comparator<Integer> comparator = Comparators.newComparator();
  62. return new BPlusTreeMap<>(pageManager, comparator, keyManager, valueManager);
  63. }
  64. public static <V> Map<Integer, V> newIntSeralizableTempDisk(final Map<Integer, V> values) {
  65. final File file = FileUtil.newTempFile("int", ".btree");
  66. final PageManager pageManager = new FilePageManager(file);
  67. final PageValueManager<Integer> keyManager = PageValueManager.INT;
  68. final SerializablePageValueManager<V> valueSerializer = new SerializablePageValueManager<>();
  69. final PageValueManager<V> valueManager = BPlusTreePageValueManager
  70. .newPageValueManager(pageManager, valueSerializer);
  71. final Comparator<Integer> comparator = Comparators.newComparator();
  72. final BPlusTreeMap<Integer, V> map = new BPlusTreeMap<>(pageManager, comparator, keyManager,
  73. valueManager);
  74. map.putAll(values);
  75. return map;
  76. }
  77. public static <K, V> Map<K, V> newMap(final PageManager pages, final Comparator<K> comparator,
  78. final PageValueManager<K> keyManager, final PageValueManager<V> valueManager) {
  79. return new BPlusTreeMap<>(pages, comparator, keyManager, valueManager);
  80. }
  81. public static <K extends Comparable<K>, V> Map<K, V> newMap(final PageManager pages,
  82. final PageValueManager<K> keyManager, final PageValueManager<V> valueManager) {
  83. final Comparator<K> comparator = Comparators.newComparator();
  84. return new BPlusTreeMap<>(pages, comparator, keyManager, valueManager);
  85. }
  86. public static <K extends Comparable<?>, V> Map<K, V> newTempDisk(final Map<K, V> values,
  87. PageValueManager<K> keyManager, PageValueManager<V> valueManager) {
  88. final File file = FileUtil.newTempFile("temp", ".bplustree");
  89. final PageManager pageManager = new FilePageManager(file);
  90. if (keyManager instanceof SerializablePageValueManager) {
  91. final SerializablePageValueManager<K> serializeableManager = (SerializablePageValueManager<K>)keyManager;
  92. keyManager = BPlusTreePageValueManager.newPageValueManager(pageManager, serializeableManager);
  93. }
  94. if (valueManager instanceof SerializablePageValueManager) {
  95. final SerializablePageValueManager<V> serializeableManager = (SerializablePageValueManager<V>)valueManager;
  96. valueManager = BPlusTreePageValueManager.newPageValueManager(pageManager,
  97. serializeableManager);
  98. }
  99. final Comparator<K> comparator = (o1, o2) -> ((Comparable<Object>)o1).compareTo(o2);
  100. final BPlusTreeMap<K, V> map = new BPlusTreeMap<>(pageManager, comparator, keyManager,
  101. valueManager);
  102. map.putAll(values);
  103. return map;
  104. }
  105. public static <K extends Comparable<K>, V> Map<K, V> newTempDisk(PageValueManager<K> keyManager,
  106. PageValueManager<V> valueManager) {
  107. final File file = FileUtil.newTempFile("temp", ".bplustree");
  108. final PageManager pageManager = new FileMappedPageManager(file);
  109. if (keyManager instanceof SerializablePageValueManager) {
  110. final SerializablePageValueManager<K> serializeableManager = (SerializablePageValueManager<K>)keyManager;
  111. keyManager = BPlusTreePageValueManager.newPageValueManager(pageManager, serializeableManager);
  112. }
  113. if (valueManager instanceof SerializablePageValueManager) {
  114. final SerializablePageValueManager<V> serializeableManager = (SerializablePageValueManager<V>)valueManager;
  115. valueManager = BPlusTreePageValueManager.newPageValueManager(pageManager,
  116. serializeableManager);
  117. }
  118. final Comparator<K> comparator = Comparators.newComparator();
  119. final BPlusTreeMap<K, V> map = new BPlusTreeMap<>(pageManager, comparator, keyManager,
  120. valueManager);
  121. return map;
  122. }
  123. protected static void setNumBytes(final Page page) {
  124. final int offset = page.getOffset();
  125. page.setOffset(1);
  126. page.writeShort((short)offset);
  127. page.setOffset(offset);
  128. }
  129. protected static void skipHeader(final Page page) {
  130. page.setOffset(3);
  131. }
  132. protected static void writeLeafHeader(final Page page, final byte pageType,
  133. final int nextPageIndex) {
  134. page.writeByte(pageType);
  135. page.writeShort((short)7);
  136. page.writeInt(nextPageIndex);
  137. }
  138. protected static void writePageHeader(final Page page, final byte pageType) {
  139. page.writeByte(pageType);
  140. page.writeShort((short)3);
  141. }
  142. private final Comparator<K> comparator;
  143. private final double fillFactor = 0.5;
  144. private final int headerSize = 3;
  145. private final PageValueManager<K> keyManager;
  146. private final int leafHeaderSize = 7;
  147. private final int minSize;
  148. private volatile transient int modCount;
  149. private final PageManager pages;
  150. private final int rootPageIndex = 0;
  151. private int size = 0;
  152. private final PageValueManager<V> valueManager;
  153. public BPlusTreeMap(final PageManager pages, final Comparator<K> comparator,
  154. final PageValueManager<K> keyManager, final PageValueManager<V> valueManager) {
  155. this.pages = pages;
  156. this.comparator = comparator;
  157. this.keyManager = keyManager;
  158. this.valueManager = valueManager;
  159. this.minSize = (int)(this.fillFactor * pages.getPageSize());
  160. if (pages.getNumPages() == 0) {
  161. final Page rootPage = pages.newPage();
  162. writeLeafHeader(rootPage, LEAF, -1);
  163. pages.releasePage(rootPage);
  164. }
  165. }
  166. @Override
  167. public Set<Map.Entry<K, V>> entrySet() {
  168. return new MapKeySetEntrySet<>(this);
  169. }
  170. protected V get(final int pageIndex, final K key) {
  171. V result;
  172. final Page page = this.pages.getPage(pageIndex);
  173. final byte pageType = page.readByte();
  174. if (pageType == INTERIOR) {
  175. result = getInterior(page, key);
  176. } else if (pageType == LEAF) {
  177. result = getLeaf(page, key);
  178. } else {
  179. throw new IllegalArgumentException("Unknown page type " + pageType);
  180. }
  181. this.pages.releasePage(page);
  182. return result;
  183. }
  184. @Override
  185. @SuppressWarnings("unchecked")
  186. public V get(final Object key) {
  187. return get(this.rootPageIndex, (K)key);
  188. }
  189. private V getInterior(final Page page, final K key) {
  190. final int numBytes = page.readShort();
  191. final int pageIndex = page.readInt();
  192. int previousPageIndex = pageIndex;
  193. while (page.getOffset() < numBytes) {
  194. final K currentKey = this.keyManager.readFromPage(page);
  195. final int nextPageIndex = page.readInt();
  196. final int compare = this.comparator.compare(currentKey, key);
  197. if (compare > 0) {
  198. return get(previousPageIndex, key);
  199. }
  200. previousPageIndex = nextPageIndex;
  201. }
  202. return get(previousPageIndex, key);
  203. }
  204. private V getLeaf(final Page page, final K key) {
  205. final int numBytes = page.readShort();
  206. page.setOffset(this.leafHeaderSize);
  207. while (page.getOffset() < numBytes) {
  208. final K currentKey = this.keyManager.readFromPage(page);
  209. final V currentValue = this.valueManager.readFromPage(page);
  210. final int compare = this.comparator.compare(currentKey, key);
  211. if (compare == 0) {
  212. return currentValue;
  213. }
  214. }
  215. return null;
  216. }
  217. @SuppressWarnings("unchecked")
  218. <T> int getLeafValues(final List<T> values, int pageIndex, final boolean key) {
  219. values.clear();
  220. final Page page = this.pages.getPage(pageIndex);
  221. final byte pageType = page.readByte();
  222. while (pageType == INTERIOR) {
  223. page.readShort(); // skip num bytes
  224. pageIndex = page.readInt();
  225. this.pages.releasePage(page);
  226. }
  227. if (pageType != LEAF) {
  228. throw new IllegalArgumentException("Unknown page type " + pageType);
  229. }
  230. // TODO traverse to leaf
  231. try {
  232. final int numBytes = page.readShort();
  233. final int nextPageId = page.readInt();
  234. while (page.getOffset() < numBytes) {
  235. final K currentKey = this.keyManager.readFromPage(page);
  236. final V currentValue = this.valueManager.readFromPage(page);
  237. if (key) {
  238. values.add((T)currentKey);
  239. } else {
  240. values.add((T)currentValue);
  241. }
  242. }
  243. return nextPageId;
  244. } finally {
  245. this.pages.releasePage(page);
  246. }
  247. }
  248. public int getModCount() {
  249. return this.modCount;
  250. }
  251. @Override
  252. public Set<K> keySet() {
  253. return new BPlusTreeLeafSet<>(this, true);
  254. }
  255. public void print() {
  256. printPage(this.rootPageIndex);
  257. }
  258. private void printPage(final int pageIndex) {
  259. final Page page = this.pages.getPage(pageIndex);
  260. try {
  261. final List<Integer> pageIndexes = new ArrayList<>();
  262. final int offset = page.getOffset();
  263. page.setOffset(0);
  264. final byte pageType = page.readByte();
  265. final int numBytes = page.readShort();
  266. if (pageType == INTERIOR) {
  267. final int pageIndex1 = page.readInt();
  268. int childPageIndex = pageIndex1;
  269. pageIndexes.add(childPageIndex);
  270. System.out.print("I");
  271. System.out.print(page.getIndex());
  272. System.out.print("\t");
  273. System.out.print(numBytes);
  274. System.out.print("\t");
  275. System.out.print(pageIndex1);
  276. while (page.getOffset() < numBytes) {
  277. final K value = this.keyManager.readFromPage(page);
  278. final int pageIndex2 = page.readInt();
  279. childPageIndex = pageIndex2;
  280. pageIndexes.add(childPageIndex);
  281. System.out.print("<-");
  282. System.out.print(value);
  283. System.out.print("->");
  284. System.out.print(childPageIndex);
  285. }
  286. } else if (pageType == LEAF) {
  287. System.out.print("L");
  288. System.out.print(page.getIndex());
  289. System.out.print("\t");
  290. System.out.print(numBytes);
  291. System.out.print("\t");
  292. boolean first = true;
  293. while (page.getOffset() < numBytes) {
  294. if (first) {
  295. first = false;
  296. } else {
  297. System.out.print(",");
  298. }
  299. final K key = this.keyManager.readFromPage(page);
  300. final V value = this.valueManager.readFromPage(page);
  301. System.out.print(key);
  302. System.out.print("=");
  303. System.out.print(value);
  304. }
  305. }
  306. page.setOffset(offset);
  307. for (final Integer childPageIndex : pageIndexes) {
  308. printPage(childPageIndex);
  309. }
  310. } finally {
  311. this.pages.releasePage(page);
  312. }
  313. }
  314. protected PutResult put(final int pageIndex, final Integer nextPageIndex, final K key,
  315. final V value) {
  316. PutResult result;
  317. final Page page = this.pages.getPage(pageIndex);
  318. final byte pageType = page.readByte();
  319. if (pageType == INTERIOR) {
  320. result = putInterior(page, key, value);
  321. } else if (pageType == LEAF) {
  322. result = putLeaf(page, nextPageIndex, key, value);
  323. } else {
  324. throw new IllegalArgumentException("Unknown page type " + pageType);
  325. }
  326. this.pages.releasePage(page);
  327. return result;
  328. }
  329. @Override
  330. public V put(final K key, final V value) {
  331. this.modCount++;
  332. final PutResult result = put(this.rootPageIndex, -1, key, value);
  333. if (result.wasSplit()) {
  334. final Page rootPage = this.pages.getPage(this.rootPageIndex);
  335. final Page leftPage = this.pages.newPage();
  336. leftPage.setContent(rootPage);
  337. rootPage.clear();
  338. writePageHeader(rootPage, INTERIOR);
  339. final int firstChildPageIndex = leftPage.getIndex();
  340. rootPage.writeInt(firstChildPageIndex);
  341. final byte[] keyBytes = result.newKeyBytes;
  342. rootPage.writeBytes(keyBytes);
  343. rootPage.writeBytes(result.newPageIndexBytes);
  344. setNumBytes(rootPage);
  345. this.pages.releasePage(rootPage);
  346. this.pages.releasePage(leftPage);
  347. }
  348. if (!result.hasOldValue) {
  349. this.size++;
  350. }
  351. return result.oldValue;
  352. }
  353. private PutResult putInterior(final Page page, final K key, final V value) {
  354. PutResult result = null;
  355. final List<byte[]> pageIndexesBytes = new ArrayList<>();
  356. final List<byte[]> keysBytes = new ArrayList<>();
  357. final int numBytes = page.readShort();
  358. final byte[] pageIndexBytes = MethodPageValueManager.getIntBytes(page);
  359. byte[] previousPageIndexBytes = pageIndexBytes;
  360. pageIndexesBytes.add(previousPageIndexBytes);
  361. while (page.getOffset() < numBytes) {
  362. final byte[] currentKeyBytes = this.keyManager.getBytes(page);
  363. final K currentKey = this.keyManager.getValue(currentKeyBytes);
  364. final byte[] nextPageIndexBytes = MethodPageValueManager.getIntBytes(page);
  365. if (result == null) {
  366. final int compare = this.comparator.compare(currentKey, key);
  367. if (compare > 0) {
  368. final int previousPageIndex = MethodPageValueManager.getIntValue(previousPageIndexBytes);
  369. final int nextPageIndex = MethodPageValueManager.getIntValue(nextPageIndexBytes);
  370. result = put(previousPageIndex, nextPageIndex, key, value);
  371. if (result.wasSplit()) {
  372. pageIndexesBytes.add(result.newPageIndexBytes);
  373. keysBytes.add(result.newKeyBytes);
  374. } else {
  375. return result;
  376. }
  377. }
  378. }
  379. keysBytes.add(currentKeyBytes);
  380. pageIndexesBytes.add(nextPageIndexBytes);
  381. previousPageIndexBytes = nextPageIndexBytes;
  382. }
  383. if (result == null) {
  384. final int previousPageIndex = MethodPageValueManager.getIntValue(previousPageIndexBytes);
  385. result = put(previousPageIndex, 0, key, value);
  386. if (result.wasSplit()) {
  387. pageIndexesBytes.add(result.newPageIndexBytes);
  388. keysBytes.add(result.newKeyBytes);
  389. } else {
  390. return result;
  391. }
  392. }
  393. updateOrSplitInteriorPage(result, page, keysBytes, pageIndexesBytes);
  394. return result;
  395. }
  396. private PutResult putLeaf(final Page page, final int nextPageIndex, final K key, final V value) {
  397. final PutResult result = new PutResult();
  398. final byte[] keyBytes = this.keyManager.getBytes(key);
  399. final List<byte[]> keysBytes = new ArrayList<>();
  400. final List<byte[]> valuesBytes = new ArrayList<>();
  401. final byte[] valueBytes = this.valueManager.getBytes(value);
  402. boolean newValueWritten = false;
  403. final int numBytes = page.readShort();
  404. page.readInt();
  405. while (page.getOffset() < numBytes) {
  406. final byte[] currentKeyBytes = this.keyManager.getBytes(page);
  407. final K currentKey = this.keyManager.getValue(currentKeyBytes);
  408. final byte[] currentValueBytes = this.valueManager.getBytes(page);
  409. final int compare = this.comparator.compare(currentKey, key);
  410. if (compare >= 0) {
  411. keysBytes.add(keyBytes);
  412. valuesBytes.add(valueBytes);
  413. newValueWritten = true;
  414. result.hasOldValue = true;
  415. }
  416. if (compare == 0) {
  417. result.oldValue = this.valueManager.getValue(currentValueBytes);
  418. } else {
  419. keysBytes.add(currentKeyBytes);
  420. valuesBytes.add(currentValueBytes);
  421. }
  422. }
  423. if (!newValueWritten) {
  424. keysBytes.add(keyBytes);
  425. valuesBytes.add(valueBytes);
  426. }
  427. updateOrSplitLeafPage(result, page, numBytes, keysBytes, valuesBytes, nextPageIndex);
  428. return result;
  429. }
  430. private RemoveResult remove(final int pageIndex, final K key) {
  431. final Page page = this.pages.getPage(pageIndex);
  432. try {
  433. final byte pageType = page.readByte();
  434. if (pageType == INTERIOR) {
  435. return removeInterior(page, key);
  436. } else if (pageType == LEAF) {
  437. return removeLeaf(page, key);
  438. } else {
  439. throw new IllegalArgumentException("Unknown page type " + pageType);
  440. }
  441. } finally {
  442. this.pages.releasePage(page);
  443. }
  444. }
  445. @SuppressWarnings("unchecked")
  446. @Override
  447. public V remove(final Object key) {
  448. this.modCount++;
  449. final RemoveResult result = remove(this.rootPageIndex, (K)key);
  450. // TODO merge if required
  451. if (result.hasOldValue) {
  452. this.size--;
  453. }
  454. return result.oldValue;
  455. }
  456. private RemoveResult removeInterior(final Page page, final K key) {
  457. final int numBytes = page.readShort();
  458. final int pageIndex = page.readInt();
  459. int previousPageIndex = pageIndex;
  460. while (page.getOffset() < numBytes) {
  461. final K currentKey = this.keyManager.readFromPage(page);
  462. final int nextPageIndex = page.readInt();
  463. final int compare = this.comparator.compare(currentKey, key);
  464. if (compare > 0) {
  465. return remove(previousPageIndex, key);
  466. }
  467. previousPageIndex = nextPageIndex;
  468. }
  469. return remove(previousPageIndex, key);
  470. }
  471. private RemoveResult removeLeaf(final Page page, final K key) {
  472. final RemoveResult result = new RemoveResult();
  473. final List<byte[]> keysBytes = new ArrayList<>();
  474. final List<byte[]> valuesBytes = new ArrayList<>();
  475. final int numBytes = page.readShort();
  476. final int nextPageIndex = page.readInt();
  477. while (page.getOffset() < numBytes) {
  478. final byte[] keyBytes = this.keyManager.getBytes(page);
  479. final byte[] valueBytes = this.valueManager.getBytes(page);
  480. if (result.oldValue == null) {
  481. final K currentKey = this.keyManager.getValue(keyBytes);
  482. final int compare = this.comparator.compare(currentKey, key);
  483. if (compare == 0) {
  484. result.oldValue = this.valueManager.getValue(valueBytes);
  485. result.hasOldValue = true;
  486. } else {
  487. keysBytes.add(keyBytes);
  488. valuesBytes.add(valueBytes);
  489. }
  490. } else {
  491. keysBytes.add(keyBytes);
  492. valuesBytes.add(valueBytes);
  493. }
  494. }
  495. if (result.oldValue != null) {
  496. setLeafKeyAndValueBytes(page, keysBytes, valuesBytes, 0, keysBytes.size(), nextPageIndex);
  497. }
  498. // TODO size
  499. return result;
  500. }
  501. private void setInteriorKeyAndValueBytes(final Page page, final List<byte[]> keysBytes,
  502. final List<byte[]> pageIndexesBytes, final int startIndex, final int endIndex) {
  503. page.setOffset(0);
  504. page.writeByte(INTERIOR);
  505. page.writeShort((short)0);
  506. int i = startIndex;
  507. writeBytes(page, pageIndexesBytes, i);
  508. for (; i < endIndex; i++) {
  509. writeBytes(page, keysBytes, i);
  510. writeBytes(page, pageIndexesBytes, i + 1);
  511. }
  512. setNumBytes(page);
  513. page.clearBytes(page.getOffset());
  514. }
  515. private void setLeafKeyAndValueBytes(final Page page, final List<byte[]> keysBytes,
  516. final List<byte[]> valuesBytes, final int startIndex, final int endIndex,
  517. final int nextPageIndex) {
  518. page.setOffset(0);
  519. writeLeafHeader(page, LEAF, nextPageIndex);
  520. int i = startIndex;
  521. for (; i < endIndex; i++) {
  522. writeBytes(page, keysBytes, i);
  523. writeBytes(page, valuesBytes, i);
  524. }
  525. setNumBytes(page);
  526. page.clearBytes(page.getOffset());
  527. }
  528. @Override
  529. public int size() {
  530. return this.size;
  531. }
  532. private void updateOrSplitInteriorPage(final PutResult result, final Page page,
  533. final List<byte[]> keysBytes, final List<byte[]> pageIndexBytes) {
  534. result.clear();
  535. int numBytes = this.headerSize;
  536. int splitIndex = -1;
  537. int i = 0;
  538. numBytes += pageIndexBytes.get(0).length;
  539. while (i < keysBytes.size()) {
  540. numBytes += keysBytes.get(i).length;
  541. numBytes += pageIndexBytes.get(i + 1).length;
  542. i++;
  543. if (splitIndex == -1 && numBytes > this.minSize) {
  544. splitIndex = i;
  545. }
  546. }
  547. if (numBytes < page.getSize()) {
  548. setInteriorKeyAndValueBytes(page, keysBytes, pageIndexBytes, 0, keysBytes.size());
  549. } else {
  550. setInteriorKeyAndValueBytes(page, keysBytes, pageIndexBytes, 0, splitIndex);
  551. final Page rightPage = this.pages.newPage();
  552. setInteriorKeyAndValueBytes(rightPage, keysBytes, pageIndexBytes, splitIndex,
  553. keysBytes.size());
  554. result.newPageIndexBytes = MethodPageValueManager.getValueIntBytes(rightPage.getIndex());
  555. result.newKeyBytes = keysBytes.get(splitIndex);
  556. this.pages.releasePage(rightPage);
  557. }
  558. }
  559. private void updateOrSplitLeafPage(final PutResult result, final Page page, final int oldNumBytes,
  560. final List<byte[]> keysBytes, final List<byte[]> valuesBytes, final int nextPageIndex) {
  561. int numBytes = this.leafHeaderSize;
  562. int splitIndex = -1;
  563. int i = 0;
  564. while (i < keysBytes.size()) {
  565. final byte[] keyBytes = keysBytes.get(i);
  566. numBytes += keyBytes.length;
  567. final byte[] valueBytes = valuesBytes.get(i);
  568. numBytes += valueBytes.length;
  569. i++;
  570. if (splitIndex == -1 && numBytes > this.minSize) {
  571. splitIndex = i;
  572. }
  573. }
  574. if (numBytes < page.getSize()) {
  575. setLeafKeyAndValueBytes(page, keysBytes, valuesBytes, 0, keysBytes.size(), nextPageIndex);
  576. } else {
  577. final Page rightPage = this.pages.newPage();
  578. final int rightPageIndex = rightPage.getIndex();
  579. setLeafKeyAndValueBytes(page, keysBytes, valuesBytes, 0, splitIndex, rightPageIndex);
  580. setLeafKeyAndValueBytes(rightPage, keysBytes, valuesBytes, splitIndex, keysBytes.size(),
  581. nextPageIndex);
  582. result.newPageIndexBytes = MethodPageValueManager.getValueIntBytes(rightPageIndex);
  583. result.newKeyBytes = keysBytes.get(splitIndex);
  584. this.pages.releasePage(rightPage);
  585. }
  586. }
  587. @Override
  588. public Collection<V> values() {
  589. return new BPlusTreeLeafSet<>(this, false);
  590. }
  591. private void writeBytes(final Page page, final List<byte[]> bytesList, final int i) {
  592. final byte[] pageIndexBytes = bytesList.get(i);
  593. page.writeBytes(pageIndexBytes);
  594. }
  595. }