PageRenderTime 94ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 1ms

/simpledbm-rss/code/simpledbm-rss/src/test/java/org/simpledbm/rss/impl/im/btree/TestBTreeManager.java

https://code.google.com/p/simpledbm/
Java | 3999 lines | 3275 code | 283 blank | 441 comment | 249 complexity | 1a67f4013060108c5770fd6e0fe78476 MD5 | raw file
Possible License(s): GPL-2.0
  1. /***
  2. * This program is free software; you can redistribute it and/or modify
  3. * it under the terms of the GNU General Public License as published by
  4. * the Free Software Foundation; either version 2 of the License, or
  5. * (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program; if not, write to the Free Software
  14. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. *
  16. * Linking this library statically or dynamically with other modules
  17. * is making a combined work based on this library. Thus, the terms and
  18. * conditions of the GNU General Public License cover the whole
  19. * combination.
  20. *
  21. * As a special exception, the copyright holders of this library give
  22. * you permission to link this library with independent modules to
  23. * produce an executable, regardless of the license terms of these
  24. * independent modules, and to copy and distribute the resulting
  25. * executable under terms of your choice, provided that you also meet,
  26. * for each linked independent module, the terms and conditions of the
  27. * license of that module. An independent module is a module which
  28. * is not derived from or based on this library. If you modify this
  29. * library, you may extend this exception to your version of the
  30. * library, but you are not obligated to do so. If you do not wish
  31. * to do so, delete this exception statement from your version.
  32. *
  33. * Project: www.simpledbm.org
  34. * Author : Dibyendu Majumdar
  35. * Email : d dot majumdar at gmail dot com ignore
  36. */
  37. package org.simpledbm.rss.impl.im.btree;
  38. import java.io.BufferedReader;
  39. import java.io.InputStreamReader;
  40. import java.nio.ByteBuffer;
  41. import java.util.Arrays;
  42. import java.util.Properties;
  43. import java.util.StringTokenizer;
  44. import java.util.concurrent.TimeUnit;
  45. import java.util.concurrent.atomic.AtomicInteger;
  46. import java.util.concurrent.locks.Condition;
  47. import java.util.concurrent.locks.Lock;
  48. import java.util.concurrent.locks.ReentrantLock;
  49. import junit.framework.Test;
  50. import junit.framework.TestSuite;
  51. import org.simpledbm.common.api.exception.SimpleDBMException;
  52. import org.simpledbm.common.api.key.IndexKey;
  53. import org.simpledbm.common.api.key.IndexKeyFactory;
  54. import org.simpledbm.common.api.locking.LockMode;
  55. import org.simpledbm.common.api.platform.Platform;
  56. import org.simpledbm.common.api.platform.PlatformObjects;
  57. import org.simpledbm.common.api.registry.ObjectRegistry;
  58. import org.simpledbm.common.api.tx.IsolationMode;
  59. import org.simpledbm.common.impl.registry.ObjectRegistryImpl;
  60. import org.simpledbm.common.tools.diagnostics.TraceBuffer;
  61. import org.simpledbm.common.util.ByteString;
  62. import org.simpledbm.junit.BaseTestCase;
  63. import org.simpledbm.rss.api.bm.BufferAccessBlock;
  64. import org.simpledbm.rss.api.fsm.FreeSpaceManager;
  65. import org.simpledbm.rss.api.im.IndexContainer;
  66. import org.simpledbm.rss.api.im.IndexManager;
  67. import org.simpledbm.rss.api.im.IndexScan;
  68. import org.simpledbm.rss.api.im.UniqueConstraintViolationException;
  69. import org.simpledbm.rss.api.latch.LatchFactory;
  70. import org.simpledbm.rss.api.loc.Location;
  71. import org.simpledbm.rss.api.loc.LocationFactory;
  72. import org.simpledbm.rss.api.locking.LockDeadlockException;
  73. import org.simpledbm.rss.api.locking.LockDuration;
  74. import org.simpledbm.rss.api.locking.LockMgrFactory;
  75. import org.simpledbm.rss.api.locking.util.LockAdaptor;
  76. import org.simpledbm.rss.api.pm.Page;
  77. import org.simpledbm.rss.api.pm.PageId;
  78. import org.simpledbm.rss.api.pm.PageManager;
  79. import org.simpledbm.rss.api.sp.SlottedPage;
  80. import org.simpledbm.rss.api.sp.SlottedPageManager;
  81. import org.simpledbm.rss.api.st.StorageContainer;
  82. import org.simpledbm.rss.api.st.StorageContainerFactory;
  83. import org.simpledbm.rss.api.st.StorageManager;
  84. import org.simpledbm.rss.api.tx.BaseLockable;
  85. import org.simpledbm.rss.api.tx.LoggableFactory;
  86. import org.simpledbm.rss.api.tx.Savepoint;
  87. import org.simpledbm.rss.api.tx.Transaction;
  88. import org.simpledbm.rss.api.tx.TransactionalModuleRegistry;
  89. import org.simpledbm.rss.api.wal.Lsn;
  90. import org.simpledbm.rss.impl.bm.BufferManagerImpl;
  91. import org.simpledbm.rss.impl.fsm.FreeSpaceManagerImpl;
  92. import org.simpledbm.rss.impl.im.btree.BTreeIndexManagerImpl.BTreeContext;
  93. import org.simpledbm.rss.impl.im.btree.BTreeIndexManagerImpl.BTreeImpl;
  94. import org.simpledbm.rss.impl.im.btree.BTreeIndexManagerImpl.BTreeNode;
  95. import org.simpledbm.rss.impl.im.btree.BTreeIndexManagerImpl.IndexItem;
  96. import org.simpledbm.rss.impl.im.btree.BTreeIndexManagerImpl.IndexItemFactory;
  97. import org.simpledbm.rss.impl.im.btree.BTreeIndexManagerImpl.LoadPageOperation;
  98. import org.simpledbm.rss.impl.im.btree.BTreeIndexManagerImpl.SearchResult;
  99. import org.simpledbm.rss.impl.latch.LatchFactoryImpl;
  100. import org.simpledbm.rss.impl.locking.LockEventListener;
  101. import org.simpledbm.rss.impl.locking.LockManagerFactoryImpl;
  102. import org.simpledbm.rss.impl.locking.LockManagerImpl;
  103. import org.simpledbm.rss.impl.locking.util.DefaultLockAdaptor;
  104. import org.simpledbm.rss.impl.pm.PageManagerImpl;
  105. import org.simpledbm.rss.impl.sp.SlottedPageImpl;
  106. import org.simpledbm.rss.impl.sp.SlottedPageManagerImpl;
  107. import org.simpledbm.rss.impl.st.FileStorageContainerFactory;
  108. import org.simpledbm.rss.impl.st.StorageManagerImpl;
  109. import org.simpledbm.rss.impl.tx.LoggableFactoryImpl;
  110. import org.simpledbm.rss.impl.tx.TransactionManagerImpl;
  111. import org.simpledbm.rss.impl.tx.TransactionalModuleRegistryImpl;
  112. import org.simpledbm.rss.impl.wal.LogFactoryImpl;
  113. import org.simpledbm.rss.impl.wal.LogManagerImpl;
  114. public class TestBTreeManager extends BaseTestCase {
  115. static final short TYPE_STRINGKEYFACTORY = 25000;
  116. static final short TYPE_ROWLOCATIONFACTORY = 25001;
  117. boolean doCrashTesting = false;
  118. public TestBTreeManager() {
  119. super();
  120. }
  121. public TestBTreeManager(String arg0) {
  122. super(arg0);
  123. }
  124. public TestBTreeManager(String arg0, boolean crashTesting) {
  125. super(arg0);
  126. doCrashTesting = crashTesting;
  127. }
  128. static boolean compressKeys = false;
  129. static boolean largeBM = false;
  130. /**
  131. * A simple string key.
  132. */
  133. public static class StringKey implements IndexKey {
  134. static final String MAX_KEY = "<INFINITY>";
  135. static final String MIN_KEY = "<NEG_INFINITY>";
  136. ByteString string = new ByteString();
  137. public StringKey() {
  138. }
  139. public StringKey(StringKey key) {
  140. string = new ByteString(key.string);
  141. }
  142. public StringKey(ByteBuffer bb) {
  143. string = new ByteString(bb);
  144. }
  145. public IndexKey cloneIndexKey() {
  146. return new StringKey(this);
  147. }
  148. public StringKey(final String s) {
  149. setString(s);
  150. }
  151. public void setBytes(byte[] bytes) {
  152. string = new ByteString(bytes);
  153. }
  154. @Override
  155. public String toString() {
  156. if (isMaxKey()) {
  157. return MAX_KEY;
  158. } else if (isMinKey()) {
  159. return MIN_KEY;
  160. }
  161. return string.toString().trim();
  162. }
  163. public void setString(String string) {
  164. if (MAX_KEY.equals(string)) {
  165. this.string = new ByteString(new byte[1]);
  166. } else if (MIN_KEY.equals(string)) {
  167. byte[] data = { ' ' };
  168. this.string = new ByteString(data);
  169. } else {
  170. byte data[];
  171. if (!compressKeys) {
  172. data = new byte[1024];
  173. Arrays.fill(data, (byte) ' ');
  174. byte[] srcdata = string.getBytes();
  175. System.arraycopy(srcdata, 0, data, 0, srcdata.length);
  176. } else {
  177. data = string.getBytes();
  178. }
  179. this.string = new ByteString(data);
  180. }
  181. }
  182. public int getStoredLength() {
  183. return string.getStoredLength();
  184. }
  185. public void store(ByteBuffer bb) {
  186. string.store(bb);
  187. }
  188. public boolean isMaxKey() {
  189. return string.length() == 1 && string.get(0) == 0;
  190. }
  191. public boolean isMinKey() {
  192. return string.length() == 1 && string.get(0) == ' ';
  193. }
  194. public int compareTo(IndexKey o) {
  195. StringKey sk = (StringKey) o;
  196. if (isMaxKey() || sk.isMaxKey()) {
  197. if (isMaxKey() && sk.isMaxKey()) {
  198. return 0;
  199. } else if (isMaxKey()) {
  200. return 1;
  201. } else {
  202. return -1;
  203. }
  204. } else if (isMinKey() || sk.isMinKey()) {
  205. if (isMinKey() && sk.isMinKey()) {
  206. return 0;
  207. } else if (isMinKey()) {
  208. return -1;
  209. } else {
  210. return 1;
  211. }
  212. }
  213. return string.compareTo(sk.string);
  214. }
  215. @Override
  216. public boolean equals(Object arg0) {
  217. return compareTo((IndexKey) arg0) == 0;
  218. }
  219. }
  220. public static class StringKeyFactory implements IndexKeyFactory {
  221. public IndexKey newIndexKey(int id) {
  222. return new StringKey();
  223. }
  224. public IndexKey maxIndexKey(int id) {
  225. StringKey s = new StringKey();
  226. s.setBytes(new byte[1]);
  227. return s;
  228. }
  229. public IndexKey minIndexKey(int id) {
  230. StringKey s = new StringKey(StringKey.MIN_KEY);
  231. return s;
  232. }
  233. public IndexKey newIndexKey(int containerId, ByteBuffer bb) {
  234. return new StringKey(bb);
  235. }
  236. public IndexKey parseIndexKey(int containerId, String s) {
  237. return new StringKey(s);
  238. }
  239. }
  240. /**
  241. * A simple location.
  242. */
  243. public static class RowLocation extends BaseLockable implements Location {
  244. int loc;
  245. protected RowLocation() {
  246. super((byte) 'R');
  247. }
  248. RowLocation(RowLocation other) {
  249. super(other);
  250. this.loc = other.loc;
  251. }
  252. RowLocation(ByteBuffer bb) {
  253. super((byte) 'R');
  254. loc = bb.getInt();
  255. }
  256. RowLocation(String s) {
  257. super((byte) 'R');
  258. loc = Integer.parseInt(s);
  259. }
  260. public Location cloneLocation() {
  261. return new RowLocation(this);
  262. }
  263. public void store(ByteBuffer bb) {
  264. bb.putInt(loc);
  265. }
  266. public int getStoredLength() {
  267. return Integer.SIZE / Byte.SIZE;
  268. }
  269. public int compareTo(Location o) {
  270. RowLocation rl = (RowLocation) o;
  271. return loc - rl.loc;
  272. }
  273. @Override
  274. public boolean equals(Object o) {
  275. return compareTo((Location) o) == 0;
  276. }
  277. @Override
  278. public int hashCode() {
  279. return loc;
  280. }
  281. @Override
  282. public String toString() {
  283. return Integer.toString(loc);
  284. }
  285. public int getContainerId() {
  286. return loc;
  287. }
  288. public int getX() {
  289. return 0;
  290. }
  291. public int getY() {
  292. return 0;
  293. }
  294. }
  295. public static class RowLocationFactory implements LocationFactory {
  296. public Location newLocation() {
  297. return new RowLocation();
  298. }
  299. public Location newLocation(ByteBuffer bb) {
  300. return new RowLocation(bb);
  301. }
  302. public Location newLocation(String s) {
  303. return new RowLocation(s);
  304. }
  305. }
  306. private IndexItem generateKey(IndexItemFactory btree, String s,
  307. int location, int childpage, boolean isLeaf) {
  308. StringKey key = (StringKey) btree.getNewIndexKey(1, s);
  309. RowLocation loc = (RowLocation) btree.getNewLocation();
  310. loc.loc = location;
  311. IndexItem item = new IndexItem(key, loc, childpage, isLeaf, btree
  312. .isUnique());
  313. return item;
  314. }
  315. /**
  316. * Initialize the test harness. New log is created, and the test container
  317. * initialized. The container is allocated an extent of 64 pages which ought
  318. * to be large enough for all the test cases.
  319. */
  320. void doInitContainer() throws Exception {
  321. final BTreeDB db = new BTreeDB(platform, true);
  322. try {
  323. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  324. db.spacemgr.createContainer(trx, "testctr.dat", 1, 1, 20, db.spmgr
  325. .getPageType());
  326. trx.commit();
  327. } finally {
  328. db.shutdown();
  329. }
  330. }
  331. void doInitContainer2() throws Exception {
  332. final BTreeDB db = new BTreeDB(platform, true);
  333. try {
  334. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  335. db.btreeMgr.createIndex(trx, "testctr.dat", 1, 20,
  336. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, true);
  337. trx.commit();
  338. } finally {
  339. db.shutdown();
  340. }
  341. }
  342. void doLoadData(ScanResult[] results) throws Exception {
  343. final BTreeDB db = new BTreeDB(platform, false);
  344. try {
  345. IndexContainer index = db.btreeMgr.getIndex(1);
  346. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  347. .getSingleton(TYPE_STRINGKEYFACTORY);
  348. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  349. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  350. for (int i = 0; i < results.length; i++) {
  351. IndexKey key = keyFactory.parseIndexKey(1, results[i].getKey());
  352. Location location = locationFactory.newLocation(results[i]
  353. .getLocation());
  354. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  355. index.insert(trx, key, location);
  356. trx.commit();
  357. }
  358. } finally {
  359. db.shutdown();
  360. }
  361. }
  362. void doLoadData(String filename) throws Exception {
  363. BufferedReader reader = new BufferedReader(new InputStreamReader(Thread
  364. .currentThread().getContextClassLoader().getResourceAsStream(
  365. filename)));
  366. final BTreeDB db = new BTreeDB(platform, false);
  367. try {
  368. IndexContainer index = db.btreeMgr.getIndex(1);
  369. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  370. .getSingleton(TYPE_STRINGKEYFACTORY);
  371. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  372. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  373. String line = reader.readLine();
  374. while (line != null) {
  375. StringTokenizer st = new StringTokenizer(line, " ");
  376. String k = st.nextToken();
  377. IndexKey key = keyFactory.parseIndexKey(1, k);
  378. String l = st.nextToken();
  379. Location location = locationFactory.newLocation(l);
  380. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  381. // System.out.println("Inserting (" + key + ", " + location +
  382. // ")");
  383. index.insert(trx, key, location);
  384. trx.commit();
  385. line = reader.readLine();
  386. }
  387. } finally {
  388. reader.close();
  389. db.shutdown();
  390. }
  391. }
  392. /**
  393. * Initialize data pages by loading data from specified XML resource.
  394. */
  395. public void doLoadXml(boolean testUnique, String dataFile) throws Exception {
  396. final BTreeDB db = new BTreeDB(platform, false);
  397. try {
  398. BTreeIndexManagerImpl.XMLLoader loader = new BTreeIndexManagerImpl.XMLLoader(
  399. db.btreeMgr);
  400. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  401. try {
  402. loader.parseResource(dataFile);
  403. for (LoadPageOperation loadPageOp : loader.getPageOperations()) {
  404. final PageId pageid = loadPageOp.getPageId();
  405. final BTreeIndexManagerImpl btreemgr = db.btreeMgr;
  406. BufferAccessBlock bab = btreemgr.bufmgr.fixExclusive(
  407. pageid, false, -1, 0);
  408. try {
  409. PageId spaceMapPageId = new PageId(pageid
  410. .getContainerId(), loadPageOp
  411. .getSpaceMapPageNumber());
  412. BufferAccessBlock smpBab = btreemgr.bufmgr
  413. .fixExclusive(spaceMapPageId, false, -1, 0);
  414. try {
  415. Lsn lsn = trx.logInsert(bab.getPage(), loadPageOp);
  416. btreemgr.redo(bab.getPage(), loadPageOp);
  417. bab.setDirty(lsn);
  418. btreemgr.redo(smpBab.getPage(), loadPageOp);
  419. smpBab.setDirty(lsn);
  420. } finally {
  421. smpBab.unfix();
  422. }
  423. } finally {
  424. bab.unfix();
  425. }
  426. }
  427. } finally {
  428. // Doesn't matter whether we commit or abort as the changes are
  429. // logged as redo-only.
  430. trx.abort();
  431. }
  432. } finally {
  433. db.shutdown();
  434. }
  435. }
  436. /**
  437. * Initialize data pages by loading data from specified XML resource.
  438. */
  439. public void doValidateTree(String dataFile) throws Exception {
  440. final BTreeDB db = new BTreeDB(platform, false);
  441. try {
  442. doValidateTree(db, dataFile);
  443. } finally {
  444. db.shutdown();
  445. }
  446. }
  447. /**
  448. * Initialize data pages by loading data from specified XML resource.
  449. */
  450. public void doValidateTree(final BTreeDB db, String dataFile)
  451. throws Exception {
  452. BTreeIndexManagerImpl.XMLLoader loader = new BTreeIndexManagerImpl.XMLLoader(
  453. db.btreeMgr);
  454. loader.parseResource(dataFile);
  455. for (LoadPageOperation loadPageOp : loader.getPageOperations()) {
  456. final PageId pageid = loadPageOp.getPageId();
  457. final BTreeIndexManagerImpl btreemgr = db.btreeMgr;
  458. final PlatformObjects po = db.platform
  459. .getPlatformObjects(IndexManager.LOGGER_NAME);
  460. BufferAccessBlock bab = btreemgr.bufmgr.fixExclusive(pageid, false,
  461. -1, 0);
  462. try {
  463. /*
  464. * Log record is being applied to BTree page.
  465. */
  466. SlottedPage r = (SlottedPage) bab.getPage();
  467. BTreeNode node = new BTreeNode(po, loadPageOp
  468. .getIndexItemFactory(), r);
  469. // System.out.println("Validating page ->");
  470. // node.dumpAsXml();
  471. // System.out.println("------------------");
  472. assertEquals(node.header.keyCount, loadPageOp.items.size());
  473. assertEquals(node.header.leftSibling, loadPageOp.leftSibling);
  474. assertEquals(node.header.rightSibling, loadPageOp.rightSibling);
  475. assertEquals(node.header.keyFactoryType, loadPageOp
  476. .getKeyFactoryType());
  477. assertEquals(node.header.locationFactoryType, loadPageOp
  478. .getLocationFactoryType());
  479. assertEquals(node.isLeaf(), loadPageOp.isLeaf());
  480. assertEquals(node.isUnique(), loadPageOp.isUnique());
  481. for (int k = 1, i = 0; k < r.getNumberOfSlots(); k++, i++) {
  482. if (r.isSlotDeleted(k)) {
  483. continue;
  484. }
  485. IndexItem item = loadPageOp.items.get(i);
  486. IndexItem item1 = node.getItem(k);
  487. assertEquals(item, item1);
  488. }
  489. } finally {
  490. bab.unfix();
  491. }
  492. }
  493. }
  494. /*
  495. * Splits page 2 into 2 and 3.
  496. */
  497. void doPageSplit(boolean testLeaf, boolean testUnique) throws Exception {
  498. /* Create the write ahead log */
  499. final BTreeDB db = new BTreeDB(platform, false);
  500. try {
  501. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  502. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  503. int pageNumber = 2;
  504. Transaction trx;
  505. BTreeContext bcursor = new BTreeContext(db.tracer);
  506. bcursor.setQ(db.bufmgr.fixForUpdate(new PageId(1, pageNumber), 0));
  507. try {
  508. trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  509. boolean okay = false;
  510. try {
  511. // System.out.println("--> SPLITTING PAGE");
  512. bcursor.searchKey = generateKey(btree.indexItemFactory,
  513. "da", 5, -1, testLeaf);
  514. btree.doSplit(trx, bcursor);
  515. } finally {
  516. if (okay)
  517. trx.commit();
  518. else {
  519. trx.abort();
  520. }
  521. }
  522. } finally {
  523. bcursor.unfixQ();
  524. }
  525. } finally {
  526. db.shutdown();
  527. }
  528. }
  529. /*
  530. * Merges previously split pages 2 and 3.
  531. */
  532. void doRestartAndMerge(boolean testLeaf, boolean testUnique, int l, int r)
  533. throws Exception {
  534. final BTreeDB db = new BTreeDB(platform, false);
  535. final PlatformObjects po = db.platform
  536. .getPlatformObjects(IndexManager.LOGGER_NAME);
  537. try {
  538. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  539. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  540. // System.out.println("--> BEFORE MERGE");
  541. BufferAccessBlock bab = db.bufmgr.fixShared(new PageId(1, l), 0);
  542. try {
  543. BTreeNode node = new BTreeNode(po, btree.indexItemFactory, bab
  544. .getPage());
  545. node.dump();
  546. } finally {
  547. bab.unfix();
  548. }
  549. bab = db.bufmgr.fixShared(new PageId(1, r), 0);
  550. try {
  551. BTreeNode node = new BTreeNode(po, btree.indexItemFactory, bab
  552. .getPage());
  553. node.dump();
  554. } finally {
  555. bab.unfix();
  556. }
  557. BTreeContext bcursor = new BTreeContext(db.tracer);
  558. bcursor.setQ(db.bufmgr.fixForUpdate(new PageId(1, l), 0));
  559. bcursor.setR(db.bufmgr.fixForUpdate(new PageId(1, r), 0));
  560. try {
  561. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  562. boolean okay = false;
  563. try {
  564. // System.out.println("--> MERGING PAGE");
  565. btree.doMerge(trx, bcursor);
  566. } finally {
  567. if (okay)
  568. trx.commit();
  569. else {
  570. trx.abort();
  571. }
  572. }
  573. } finally {
  574. bcursor.unfixQ();
  575. }
  576. } finally {
  577. db.shutdown();
  578. }
  579. }
  580. /*
  581. * Merges previously split pages 2 and 3.
  582. */
  583. void doRestart() throws Exception {
  584. final BTreeDB db = new BTreeDB(platform, false);
  585. try {
  586. System.out.println("RESTART PROCESSING COMPLETED");
  587. } finally {
  588. db.shutdown();
  589. }
  590. }
  591. void doRestartAndLink(boolean testLeaf, boolean testUnique)
  592. throws Exception {
  593. final BTreeDB db = new BTreeDB(platform, false);
  594. final PlatformObjects po = db.platform
  595. .getPlatformObjects(IndexManager.LOGGER_NAME);
  596. try {
  597. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  598. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  599. // System.out.println("--> BEFORE LINKING CHILD TO PARENT");
  600. BufferAccessBlock bab = db.bufmgr.fixShared(new PageId(1, 2), 0);
  601. try {
  602. BTreeNode node = new BTreeNode(po, btree.indexItemFactory, bab
  603. .getPage());
  604. node.dump();
  605. } finally {
  606. bab.unfix();
  607. }
  608. bab = db.bufmgr.fixShared(new PageId(1, 3), 0);
  609. try {
  610. BTreeNode node = new BTreeNode(po, btree.indexItemFactory, bab
  611. .getPage());
  612. node.dump();
  613. } finally {
  614. bab.unfix();
  615. }
  616. // prepareParentPage(pageFactory, bufmgr, btree, 1, 4, testUnique,
  617. // 2);
  618. BTreeContext bcursor = new BTreeContext(db.tracer);
  619. bcursor.setQ(db.bufmgr.fixForUpdate(new PageId(1, 2), 0));
  620. bcursor.setR(db.bufmgr.fixForUpdate(new PageId(1, 3), 0));
  621. bcursor.setP(db.bufmgr.fixForUpdate(new PageId(1, 4), 0));
  622. try {
  623. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  624. boolean okay = false;
  625. try {
  626. // System.out.println("--> LINKING CHILD TO PARENT");
  627. btree.doLink(trx, bcursor);
  628. } finally {
  629. if (okay)
  630. trx.commit();
  631. else {
  632. trx.abort();
  633. }
  634. }
  635. } finally {
  636. bcursor.unfixQ();
  637. bcursor.unfixR();
  638. bcursor.unfixP();
  639. }
  640. bcursor.setQ(db.bufmgr.fixForUpdate(new PageId(1, 2), 0));
  641. bcursor.setR(db.bufmgr.fixForUpdate(new PageId(1, 3), 0));
  642. bcursor.setP(db.bufmgr.fixForUpdate(new PageId(1, 4), 0));
  643. try {
  644. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  645. boolean okay = false;
  646. try {
  647. // System.out.println("--> DE-LINKING CHILD FROM PARENT");
  648. btree.doUnlink(trx, bcursor);
  649. } finally {
  650. if (okay)
  651. trx.commit();
  652. else {
  653. trx.abort();
  654. }
  655. }
  656. } finally {
  657. bcursor.unfixQ();
  658. bcursor.unfixR();
  659. }
  660. } finally {
  661. db.shutdown();
  662. }
  663. }
  664. void doRestartLink(boolean testLeaf, boolean testUnique) throws Exception {
  665. final BTreeDB db = new BTreeDB(platform, false);
  666. final PlatformObjects po = db.platform
  667. .getPlatformObjects(IndexManager.LOGGER_NAME);
  668. try {
  669. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  670. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  671. // System.out.println("--> BEFORE LINKING CHILD TO PARENT");
  672. BufferAccessBlock bab = db.bufmgr.fixShared(new PageId(1, 2), 0);
  673. try {
  674. BTreeNode node = new BTreeNode(po, btree.indexItemFactory, bab
  675. .getPage());
  676. node.dump();
  677. } finally {
  678. bab.unfix();
  679. }
  680. bab = db.bufmgr.fixShared(new PageId(1, 3), 0);
  681. try {
  682. BTreeNode node = new BTreeNode(po, btree.indexItemFactory, bab
  683. .getPage());
  684. node.dump();
  685. } finally {
  686. bab.unfix();
  687. }
  688. // prepareParentPage(pageFactory, bufmgr, btree, 1, 4, testUnique,
  689. // 2);
  690. BTreeContext bcursor = new BTreeContext(db.tracer);
  691. bcursor.setQ(db.bufmgr.fixForUpdate(new PageId(1, 2), 0));
  692. bcursor.setR(db.bufmgr.fixForUpdate(new PageId(1, 3), 0));
  693. bcursor.setP(db.bufmgr.fixForUpdate(new PageId(1, 4), 0));
  694. try {
  695. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  696. boolean okay = false;
  697. try {
  698. // System.out.println("--> LINKING CHILD TO PARENT");
  699. btree.doLink(trx, bcursor);
  700. } finally {
  701. if (okay)
  702. trx.commit();
  703. else {
  704. trx.abort();
  705. }
  706. }
  707. } finally {
  708. bcursor.unfixQ();
  709. bcursor.unfixR();
  710. bcursor.unfixP();
  711. }
  712. } finally {
  713. db.shutdown();
  714. }
  715. }
  716. void doRestartDelink(boolean testLeaf, boolean testUnique) throws Exception {
  717. final BTreeDB db = new BTreeDB(platform, false);
  718. try {
  719. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  720. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  721. BTreeContext bcursor = new BTreeContext(db.tracer);
  722. bcursor.setQ(db.bufmgr.fixForUpdate(new PageId(1, 2), 0));
  723. bcursor.setR(db.bufmgr.fixForUpdate(new PageId(1, 3), 0));
  724. bcursor.setP(db.bufmgr.fixForUpdate(new PageId(1, 4), 0));
  725. try {
  726. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  727. boolean okay = false;
  728. try {
  729. // System.out.println("--> DE-LINKING CHILD FROM PARENT");
  730. btree.doUnlink(trx, bcursor);
  731. } finally {
  732. if (okay)
  733. trx.commit();
  734. else {
  735. trx.abort();
  736. }
  737. }
  738. } finally {
  739. bcursor.unfixQ();
  740. bcursor.unfixR();
  741. }
  742. } finally {
  743. db.shutdown();
  744. }
  745. }
  746. void doRestartAndUnlink(boolean testLeaf, boolean testUnique, int p, int q,
  747. int r) throws Exception {
  748. final BTreeDB db = new BTreeDB(platform, false);
  749. try {
  750. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  751. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  752. BTreeContext bcursor = new BTreeContext(db.tracer);
  753. bcursor.setQ(db.bufmgr.fixForUpdate(new PageId(1, q), 0));
  754. bcursor.setR(db.bufmgr.fixForUpdate(new PageId(1, r), 0));
  755. bcursor.setP(db.bufmgr.fixForUpdate(new PageId(1, p), 0));
  756. try {
  757. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  758. boolean okay = false;
  759. try {
  760. // System.out.println("--> DE-LINKING CHILD FROM PARENT");
  761. btree.doUnlink(trx, bcursor);
  762. } finally {
  763. if (okay)
  764. trx.commit();
  765. else {
  766. trx.abort();
  767. }
  768. }
  769. } finally {
  770. bcursor.unfixQ();
  771. bcursor.unfixR();
  772. }
  773. } finally {
  774. db.shutdown();
  775. }
  776. }
  777. void doRestartAndRedistribute(boolean testLeaf, boolean testUnique)
  778. throws Exception {
  779. final BTreeDB db = new BTreeDB(platform, false);
  780. final PlatformObjects po = db.platform
  781. .getPlatformObjects(IndexManager.LOGGER_NAME);
  782. try {
  783. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  784. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  785. // System.out.println("--> BEFORE REDISTRIBUTING KEYS");
  786. BufferAccessBlock bab = db.bufmgr.fixShared(new PageId(1, 2), 0);
  787. try {
  788. BTreeNode node = new BTreeNode(po, btree.indexItemFactory, bab
  789. .getPage());
  790. node.dump();
  791. } finally {
  792. bab.unfix();
  793. }
  794. bab = db.bufmgr.fixShared(new PageId(1, 3), 0);
  795. try {
  796. BTreeNode node = new BTreeNode(po, btree.indexItemFactory, bab
  797. .getPage());
  798. node.dump();
  799. } finally {
  800. bab.unfix();
  801. }
  802. BTreeContext bcursor = new BTreeContext(db.tracer);
  803. bcursor.setQ(db.bufmgr.fixForUpdate(new PageId(1, 2), 0));
  804. bcursor.setR(db.bufmgr.fixForUpdate(new PageId(1, 3), 0));
  805. try {
  806. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  807. boolean okay = false;
  808. try {
  809. bcursor.searchKey = generateKey(btree.indexItemFactory,
  810. "da", 5, -1, testLeaf);
  811. // System.out.println("--> REDISTRIBUTING KEYS");
  812. btree.doRedistribute(trx, bcursor);
  813. } finally {
  814. if (okay)
  815. trx.commit();
  816. else {
  817. trx.abort();
  818. }
  819. }
  820. } finally {
  821. bcursor.unfixQ();
  822. }
  823. } finally {
  824. db.shutdown();
  825. }
  826. }
  827. void doRedistributeIssue28() throws Exception {
  828. boolean testUnique = false;
  829. boolean testLeaf = true;
  830. final BTreeDB db = new BTreeDB(platform, false);
  831. final PlatformObjects po = db.platform
  832. .getPlatformObjects(IndexManager.LOGGER_NAME);
  833. try {
  834. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  835. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  836. BufferAccessBlock bab = db.bufmgr.fixShared(new PageId(1, 2), 0);
  837. try {
  838. BTreeNode node = new BTreeNode(po, btree.indexItemFactory, bab
  839. .getPage());
  840. node.dump();
  841. } finally {
  842. bab.unfix();
  843. }
  844. bab = db.bufmgr.fixShared(new PageId(1, 3), 0);
  845. try {
  846. BTreeNode node = new BTreeNode(po, btree.indexItemFactory, bab
  847. .getPage());
  848. node.dump();
  849. } finally {
  850. bab.unfix();
  851. }
  852. BTreeContext bcursor = new BTreeContext(db.tracer);
  853. bcursor.setQ(db.bufmgr.fixForUpdate(new PageId(1, 2), 0));
  854. bcursor.setR(db.bufmgr.fixForUpdate(new PageId(1, 3), 0));
  855. try {
  856. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  857. boolean okay = false;
  858. try {
  859. bcursor.searchKey = generateKey(btree.indexItemFactory,
  860. "da", 5, -1, testLeaf);
  861. btree.doRedistribute(trx, bcursor);
  862. } finally {
  863. if (okay)
  864. trx.commit();
  865. else {
  866. trx.abort();
  867. }
  868. }
  869. } finally {
  870. bcursor.unfixQ();
  871. }
  872. } finally {
  873. db.shutdown();
  874. }
  875. }
  876. void doRestartAndIncreaseTreeHeight(boolean testLeaf, boolean testUnique)
  877. throws Exception {
  878. final BTreeDB db = new BTreeDB(platform, false);
  879. final PlatformObjects po = db.platform
  880. .getPlatformObjects(IndexManager.LOGGER_NAME);
  881. try {
  882. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  883. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  884. // System.out.println("--> BEFORE INCREASING TREE HEIGHT");
  885. BufferAccessBlock bab = db.bufmgr.fixShared(new PageId(1, 2), 0);
  886. try {
  887. BTreeNode node = new BTreeNode(po, btree.indexItemFactory, bab
  888. .getPage());
  889. node.dump();
  890. } finally {
  891. bab.unfix();
  892. }
  893. bab = db.bufmgr.fixShared(new PageId(1, 3), 0);
  894. try {
  895. BTreeNode node = new BTreeNode(po, btree.indexItemFactory, bab
  896. .getPage());
  897. node.dump();
  898. } finally {
  899. bab.unfix();
  900. }
  901. BTreeContext bcursor = new BTreeContext(db.tracer);
  902. bcursor.setQ(db.bufmgr.fixForUpdate(new PageId(1, 2), 0));
  903. bcursor.setR(db.bufmgr.fixForUpdate(new PageId(1, 3), 0));
  904. try {
  905. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  906. boolean okay = false;
  907. try {
  908. bcursor.searchKey = generateKey(btree.indexItemFactory,
  909. "da", 5, -1, testLeaf);
  910. // System.out.println("--> INCREASING TREE HEIGHT");
  911. btree.doIncreaseTreeHeight(trx, bcursor);
  912. } finally {
  913. if (okay)
  914. trx.commit();
  915. else {
  916. trx.abort();
  917. }
  918. }
  919. } finally {
  920. bcursor.unfixQ();
  921. }
  922. } finally {
  923. db.shutdown();
  924. }
  925. }
  926. void doRestartAndDecreaseTreeHeight(boolean testLeaf, boolean testUnique,
  927. int p, int q) throws Exception {
  928. final BTreeDB db = new BTreeDB(platform, false);
  929. final PlatformObjects po = db.platform
  930. .getPlatformObjects(IndexManager.LOGGER_NAME);
  931. try {
  932. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  933. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  934. // System.out.println("--> BEFORE DECREASING TREE HEIGHT");
  935. BufferAccessBlock bab = db.bufmgr.fixShared(new PageId(1, p), 0);
  936. try {
  937. BTreeNode node = new BTreeNode(po, btree.indexItemFactory, bab
  938. .getPage());
  939. node.dump();
  940. } finally {
  941. bab.unfix();
  942. }
  943. bab = db.bufmgr.fixShared(new PageId(1, q), 0);
  944. try {
  945. BTreeNode node = new BTreeNode(po, btree.indexItemFactory, bab
  946. .getPage());
  947. node.dump();
  948. } finally {
  949. bab.unfix();
  950. }
  951. BTreeContext bcursor = new BTreeContext(db.tracer);
  952. bcursor.setP(db.bufmgr.fixForUpdate(new PageId(1, p), 0));
  953. bcursor.setQ(db.bufmgr.fixForUpdate(new PageId(1, q), 0));
  954. try {
  955. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  956. boolean okay = false;
  957. try {
  958. bcursor.searchKey = generateKey(btree.indexItemFactory,
  959. "da", 5, -1, testLeaf);
  960. // System.out.println("--> DECREASING TREE HEIGHT");
  961. btree.doDecreaseTreeHeight(trx, bcursor);
  962. } finally {
  963. if (okay)
  964. trx.commit();
  965. else {
  966. trx.abort();
  967. }
  968. }
  969. } finally {
  970. bcursor.unfixP();
  971. }
  972. } finally {
  973. db.shutdown();
  974. }
  975. }
  976. void doNewRedistribute(boolean testLeaf) throws Exception {
  977. boolean testUnique = false;
  978. final BTreeDB db = new BTreeDB(platform, false);
  979. final PlatformObjects po = db.platform
  980. .getPlatformObjects(IndexManager.LOGGER_NAME);
  981. try {
  982. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  983. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  984. BufferAccessBlock bab = db.bufmgr.fixShared(new PageId(1, 2), 0);
  985. try {
  986. BTreeNode node = new BTreeNode(po, btree.indexItemFactory, bab
  987. .getPage());
  988. node.dump();
  989. } finally {
  990. bab.unfix();
  991. }
  992. bab = db.bufmgr.fixShared(new PageId(1, 3), 0);
  993. try {
  994. BTreeNode node = new BTreeNode(po, btree.indexItemFactory, bab
  995. .getPage());
  996. node.dump();
  997. } finally {
  998. bab.unfix();
  999. }
  1000. BTreeContext bcursor = new BTreeContext(db.tracer);
  1001. bcursor.setQ(db.bufmgr.fixForUpdate(new PageId(1, 2), 0));
  1002. bcursor.setR(db.bufmgr.fixForUpdate(new PageId(1, 3), 0));
  1003. try {
  1004. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  1005. boolean okay = false;
  1006. try {
  1007. bcursor.searchKey = generateKey(btree.indexItemFactory,
  1008. "da", 5, -1, testLeaf);
  1009. btree.doNewRedistribute(trx, bcursor);
  1010. } finally {
  1011. if (okay)
  1012. trx.commit();
  1013. else {
  1014. trx.abort();
  1015. }
  1016. }
  1017. } finally {
  1018. bcursor.unfixQ();
  1019. }
  1020. } finally {
  1021. db.shutdown();
  1022. }
  1023. }
  1024. /**
  1025. * Test case for Issue 64.
  1026. */
  1027. void doSearchIssue64() throws Exception {
  1028. final boolean testUnique = false;
  1029. final BTreeDB db = new BTreeDB(platform, false);
  1030. try {
  1031. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  1032. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  1033. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  1034. .getSingleton(TYPE_STRINGKEYFACTORY);
  1035. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  1036. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  1037. IndexKey key = keyFactory.parseIndexKey(1, "zzz");
  1038. Location location = locationFactory.newLocation();
  1039. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  1040. IndexScan scan = btree.openScan(trx, key, location, true);
  1041. try {
  1042. if (scan.fetchNext()) {
  1043. fail("Unexpected result");
  1044. }
  1045. } catch (SimpleDBMException e) {
  1046. fail("Unexpected exception " + e.getMessage());
  1047. } finally {
  1048. scan.close();
  1049. trx.abort();
  1050. }
  1051. } finally {
  1052. db.shutdown();
  1053. }
  1054. }
  1055. void doSingleInsert(boolean testUnique, boolean commit, String k, String loc)
  1056. throws Exception {
  1057. doSingleInsert(testUnique, commit, k, loc, null, null);
  1058. }
  1059. void doSingleInsert(boolean testUnique, boolean commit, String k,
  1060. String loc, String commitresult, String abortresult)
  1061. throws Exception {
  1062. final BTreeDB db = new BTreeDB(platform, false);
  1063. try {
  1064. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  1065. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  1066. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  1067. .getSingleton(TYPE_STRINGKEYFACTORY);
  1068. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  1069. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  1070. IndexKey key = keyFactory.parseIndexKey(1, k);
  1071. Location location = locationFactory.newLocation(loc);
  1072. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  1073. boolean okay = false;
  1074. try {
  1075. // System.out.println("--> INSERTING KEY");
  1076. btree.insert(trx, key, location);
  1077. if (commitresult != null) {
  1078. doValidateTree(db, commitresult);
  1079. }
  1080. okay = true;
  1081. } finally {
  1082. if (okay && commit) {
  1083. // System.out.println("--> COMMITTING INSERT");
  1084. trx.commit();
  1085. if (commitresult != null) {
  1086. doValidateTree(db, commitresult);
  1087. }
  1088. } else {
  1089. // System.out.println("--> ABORTING INSERT");
  1090. trx.abort();
  1091. if (abortresult != null) {
  1092. doValidateTree(db, abortresult);
  1093. }
  1094. }
  1095. }
  1096. } finally {
  1097. db.shutdown();
  1098. }
  1099. }
  1100. void doDoubleInsert(boolean testUnique, boolean commit1, String k1,
  1101. String loc1, boolean commit2, String k2, String loc2,
  1102. String result1, String result2, String result3) throws Exception {
  1103. final BTreeDB db = new BTreeDB(platform, false);
  1104. try {
  1105. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  1106. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  1107. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  1108. .getSingleton(TYPE_STRINGKEYFACTORY);
  1109. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  1110. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  1111. IndexKey key1 = keyFactory.parseIndexKey(1, k1);
  1112. Location location1 = locationFactory.newLocation(loc1);
  1113. Transaction trx1 = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  1114. boolean okay1 = false;
  1115. try {
  1116. // System.out.println("--> INSERTING KEY 1");
  1117. btree.insert(trx1, key1, location1);
  1118. doValidateTree(db, result1);
  1119. okay1 = true;
  1120. IndexKey key2 = keyFactory.parseIndexKey(1, k2);
  1121. Location location2 = locationFactory.newLocation(loc2);
  1122. Transaction trx2 = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  1123. boolean okay2 = false;
  1124. try {
  1125. // System.out.println("--> INSERTING KEY 2");
  1126. btree.insert(trx2, key2, location2);
  1127. doValidateTree(db, result2);
  1128. okay2 = true;
  1129. } finally {
  1130. if (okay2 && commit2) {
  1131. // System.out.println("--> COMMITTING KEY 2");
  1132. trx2.commit();
  1133. } else {
  1134. // System.out.println("--> ABORTING KEY 2");
  1135. trx2.abort();
  1136. }
  1137. }
  1138. } finally {
  1139. if (okay1 && commit1) {
  1140. // System.out.println("--> COMMITTING KEY 1");
  1141. trx1.commit();
  1142. } else {
  1143. // System.out.println("--> ABORTING KEY 1");
  1144. trx1.abort();
  1145. doValidateTree(db, result3);
  1146. }
  1147. }
  1148. } finally {
  1149. db.shutdown();
  1150. }
  1151. }
  1152. void doSingleDelete(boolean testUnique, boolean commit, String k, String loc)
  1153. throws Exception {
  1154. final BTreeDB db = new BTreeDB(platform, false);
  1155. try {
  1156. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  1157. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  1158. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  1159. .getSingleton(TYPE_STRINGKEYFACTORY);
  1160. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  1161. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  1162. IndexKey key = keyFactory.parseIndexKey(1, k);
  1163. Location location = locationFactory.newLocation(loc);
  1164. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  1165. boolean okay = false;
  1166. try {
  1167. // System.out.println("--> DELETING KEY");
  1168. btree.delete(trx, key, location);
  1169. okay = true;
  1170. } finally {
  1171. if (okay && commit)
  1172. trx.commit();
  1173. else {
  1174. trx.abort();
  1175. }
  1176. }
  1177. } finally {
  1178. db.shutdown();
  1179. }
  1180. }
  1181. boolean t1Failed = false;
  1182. boolean t2Failed = false;
  1183. /**
  1184. * In this test, a delete is started on one thread, and on aother thread, a
  1185. * concurrent insert is started. The test should have following behaviour.
  1186. * The insert should wait for the outcome of the delete. If the delete
  1187. * commits, the insert should successfully proceed. If the delete aborts,
  1188. * the insert should fail with unique constraint violation error.
  1189. */
  1190. void doDeleteInsertThreads(final boolean testUnique,
  1191. final boolean commitDelete, final String k, final String loc,
  1192. final String deleteResult, final String insertResult)
  1193. throws Exception {
  1194. final BTreeDB db = new BTreeDB(platform, false);
  1195. final boolean testingUniqueIndex = testUnique;
  1196. try {
  1197. final Thread t1 = new Thread(new Runnable() {
  1198. public void run() {
  1199. try {
  1200. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  1201. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY,
  1202. testingUniqueIndex);
  1203. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  1204. .getSingleton(TYPE_STRINGKEYFACTORY);
  1205. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  1206. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  1207. IndexKey key = keyFactory.parseIndexKey(1, k);
  1208. Location location = locationFactory.newLocation(loc);
  1209. Transaction trx = db.trxmgr
  1210. .begin(IsolationMode.SERIALIZABLE);
  1211. boolean okay = false;
  1212. try {
  1213. // System.out.println("--> DELETING KEY");
  1214. btree.delete(trx, key, location);
  1215. if (deleteResult != null)
  1216. doValidateTree(db, deleteResult);
  1217. Thread.sleep(2000);
  1218. okay = true;
  1219. } finally {
  1220. if (okay && commitDelete)
  1221. trx.commit();
  1222. else {
  1223. trx.abort();
  1224. }
  1225. t1Failed = false;
  1226. }
  1227. } catch (Exception e) {
  1228. e.printStackTrace();
  1229. }
  1230. }
  1231. }, "T1");
  1232. final Thread t2 = new Thread(new Runnable() {
  1233. public void run() {
  1234. try {
  1235. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  1236. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY,
  1237. testingUniqueIndex);
  1238. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  1239. .getSingleton(TYPE_STRINGKEYFACTORY);
  1240. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  1241. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  1242. IndexKey key = keyFactory.parseIndexKey(1, k);
  1243. Location location = locationFactory.newLocation(loc);
  1244. Transaction trx = db.trxmgr
  1245. .begin(IsolationMode.SERIALIZABLE);
  1246. boolean okay = false;
  1247. try {
  1248. // System.out.println("--> INSERTING KEY");
  1249. btree.insert(trx, key, location);
  1250. if (insertResult != null)
  1251. doValidateTree(db, insertResult);
  1252. okay = true;
  1253. if (commitDelete) {
  1254. // System.out.println("Setting t2Failed to
  1255. // false");
  1256. t2Failed = false;
  1257. }
  1258. } finally {
  1259. if (okay /* && commit */) {
  1260. trx.commit();
  1261. } else {
  1262. trx.abort();
  1263. }
  1264. }
  1265. } catch (Exception e) {
  1266. if (!commitDelete
  1267. && e instanceof UniqueConstraintViolationException) {
  1268. t2Failed = false;
  1269. }
  1270. e.printStackTrace();
  1271. }
  1272. }
  1273. }, "T2");
  1274. t1Failed = true;
  1275. t2Failed = true;
  1276. t1.start();
  1277. Thread.sleep(1000);
  1278. t2.start();
  1279. t1.join();
  1280. t2.join();
  1281. assertTrue(!t1.isAlive());
  1282. assertTrue(!t2.isAlive());
  1283. assertTrue(!t2Failed);
  1284. } finally {
  1285. db.shutdown();
  1286. }
  1287. }
  1288. void doScanAndDelete(boolean testUnique, boolean commit, String k,
  1289. String loc) throws Exception {
  1290. final BTreeDB db = new BTreeDB(platform, false);
  1291. try {
  1292. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  1293. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  1294. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  1295. .getSingleton(TYPE_STRINGKEYFACTORY);
  1296. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  1297. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  1298. IndexKey key = keyFactory.parseIndexKey(1, k);
  1299. Location location = locationFactory.newLocation(loc);
  1300. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  1301. boolean okay = false;
  1302. IndexScan scan = btree.openScan(trx, key, location, true);
  1303. try {
  1304. // System.out.println("--> SCANNING TREE");
  1305. while (scan.fetchNext()) {
  1306. // System.out.println("new ScanResult(\"" +
  1307. // scan.getCurrentKey() + "\", \"" +
  1308. // scan.getCurrentLocation() + "\"),");
  1309. // System.out.println("SCAN=" + scan.getCurrentKey() + "," +
  1310. // scan.getCurrentLocation());
  1311. trx.acquireLock(scan.getCurrentLocation(),
  1312. LockMode.EXCLUSIVE, LockDuration.COMMIT_DURATION);
  1313. if (scan.isEof()) {
  1314. break;
  1315. }
  1316. // System.out.println("DELETING=" + scan.getCurrentKey() +
  1317. // "," + scan.getCurrentLocation());
  1318. btree.delete(trx, scan.getCurrentKey(), scan
  1319. .getCurrentLocation());
  1320. scan.fetchCompleted(true);
  1321. }
  1322. } finally {
  1323. scan.close();
  1324. if (!doCrashTesting) {
  1325. if (okay && commit)
  1326. trx.commit();
  1327. else {
  1328. trx.abort();
  1329. }
  1330. }
  1331. }
  1332. } finally {
  1333. db.shutdown();
  1334. }
  1335. }
  1336. class ScanResult {
  1337. String key;
  1338. String location;
  1339. public ScanResult(String key, String location) {
  1340. this.key = key;
  1341. this.location = location;
  1342. }
  1343. public String getKey() {
  1344. return key;
  1345. }
  1346. public void setKey(String key) {
  1347. this.key = key;
  1348. }
  1349. public String getLocation() {
  1350. return location;
  1351. }
  1352. public void setLocation(String location) {
  1353. this.location = location;
  1354. }
  1355. }
  1356. /**
  1357. * Scans the tree from a starting key to the eof.
  1358. */
  1359. void doScanTree(boolean testUnique, boolean commit, String k, String loc,
  1360. ScanResult[] result) throws Exception {
  1361. final BTreeDB db = new BTreeDB(platform, false);
  1362. try {
  1363. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  1364. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  1365. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  1366. .getSingleton(TYPE_STRINGKEYFACTORY);
  1367. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  1368. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  1369. IndexKey key = keyFactory.parseIndexKey(1, k);
  1370. Location location = locationFactory.newLocation(loc);
  1371. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  1372. boolean okay = false;
  1373. IndexScan scan = btree.openScan(trx, key, location, false);
  1374. try {
  1375. // System.out.println("--> SCANNING TREE {");
  1376. int i = 0;
  1377. while (scan.fetchNext()) {
  1378. if (result != null) {
  1379. assertEquals(result[i].getKey(), scan.getCurrentKey()
  1380. .toString());
  1381. assertEquals(result[i].getLocation(), scan
  1382. .getCurrentLocation().toString());
  1383. i++;
  1384. }
  1385. scan.fetchCompleted(true);
  1386. // System.out.println("new ScanResult(\"" +
  1387. // scan.getCurrentKey() + "\", \"" +
  1388. // scan.getCurrentLocation() + "\"),");
  1389. }
  1390. } finally {
  1391. scan.close();
  1392. if (okay && commit)
  1393. trx.commit();
  1394. else {
  1395. trx.abort();
  1396. }
  1397. }
  1398. } finally {
  1399. db.shutdown();
  1400. }
  1401. }
  1402. /**
  1403. * Scans the tree from a starting key to the eof, and then rolls back to
  1404. * savepoint.
  1405. */
  1406. void doTestCursorStateAfterRollbackToSavepoint(boolean testUnique,
  1407. boolean commit, String k, String loc) throws Exception {
  1408. final BTreeDB db = new BTreeDB(platform, false);
  1409. try {
  1410. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  1411. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  1412. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  1413. .getSingleton(TYPE_STRINGKEYFACTORY);
  1414. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  1415. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  1416. IndexKey key = keyFactory.parseIndexKey(1, k);
  1417. Location location = locationFactory.newLocation(loc);
  1418. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  1419. boolean okay = false;
  1420. IndexScan scan = btree.openScan(trx, key, location, false);
  1421. try {
  1422. int i;
  1423. // fetch a couple of items just to set the initial position
  1424. for (i = 0; i < 2; i++) {
  1425. if (scan.fetchNext()) {
  1426. scan.fetchCompleted(true);
  1427. } else {
  1428. break;
  1429. }
  1430. }
  1431. assertEquals(2, i);
  1432. // make a note of where we are
  1433. IndexKey savedkey = scan.getCurrentKey();
  1434. Location savedlocation = scan.getCurrentLocation();
  1435. // create savepoint and save cursor position
  1436. Savepoint sp = trx.createSavepoint(true);
  1437. i = 0;
  1438. while (scan.fetchNext()) {
  1439. i++;
  1440. scan.fetchCompleted(true);
  1441. }
  1442. assertEquals(32, i);
  1443. int j = i;
  1444. // rollback to savepoint
  1445. trx.rollback(sp);
  1446. // verify that we are back to the remembered position
  1447. assertEquals(savedkey, scan.getCurrentKey());
  1448. assertEquals(savedlocation, scan.getCurrentLocation());
  1449. // repeat scan of remaining items
  1450. i = 0;
  1451. while (scan.fetchNext()) {
  1452. i++;
  1453. scan.fetchCompleted(true);
  1454. }
  1455. // verify that we got the same count as before.
  1456. assertEquals(j, i);
  1457. } finally {
  1458. scan.close();
  1459. if (okay && commit)
  1460. trx.commit();
  1461. else {
  1462. trx.abort();
  1463. }
  1464. }
  1465. } finally {
  1466. db.shutdown();
  1467. }
  1468. }
  1469. /**
  1470. * Scans the tree from a starting key to the eof, and then rolls back to
  1471. * savepoint.
  1472. */
  1473. void doTestCursorStateAfterRollbackToSavepoint2(boolean testUnique,
  1474. boolean commit, String k, String loc) throws Exception {
  1475. final BTreeDB db = new BTreeDB(platform, false);
  1476. try {
  1477. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  1478. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  1479. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  1480. .getSingleton(TYPE_STRINGKEYFACTORY);
  1481. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  1482. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  1483. IndexKey key = keyFactory.parseIndexKey(1, k);
  1484. Location location = locationFactory.newLocation(loc);
  1485. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  1486. boolean okay = false;
  1487. IndexScan scan = btree.openScan(trx, key, location, false);
  1488. try {
  1489. Savepoint sp = trx.createSavepoint(true);
  1490. int i;
  1491. // fetch a couple of items just to set the initial position
  1492. for (i = 0; i < 2; i++) {
  1493. if (scan.fetchNext()) {
  1494. scan.fetchCompleted(true);
  1495. } else {
  1496. break;
  1497. }
  1498. }
  1499. assertEquals(2, i);
  1500. // make a note of where we are
  1501. IndexKey savedkey = scan.getCurrentKey();
  1502. Location savedlocation = scan.getCurrentLocation();
  1503. // create savepoint and save cursor position
  1504. i = 0;
  1505. while (scan.fetchNext()) {
  1506. i++;
  1507. scan.fetchCompleted(true);
  1508. }
  1509. assertEquals(32, i);
  1510. int j = i;
  1511. // rollback to savepoint
  1512. trx.rollback(sp);
  1513. // verify that we are back to the remembered position
  1514. for (i = 0; i < 2; i++) {
  1515. if (scan.fetchNext()) {
  1516. scan.fetchCompleted(true);
  1517. } else {
  1518. break;
  1519. }
  1520. }
  1521. assertEquals(2, i);
  1522. assertEquals(savedkey, scan.getCurrentKey());
  1523. assertEquals(savedlocation, scan.getCurrentLocation());
  1524. // repeat scan of remaining items
  1525. i = 0;
  1526. while (scan.fetchNext()) {
  1527. i++;
  1528. scan.fetchCompleted(true);
  1529. }
  1530. // verify that we got the same count as before.
  1531. assertEquals(j, i);
  1532. } finally {
  1533. scan.close();
  1534. if (okay && commit)
  1535. trx.commit();
  1536. else {
  1537. trx.abort();
  1538. }
  1539. }
  1540. } finally {
  1541. db.shutdown();
  1542. }
  1543. }
  1544. /**
  1545. * Scans the tree from a starting key to the eof.
  1546. */
  1547. void doScanTree(String filename) throws Exception {
  1548. BufferedReader reader = new BufferedReader(new InputStreamReader(Thread
  1549. .currentThread().getContextClassLoader().getResourceAsStream(
  1550. filename)));
  1551. final BTreeDB db = new BTreeDB(platform, false);
  1552. try {
  1553. IndexContainer index = db.btreeMgr.getIndex(1);
  1554. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  1555. .getSingleton(TYPE_STRINGKEYFACTORY);
  1556. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  1557. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  1558. String line = reader.readLine();
  1559. IndexScan scan = null;
  1560. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  1561. try {
  1562. while (line != null) {
  1563. StringTokenizer st = new StringTokenizer(line, " ");
  1564. String k = st.nextToken();
  1565. IndexKey key = keyFactory.parseIndexKey(1, k);
  1566. String l = st.nextToken();
  1567. Location location = locationFactory.newLocation(l);
  1568. if (scan == null) {
  1569. scan = index.openScan(trx, key, location, false);
  1570. }
  1571. if (scan.fetchNext()) {
  1572. // System.out.println("new ScanResult(\"" +
  1573. // scan.getCurrentKey() + "\", \"" +
  1574. // scan.getCurrentLocation() + "\"),");
  1575. assertEquals(key.toString(), scan.getCurrentKey()
  1576. .toString());
  1577. assertEquals(location.toString(), scan
  1578. .getCurrentLocation().toString());
  1579. scan.fetchCompleted(true);
  1580. } else {
  1581. fail("Scan for next key failed at (" + key + ", "
  1582. + location + ")");
  1583. }
  1584. line = reader.readLine();
  1585. }
  1586. } finally {
  1587. if (scan != null) {
  1588. scan.close();
  1589. }
  1590. trx.abort();
  1591. }
  1592. } finally {
  1593. reader.close();
  1594. db.shutdown();
  1595. }
  1596. }
  1597. /**
  1598. * Scans the tree from a starting key to the eof.
  1599. */
  1600. void doFindInTree(String filename) throws Exception {
  1601. BufferedReader reader = new BufferedReader(new InputStreamReader(Thread
  1602. .currentThread().getContextClassLoader().getResourceAsStream(
  1603. filename)));
  1604. final BTreeDB db = new BTreeDB(platform, false);
  1605. try {
  1606. IndexContainer index = db.btreeMgr.getIndex(1);
  1607. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  1608. .getSingleton(TYPE_STRINGKEYFACTORY);
  1609. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  1610. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  1611. String line = reader.readLine();
  1612. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  1613. try {
  1614. while (line != null) {
  1615. StringTokenizer st = new StringTokenizer(line, " ");
  1616. String k = st.nextToken();
  1617. IndexKey key = keyFactory.parseIndexKey(1, k);
  1618. String l = st.nextToken();
  1619. Location location = locationFactory.newLocation(l);
  1620. IndexScan scan = index.openScan(trx, key, location, false);
  1621. if (scan.fetchNext()) {
  1622. // System.out.println("new FindResult(\"" +
  1623. // scan.getCurrentKey() + "\", \"" +
  1624. // scan.getCurrentLocation() + "\"),");
  1625. assertEquals(key.toString(), scan.getCurrentKey()
  1626. .toString());
  1627. assertEquals(location.toString(), scan
  1628. .getCurrentLocation().toString());
  1629. scan.fetchCompleted(true);
  1630. } else {
  1631. fail("Find failed for (" + key + ", " + location + ")");
  1632. }
  1633. scan.close();
  1634. line = reader.readLine();
  1635. }
  1636. } finally {
  1637. trx.abort();
  1638. }
  1639. } finally {
  1640. reader.close();
  1641. db.shutdown();
  1642. }
  1643. }
  1644. /**
  1645. * Starts two threads. First thread starts a delete on a key and then goes
  1646. * to sleep. Second thread scans the tree, and blocks when it reaches the
  1647. * deleted key. The delete thread resumes and commits the delete. This lets
  1648. * the scan thread continue and finish the scan.
  1649. */
  1650. void doDeleteAndScanThreads(final boolean testUnique, final boolean commit,
  1651. final String k, final String loc, final ScanResult[] result)
  1652. throws Exception {
  1653. final BTreeDB db = new BTreeDB(platform, false);
  1654. final boolean testingUniqueIndex = testUnique;
  1655. final Lock lock = new ReentrantLock();
  1656. final Condition deleted = lock.newCondition();
  1657. final Condition lockWaitStarted = lock.newCondition();
  1658. final LockEventListener listener = new LockEventListener() {
  1659. public void beforeLockWait(Object owner, Object lockable,
  1660. LockMode mode) {
  1661. // System.out.println("LOCK WAIT STARTED");
  1662. lock.lock();
  1663. lockWaitStarted.signal();
  1664. lock.unlock();
  1665. }
  1666. };
  1667. try {
  1668. Thread t1 = new Thread(new Runnable() {
  1669. public void run() {
  1670. try {
  1671. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  1672. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY,
  1673. testingUniqueIndex);
  1674. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  1675. .getSingleton(TYPE_STRINGKEYFACTORY);
  1676. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  1677. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  1678. IndexKey key = keyFactory.parseIndexKey(1, k);
  1679. Location location = locationFactory.newLocation(loc);
  1680. // Allow the main thread to enter lock wait
  1681. Thread.sleep(100);
  1682. Transaction trx = db.trxmgr
  1683. .begin(IsolationMode.SERIALIZABLE);
  1684. boolean okay = false;
  1685. try {
  1686. // System.out.println("--> DELETING KEY [" + k + ","
  1687. // + loc + "]");
  1688. btree.delete(trx, key, location);
  1689. lock.lock();
  1690. try {
  1691. deleted.signal();
  1692. // System.out.println("Awaiting
  1693. // lockWaitStarted");
  1694. long n = lockWaitStarted
  1695. .awaitNanos(TimeUnit.NANOSECONDS
  1696. .convert(2, TimeUnit.SECONDS));
  1697. assertFalse(n <= 0);
  1698. // System.out.println("Received lockWaitStarted
  1699. // signal");
  1700. } finally {
  1701. lock.unlock();
  1702. }
  1703. // Thread.sleep(5000);
  1704. okay = true;
  1705. } finally {
  1706. if (okay && commit) {
  1707. // System.out.println("--> COMMITTING DELETE OF
  1708. // KEY [" + k + "," + loc + "]");
  1709. trx.commit();
  1710. } else {
  1711. // System.out.println("--> ABORTING DELETE OF
  1712. // KEY [" + k + "," + loc + "]");
  1713. trx.abort();
  1714. }
  1715. }
  1716. } catch (Exception e) {
  1717. e.printStackTrace();
  1718. t1Failed = true;
  1719. }
  1720. }
  1721. }, "T1");
  1722. Thread t2 = new Thread(new Runnable() {
  1723. public void run() {
  1724. try {
  1725. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  1726. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY,
  1727. testingUniqueIndex);
  1728. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  1729. .getSingleton(TYPE_STRINGKEYFACTORY);
  1730. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  1731. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  1732. IndexKey key = keyFactory.parseIndexKey(1, "a1");
  1733. Location location = locationFactory.newLocation("10");
  1734. Transaction trx = db.trxmgr
  1735. .begin(IsolationMode.SERIALIZABLE);
  1736. boolean okay = false;
  1737. IndexScan scan = btree.openScan(trx, key, location,
  1738. false);
  1739. db.lockmgr.addLockEventListener(listener);
  1740. try {
  1741. // System.out.println("--> SCANNING TREE");
  1742. int i = 0;
  1743. while (scan.fetchNext()) {
  1744. if (result != null) {
  1745. assertEquals(result[i].getKey(), scan
  1746. .getCurrentKey().toString());
  1747. assertEquals(result[i].getLocation(), scan
  1748. .getCurrentLocation().toString());
  1749. i++;
  1750. }
  1751. scan.fetchCompleted(true);
  1752. if (scan.isEof()) {
  1753. break;
  1754. }
  1755. }
  1756. } finally {
  1757. db.lockmgr.clearLockEventListeners();
  1758. scan.close();
  1759. if (okay && commit)
  1760. trx.commit();
  1761. else {
  1762. trx.abort();
  1763. }
  1764. }
  1765. } catch (Exception e) {
  1766. e.printStackTrace();
  1767. t2Failed = true;
  1768. }
  1769. }
  1770. }, "T2");
  1771. t1Failed = false;
  1772. t2Failed = false;
  1773. t1.start();
  1774. lock.lock();
  1775. try {
  1776. long n = deleted.awaitNanos(TimeUnit.NANOSECONDS.convert(2,
  1777. TimeUnit.SECONDS));
  1778. assertFalse(n <= 0);
  1779. } finally {
  1780. lock.unlock();
  1781. }
  1782. // System.out.println("PROCEEDING");
  1783. // Thread.sleep(1000);
  1784. t2.start();
  1785. t1.join();
  1786. t2.join();
  1787. assertTrue(!t1.isAlive());
  1788. assertTrue(!t2.isAlive());
  1789. assertFalse(t1Failed);
  1790. assertFalse(t2Failed);
  1791. } finally {
  1792. db.shutdown();
  1793. }
  1794. }
  1795. void doScanAndDeleteThreads(final boolean testUnique, final boolean commit,
  1796. final String k, final String loc, final ScanResult[] result)
  1797. throws Exception {
  1798. final BTreeDB db = new BTreeDB(platform, false);
  1799. final boolean testingUniqueIndex = testUnique;
  1800. final Lock lock = new ReentrantLock();
  1801. final Condition lockWaitStarted = lock.newCondition();
  1802. final LockEventListener listener = new LockEventListener() {
  1803. public void beforeLockWait(Object owner, Object lockable,
  1804. LockMode mode) {
  1805. // System.out.println("LOCK WAIT STARTED");
  1806. lock.lock();
  1807. try {
  1808. lockWaitStarted.signal();
  1809. } finally {
  1810. lock.unlock();
  1811. }
  1812. }
  1813. };
  1814. try {
  1815. final Thread t1 = new Thread(new Runnable() {
  1816. public void run() {
  1817. try {
  1818. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  1819. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY,
  1820. testingUniqueIndex);
  1821. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  1822. .getSingleton(TYPE_STRINGKEYFACTORY);
  1823. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  1824. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  1825. IndexKey key = keyFactory.parseIndexKey(1, k);
  1826. Location location = locationFactory.newLocation(loc);
  1827. Transaction trx = db.trxmgr
  1828. .begin(IsolationMode.SERIALIZABLE);
  1829. boolean okay = false;
  1830. try {
  1831. // System.out.println("--> DELETING KEY [" + k + ","
  1832. // + loc + "]");
  1833. db.lockmgr.addLockEventListener(listener);
  1834. trx.acquireLock(location, LockMode.EXCLUSIVE,
  1835. LockDuration.COMMIT_DURATION);
  1836. btree.delete(trx, key, location);
  1837. okay = true;
  1838. } finally {
  1839. db.lockmgr.clearLockEventListeners();
  1840. if (okay && commit) {
  1841. // System.out.println("--> COMMITTING DELETE OF
  1842. // KEY [" + k + "," + loc + "]");
  1843. trx.commit();
  1844. } else {
  1845. // System.out.println("--> ABORTING DELETE OF
  1846. // KEY [" + k + "," + loc + "]");
  1847. trx.abort();
  1848. }
  1849. }
  1850. } catch (Exception e) {
  1851. e.printStackTrace();
  1852. t1Failed = true;
  1853. }
  1854. }
  1855. }, "T1");
  1856. Thread t2 = new Thread(new Runnable() {
  1857. public void run() {
  1858. try {
  1859. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  1860. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY,
  1861. testingUniqueIndex);
  1862. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  1863. .getSingleton(TYPE_STRINGKEYFACTORY);
  1864. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  1865. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  1866. IndexKey key = keyFactory.parseIndexKey(1, "a1");
  1867. Location location = locationFactory.newLocation("10");
  1868. IndexKey delkey = keyFactory.parseIndexKey(1, k);
  1869. Transaction trx = db.trxmgr
  1870. .begin(IsolationMode.SERIALIZABLE);
  1871. boolean okay = false;
  1872. IndexScan scan = btree.openScan(trx, key, location,
  1873. false);
  1874. try {
  1875. // System.out.println("--> SCANNING TREE");
  1876. int i = 0;
  1877. while (scan.fetchNext()) {
  1878. if (result != null) {
  1879. assertEquals(result[i].getKey(), scan
  1880. .getCurrentKey().toString());
  1881. assertEquals(result[i].getLocation(), scan
  1882. .getCurrentLocation().toString());
  1883. i++;
  1884. }
  1885. if (scan.getCurrentKey().equals(delkey)) {
  1886. lock.lock();
  1887. lockWaitStarted.await(15, TimeUnit.SECONDS);
  1888. lock.unlock();
  1889. }
  1890. scan.fetchCompleted(true);
  1891. if (scan.isEof()) {
  1892. break;
  1893. }
  1894. }
  1895. } finally {
  1896. scan.close();
  1897. if (okay && commit)
  1898. trx.commit();
  1899. else {
  1900. trx.abort();
  1901. }
  1902. }
  1903. } catch (Exception e) {
  1904. e.printStackTrace();
  1905. t2Failed = true;
  1906. }
  1907. }
  1908. }, "T2");
  1909. t1Failed = false;
  1910. t2Failed = false;
  1911. t2.start();
  1912. Thread.sleep(1000);
  1913. t1.start();
  1914. t1.join();
  1915. t2.join();
  1916. assertTrue(!t1.isAlive());
  1917. assertTrue(!t2.isAlive());
  1918. } finally {
  1919. db.shutdown();
  1920. }
  1921. }
  1922. /**
  1923. * Tests that when serialization mode is enabled, even if read unique for X
  1924. * fails, another transaction must wait for the reader to finish before it
  1925. * can insert X.
  1926. */
  1927. void doReadUniqueX() throws Exception {
  1928. final boolean testingUniqueIndex = true;
  1929. final Lock lock = new ReentrantLock();
  1930. final Condition lockWaitStarted = lock.newCondition();
  1931. final AtomicInteger status = new AtomicInteger(0);
  1932. final LockEventListener listener = new LockEventListener() {
  1933. public void beforeLockWait(Object owner, Object lockable,
  1934. LockMode mode) {
  1935. // System.out.println("LOCK WAIT STARTED");
  1936. lock.lock();
  1937. lockWaitStarted.signal();
  1938. status.incrementAndGet();
  1939. lock.unlock();
  1940. }
  1941. };
  1942. final BTreeDB db = new BTreeDB(platform, false);
  1943. final Thread t1 = new Thread(new Runnable() {
  1944. public void run() {
  1945. try {
  1946. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  1947. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY,
  1948. testingUniqueIndex);
  1949. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  1950. .getSingleton(TYPE_STRINGKEYFACTORY);
  1951. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  1952. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  1953. IndexKey key = keyFactory.parseIndexKey(1, "x");
  1954. Location location = locationFactory.newLocation("2");
  1955. Transaction trx = db.trxmgr
  1956. .begin(IsolationMode.SERIALIZABLE);
  1957. boolean okay = false;
  1958. try {
  1959. IndexScan scan = btree.openScan(trx, key, location,
  1960. false);
  1961. try {
  1962. scan.fetchNext();
  1963. lock.lock();
  1964. lockWaitStarted.await(3, TimeUnit.SECONDS);
  1965. lock.unlock();
  1966. scan.fetchCompleted(true);
  1967. } finally {
  1968. scan.close();
  1969. }
  1970. okay = true;
  1971. } finally {
  1972. if (okay) {
  1973. trx.commit();
  1974. } else {
  1975. trx.abort();
  1976. }
  1977. }
  1978. } catch (Exception e) {
  1979. setThreadFailed(Thread.currentThread(), e);
  1980. }
  1981. }
  1982. }, "T1");
  1983. final Thread t2 = new Thread(new Runnable() {
  1984. public void run() {
  1985. try {
  1986. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  1987. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY,
  1988. testingUniqueIndex);
  1989. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  1990. .getSingleton(TYPE_STRINGKEYFACTORY);
  1991. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  1992. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  1993. IndexKey key = keyFactory.parseIndexKey(1, "x");
  1994. Location location = locationFactory.newLocation("2");
  1995. Transaction trx = db.trxmgr
  1996. .begin(IsolationMode.SERIALIZABLE);
  1997. boolean okay = false;
  1998. try {
  1999. try {
  2000. db.lockmgr.addLockEventListener(listener);
  2001. trx.acquireLock(location, LockMode.EXCLUSIVE,
  2002. LockDuration.COMMIT_DURATION);
  2003. btree.insert(trx, key, location);
  2004. } finally {
  2005. db.lockmgr.clearLockEventListeners();
  2006. }
  2007. okay = true;
  2008. } finally {
  2009. if (okay) {
  2010. trx.commit();
  2011. } else {
  2012. trx.abort();
  2013. }
  2014. }
  2015. } catch (Exception e) {
  2016. setThreadFailed(Thread.currentThread(), e);
  2017. }
  2018. }
  2019. }, "T2");
  2020. try {
  2021. t1.start();
  2022. Thread.sleep(1000);
  2023. t2.start();
  2024. t1.join(10000);
  2025. t2.join(10000);
  2026. assertTrue(!t1.isAlive());
  2027. assertTrue(!t2.isAlive());
  2028. checkThreadFailures();
  2029. assertEquals(1, status.get());
  2030. } finally {
  2031. db.shutdown();
  2032. }
  2033. }
  2034. /**
  2035. * Tests the situation where a transaction needs to wait for the next key
  2036. * lock during insert, and between the gap when it releases the latches and
  2037. * attempts an unconditional lock, another transaction inserts a key that
  2038. * changes the key range, and forces the first transaction, after it obtains
  2039. * the lock, to restart.
  2040. */
  2041. void doReadUniqueX2() throws Exception {
  2042. final boolean testingUniqueIndex = true;
  2043. final Lock lock = new ReentrantLock();
  2044. final Condition lockWaitStarted = lock.newCondition();
  2045. final AtomicInteger status = new AtomicInteger(0);
  2046. final LockEventListener listener = new LockEventListener() {
  2047. public void beforeLockWait(Object owner, Object lockable,
  2048. LockMode mode) {
  2049. // System.out.println("LOCK WAIT STARTED");
  2050. lock.lock();
  2051. lockWaitStarted.signal();
  2052. status.incrementAndGet();
  2053. lock.unlock();
  2054. }
  2055. };
  2056. final BTreeDB db = new BTreeDB(platform, false);
  2057. final Thread t1 = new Thread(new Runnable() {
  2058. public void run() {
  2059. try {
  2060. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  2061. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY,
  2062. testingUniqueIndex);
  2063. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  2064. .getSingleton(TYPE_STRINGKEYFACTORY);
  2065. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  2066. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  2067. IndexKey key = keyFactory.parseIndexKey(1, "x");
  2068. Location location = locationFactory.newLocation("2");
  2069. Transaction trx = db.trxmgr
  2070. .begin(IsolationMode.SERIALIZABLE);
  2071. boolean okay = false;
  2072. try {
  2073. IndexScan scan = btree.openScan(trx, key, location,
  2074. false);
  2075. try {
  2076. scan.fetchNext();
  2077. lock.lock();
  2078. lockWaitStarted.await(3, TimeUnit.SECONDS);
  2079. lock.unlock();
  2080. scan.fetchCompleted(true);
  2081. } finally {
  2082. scan.close();
  2083. }
  2084. okay = true;
  2085. } finally {
  2086. if (okay) {
  2087. trx.commit();
  2088. } else {
  2089. trx.abort();
  2090. }
  2091. }
  2092. } catch (Exception e) {
  2093. setThreadFailed(Thread.currentThread(), e);
  2094. }
  2095. }
  2096. }, "T1");
  2097. final Thread t2 = new Thread(new Runnable() {
  2098. public void run() {
  2099. try {
  2100. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  2101. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY,
  2102. testingUniqueIndex);
  2103. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  2104. .getSingleton(TYPE_STRINGKEYFACTORY);
  2105. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  2106. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  2107. IndexKey key = keyFactory.parseIndexKey(1, "x");
  2108. Location location = locationFactory.newLocation("2");
  2109. Transaction trx = db.trxmgr
  2110. .begin(IsolationMode.SERIALIZABLE);
  2111. boolean okay = false;
  2112. try {
  2113. try {
  2114. trx.acquireLock(location, LockMode.EXCLUSIVE,
  2115. LockDuration.COMMIT_DURATION);
  2116. btree.insert(trx, key, location);
  2117. } finally {
  2118. }
  2119. okay = true;
  2120. } finally {
  2121. if (okay) {
  2122. trx.commit();
  2123. } else {
  2124. trx.abort();
  2125. }
  2126. }
  2127. } catch (Exception e) {
  2128. setThreadFailed(Thread.currentThread(), e);
  2129. }
  2130. }
  2131. }, "TestingInsertRestartDueToKeyRangeModification");
  2132. final Thread t3 = new Thread(new Runnable() {
  2133. public void run() {
  2134. try {
  2135. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  2136. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY,
  2137. testingUniqueIndex);
  2138. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  2139. .getSingleton(TYPE_STRINGKEYFACTORY);
  2140. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  2141. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  2142. IndexKey key = keyFactory.parseIndexKey(1, "x1");
  2143. Location location = locationFactory.newLocation("21");
  2144. Transaction trx = db.trxmgr
  2145. .begin(IsolationMode.SERIALIZABLE);
  2146. boolean okay = false;
  2147. try {
  2148. try {
  2149. db.lockmgr.addLockEventListener(listener);
  2150. trx.acquireLock(location, LockMode.EXCLUSIVE,
  2151. LockDuration.COMMIT_DURATION);
  2152. btree.insert(trx, key, location);
  2153. } finally {
  2154. db.lockmgr.clearLockEventListeners();
  2155. }
  2156. okay = true;
  2157. } finally {
  2158. if (okay) {
  2159. trx.commit();
  2160. } else {
  2161. trx.abort();
  2162. }
  2163. }
  2164. } catch (Exception e) {
  2165. setThreadFailed(Thread.currentThread(), e);
  2166. }
  2167. }
  2168. }, "T3");
  2169. try {
  2170. t1.start();
  2171. Thread.sleep(1000);
  2172. t2.start();
  2173. Thread.sleep(1000);
  2174. t3.start();
  2175. t1.join(10000);
  2176. t2.join(10000);
  2177. t3.join(10000);
  2178. assertTrue(!t1.isAlive());
  2179. assertTrue(!t2.isAlive());
  2180. assertTrue(!t3.isAlive());
  2181. assertEquals(1, status.get());
  2182. checkThreadFailures();
  2183. } finally {
  2184. db.shutdown();
  2185. }
  2186. }
  2187. public void testPageSplitLeafUnique() throws Exception {
  2188. doInitContainer();
  2189. doLoadXml(true, "org/simpledbm/rss/impl/im/btree/data1ul.xml");
  2190. doPageSplit(true, true);
  2191. doValidateTree("org/simpledbm/rss/impl/im/btree/testPageSplitLeafUnique.xml");
  2192. }
  2193. public void testPageSplitNonLeafUnique2() throws Exception {
  2194. doInitContainer();
  2195. doLoadXml(true, "org/simpledbm/rss/impl/im/btree/data1unl.xml");
  2196. doPageSplit(false, true);
  2197. doValidateTree("org/simpledbm/rss/impl/im/btree/testPageSplitNonLeafUnique2.xml");
  2198. doRestartAndMerge(false, true, 2, 3);
  2199. doValidateTree("org/simpledbm/rss/impl/im/btree/testRestartAndMerge.xml");
  2200. }
  2201. public void testPageSplitLeafUnique2() throws Exception {
  2202. doInitContainer();
  2203. doLoadXml(true, "org/simpledbm/rss/impl/im/btree/data1ul.xml");
  2204. doPageSplit(true, true);
  2205. doValidateTree("org/simpledbm/rss/impl/im/btree/testPageSplitLeafUnique2.xml");
  2206. doLoadXml(true, "org/simpledbm/rss/impl/im/btree/data2unl.xml");
  2207. doRestartLink(false, true);
  2208. doValidateTree("org/simpledbm/rss/impl/im/btree/testRestartLink.xml");
  2209. doRestartDelink(false, true);
  2210. doValidateTree("org/simpledbm/rss/impl/im/btree/testRestartDelink.xml");
  2211. doLoadXml(true, "org/simpledbm/rss/impl/im/btree/data2unl.xml");
  2212. doRestartAndLink(false, true);
  2213. doRestartAndRedistribute(false, true);
  2214. doValidateTree("org/simpledbm/rss/impl/im/btree/testRestartAndRedistribute.xml");
  2215. doRestartAndIncreaseTreeHeight(false, true);
  2216. doValidateTree("org/simpledbm/rss/impl/im/btree/testRestartAndIncreaseTreeHeight.xml");
  2217. doRestartAndUnlink(false, true, 2, 5, 3);
  2218. doRestartAndMerge(false, true, 5, 3);
  2219. doRestartAndDecreaseTreeHeight(false, true, 2, 5);
  2220. doValidateTree("org/simpledbm/rss/impl/im/btree/testRestartAndDecreaseTreeHeight.xml");
  2221. }
  2222. public void testRedistributeIssue28() throws Exception {
  2223. doInitContainer();
  2224. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data9nul.xml");
  2225. doRedistributeIssue28();
  2226. doValidateTree("org/simpledbm/rss/impl/im/btree/testRedistributeIssue28.xml");
  2227. }
  2228. /**
  2229. * Test leaf right to left
  2230. *
  2231. * @throws Exception
  2232. */
  2233. public void testNewRedistribute1() throws Exception {
  2234. doInitContainer();
  2235. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data10nul.xml");
  2236. doNewRedistribute(true);
  2237. doValidateTree("org/simpledbm/rss/impl/im/btree/testNewRedistribute.xml");
  2238. }
  2239. /**
  2240. * Test leaf left to right
  2241. *
  2242. * @throws Exception
  2243. */
  2244. public void testNewRedistribute2() throws Exception {
  2245. doInitContainer();
  2246. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data11nul.xml");
  2247. doNewRedistribute(true);
  2248. doValidateTree("org/simpledbm/rss/impl/im/btree/testNewRedistribute.xml");
  2249. }
  2250. /**
  2251. * Test non-leaf right to left
  2252. *
  2253. * @throws Exception
  2254. */
  2255. public void testNewRedistribute3() throws Exception {
  2256. doInitContainer();
  2257. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data10nu.xml");
  2258. doNewRedistribute(false);
  2259. doValidateTree("org/simpledbm/rss/impl/im/btree/testNewRedistribute_i.xml");
  2260. }
  2261. /**
  2262. * Test non-leaf left to right
  2263. *
  2264. * @throws Exception
  2265. */
  2266. public void testNewRedistribute4() throws Exception {
  2267. doInitContainer();
  2268. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data11nu.xml");
  2269. doNewRedistribute(false);
  2270. doValidateTree("org/simpledbm/rss/impl/im/btree/testNewRedistribute_i.xml");
  2271. }
  2272. public void testSearchIssue64() throws Exception {
  2273. doInitContainer();
  2274. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/dataIssue64.xml");
  2275. doSearchIssue64();
  2276. }
  2277. public void testSimpleInsertAbort() throws Exception {
  2278. doInitContainer();
  2279. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data3nul.xml");
  2280. doSingleInsert(false, false, "a", "1",
  2281. "org/simpledbm/rss/impl/im/btree/testSimpleInsertAbort_1.xml",
  2282. "org/simpledbm/rss/impl/im/btree/testSimpleInsertAbort_2.xml");
  2283. }
  2284. public void testSimpleInsertCommit() throws Exception {
  2285. doInitContainer();
  2286. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data3nul.xml");
  2287. doSingleInsert(false, true, "a", "1",
  2288. "org/simpledbm/rss/impl/im/btree/testSimpleInsertAbort_1.xml",
  2289. "org/simpledbm/rss/impl/im/btree/testSimpleInsertAbort_1.xml");
  2290. }
  2291. public void testInsertSplitRootAbort() throws Exception {
  2292. doInitContainer();
  2293. // Generate a tree with just the root node which should be full
  2294. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data4nul.xml");
  2295. // Following should split the root node
  2296. doSingleInsert(
  2297. false,
  2298. true,
  2299. "da",
  2300. "8",
  2301. "org/simpledbm/rss/impl/im/btree/testInsertSplitRootAbort_1.xml",
  2302. null);
  2303. // Following should cause tree height increase
  2304. doSingleInsert(
  2305. false,
  2306. false,
  2307. "b1",
  2308. "9",
  2309. "org/simpledbm/rss/impl/im/btree/testInsertSplitRootAbort_2.xml",
  2310. "org/simpledbm/rss/impl/im/btree/testInsertSplitRootAbort_3.xml");
  2311. }
  2312. public void testInsertSplitRootCommit() throws Exception {
  2313. doInitContainer();
  2314. // Generate a tree with just the root node which should be full
  2315. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data4nul.xml");
  2316. // Following should split the root node
  2317. doSingleInsert(
  2318. false,
  2319. true,
  2320. "da",
  2321. "8",
  2322. "org/simpledbm/rss/impl/im/btree/testInsertSplitRootAbort_1.xml",
  2323. "org/simpledbm/rss/impl/im/btree/testInsertSplitRootAbort_1.xml");
  2324. // Following should cause tree height increase
  2325. doSingleInsert(
  2326. false,
  2327. true,
  2328. "b1",
  2329. "9",
  2330. "org/simpledbm/rss/impl/im/btree/testInsertSplitRootAbort_2.xml",
  2331. "org/simpledbm/rss/impl/im/btree/testInsertSplitRootAbort_2.xml");
  2332. }
  2333. public void testInsertSplitRootAbortLogical() throws Exception {
  2334. doInitContainer();
  2335. // Generate a tree with just the root node which should be full
  2336. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data5nul.xml");
  2337. // This should trigger logical undo as page will be split by
  2338. // second insert
  2339. doDoubleInsert(
  2340. false,
  2341. false,
  2342. "g",
  2343. "7",
  2344. true,
  2345. "da",
  2346. "8",
  2347. "org/simpledbm/rss/impl/im/btree/testInsertSplitRootAbortLogical_1.xml",
  2348. "org/simpledbm/rss/impl/im/btree/testInsertSplitRootAbortLogical_2.xml",
  2349. "org/simpledbm/rss/impl/im/btree/testInsertSplitRootAbortLogical_3.xml");
  2350. }
  2351. public void testInsertUnderflowFig13() throws Exception {
  2352. doInitContainer();
  2353. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data6nul.xml");
  2354. doSingleInsert(false, true, "a0", "1");
  2355. doValidateTree("org/simpledbm/rss/impl/im/btree/testInsertUnderflowFig13.xml");
  2356. }
  2357. public void testInsertUnderflowFig14() throws Exception {
  2358. doInitContainer();
  2359. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data6nul.xml");
  2360. doSingleInsert(false, true, "c19", "1");
  2361. doValidateTree("org/simpledbm/rss/impl/im/btree/testInsertUnderflowFig14.xml");
  2362. }
  2363. public void testInsertUnderflowFig5() throws Exception {
  2364. doInitContainer();
  2365. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data7nul.xml");
  2366. doSingleInsert(false, true, "k3", "1");
  2367. doValidateTree("org/simpledbm/rss/impl/im/btree/testInsertUnderflowFig5.xml");
  2368. }
  2369. public void testInsertUnderflowFig19() throws Exception {
  2370. doInitContainer();
  2371. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data6nul.xml");
  2372. doSingleInsert(false, true, "k3", "1");
  2373. doValidateTree("org/simpledbm/rss/impl/im/btree/testInsertUnderflowFig19.xml");
  2374. }
  2375. public void testInsertUnderflowFig15() throws Exception {
  2376. doInitContainer();
  2377. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data6nul.xml");
  2378. doSingleInsert(false, true, "g19", "1");
  2379. doValidateTree("org/simpledbm/rss/impl/im/btree/testInsertUnderflowFig15.xml");
  2380. }
  2381. // TODO test next key loc across a page
  2382. public void testInsertNextKeyInNextPage() throws Exception {
  2383. doInitContainer();
  2384. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data7nul.xml");
  2385. doSingleInsert(false, true, "b4", "1");
  2386. doValidateTree("org/simpledbm/rss/impl/im/btree/testInsertNextKeyInNextPage.xml");
  2387. }
  2388. public void testInsertUnderflowFig17() throws Exception {
  2389. doInitContainer();
  2390. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data8nul.xml");
  2391. doSingleInsert(false, true, "c0", "1");
  2392. doValidateTree("org/simpledbm/rss/impl/im/btree/testInsertUnderflowFig17.xml");
  2393. }
  2394. public void testDelete1() throws Exception {
  2395. doInitContainer();
  2396. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data6nul.xml");
  2397. doSingleDelete(false, true, "a1", "10");
  2398. doValidateTree("org/simpledbm/rss/impl/im/btree/testDelete1.xml");
  2399. }
  2400. public void testDeleteInsert1() throws Exception {
  2401. doInitContainer();
  2402. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data6nul.xml");
  2403. doDeleteInsertThreads(false, true, "a1", "10",
  2404. "org/simpledbm/rss/impl/im/btree/testDeleteInsert1_1.xml",
  2405. "org/simpledbm/rss/impl/im/btree/testDeleteInsert1_2.xml");
  2406. }
  2407. public void testDeleteInsert2() throws Exception {
  2408. doInitContainer();
  2409. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data6nul.xml");
  2410. doDeleteInsertThreads(false, false, "a1", "10",
  2411. "org/simpledbm/rss/impl/im/btree/testDeleteInsert1_1.xml", null);
  2412. }
  2413. public void testIssue71() throws Exception {
  2414. doInitContainer();
  2415. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/issue71.xml");
  2416. doFindSingleValue("b4", "24", "c1", "31");
  2417. }
  2418. public void testIssue71_Insert() throws Exception {
  2419. doInitContainer();
  2420. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/issue71_insert.xml");
  2421. doSingleInsert(false, true, "a3", "10");
  2422. doValidateTree("org/simpledbm/rss/impl/im/btree/testIssue71_insert.xml");
  2423. }
  2424. /**
  2425. * Scans the tree from a starting key to the eof.
  2426. */
  2427. void doFindSingleValue(String k, String l, String expectedKey,
  2428. String expectedLoc) throws Exception {
  2429. final BTreeDB db = new BTreeDB(platform, false);
  2430. try {
  2431. IndexContainer index = db.btreeMgr.getIndex(1);
  2432. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  2433. .getSingleton(TYPE_STRINGKEYFACTORY);
  2434. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  2435. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  2436. Transaction trx = db.trxmgr.begin(IsolationMode.READ_COMMITTED);
  2437. try {
  2438. IndexKey key = keyFactory.parseIndexKey(1, k);
  2439. Location location = locationFactory.newLocation(l);
  2440. IndexScan scan = index.openScan(trx, key, location, false);
  2441. if (scan.fetchNext()) {
  2442. if (!(scan.getCurrentKey().toString().equals(expectedKey) && scan
  2443. .getCurrentLocation().toString()
  2444. .equals(expectedLoc))) {
  2445. fail("Found (" + scan.getCurrentKey().toString() + ", "
  2446. + scan.getCurrentLocation().toString()
  2447. + ") instead of (" + expectedKey + ","
  2448. + expectedLoc + ")");
  2449. }
  2450. scan.fetchCompleted(true);
  2451. }
  2452. scan.close();
  2453. } finally {
  2454. trx.abort();
  2455. }
  2456. } finally {
  2457. db.shutdown();
  2458. }
  2459. }
  2460. public void testScan1() throws Exception {
  2461. doInitContainer();
  2462. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data6nul.xml");
  2463. ScanResult[] scanResults = new ScanResult[] {
  2464. new ScanResult("a1", "10"), new ScanResult("a2", "11"),
  2465. new ScanResult("b1", "21"), new ScanResult("b2", "22"),
  2466. new ScanResult("b3", "23"), new ScanResult("b4", "24"),
  2467. new ScanResult("c1", "31"), new ScanResult("c2", "32"),
  2468. new ScanResult("d1", "41"), new ScanResult("d2", "42"),
  2469. new ScanResult("d3", "43"), new ScanResult("d4", "44"),
  2470. new ScanResult("e1", "51"), new ScanResult("e2", "52"),
  2471. new ScanResult("e3", "53"), new ScanResult("e4", "54"),
  2472. new ScanResult("f1", "61"), new ScanResult("f2", "62"),
  2473. new ScanResult("f3", "63"), new ScanResult("f4", "64"),
  2474. new ScanResult("g1", "71"), new ScanResult("g2", "72"),
  2475. new ScanResult("h1", "81"), new ScanResult("h2", "82"),
  2476. new ScanResult("h3", "83"), new ScanResult("h4", "84"),
  2477. new ScanResult("i1", "91"), new ScanResult("i2", "92"),
  2478. new ScanResult("j1", "101"), new ScanResult("j2", "102"),
  2479. new ScanResult("j3", "103"), new ScanResult("j4", "104"),
  2480. new ScanResult("k1", "111"), new ScanResult("k2", "112"),
  2481. new ScanResult("<INFINITY>", "999") };
  2482. doScanTree(false, false, "a1", "10", scanResults);
  2483. }
  2484. public void testScan2() throws Exception {
  2485. doInitContainer();
  2486. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data6nul.xml");
  2487. ScanResult[] scanResults = new ScanResult[] {
  2488. new ScanResult("a1", "10"), new ScanResult("a2", "11"),
  2489. new ScanResult("b1", "21"), new ScanResult("b2", "22"),
  2490. new ScanResult("b3", "23"), new ScanResult("b4", "24"),
  2491. new ScanResult("c1", "31"), new ScanResult("c2", "32"),
  2492. new ScanResult("d1", "41"), new ScanResult("d2", "42"),
  2493. new ScanResult("d3", "43"), new ScanResult("d4", "44"),
  2494. new ScanResult("e1", "51"), new ScanResult("e2", "52"),
  2495. new ScanResult("e3", "53"), new ScanResult("e4", "54"),
  2496. new ScanResult("f1", "61"), new ScanResult("f2", "62"),
  2497. new ScanResult("f3", "63"), new ScanResult("f4", "64"),
  2498. new ScanResult("g1", "71"), new ScanResult("g2", "72"),
  2499. new ScanResult("h1", "81"), new ScanResult("h2", "82"),
  2500. new ScanResult("h3", "83"), new ScanResult("h4", "84"),
  2501. new ScanResult("i1", "91"), new ScanResult("i2", "92"),
  2502. new ScanResult("j1", "101"), new ScanResult("j2", "102"),
  2503. new ScanResult("j3", "103"), new ScanResult("j4", "104"),
  2504. new ScanResult("k1", "111"), new ScanResult("k2", "112"),
  2505. new ScanResult("<INFINITY>", "999") };
  2506. ScanResult[] scanResults2 = new ScanResult[] {
  2507. new ScanResult("a1", "10"), new ScanResult("a2", "11"),
  2508. new ScanResult("b1", "21"), new ScanResult("b2", "22"),
  2509. new ScanResult("b3", "23"), new ScanResult("b4", "24"),
  2510. new ScanResult("c1", "31"), new ScanResult("c2", "32"),
  2511. new ScanResult("d1", "41"), new ScanResult("d2", "42"),
  2512. new ScanResult("d3", "43"), new ScanResult("d4", "44"),
  2513. new ScanResult("e1", "51"), new ScanResult("e2", "52"),
  2514. new ScanResult("e3", "53"), new ScanResult("e4", "54"),
  2515. new ScanResult("f1", "61"), new ScanResult("f2", "62"),
  2516. new ScanResult("f4", "64"), new ScanResult("g1", "71"),
  2517. new ScanResult("g2", "72"), new ScanResult("h1", "81"),
  2518. new ScanResult("h2", "82"), new ScanResult("h3", "83"),
  2519. new ScanResult("h4", "84"), new ScanResult("i1", "91"),
  2520. new ScanResult("i2", "92"), new ScanResult("j1", "101"),
  2521. new ScanResult("j2", "102"), new ScanResult("j3", "103"),
  2522. new ScanResult("j4", "104"), new ScanResult("k1", "111"),
  2523. new ScanResult("k2", "112"),
  2524. new ScanResult("<INFINITY>", "999") };
  2525. doScanAndDelete(false, false, "a1", "10");
  2526. doScanTree(false, false, "a1", "10", scanResults);
  2527. doDeleteAndScanThreads(false, true, "f3", "63", scanResults2);
  2528. }
  2529. public void testScan3() throws Exception {
  2530. ScanResult[] scanResults = new ScanResult[] {
  2531. new ScanResult("a1", "10"), new ScanResult("a2", "11"),
  2532. new ScanResult("b1", "21"), new ScanResult("b2", "22"),
  2533. new ScanResult("b3", "23"), new ScanResult("b4", "24"),
  2534. new ScanResult("c1", "31"), new ScanResult("c2", "32"),
  2535. new ScanResult("d1", "41"), new ScanResult("d2", "42"),
  2536. new ScanResult("d3", "43"), new ScanResult("d4", "44"),
  2537. new ScanResult("e1", "51"), new ScanResult("e2", "52"),
  2538. new ScanResult("e3", "53"), new ScanResult("e4", "54"),
  2539. new ScanResult("f1", "61"), new ScanResult("f2", "62"),
  2540. new ScanResult("f3", "63"), new ScanResult("f4", "64"),
  2541. new ScanResult("g1", "71"), new ScanResult("g2", "72"),
  2542. new ScanResult("h1", "81"), new ScanResult("h2", "82"),
  2543. new ScanResult("h3", "83"), new ScanResult("h4", "84"),
  2544. new ScanResult("i1", "91"), new ScanResult("i2", "92"),
  2545. new ScanResult("j1", "101"), new ScanResult("j2", "102"),
  2546. new ScanResult("j3", "103"), new ScanResult("j4", "104"),
  2547. new ScanResult("k1", "111"), new ScanResult("k2", "112"),
  2548. new ScanResult("<INFINITY>", "999") };
  2549. doInitContainer();
  2550. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data6nul.xml");
  2551. doDeleteAndScanThreads(false, false, "f3", "63", scanResults);
  2552. }
  2553. public void testScan4() throws Exception {
  2554. ScanResult[] scanResults = new ScanResult[] {
  2555. new ScanResult("a1", "10"), new ScanResult("a2", "11"),
  2556. new ScanResult("b1", "21"), new ScanResult("b2", "22"),
  2557. new ScanResult("b3", "23"), new ScanResult("b4", "24"),
  2558. new ScanResult("c1", "31"), new ScanResult("c2", "32"),
  2559. new ScanResult("d1", "41"), new ScanResult("d2", "42"),
  2560. new ScanResult("d3", "43"), new ScanResult("d4", "44"),
  2561. new ScanResult("e1", "51"), new ScanResult("e2", "52"),
  2562. new ScanResult("e3", "53"), new ScanResult("e4", "54"),
  2563. new ScanResult("f1", "61"), new ScanResult("f2", "62"),
  2564. new ScanResult("f3", "63"), new ScanResult("f4", "64"),
  2565. new ScanResult("g1", "71"), new ScanResult("g2", "72"),
  2566. new ScanResult("h1", "81"), new ScanResult("h2", "82"),
  2567. new ScanResult("h3", "83"), new ScanResult("h4", "84"),
  2568. new ScanResult("i1", "91"), new ScanResult("i2", "92"),
  2569. new ScanResult("j1", "101"), new ScanResult("j2", "102"),
  2570. new ScanResult("j3", "103"), new ScanResult("j4", "104"),
  2571. new ScanResult("k1", "111"), new ScanResult("k2", "112"),
  2572. new ScanResult("<INFINITY>", "999") };
  2573. doInitContainer();
  2574. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data6nul.xml");
  2575. doScanAndDeleteThreads(false, false, "f3", "63", scanResults);
  2576. }
  2577. public void testCursorStateAfterRollback() throws Exception {
  2578. doInitContainer();
  2579. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data6nul.xml");
  2580. doTestCursorStateAfterRollbackToSavepoint(false, false, "a1", "10");
  2581. doTestCursorStateAfterRollbackToSavepoint2(false, false, "a1", "10");
  2582. }
  2583. /**
  2584. * This test scans and deletes all keys from the BTree as a single
  2585. * transaction. It completes without committing or aborting the transaction.
  2586. * At next restart, the expected behaviour is that the tree will be restored
  2587. * because the delete transaction will be rolled back.
  2588. * <p>
  2589. * This test must be followed by {@link #testScanAfterCrash()}.
  2590. *
  2591. * @throws Exception
  2592. */
  2593. public void testScanDeleteCrash() throws Exception {
  2594. doInitContainer();
  2595. doLoadXml(false, "org/simpledbm/rss/impl/im/btree/data6nul.xml");
  2596. doScanAndDelete(false, false, "a1", "10");
  2597. ScanResult[] scanResults = new ScanResult[] {
  2598. new ScanResult("a1", "10"), new ScanResult("a2", "11"),
  2599. new ScanResult("b1", "21"), new ScanResult("b2", "22"),
  2600. new ScanResult("b3", "23"), new ScanResult("b4", "24"),
  2601. new ScanResult("c1", "31"), new ScanResult("c2", "32"),
  2602. new ScanResult("d1", "41"), new ScanResult("d2", "42"),
  2603. new ScanResult("d3", "43"), new ScanResult("d4", "44"),
  2604. new ScanResult("e1", "51"), new ScanResult("e2", "52"),
  2605. new ScanResult("e3", "53"), new ScanResult("e4", "54"),
  2606. new ScanResult("f1", "61"), new ScanResult("f2", "62"),
  2607. new ScanResult("f3", "63"), new ScanResult("f4", "64"),
  2608. new ScanResult("g1", "71"), new ScanResult("g2", "72"),
  2609. new ScanResult("h1", "81"), new ScanResult("h2", "82"),
  2610. new ScanResult("h3", "83"), new ScanResult("h4", "84"),
  2611. new ScanResult("i1", "91"), new ScanResult("i2", "92"),
  2612. new ScanResult("j1", "101"), new ScanResult("j2", "102"),
  2613. new ScanResult("j3", "103"), new ScanResult("j4", "104"),
  2614. new ScanResult("k1", "111"), new ScanResult("k2", "112"),
  2615. new ScanResult("<INFINITY>", "999") };
  2616. doScanTree(false, false, "a1", "10", scanResults);
  2617. }
  2618. /**
  2619. * This test loads a set of sorted data, and then scans the tree to verify
  2620. * that the tree contains the data in the same sort order.
  2621. */
  2622. public void testInsertInOrder() throws Exception {
  2623. ScanResult[] inserts = new ScanResult[] { new ScanResult("a1", "10"),
  2624. new ScanResult("a2", "11"), new ScanResult("b1", "21"),
  2625. new ScanResult("b2", "22"), new ScanResult("b3", "23"),
  2626. new ScanResult("b4", "24"), new ScanResult("c1", "31"),
  2627. new ScanResult("c2", "32"), new ScanResult("d1", "41"),
  2628. new ScanResult("d2", "42"), new ScanResult("d3", "43"),
  2629. new ScanResult("d4", "44"), new ScanResult("e1", "51"),
  2630. new ScanResult("e2", "52"), new ScanResult("e3", "53"),
  2631. new ScanResult("e4", "54"), new ScanResult("f1", "61"),
  2632. new ScanResult("f2", "62"), new ScanResult("f3", "63"),
  2633. new ScanResult("f4", "64"), new ScanResult("g1", "71"),
  2634. new ScanResult("g2", "72"), new ScanResult("h1", "81"),
  2635. new ScanResult("h2", "82"), new ScanResult("h3", "83"),
  2636. new ScanResult("h4", "84"), new ScanResult("i1", "91"),
  2637. new ScanResult("i2", "92"), new ScanResult("j1", "101"),
  2638. new ScanResult("j2", "102"), new ScanResult("j3", "103"),
  2639. new ScanResult("j4", "104"), new ScanResult("k1", "111"),
  2640. new ScanResult("k2", "112") };
  2641. ScanResult[] scanResults = new ScanResult[] {
  2642. new ScanResult("a1", "10"), new ScanResult("a2", "11"),
  2643. new ScanResult("b1", "21"), new ScanResult("b2", "22"),
  2644. new ScanResult("b3", "23"), new ScanResult("b4", "24"),
  2645. new ScanResult("c1", "31"), new ScanResult("c2", "32"),
  2646. new ScanResult("d1", "41"), new ScanResult("d2", "42"),
  2647. new ScanResult("d3", "43"), new ScanResult("d4", "44"),
  2648. new ScanResult("e1", "51"), new ScanResult("e2", "52"),
  2649. new ScanResult("e3", "53"), new ScanResult("e4", "54"),
  2650. new ScanResult("f1", "61"), new ScanResult("f2", "62"),
  2651. new ScanResult("f3", "63"), new ScanResult("f4", "64"),
  2652. new ScanResult("g1", "71"), new ScanResult("g2", "72"),
  2653. new ScanResult("h1", "81"), new ScanResult("h2", "82"),
  2654. new ScanResult("h3", "83"), new ScanResult("h4", "84"),
  2655. new ScanResult("i1", "91"), new ScanResult("i2", "92"),
  2656. new ScanResult("j1", "101"), new ScanResult("j2", "102"),
  2657. new ScanResult("j3", "103"), new ScanResult("j4", "104"),
  2658. new ScanResult("k1", "111"), new ScanResult("k2", "112"),
  2659. new ScanResult("<INFINITY>", "0") };
  2660. doInitContainer2();
  2661. doLoadData(inserts);
  2662. doScanTree(true, false, "a1", "10", scanResults);
  2663. }
  2664. /**
  2665. * This test loads a set of sorted data from a file. Scans the tree and
  2666. * verifies that the scan order matches the sort order in the file. It then
  2667. * does a find for each key and verifies that all finds succeed. The data
  2668. * set is large enough to cause the container to be extended.
  2669. */
  2670. public void testInsertInOrderFromFile() throws Exception {
  2671. doInitContainer2();
  2672. doLoadData("org/simpledbm/rss/impl/im/btree/data1.txt");
  2673. doScanTree("org/simpledbm/rss/impl/im/btree/data1.txt");
  2674. doFindInTree("org/simpledbm/rss/impl/im/btree/data1.txt");
  2675. }
  2676. /**
  2677. * Tests the phantom record scenario as described in TPCT. Suppose that a
  2678. * file has sorted list of records with key values w, y, z. There are 4
  2679. * operations of interest:
  2680. * <ol>
  2681. * <li>Read unique. Read a unique record (say X), given its key.</li>
  2682. * <li>Read next. Read the next record, Y, after the record W.</li>
  2683. * <li>Insert. Insert record X between W and Y.</li>
  2684. * <li>Delete. Delete record Y.</li>
  2685. * </ol>
  2686. * <p>
  2687. * Phantom records with keys X and Y arise in the following cases.
  2688. * </p>
  2689. * <p>
  2690. * If transaction T performs a read unique of record X, and it is not found,
  2691. * T must prevent others from inserting phantom record X until T commits.
  2692. * </p>
  2693. * <p>
  2694. * If T is at record W and does a read next to get record Y, then W and Y
  2695. * cannot change; in addition, no one may insert a new record (phantom
  2696. * record X) between W and Y, until T commits.
  2697. * </p>
  2698. * <p>
  2699. * If T deletes record Y, no other transaction should insert a phantom Y,
  2700. * until T commits. In addition no other transaction should notice that the
  2701. * original Y is missing and that Z is now immediately after X, until T
  2702. * commits.
  2703. * </p>
  2704. *
  2705. * @throws Exception
  2706. */
  2707. public void testPhantomRecords1() throws Exception {
  2708. doInitContainer2();
  2709. doLoadData("org/simpledbm/rss/impl/im/btree/data2.txt");
  2710. doReadUniqueX();
  2711. ScanResult[] scanResults = new ScanResult[] { new ScanResult("w", "1"),
  2712. new ScanResult("x", "2"), new ScanResult("y", "3"),
  2713. new ScanResult("z", "4"), new ScanResult("<INFINITY>", "0") };
  2714. doScanTree(true, false, "w", "1", scanResults);
  2715. }
  2716. public void testPhantomRecords2() throws Exception {
  2717. doInitContainer2();
  2718. doLoadData("org/simpledbm/rss/impl/im/btree/data2.txt");
  2719. doReadUniqueX2();
  2720. ScanResult[] scanResults = new ScanResult[] { new ScanResult("w", "1"),
  2721. new ScanResult("x", "2"), new ScanResult("x1", "21"),
  2722. new ScanResult("y", "3"), new ScanResult("z", "4"),
  2723. new ScanResult("<INFINITY>", "0") };
  2724. doScanTree(true, false, "w", "1", scanResults);
  2725. }
  2726. class DataLoaderThread implements Runnable {
  2727. final String filename;
  2728. final BTreeDB db;
  2729. int count = 0;
  2730. public DataLoaderThread(final BTreeDB db, String filename) {
  2731. this.db = db;
  2732. this.filename = filename;
  2733. }
  2734. void doLoadData() throws Exception {
  2735. BufferedReader reader = new BufferedReader(new InputStreamReader(
  2736. Thread.currentThread().getContextClassLoader()
  2737. .getResourceAsStream(filename)));
  2738. try {
  2739. IndexContainer index = db.btreeMgr.getIndex(1);
  2740. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  2741. .getSingleton(TYPE_STRINGKEYFACTORY);
  2742. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  2743. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  2744. String line = reader.readLine();
  2745. int i = 1;
  2746. while (line != null) {
  2747. String k = line.trim();
  2748. IndexKey key = keyFactory.parseIndexKey(1, k);
  2749. RowLocation location = (RowLocation) locationFactory
  2750. .newLocation();
  2751. location.loc = i++;
  2752. while (true) {
  2753. Transaction trx = db.trxmgr
  2754. .begin(IsolationMode.SERIALIZABLE);
  2755. boolean okay = false;
  2756. try {
  2757. // System.out.println("Inserting (" + key + ", " +
  2758. // location
  2759. // + ")");
  2760. trx.acquireLock(location, LockMode.EXCLUSIVE,
  2761. LockDuration.COMMIT_DURATION);
  2762. index.insert(trx, key, location);
  2763. // System.out.println(Thread.currentThread() + ":
  2764. // inserted " + k);
  2765. okay = true;
  2766. } catch (LockDeadlockException e) {
  2767. // assume deadlock
  2768. e.printStackTrace();
  2769. } catch (UniqueConstraintViolationException e) {
  2770. break;
  2771. } finally {
  2772. if (okay)
  2773. trx.commit();
  2774. else
  2775. trx.abort();
  2776. }
  2777. if (okay) {
  2778. break;
  2779. }
  2780. }
  2781. line = reader.readLine();
  2782. }
  2783. count = i - 1;
  2784. } finally {
  2785. reader.close();
  2786. }
  2787. }
  2788. public void run() {
  2789. try {
  2790. doLoadData();
  2791. } catch (Exception e) {
  2792. e.printStackTrace();
  2793. TestBTreeManager.this
  2794. .setThreadFailed(Thread.currentThread(), e);
  2795. }
  2796. }
  2797. }
  2798. class DataDeleterThread implements Runnable {
  2799. final String filename;
  2800. final BTreeDB db;
  2801. int count = 0;
  2802. boolean doCommit;
  2803. public DataDeleterThread(final BTreeDB db, String filename,
  2804. boolean doCommit) {
  2805. this.db = db;
  2806. this.filename = filename;
  2807. this.doCommit = doCommit;
  2808. }
  2809. void doLoadData() throws Exception {
  2810. BufferedReader reader = new BufferedReader(new InputStreamReader(
  2811. Thread.currentThread().getContextClassLoader()
  2812. .getResourceAsStream(filename)));
  2813. try {
  2814. IndexContainer index = db.btreeMgr.getIndex(1);
  2815. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  2816. .getSingleton(TYPE_STRINGKEYFACTORY);
  2817. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  2818. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  2819. String line = reader.readLine();
  2820. int i = 1;
  2821. while (line != null) {
  2822. String k = line.trim();
  2823. IndexKey key = keyFactory.parseIndexKey(1, k);
  2824. RowLocation location = (RowLocation) locationFactory
  2825. .newLocation();
  2826. location.loc = i++;
  2827. while (true) {
  2828. Transaction trx = db.trxmgr
  2829. .begin(IsolationMode.SERIALIZABLE);
  2830. boolean okay = false;
  2831. try {
  2832. // System.out.println("Inserting (" + key + ", " +
  2833. // location
  2834. // + ")");
  2835. trx.acquireLock(location, LockMode.EXCLUSIVE,
  2836. LockDuration.COMMIT_DURATION);
  2837. index.delete(trx, key, location);
  2838. // System.out.println(Thread.currentThread() + ":
  2839. // inserted " + k);
  2840. okay = true;
  2841. } catch (LockDeadlockException e) {
  2842. // assume deadlock
  2843. e.printStackTrace();
  2844. } finally {
  2845. if (okay && doCommit) {
  2846. trx.commit();
  2847. count++;
  2848. } else
  2849. trx.abort();
  2850. }
  2851. if (okay) {
  2852. break;
  2853. }
  2854. }
  2855. line = reader.readLine();
  2856. }
  2857. } finally {
  2858. reader.close();
  2859. }
  2860. }
  2861. public void run() {
  2862. try {
  2863. doLoadData();
  2864. } catch (Exception e) {
  2865. e.printStackTrace();
  2866. TestBTreeManager.this
  2867. .setThreadFailed(Thread.currentThread(), e);
  2868. }
  2869. }
  2870. }
  2871. int doConcurrentInserts(String file1, String file2) throws Exception {
  2872. final BTreeDB db = new BTreeDB(platform, false);
  2873. try {
  2874. DataLoaderThread d1 = new DataLoaderThread(db, file1);
  2875. DataLoaderThread d2 = new DataLoaderThread(db, file2);
  2876. Thread t1 = new Thread(d1, "T1");
  2877. Thread t2 = new Thread(d2, "T2");
  2878. t1.start();
  2879. t2.start();
  2880. t1.join();
  2881. t2.join();
  2882. checkThreadFailures();
  2883. System.out.println("Inserted " + (d1.count + d2.count) + " keys");
  2884. return d1.count + d2.count;
  2885. } finally {
  2886. db.shutdown();
  2887. }
  2888. }
  2889. int doConcurrentDeletes(String file1, String file2) throws Exception {
  2890. final BTreeDB db = new BTreeDB(platform, false);
  2891. try {
  2892. DataDeleterThread d1 = new DataDeleterThread(db, file1, true);
  2893. DataDeleterThread d2 = new DataDeleterThread(db, file2, false);
  2894. Thread t1 = new Thread(d1, "T1");
  2895. Thread t2 = new Thread(d2, "T2");
  2896. t1.start();
  2897. t2.start();
  2898. t1.join();
  2899. t2.join();
  2900. checkThreadFailures();
  2901. System.out.println("Deleted " + (d1.count + d2.count) + " keys");
  2902. return d1.count + d2.count;
  2903. } finally {
  2904. db.shutdown();
  2905. }
  2906. }
  2907. /**
  2908. * Scans the tree from a starting key to the eof.
  2909. */
  2910. void doFindInTree2(String filename) throws Exception {
  2911. BufferedReader reader = new BufferedReader(new InputStreamReader(Thread
  2912. .currentThread().getContextClassLoader().getResourceAsStream(
  2913. filename)));
  2914. final BTreeDB db = new BTreeDB(platform, false);
  2915. try {
  2916. IndexContainer index = db.btreeMgr.getIndex(1);
  2917. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  2918. .getSingleton(TYPE_STRINGKEYFACTORY);
  2919. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  2920. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  2921. String line = reader.readLine();
  2922. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  2923. try {
  2924. int i = 1;
  2925. while (line != null) {
  2926. String k = line.trim();
  2927. IndexKey key = keyFactory.parseIndexKey(1, k);
  2928. RowLocation location = (RowLocation) locationFactory
  2929. .newLocation();
  2930. location.loc = i++;
  2931. IndexScan scan = index.openScan(trx, key, location, false);
  2932. if (scan.fetchNext()) {
  2933. // System.out.println("new FindResult(\"" +
  2934. // scan.getCurrentKey() + "\", \"" +
  2935. // scan.getCurrentLocation() + "\"),");
  2936. if (!(key.toString().equals(
  2937. scan.getCurrentKey().toString()) && location
  2938. .toString().equals(
  2939. scan.getCurrentLocation().toString()))) {
  2940. fail("Find failed for (" + key + ", " + location
  2941. + ")");
  2942. }
  2943. // assertEquals(key.toString(), scan
  2944. // .getCurrentKey()
  2945. // .toString());
  2946. // assertEquals(location.toString(), scan
  2947. // .getCurrentLocation()
  2948. // .toString());
  2949. scan.fetchCompleted(true);
  2950. } else {
  2951. fail("Find failed for (" + key + ", " + location + ")");
  2952. }
  2953. scan.close();
  2954. line = reader.readLine();
  2955. }
  2956. } finally {
  2957. trx.abort();
  2958. }
  2959. } finally {
  2960. reader.close();
  2961. db.shutdown();
  2962. }
  2963. }
  2964. /**
  2965. * Scans the tree from a starting key to the eof. Verifies that the keys are
  2966. * in sorted order.
  2967. */
  2968. int doDumpTree(String filename) throws Exception {
  2969. // BufferedWriter writer = new BufferedWriter(new FileWriter(
  2970. // filename));
  2971. final BTreeDB db = new BTreeDB(platform, false);
  2972. int count = 0;
  2973. try {
  2974. IndexContainer index = db.btreeMgr.getIndex(1);
  2975. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  2976. .getSingleton(TYPE_STRINGKEYFACTORY);
  2977. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  2978. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  2979. Transaction trx = db.trxmgr.begin(IsolationMode.READ_COMMITTED);
  2980. try {
  2981. IndexKey key = keyFactory.parseIndexKey(1, " ");
  2982. RowLocation location = (RowLocation) locationFactory
  2983. .newLocation();
  2984. location.loc = 1;
  2985. IndexScan scan = index.openScan(trx, key, location, false);
  2986. String prevKey = null;
  2987. try {
  2988. while (scan.fetchNext()) {
  2989. if (scan.isEof()) {
  2990. break;
  2991. }
  2992. count++;
  2993. // writer.write(scan.getCurrentKey() + ","
  2994. // + scan.getCurrentLocation() + "\n");
  2995. if (prevKey != null
  2996. && !scan.getCurrentKey().toString().equals(
  2997. StringKey.MAX_KEY)) {
  2998. assertTrue(scan.getCurrentKey().toString()
  2999. .compareTo(prevKey) > 0);
  3000. }
  3001. prevKey = scan.getCurrentKey().toString();
  3002. scan.fetchCompleted(true);
  3003. }
  3004. } finally {
  3005. scan.close();
  3006. }
  3007. } finally {
  3008. trx.abort();
  3009. }
  3010. } finally {
  3011. // writer.close();
  3012. db.shutdown();
  3013. }
  3014. System.out.println("Number of keys found = " + count);
  3015. return count;
  3016. }
  3017. void doIsolationTest_ReadCommitted() throws Exception {
  3018. final BTreeDB db = new BTreeDB(platform, false);
  3019. try {
  3020. int containerId = 1;
  3021. IndexContainer index = db.btreeMgr.getIndex(containerId);
  3022. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  3023. .getSingleton(TYPE_STRINGKEYFACTORY);
  3024. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  3025. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  3026. /*
  3027. * Scan the tree with lock isolation mode of READ_COMMITTED and
  3028. * verify locks.
  3029. */
  3030. Transaction trx = db.trxmgr.begin(IsolationMode.READ_COMMITTED);
  3031. try {
  3032. IndexKey key = keyFactory.parseIndexKey(containerId, " ");
  3033. RowLocation location = (RowLocation) locationFactory
  3034. .newLocation();
  3035. location.loc = 1;
  3036. IndexScan scan = index.openScan(trx, key, location, false);
  3037. Location prevLocation = null;
  3038. try {
  3039. int i = 0;
  3040. while (scan.fetchNext()) {
  3041. if (scan.isEof()) {
  3042. break;
  3043. }
  3044. assertEquals(LockMode.SHARED, trx.hasLock(scan
  3045. .getCurrentLocation()));
  3046. if (prevLocation != null) {
  3047. assertEquals(LockMode.NONE, trx
  3048. .hasLock(prevLocation));
  3049. }
  3050. prevLocation = scan.getCurrentLocation();
  3051. scan.fetchCompleted(true);
  3052. // assertEquals(LockMode.NONE, trx.hasLock(prevLocation));
  3053. i++;
  3054. if (i == 10)
  3055. break;
  3056. }
  3057. } finally {
  3058. scan.close();
  3059. }
  3060. int count = ((TransactionManagerImpl.TransactionImpl) trx)
  3061. .countLocks();
  3062. assertEquals(0, count);
  3063. } finally {
  3064. trx.abort();
  3065. }
  3066. } finally {
  3067. db.shutdown();
  3068. }
  3069. }
  3070. void doIsolationTest_CursorStability() throws Exception {
  3071. final BTreeDB db = new BTreeDB(platform, false);
  3072. try {
  3073. int containerId = 1;
  3074. IndexContainer index = db.btreeMgr.getIndex(containerId);
  3075. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  3076. .getSingleton(TYPE_STRINGKEYFACTORY);
  3077. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  3078. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  3079. /*
  3080. * Scan the tree with lock isolation mode of CURSOR_STABILITY and
  3081. * verify locks.
  3082. */
  3083. Transaction trx = db.trxmgr.begin(IsolationMode.CURSOR_STABILITY);
  3084. try {
  3085. IndexKey key = keyFactory.parseIndexKey(containerId, " ");
  3086. RowLocation location = (RowLocation) locationFactory
  3087. .newLocation();
  3088. location.loc = 1;
  3089. IndexScan scan = index.openScan(trx, key, location, false);
  3090. Location prevLocation = null;
  3091. try {
  3092. int i = 0;
  3093. while (scan.fetchNext()) {
  3094. if (scan.isEof()) {
  3095. break;
  3096. }
  3097. assertEquals(LockMode.SHARED, trx.hasLock(scan
  3098. .getCurrentLocation()));
  3099. if (prevLocation != null) {
  3100. assertEquals(LockMode.NONE, trx
  3101. .hasLock(prevLocation));
  3102. }
  3103. prevLocation = scan.getCurrentLocation();
  3104. scan.fetchCompleted(true);
  3105. // assertEquals(LockMode.SHARED, trx.hasLock(prevLocation));
  3106. i++;
  3107. if (i == 10)
  3108. break;
  3109. }
  3110. } finally {
  3111. scan.close();
  3112. }
  3113. int count = ((TransactionManagerImpl.TransactionImpl) trx)
  3114. .countLocks();
  3115. assertEquals(0, count);
  3116. } finally {
  3117. trx.abort();
  3118. }
  3119. } finally {
  3120. db.shutdown();
  3121. }
  3122. }
  3123. void doIsolationTest_RepeatableRead(boolean updateMode) throws Exception {
  3124. final BTreeDB db = new BTreeDB(platform, false);
  3125. try {
  3126. int containerId = 1;
  3127. IndexContainer index = db.btreeMgr.getIndex(containerId);
  3128. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  3129. .getSingleton(TYPE_STRINGKEYFACTORY);
  3130. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  3131. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  3132. /*
  3133. * Scan the tree with lock isolation mode of CURSOR_STABILITY and
  3134. * verify locks.
  3135. */
  3136. Transaction trx = db.trxmgr.begin(IsolationMode.REPEATABLE_READ);
  3137. try {
  3138. IndexKey key = keyFactory.parseIndexKey(containerId, " ");
  3139. RowLocation location = (RowLocation) locationFactory
  3140. .newLocation();
  3141. location.loc = 1;
  3142. IndexScan scan = index.openScan(trx, key, location, updateMode);
  3143. Location prevLocation = null;
  3144. try {
  3145. int i = 0;
  3146. LockMode mode = LockMode.SHARED;
  3147. if (updateMode) {
  3148. mode = LockMode.UPDATE;
  3149. }
  3150. while (scan.fetchNext()) {
  3151. if (scan.isEof()) {
  3152. break;
  3153. }
  3154. assertEquals(mode, trx.hasLock(scan
  3155. .getCurrentLocation()));
  3156. if (prevLocation != null) {
  3157. assertEquals(LockMode.SHARED, trx
  3158. .hasLock(prevLocation));
  3159. }
  3160. prevLocation = scan.getCurrentLocation();
  3161. scan.fetchCompleted(true);
  3162. // assertEquals(mode, trx.hasLock(prevLocation));
  3163. i++;
  3164. if (i == 10)
  3165. break;
  3166. }
  3167. } finally {
  3168. scan.close();
  3169. int count = ((TransactionManagerImpl.TransactionImpl) trx)
  3170. .countLocks();
  3171. assertEquals(10, count);
  3172. }
  3173. } finally {
  3174. trx.abort();
  3175. }
  3176. } finally {
  3177. db.shutdown();
  3178. }
  3179. }
  3180. /**
  3181. * Search for a specific key and return true if found.
  3182. */
  3183. boolean doFindKeyLockTest(IsolationMode isolationMode, String k, int loc,
  3184. boolean forUpdate) throws Exception {
  3185. final BTreeDB db = new BTreeDB(platform, false);
  3186. try {
  3187. BTreeImpl btree = (BTreeImpl) db.btreeMgr.getIndex(1);
  3188. IndexKey key = btree.indexItemFactory.getNewIndexKey(1, k);
  3189. RowLocation location = (RowLocation) btree.indexItemFactory
  3190. .getNewLocation();
  3191. location.loc = loc;
  3192. /*
  3193. * Searches for a specified key and verifies lock mode in found and
  3194. * not found situations.
  3195. */
  3196. Location currentLocation = null;
  3197. Transaction trx = db.trxmgr.begin(isolationMode);
  3198. boolean found = false;
  3199. int eof = 0;
  3200. try {
  3201. IndexScan scan = btree.openScan(trx, key, location, forUpdate);
  3202. try {
  3203. if (scan.fetchNext()) {
  3204. currentLocation = scan.getCurrentLocation();
  3205. if (key.toString().equals(
  3206. scan.getCurrentKey().toString())
  3207. && location.equals(scan.getCurrentLocation())) {
  3208. // found
  3209. if (forUpdate) {
  3210. assertEquals(LockMode.UPDATE, trx.hasLock(scan
  3211. .getCurrentLocation()));
  3212. } else {
  3213. assertEquals(LockMode.SHARED, trx.hasLock(scan
  3214. .getCurrentLocation()));
  3215. }
  3216. found = true;
  3217. } else {
  3218. // not found - but IndexScan has no concept of not
  3219. // found
  3220. // so lock should be held on next key - lock is
  3221. // released if necessary when the next row
  3222. // is fetched or the scan is closed
  3223. if (forUpdate) {
  3224. assertEquals(LockMode.UPDATE, trx.hasLock(scan
  3225. .getCurrentLocation()));
  3226. } else {
  3227. assertEquals(LockMode.SHARED, trx.hasLock(scan
  3228. .getCurrentLocation()));
  3229. }
  3230. }
  3231. // do another fetch to release the lock on current key
  3232. scan.fetchNext();
  3233. // System.err.println("FOUND = " + found);
  3234. // System.err.println("KEY = " +
  3235. // scan.getCurrentKey().toString());
  3236. // System.err.println("LOCATION = " +
  3237. // scan.getCurrentLocation().toString());
  3238. scan.fetchCompleted(found);
  3239. if (trx.getIsolationMode() == IsolationMode.READ_COMMITTED
  3240. || trx.getIsolationMode() == IsolationMode.CURSOR_STABILITY) {
  3241. /*
  3242. * Regardless of fetch result, lock on previous key
  3243. * should have been released after fetchNext().
  3244. */
  3245. assertEquals(LockMode.NONE, trx
  3246. .hasLock(currentLocation));
  3247. } else if (trx.getIsolationMode() == IsolationMode.REPEATABLE_READ) {
  3248. /*
  3249. * Lock on previous key should be held
  3250. */
  3251. assertEquals(LockMode.SHARED, trx
  3252. .hasLock(currentLocation));
  3253. } else if (trx.getIsolationMode() == IsolationMode.SERIALIZABLE) {
  3254. /*
  3255. * Lock on previous key should have been downgraded
  3256. */
  3257. assertEquals(LockMode.SHARED, trx
  3258. .hasLock(currentLocation));
  3259. }
  3260. return found;
  3261. } else {
  3262. assertTrue(scan.isEof());
  3263. // System.err.println("EOF");
  3264. // System.err.println("KEY = " +
  3265. // scan.getCurrentKey().toString());
  3266. // System.err.println("LOCATION = " +
  3267. // scan.getCurrentLocation().toString());
  3268. eof = 1;
  3269. return false;
  3270. }
  3271. } finally {
  3272. if (scan != null) {
  3273. scan.close();
  3274. if (isolationMode == IsolationMode.SERIALIZABLE) {
  3275. // if we did not hit eof, 2 rows would be left locked
  3276. // even if we did hit eof, at least the eof row will be left locked.
  3277. int count = ((TransactionManagerImpl.TransactionImpl) trx)
  3278. .countLocks();
  3279. assertEquals(2 - eof, count);
  3280. } else if (isolationMode == IsolationMode.REPEATABLE_READ) {
  3281. int count = ((TransactionManagerImpl.TransactionImpl) trx)
  3282. .countLocks();
  3283. // if we did not hit EOF, we should have 2 rows locked
  3284. // if we did hit EOF, none of the rows would be left locked
  3285. assertEquals(2 - (eof == 1 ? 2 : 0), count);
  3286. } else {
  3287. // in read committed or cursor stability mode,
  3288. // none of the rows will be left locked
  3289. int count = ((TransactionManagerImpl.TransactionImpl) trx)
  3290. .countLocks();
  3291. assertEquals(0, count);
  3292. }
  3293. }
  3294. }
  3295. } finally {
  3296. trx.abort();
  3297. }
  3298. } finally {
  3299. db.shutdown();
  3300. }
  3301. }
  3302. void doTestMultiThreadedInserts(String file1, String file2)
  3303. throws Exception {
  3304. compressKeys = true;
  3305. largeBM = true;
  3306. doInitContainer2();
  3307. System.out.println("Starting inserts");
  3308. doConcurrentInserts(file1, file2);
  3309. System.out.println("Dumping tree");
  3310. doDumpTree("testdata/TestBTreeManager/dump.txt");
  3311. // doFindRubens();
  3312. System.out.println("Doing first set of finds");
  3313. doFindInTree2(file1);
  3314. System.out.println("Doing second set of finds");
  3315. doFindInTree2(file2);
  3316. System.out.println("Starting deletes");
  3317. doConcurrentDeletes(file1, file2);
  3318. System.out.println("Dumping tree again");
  3319. doDumpTree("testdata/TestBTreeManager/dump2.txt");
  3320. System.out.println("Validating second set of finds");
  3321. doFindInTree2(file2);
  3322. compressKeys = false;
  3323. largeBM = false;
  3324. }
  3325. /**
  3326. * Reproduce Issue-26 - the calculation of free space is wrong when the key
  3327. * is of leaf type and the node is an index node.
  3328. */
  3329. public void testCanAccomodate() {
  3330. compressKeys = true;
  3331. Properties p = new Properties();
  3332. p.setProperty("logging.properties.file",
  3333. "classpath:simpledbm.logging.properties");
  3334. p.setProperty("logging.properties.type", "log4j");
  3335. // final Platform platform = new PlatformImpl(p);
  3336. final PlatformObjects po = platform
  3337. .getPlatformObjects(IndexManager.LOGGER_NAME);
  3338. final ObjectRegistry objectFactory = new ObjectRegistryImpl(platform, p);
  3339. final StorageManager storageManager = new StorageManagerImpl(platform,
  3340. p);
  3341. final LatchFactory latchFactory = new LatchFactoryImpl(platform, p);
  3342. final PageManager pageFactory = new PageManagerImpl(platform,
  3343. objectFactory, storageManager, latchFactory, p);
  3344. final SlottedPageManager spmgr = new SlottedPageManagerImpl(platform,
  3345. objectFactory, pageFactory, p);
  3346. objectFactory.registerSingleton(TYPE_STRINGKEYFACTORY,
  3347. new StringKeyFactory());
  3348. objectFactory.registerSingleton(TYPE_ROWLOCATIONFACTORY,
  3349. new RowLocationFactory());
  3350. BTreeIndexManagerImpl.IndexItemFactory indexHelper = new BTreeIndexManagerImpl.IndexItemFactory(
  3351. new StringKeyFactory(), new RowLocationFactory(), false);
  3352. SlottedPageImpl page = (SlottedPageImpl) pageFactory.getInstance(spmgr
  3353. .getPageType(), new PageId());
  3354. page.latchExclusive();
  3355. BTreeIndexManagerImpl.BTreeNode.formatPage(page, TYPE_STRINGKEYFACTORY,
  3356. TYPE_ROWLOCATIONFACTORY, false, indexHelper.isUnique(), 0);
  3357. BTreeNode node = new BTreeNode(po, indexHelper, page);
  3358. for (int i = 1; i < 145; i++) {
  3359. node.insert(i, generateKey(indexHelper,
  3360. "SimpleDBM needs to be totally bug free" + i, i, i, false));
  3361. }
  3362. // System.out.println(page);
  3363. IndexItem key = generateKey(indexHelper, "012345678901234", 0, 0, true);
  3364. int len = key.getStoredLength();
  3365. // System.out.println("key requires " + len + " bytes");
  3366. // it may seem we have space
  3367. assertTrue(page.getFreeSpace() - page.getSlotOverhead() > len);
  3368. // but we cannot because no space for child pointer
  3369. assertFalse(node.canAccomodate(key));
  3370. page.unlatchExclusive();
  3371. compressKeys = false;
  3372. }
  3373. /**
  3374. * Test search operations within a node
  3375. */
  3376. public void testNodeSearch() {
  3377. compressKeys = true;
  3378. Properties p = new Properties();
  3379. p.setProperty("logging.properties.file",
  3380. "classpath:simpledbm.logging.properties");
  3381. p.setProperty("logging.properties.type", "log4j");
  3382. // final Platform platform = new PlatformImpl(p);
  3383. final PlatformObjects po = platform
  3384. .getPlatformObjects(IndexManager.LOGGER_NAME);
  3385. final ObjectRegistry objectFactory = new ObjectRegistryImpl(platform, p);
  3386. final StorageManager storageManager = new StorageManagerImpl(platform,
  3387. p);
  3388. final LatchFactory latchFactory = new LatchFactoryImpl(platform, p);
  3389. final PageManager pageFactory = new PageManagerImpl(platform,
  3390. objectFactory, storageManager, latchFactory, p);
  3391. final SlottedPageManager spmgr = new SlottedPageManagerImpl(platform,
  3392. objectFactory, pageFactory, p);
  3393. objectFactory.registerSingleton(TYPE_STRINGKEYFACTORY,
  3394. new StringKeyFactory());
  3395. objectFactory.registerSingleton(TYPE_ROWLOCATIONFACTORY,
  3396. new RowLocationFactory());
  3397. BTreeIndexManagerImpl.IndexItemFactory indexHelper = new BTreeIndexManagerImpl.IndexItemFactory(
  3398. new StringKeyFactory(), new RowLocationFactory(), false);
  3399. SlottedPageImpl page = (SlottedPageImpl) pageFactory.getInstance(spmgr
  3400. .getPageType(), new PageId());
  3401. page.latchExclusive();
  3402. BTreeIndexManagerImpl.BTreeNode.formatPage(page, TYPE_STRINGKEYFACTORY,
  3403. TYPE_ROWLOCATIONFACTORY, false, indexHelper.isUnique(), 0);
  3404. BTreeNode node = new BTreeNode(po, indexHelper, page);
  3405. for (int i = 1; i < 145; i++) {
  3406. node.insert(i, generateKey(indexHelper,
  3407. "SimpleDBM needs to be totally bug free" + i, i, i, false));
  3408. }
  3409. node.header.keyCount = 144;
  3410. node.updateHeader();
  3411. // System.out.println(page);
  3412. IndexItem key = generateKey(indexHelper, "012345678901234", 0, 0, true);
  3413. SearchResult sr = node.search(key);
  3414. assertEquals(1, sr.k);
  3415. key = generateKey(indexHelper, "ZZZZ", 0, 0, true);
  3416. sr = node.search(key);
  3417. assertEquals(SearchResult.KEY_OUT_OF_BOUNDS, sr.k);
  3418. page.unlatchExclusive();
  3419. compressKeys = false;
  3420. }
  3421. void doKeyInsert(boolean testUnique, boolean commit, String k, String loc)
  3422. throws Exception {
  3423. final BTreeDB db = new BTreeDB(platform, false);
  3424. try {
  3425. final BTreeImpl btree = db.btreeMgr.getBTreeImpl(1,
  3426. TYPE_STRINGKEYFACTORY, TYPE_ROWLOCATIONFACTORY, testUnique);
  3427. IndexKeyFactory keyFactory = (IndexKeyFactory) db.objectFactory
  3428. .getSingleton(TYPE_STRINGKEYFACTORY);
  3429. LocationFactory locationFactory = (LocationFactory) db.objectFactory
  3430. .getSingleton(TYPE_ROWLOCATIONFACTORY);
  3431. IndexKey key = keyFactory.parseIndexKey(1, k);
  3432. Location location = locationFactory.newLocation(loc);
  3433. Transaction trx = db.trxmgr.begin(IsolationMode.SERIALIZABLE);
  3434. boolean okay = false;
  3435. try {
  3436. // System.out.println("--> INSERTING KEY");
  3437. btree.insert(trx, key, location);
  3438. okay = true;
  3439. } finally {
  3440. if (okay && commit) {
  3441. // System.out.println("--> COMMITTING INSERT");
  3442. trx.commit();
  3443. } else {
  3444. // System.out.println("--> ABORTING INSERT");
  3445. trx.abort();
  3446. }
  3447. }
  3448. } finally {
  3449. db.shutdown();
  3450. }
  3451. }
  3452. public void testUniqueConstraintViolation() throws Exception {
  3453. doInitContainer2();
  3454. doLoadData("org/simpledbm/rss/impl/im/btree/data1.txt");
  3455. try {
  3456. doKeyInsert(true, true, "ai", "10");
  3457. fail("Unique constraint failed to work");
  3458. } catch (UniqueConstraintViolationException e) {
  3459. // okay
  3460. e.printStackTrace();
  3461. }
  3462. }
  3463. /**
  3464. * Tests various concurrent activities.
  3465. *
  3466. * @throws Exception
  3467. */
  3468. public void testMultiThreadedInserts() throws Exception {
  3469. doTestMultiThreadedInserts("org/simpledbm/rss/impl/im/btree/english.0",
  3470. "org/simpledbm/rss/impl/im/btree/english.1");
  3471. }
  3472. public void testMultiThreadedInsertsRandom() throws Exception {
  3473. doTestMultiThreadedInserts("org/simpledbm/rss/impl/im/btree/random.0",
  3474. "org/simpledbm/rss/impl/im/btree/random.1");
  3475. }
  3476. public void testMultiThreadedInsertsDescending() throws Exception {
  3477. doTestMultiThreadedInserts("org/simpledbm/rss/impl/im/btree/reverse.0",
  3478. "org/simpledbm/rss/impl/im/btree/reverse.1");
  3479. }
  3480. public void testIsolation() throws Exception {
  3481. ScanResult[] inserts = new ScanResult[] { new ScanResult("a1", "10"),
  3482. new ScanResult("a2", "11"), new ScanResult("b1", "21"),
  3483. new ScanResult("b2", "22"), new ScanResult("b3", "23"),
  3484. new ScanResult("b4", "24"), new ScanResult("c1", "31"),
  3485. new ScanResult("c2", "32"), new ScanResult("d1", "41"),
  3486. new ScanResult("d2", "42"), new ScanResult("d3", "43"),
  3487. new ScanResult("d4", "44"), new ScanResult("e1", "51"),
  3488. new ScanResult("e2", "52"), new ScanResult("e3", "53"),
  3489. new ScanResult("e4", "54"), new ScanResult("f1", "61"),
  3490. new ScanResult("f2", "62"), new ScanResult("f3", "63"),
  3491. new ScanResult("f4", "64"), new ScanResult("g1", "71"),
  3492. new ScanResult("g2", "72"), new ScanResult("h1", "81"),
  3493. new ScanResult("h2", "82"), new ScanResult("h3", "83"),
  3494. new ScanResult("h4", "84"), new ScanResult("i1", "91"),
  3495. new ScanResult("i2", "92"), new ScanResult("j1", "101"),
  3496. new ScanResult("j2", "102"), new ScanResult("j3", "103"),
  3497. new ScanResult("j4", "104"), new ScanResult("k1", "111"),
  3498. new ScanResult("k2", "112") };
  3499. doInitContainer2();
  3500. doLoadData(inserts);
  3501. // next key locking and lock release test for various isolation modes
  3502. doIsolationTest_ReadCommitted();
  3503. doIsolationTest_CursorStability();
  3504. doIsolationTest_RepeatableRead(false);
  3505. doIsolationTest_RepeatableRead(true);
  3506. // not found scenario
  3507. doFindKeyLockTest(IsolationMode.READ_COMMITTED, "b13", 21, false);
  3508. doFindKeyLockTest(IsolationMode.READ_COMMITTED, "b13", 21, true);
  3509. doFindKeyLockTest(IsolationMode.CURSOR_STABILITY, "b13", 21, false);
  3510. doFindKeyLockTest(IsolationMode.CURSOR_STABILITY, "b13", 21, true);
  3511. doFindKeyLockTest(IsolationMode.REPEATABLE_READ, "b13", 21, false);
  3512. doFindKeyLockTest(IsolationMode.REPEATABLE_READ, "b13", 21, true);
  3513. doFindKeyLockTest(IsolationMode.SERIALIZABLE, "b13", 21, false);
  3514. doFindKeyLockTest(IsolationMode.SERIALIZABLE, "b13", 21, true);
  3515. // found scenario
  3516. doFindKeyLockTest(IsolationMode.READ_COMMITTED, "b1", 21, false);
  3517. doFindKeyLockTest(IsolationMode.READ_COMMITTED, "b1", 21, true);
  3518. doFindKeyLockTest(IsolationMode.CURSOR_STABILITY, "b1", 21, false);
  3519. doFindKeyLockTest(IsolationMode.CURSOR_STABILITY, "b1", 21, true);
  3520. doFindKeyLockTest(IsolationMode.REPEATABLE_READ, "b1", 21, false);
  3521. doFindKeyLockTest(IsolationMode.REPEATABLE_READ, "b1", 21, true);
  3522. doFindKeyLockTest(IsolationMode.SERIALIZABLE, "b1", 21, false);
  3523. doFindKeyLockTest(IsolationMode.SERIALIZABLE, "b1", 21, true);
  3524. // eof scenario
  3525. doFindKeyLockTest(IsolationMode.READ_COMMITTED, "zz", 21, false);
  3526. doFindKeyLockTest(IsolationMode.READ_COMMITTED, "zz", 21, true);
  3527. doFindKeyLockTest(IsolationMode.CURSOR_STABILITY, "zz", 21, false);
  3528. doFindKeyLockTest(IsolationMode.CURSOR_STABILITY, "zz", 21, true);
  3529. doFindKeyLockTest(IsolationMode.REPEATABLE_READ, "zz", 21, false);
  3530. doFindKeyLockTest(IsolationMode.REPEATABLE_READ, "zz", 21, true);
  3531. doFindKeyLockTest(IsolationMode.SERIALIZABLE, "zz", 21, false);
  3532. doFindKeyLockTest(IsolationMode.SERIALIZABLE, "zz", 21, true);
  3533. }
  3534. public static Test suite() {
  3535. TestSuite suite = new TestSuite();
  3536. suite.addTest(new TestBTreeManager("testPageSplitLeafUnique"));
  3537. suite.addTest(new TestBTreeManager("testPageSplitNonLeafUnique2"));
  3538. suite.addTest(new TestBTreeManager("testPageSplitLeafUnique2"));
  3539. suite.addTest(new TestBTreeManager("testRedistributeIssue28"));
  3540. suite.addTest(new TestBTreeManager("testSimpleInsertAbort"));
  3541. suite.addTest(new TestBTreeManager("testSimpleInsertCommit"));
  3542. suite.addTest(new TestBTreeManager("testInsertSplitRootAbort"));
  3543. suite.addTest(new TestBTreeManager("testInsertSplitRootCommit"));
  3544. suite.addTest(new TestBTreeManager("testInsertSplitRootAbortLogical"));
  3545. suite.addTest(new TestBTreeManager("testInsertUnderflowFig13"));
  3546. suite.addTest(new TestBTreeManager("testInsertUnderflowFig14"));
  3547. suite.addTest(new TestBTreeManager("testInsertUnderflowFig5"));
  3548. suite.addTest(new TestBTreeManager("testInsertUnderflowFig19"));
  3549. suite.addTest(new TestBTreeManager("testInsertUnderflowFig15"));
  3550. suite.addTest(new TestBTreeManager("testInsertNextKeyInNextPage"));
  3551. suite.addTest(new TestBTreeManager("testInsertUnderflowFig17"));
  3552. suite.addTest(new TestBTreeManager("testIssue71"));
  3553. suite.addTest(new TestBTreeManager("testIssue71_Insert"));
  3554. suite.addTest(new TestBTreeManager("testDelete1"));
  3555. suite.addTest(new TestBTreeManager("testDeleteInsert1"));
  3556. suite.addTest(new TestBTreeManager("testDeleteInsert2"));
  3557. suite.addTest(new TestBTreeManager("testScan1"));
  3558. suite.addTest(new TestBTreeManager("testScan2"));
  3559. suite.addTest(new TestBTreeManager("testScan3"));
  3560. suite.addTest(new TestBTreeManager("testScan4"));
  3561. suite.addTest(new TestBTreeManager("testCursorStateAfterRollback"));
  3562. suite.addTest(new TestBTreeManager("testScanDeleteCrash", true));
  3563. suite.addTest(new TestBTreeManager("testInsertInOrder"));
  3564. suite.addTest(new TestBTreeManager("testInsertInOrderFromFile"));
  3565. suite.addTest(new TestBTreeManager("testPhantomRecords1"));
  3566. suite.addTest(new TestBTreeManager("testPhantomRecords2"));
  3567. suite.addTest(new TestBTreeManager("testIsolation"));
  3568. suite.addTest(new TestBTreeManager("testMultiThreadedInserts"));
  3569. suite.addTest(new TestBTreeManager("testMultiThreadedInsertsRandom"));
  3570. suite
  3571. .addTest(new TestBTreeManager(
  3572. "testMultiThreadedInsertsDescending"));
  3573. suite.addTest(new TestBTreeManager("testCanAccomodate"));
  3574. suite.addTest(new TestBTreeManager("testUniqueConstraintViolation"));
  3575. return suite;
  3576. }
  3577. public static class BTreeDB {
  3578. final Platform platform;
  3579. final LogFactoryImpl logFactory;
  3580. final ObjectRegistry objectFactory;
  3581. final StorageContainerFactory storageFactory;
  3582. final StorageManager storageManager;
  3583. final LatchFactory latchFactory;
  3584. final PageManager pageFactory;
  3585. final SlottedPageManager spmgr;
  3586. final LockMgrFactory lockmgrFactory;
  3587. final LockManagerImpl lockmgr;
  3588. final LogManagerImpl logmgr;
  3589. final BufferManagerImpl bufmgr;
  3590. final LoggableFactory loggableFactory;
  3591. final TransactionalModuleRegistry moduleRegistry;
  3592. final TransactionManagerImpl trxmgr;
  3593. final FreeSpaceManager spacemgr;
  3594. final BTreeIndexManagerImpl btreeMgr;
  3595. final TraceBuffer tracer;
  3596. public BTreeDB(Platform platform, boolean create) throws Exception {
  3597. Properties properties = new Properties();
  3598. properties.setProperty("log.ctl.1", "ctl.a");
  3599. properties.setProperty("log.ctl.2", "ctl.b");
  3600. properties.setProperty("log.groups.1.path", ".");
  3601. properties.setProperty("log.archive.path", ".");
  3602. properties.setProperty("log.group.files", "3");
  3603. if (largeBM) {
  3604. properties.setProperty("log.file.size", "5242880");
  3605. properties.setProperty("log.buffer.size", "5242880");
  3606. properties.setProperty("log.buffer.limit", "4");
  3607. properties.setProperty("log.flush.interval", "30");
  3608. properties.setProperty("log.disableFlushRequests", "true");
  3609. properties.setProperty("bufferpool.numbuffers", "350");
  3610. properties.setProperty("bufferpool.writerSleepInterval",
  3611. "60000");
  3612. properties.setProperty("transaction.ckpt.interval", "60000");
  3613. // properties.setProperty("storage.flushMode", "noforce");
  3614. } else {
  3615. properties.setProperty("log.file.size", "16384");
  3616. properties.setProperty("log.buffer.size", "16384");
  3617. properties.setProperty("log.buffer.limit", "4");
  3618. properties.setProperty("log.flush.interval", "5");
  3619. properties.setProperty("bufferpool.numbuffers", "20");
  3620. }
  3621. properties.setProperty("logging.properties.file",
  3622. "classpath:simpledbm.logging.properties");
  3623. properties.setProperty("logging.properties.type", "log4j");
  3624. properties.setProperty("storage.basePath",
  3625. "testdata/TestBTreeManager");
  3626. // platform = new PlatformImpl(properties);
  3627. this.platform = platform;
  3628. tracer = platform.getTraceBuffer();
  3629. LockAdaptor lockAdaptor = new DefaultLockAdaptor(platform,
  3630. properties);
  3631. logFactory = new LogFactoryImpl(platform, properties);
  3632. objectFactory = new ObjectRegistryImpl(platform, properties);
  3633. storageFactory = new FileStorageContainerFactory(platform,
  3634. properties);
  3635. if (create) {
  3636. logFactory.createLog(storageFactory, properties);
  3637. }
  3638. storageManager = new StorageManagerImpl(platform, properties);
  3639. latchFactory = new LatchFactoryImpl(platform, properties);
  3640. pageFactory = new PageManagerImpl(platform, objectFactory,
  3641. storageManager, latchFactory, properties);
  3642. spmgr = new SlottedPageManagerImpl(platform, objectFactory,
  3643. pageFactory, properties);
  3644. lockmgrFactory = new LockManagerFactoryImpl(platform, properties);
  3645. lockmgr = (LockManagerImpl) lockmgrFactory.create(latchFactory,
  3646. properties);
  3647. logmgr = (LogManagerImpl) logFactory.getLog(storageFactory,
  3648. properties);
  3649. bufmgr = new BufferManagerImpl(platform, logmgr, pageFactory,
  3650. properties);
  3651. loggableFactory = new LoggableFactoryImpl(platform, objectFactory,
  3652. properties);
  3653. moduleRegistry = new TransactionalModuleRegistryImpl(platform,
  3654. properties);
  3655. trxmgr = new TransactionManagerImpl(platform, logmgr,
  3656. storageFactory, storageManager, bufmgr, lockmgr,
  3657. loggableFactory, latchFactory, objectFactory,
  3658. moduleRegistry, properties);
  3659. spacemgr = new FreeSpaceManagerImpl(platform, objectFactory,
  3660. pageFactory, logmgr, bufmgr, storageManager,
  3661. storageFactory, loggableFactory, trxmgr, moduleRegistry,
  3662. properties);
  3663. btreeMgr = new BTreeIndexManagerImpl(platform, objectFactory,
  3664. loggableFactory, spacemgr, bufmgr, spmgr, moduleRegistry,
  3665. lockAdaptor, properties);
  3666. objectFactory.registerSingleton(TYPE_STRINGKEYFACTORY,
  3667. new StringKeyFactory());
  3668. objectFactory.registerSingleton(TYPE_ROWLOCATIONFACTORY,
  3669. new RowLocationFactory());
  3670. lockmgr.start();
  3671. logmgr.start();
  3672. bufmgr.start();
  3673. if (create) {
  3674. StorageContainer sc = storageFactory.create("dual");
  3675. storageManager.register(0, sc);
  3676. Page page = pageFactory.getInstance(pageFactory
  3677. .getRawPageType(), new PageId(0, 0));
  3678. pageFactory.store(page);
  3679. }
  3680. trxmgr.start();
  3681. }
  3682. public void shutdown() {
  3683. // Trace.dump();
  3684. trxmgr.shutdown();
  3685. bufmgr.shutdown();
  3686. logmgr.shutdown();
  3687. storageManager.shutdown();
  3688. lockmgr.shutdown();
  3689. }
  3690. }
  3691. }
  3692. /*
  3693. * Write following tests:
  3694. *
  3695. * 1) Thread 1 inserts a row. Thread 2 locks the row exclusively. Thread 3
  3696. * inserts the same key as thread 1 and blocks. Thread 2 deletes the row and
  3697. * commits. Verify that thread 3 proceeds with the insert and completes
  3698. * successfully.
  3699. *
  3700. * 2) Thread 1 inserts a row. Thread 2 locks row exclusively. Thread 3 inserts
  3701. * same key as thread 1 and blocks. Thread 2 deletes key with old row, and
  3702. * inserts same key with new row and commits. Verify that thread 3 releases lock
  3703. * on old row and restarts insert. It should fail if index in unique.
  3704. *
  3705. * 3) Insert an exsting key and verify that shared lock is held in case of RR or
  3706. * CZ, but released in case of CS or RC.
  3707. *
  3708. * 4) Start an index scan and position to a row. Create a savepoint. Scan a few
  3709. * more rows. Rollback to savepoint. Test that the cursor is back on the same
  3710. * row before the savepoint. Test that the cursor has reacquired lock in case of
  3711. * CS. Test the situation where row has been deleted in the meantime. Cursor
  3712. * should be positioned on next higher key which should be locked in case of CS.
  3713. *
  3714. * 5) Run multithreaded test with random inserts/deletes. 6) Run multithreaded
  3715. * test with reverse order inserts/deletes.
  3716. */