Advertisement
Guest User

Untitled

a guest
Nov 16th, 2019
1,085
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 30.08 KB | None | 0 0
  1. package edu.berkeley.cs186.database;
  2.  
  3. import java.io.File;
  4. import java.nio.file.Path;
  5. import java.nio.file.Paths;
  6. import java.util.*;
  7. import java.util.concurrent.ConcurrentHashMap;
  8. import java.util.concurrent.locks.Condition;
  9. import java.util.concurrent.locks.ReentrantLock;
  10.  
  11. import edu.berkeley.cs186.database.common.BacktrackingIterator;
  12. import edu.berkeley.cs186.database.common.Pair;
  13. import edu.berkeley.cs186.database.concurrency.*;
  14. import edu.berkeley.cs186.database.databox.DataBox;
  15. import edu.berkeley.cs186.database.databox.Type;
  16. import edu.berkeley.cs186.database.index.BPlusTree;
  17. import edu.berkeley.cs186.database.index.BPlusTreeException;
  18. import edu.berkeley.cs186.database.io.Page;
  19. import edu.berkeley.cs186.database.query.QueryPlan;
  20. import edu.berkeley.cs186.database.query.QueryPlanException;
  21. import edu.berkeley.cs186.database.query.SortOperator;
  22. import edu.berkeley.cs186.database.table.Record;
  23. import edu.berkeley.cs186.database.table.RecordId;
  24. import edu.berkeley.cs186.database.table.RecordIterator;
  25. import edu.berkeley.cs186.database.table.Schema;
  26. import edu.berkeley.cs186.database.table.Table;
  27. import edu.berkeley.cs186.database.table.stats.TableStats;
  28. import edu.berkeley.cs186.database.io.PageAllocator.PageIterator;
  29.  
  30. public class Database {
  31. private Map<String, Table> tableLookup;
  32. private Map<String, BPlusTree> indexLookup;
  33. private Map<String, List<String>> tableIndices;
  34. private Map<Long, Transaction> activeTransactions;
  35. private long numTransactions;
  36. private String fileDir;
  37. private LockManager lockManager;
  38. private int numMemoryPages;
  39.  
  40. /**
  41. * Creates a new database with locking disabled.
  42. *
  43. * @param fileDir the directory to put the table files in
  44. * @throws DatabaseException
  45. */
  46. public Database(String fileDir) throws DatabaseException {
  47. this (fileDir, 5);
  48. }
  49.  
  50. /**
  51. * Creates a new database with locking disabled.
  52. *
  53. * @param fileDir the directory to put the table files in
  54. * @param numMemoryPages the number of pages of memory Database Operations should use when executing Queries
  55. * @throws DatabaseException
  56. */
  57. public Database(String fileDir, int numMemoryPages) throws DatabaseException {
  58. this(fileDir, numMemoryPages, new DummyLockManager());
  59. }
  60.  
  61. /**
  62. * Creates a new database.
  63. *
  64. * @param fileDir the directory to put the table files in
  65. * @param numMemoryPages the number of pages of memory Database Operations should use when executing Queries
  66. * @param lockManager the lock manager
  67. * @throws DatabaseException
  68. */
  69. public Database(String fileDir, int numMemoryPages, LockManager lockManager)
  70. throws DatabaseException {
  71. this.numMemoryPages = numMemoryPages;
  72. this.fileDir = fileDir;
  73. numTransactions = 0;
  74. tableLookup = new ConcurrentHashMap<>();
  75. indexLookup = new ConcurrentHashMap<>();
  76. tableIndices = new ConcurrentHashMap<>();
  77. activeTransactions = new ConcurrentHashMap<>();
  78.  
  79. File dir = new File(fileDir);
  80. this.lockManager = lockManager;
  81.  
  82. if (!dir.exists()) {
  83. dir.mkdirs();
  84. }
  85.  
  86. File[] files = dir.listFiles();
  87.  
  88. try (Transaction initTransaction = new Transaction(-1)) {
  89. LockContext lockContext = lockManager.databaseContext();
  90. lockContext.acquire(initTransaction, LockType.X);
  91. for (File f : files) {
  92. String fName = f.getName();
  93. if (fName.endsWith(Table.FILENAME_EXTENSION)) {
  94. int lastIndex = fName.lastIndexOf(Table.FILENAME_EXTENSION);
  95. String tableName = fName.substring(0, lastIndex);
  96. tableLookup.put(tableName, newTable(tableName, f.toPath().toString(),
  97. lockContext.childContext("table-" + tableName), initTransaction));
  98. if (!tableIndices.containsKey(tableName)) {
  99. tableIndices.put(tableName, new ArrayList<>());
  100. }
  101. } else if (fName.endsWith(BPlusTree.FILENAME_EXTENSION)) {
  102. int lastIndex = fName.lastIndexOf(BPlusTree.FILENAME_EXTENSION);
  103. String indexName = fName.substring(0, lastIndex);
  104. String tableName = indexName.split(",", 2)[0];
  105. indexLookup.put(indexName, new BPlusTree(f.toString(), getIndexContext(indexName),
  106. initTransaction));
  107. if (!tableIndices.containsKey(tableName)) {
  108. tableIndices.put(tableName, new ArrayList<>());
  109. }
  110. tableIndices.get(tableName).add(indexName);
  111. }
  112. }
  113. }
  114. }
  115.  
  116. /**
  117. * Close this database.
  118. */
  119. public synchronized void close() {
  120. try (Transaction closeTransaction = new Transaction(-2)) {
  121. lockManager.databaseContext().acquire(closeTransaction, LockType.X);
  122.  
  123. for (Table t : this.tableLookup.values()) {
  124. t.close();
  125. }
  126.  
  127. for (BPlusTree t : this.indexLookup.values()) {
  128. t.close();
  129. }
  130.  
  131. this.tableLookup.clear();
  132. this.indexLookup.clear();
  133. this.tableIndices.clear();
  134. }
  135. }
  136.  
  137. public Table getTable(String tableName) {
  138. return tableLookup.get(tableName);
  139. }
  140.  
  141. private LockContext getTableContext(String table) {
  142. return lockManager.databaseContext().childContext("table-" + table);
  143. }
  144.  
  145. private LockContext getIndexContext(String index) {
  146. return lockManager.databaseContext().childContext("index-" + index);
  147. }
  148.  
  149. /**
  150. * Start a new transaction.
  151. *
  152. * @return the new Transaction
  153. */
  154. public synchronized Transaction beginTransaction() {
  155. Transaction t = new Transaction(this.numTransactions);
  156. this.activeTransactions.put(this.numTransactions, t);
  157. this.numTransactions++;
  158. return t;
  159. }
  160.  
  161. /**
  162. * This transaction implementation assumes that exactly one transaction runs
  163. * on a thread at a time, and that, aside from the unblock() method, no methods
  164. * of the transaction are called from a different thread than the thread that the
  165. * transaction is associated with. This implementation blocks the thread when
  166. * block() is called.
  167. */
  168. public class Transaction extends BaseTransaction {
  169. long transNum;
  170. boolean active;
  171. boolean blocked;
  172. HashMap<String, Table> tempTables;
  173. HashMap<String, String> aliasMaps;
  174. long tempTableCounter;
  175.  
  176. final ReentrantLock transactionLock = new ReentrantLock();
  177. final Condition unblocked = transactionLock.newCondition();
  178.  
  179. protected Transaction(long tNum) {
  180. this.transNum = tNum;
  181. this.active = true;
  182. this.blocked = false;
  183. this.tempTables = new HashMap<String, Table>();
  184. this.aliasMaps = new HashMap<String, String>();
  185. this.tempTableCounter = 0;
  186. }
  187.  
  188. public long getTransNum() {
  189. return this.transNum;
  190. }
  191.  
  192. public boolean isActive() {
  193. return this.active;
  194. }
  195.  
  196. public void end() {
  197. assert(this.active);
  198.  
  199. List<Lock> locks = lockManager.getLocks(this);
  200. if (locks == null) {
  201. return;
  202. }
  203.  
  204. while (!locks.isEmpty()) {
  205. for (Lock lock1 : locks) {
  206. boolean comp = true;
  207. for (Lock lock2 : locks) {
  208. if (!lock1.equals(lock2) && lock2.name.isDescendantOf(lock1.name)) {
  209. comp = false;
  210. }
  211. }
  212. if (comp) {
  213. lockManager.release(this, lock1.name);
  214. locks.remove(lock1);
  215. break;
  216. }
  217. }
  218. }
  219. deleteAllTempTables();
  220. this.active = false;
  221. Database.this.activeTransactions.remove(this.transNum);
  222.  
  223. }
  224.  
  225.  
  226. /**
  227. * Create a new table in this database.
  228. *
  229. * @param s the table schema
  230. * @param tableName the name of the table
  231. * @throws DatabaseException
  232. */
  233. public void createTable(Schema s, String tableName) throws DatabaseException {
  234. // TODO(hw5_part2): add DDL locking
  235.  
  236. LockContext tableContext = getTableContext(tableName);
  237. LockUtil.ensureSufficientLockHeld(this, tableContext, LockType.X);
  238.  
  239. if (Database.this.tableLookup.containsKey(tableName)) {
  240. throw new DatabaseException("Table name already exists");
  241. }
  242.  
  243. Path path = Paths.get(fileDir, tableName + Table.FILENAME_EXTENSION);
  244. Database.this.tableLookup.put(tableName, newTable(tableName, s, path.toString(), tableContext,
  245. this));
  246. Database.this.tableIndices.put(tableName, new ArrayList<>());
  247. }
  248.  
  249. /**
  250. * Create a new table in this database with an index on each of the given column names.
  251. * @param s the table schema
  252. * @param tableName the name of the table
  253. * @param indexColumns the list of unique columnNames on the maintain an index on
  254. * @throws DatabaseException
  255. */
  256. public void createTableWithIndices(Schema s, String tableName,
  257. List<String> indexColumns) throws DatabaseException {
  258. // TODO(hw5_part2): add locking
  259.  
  260. LockContext tableContext = getTableContext(tableName);
  261. LockUtil.ensureSufficientLockHeld(this, tableContext, LockType.X);
  262.  
  263.  
  264. List<String> schemaColNames = s.getFieldNames();
  265. List<Type> schemaColType = s.getFieldTypes();
  266.  
  267. HashSet<String> seenColNames = new HashSet<String>();
  268. List<Integer> schemaColIndex = new ArrayList<Integer>();
  269. for (int i = 0; i < indexColumns.size(); i++) {
  270. String col = indexColumns.get(i);
  271. if (!schemaColNames.contains(col)) {
  272. throw new DatabaseException("Column desired for index does not exist");
  273. }
  274. if (seenColNames.contains(col)) {
  275. throw new DatabaseException("Column desired for index has been duplicated");
  276. }
  277. seenColNames.add(col);
  278. schemaColIndex.add(schemaColNames.indexOf(col));
  279. }
  280.  
  281. if (Database.this.tableLookup.containsKey(tableName)) {
  282. throw new DatabaseException("Table name already exists");
  283. }
  284.  
  285. Path path = Paths.get(fileDir, tableName + Table.FILENAME_EXTENSION);
  286. Database.this.tableLookup.put(tableName, newTable(tableName, s, path.toString(), tableContext,
  287. this));
  288. Database.this.tableIndices.put(tableName, new ArrayList<>());
  289. for (int i : schemaColIndex) {
  290. String colName = schemaColNames.get(i);
  291. Type colType = schemaColType.get(i);
  292. String indexName = tableName + "," + colName;
  293. Path p = Paths.get(Database.this.fileDir, indexName + BPlusTree.FILENAME_EXTENSION);
  294. LockContext indexContext = getIndexContext(indexName);
  295. try {
  296. Database.this.indexLookup.put(indexName, new BPlusTree(p.toString(), colType,
  297. BPlusTree.maxOrder(Page.pageSize, colType), indexContext, this));
  298. Database.this.tableIndices.get(tableName).add(indexName);
  299. } catch (BPlusTreeException e) {
  300. throw new DatabaseException(e.getMessage());
  301. }
  302. }
  303. }
  304.  
  305. /**
  306. * Delete a table in this database.
  307. *
  308. * @param tableName the name of the table
  309. * @return true if the database was successfully deleted
  310. */
  311. public boolean deleteTable(String tableName) {
  312. // TODO(hw5_part2): add locking
  313. LockContext tableContext = getTableContext(tableName);
  314. LockUtil.ensureSufficientLockHeld(this, tableContext, LockType.X);
  315.  
  316. if (!Database.this.tableLookup.containsKey(tableName)) {
  317. return false;
  318. }
  319.  
  320. Database.this.tableLookup.get(tableName).close();
  321. Database.this.tableLookup.remove(tableName);
  322.  
  323. File f = new File(fileDir + tableName + Table.FILENAME_EXTENSION);
  324. f.delete();
  325.  
  326. Iterator<String> indices = Database.this.tableIndices.get(tableName).iterator();
  327. while (indices.hasNext()) {
  328. String indexName = indices.next();
  329. indices.remove();
  330. Database.this.indexLookup.get(indexName).close();
  331. Database.this.indexLookup.remove(indexName);
  332.  
  333. File indexFile = new File(fileDir + indexName + BPlusTree.FILENAME_EXTENSION);
  334. indexFile.delete();
  335. }
  336. Database.this.tableIndices.remove(tableName);
  337.  
  338. return true;
  339. }
  340.  
  341. /**
  342. * Delete all tables from this database.
  343. */
  344. public void deleteAllTables() {
  345. // TODO(hw5_part2): add locking
  346. LockUtil.ensureSufficientLockHeld(this, lockManager.databaseContext(), LockType.X);
  347.  
  348. List<String> tableNames = new ArrayList<>(tableLookup.keySet());
  349.  
  350. for (String s : tableNames) {
  351. deleteTable(s);
  352. }
  353. }
  354.  
  355. public QueryPlan query(String tableName) throws DatabaseException {
  356. assert(this.active);
  357. return new QueryPlan(this, tableName);
  358. }
  359.  
  360. public void queryAs(String tableName, String alias) throws DatabaseException {
  361. assert(this.active);
  362.  
  363. if (Database.this.tableLookup.containsKey(alias)
  364. || this.tempTables.containsKey(alias)
  365. || this.aliasMaps.containsKey(alias)) {
  366. throw new DatabaseException("Table name already exists");
  367. }
  368.  
  369. if (Database.this.tableLookup.containsKey(tableName)) {
  370. this.aliasMaps.put(alias, tableName);
  371. } else if (tempTables.containsKey(tableName)) {
  372. this.aliasMaps.put(alias, tableName);
  373. } else {
  374. throw new DatabaseException("Table name not found");
  375. }
  376. }
  377.  
  378. public String createTempTable(Schema schema) throws DatabaseException {
  379. assert(this.active);
  380. String tempTableName = "tempTable" + tempTableCounter;
  381. tempTableCounter++;
  382. createTempTable(schema, tempTableName);
  383. return tempTableName;
  384. }
  385.  
  386. public void createTempTable(Schema schema, String tempTableName) throws DatabaseException {
  387. assert(this.active);
  388.  
  389. if (Database.this.tableLookup.containsKey(tempTableName)
  390. || this.tempTables.containsKey(tempTableName)) {
  391. throw new DatabaseException("Table name already exists");
  392. }
  393.  
  394. Path dir = Paths.get(Database.this.fileDir, "temp");
  395. File f = new File(dir.toAbsolutePath().toString());
  396. if (!f.exists()) {
  397. f.mkdirs();
  398. }
  399.  
  400. Path path = Paths.get(Database.this.fileDir, "temp", tempTableName + Table.FILENAME_EXTENSION);
  401. LockContext lockContext = lockManager.orphanContext("temp-" + tempTableName);
  402. // TODO(hw5_part2): more efficient locking on temporary tables
  403. lockContext.disableChildLocks();
  404. lockContext.acquire(this, LockType.X);
  405. this.tempTables.put(tempTableName, newTable(tempTableName, schema, path.toString(), lockContext,
  406. this));
  407. }
  408.  
  409. public boolean indexExists(String tableName, String columnName) {
  410. try {
  411. resolveIndexFromName(tableName, columnName);
  412. } catch (DatabaseException e) {
  413. return false;
  414. }
  415. return true;
  416. }
  417.  
  418. public Iterator<Record> sortedScan(String tableName, String columnName) throws DatabaseException {
  419. Table tab = getTable(tableName);
  420.  
  421. // TODO(hw5_part2): scan locking
  422. LockUtil.ensureSufficientLockHeld(this, getTableContext(tableName), LockType.S);
  423. try {
  424. Pair<String, BPlusTree> index = resolveIndexFromName(tableName, columnName);
  425. return new RecordIterator(this, tab, index.getSecond().scanAll(this));
  426. } catch (DatabaseException e1) {
  427. int offset = getTable(tableName).getSchema().getFieldNames().indexOf(columnName);
  428. try {
  429. return new SortOperator(this, tableName,
  430. Comparator.comparing((Record r) -> r.getValues().get(offset))).iterator();
  431. } catch (QueryPlanException e2) {
  432. throw new DatabaseException(e2);
  433. }
  434. }
  435. }
  436.  
  437. public Iterator<Record> sortedScanFrom(String tableName, String columnName,
  438. DataBox startValue) throws DatabaseException {
  439. Table tab = getTable(tableName);
  440. Pair<String, BPlusTree> index = resolveIndexFromName(tableName, columnName);
  441. // TODO(hw5_part2): scan locking
  442. LockUtil.ensureSufficientLockHeld(this, getTableContext(tableName), LockType.S);
  443. return new RecordIterator(this, tab, index.getSecond().scanGreaterEqual(this, startValue));
  444. }
  445.  
  446. public Iterator<Record> lookupKey(String tableName, String columnName,
  447. DataBox key) throws DatabaseException {
  448. Table tab = getTable(tableName);
  449. Pair<String, BPlusTree> index = resolveIndexFromName(tableName, columnName);
  450. return new RecordIterator(this, tab, index.getSecond().scanEqual(this, key));
  451. }
  452.  
  453. public boolean contains(String tableName, String columnName, DataBox key) throws DatabaseException {
  454. Pair<String, BPlusTree> index = resolveIndexFromName(tableName, columnName);
  455. return index.getSecond().get(this, key).isPresent();
  456. }
  457.  
  458. public RecordId addRecord(String tableName, List<DataBox> values) throws DatabaseException {
  459. assert(this.active);
  460.  
  461. Table tab = getTable(tableName);
  462. RecordId rid = tab.addRecord(this, values);
  463. Schema s = tab.getSchema();
  464. List<String> colNames = s.getFieldNames();
  465.  
  466. for (int i = 0; i < colNames.size(); i++) {
  467. String col = colNames.get(i);
  468. if (indexExists(tableName, col)) {
  469. try {
  470. resolveIndexFromName(tableName, col).getSecond().put(this, values.get(i), rid);
  471. } catch (BPlusTreeException e) {
  472. throw new DatabaseException(e.getMessage());
  473. }
  474. }
  475. }
  476. return rid;
  477. }
  478.  
  479. public int getNumMemoryPages() throws DatabaseException {
  480. assert(this.active);
  481. return Database.this.numMemoryPages;
  482. }
  483.  
  484. public RecordId deleteRecord(String tableName, RecordId rid) throws DatabaseException {
  485. assert(this.active);
  486.  
  487. Table tab = getTable(tableName);
  488. Schema s = tab.getSchema();
  489.  
  490. Record rec = tab.deleteRecord(this, rid);
  491. List<DataBox> values = rec.getValues();
  492. List<String> colNames = s.getFieldNames();
  493. for (int i = 0; i < colNames.size(); i++) {
  494. String col = colNames.get(i);
  495. if (indexExists(tableName, col)) {
  496. resolveIndexFromName(tableName, col).getSecond().remove(this, values.get(i));
  497. }
  498. }
  499.  
  500. return rid;
  501. }
  502.  
  503. public Record getRecord(String tableName, RecordId rid) throws DatabaseException {
  504. assert(this.active);
  505. return getTable(tableName).getRecord(this, rid);
  506. }
  507.  
  508. public RecordIterator getRecordIterator(String tableName) throws DatabaseException {
  509. assert(this.active);
  510. return getTable(tableName).iterator(this);
  511. }
  512.  
  513. public RecordId updateRecord(String tableName, List<DataBox> values,
  514. RecordId rid) throws DatabaseException {
  515. return runUpdateRecord(tableName, values, rid);
  516. }
  517.  
  518. public PageIterator getPageIterator(String tableName) throws DatabaseException {
  519. assert(this.active);
  520. return getTable(tableName).getAllocator().iterator(this);
  521. }
  522.  
  523. public BacktrackingIterator<Record> getBlockIterator(String tableName,
  524. Page[] block) throws DatabaseException {
  525. assert(this.active);
  526. return getTable(tableName).blockIterator(this, block);
  527. }
  528.  
  529. public BacktrackingIterator<Record> getBlockIterator(String tableName,
  530. BacktrackingIterator<Page> block) throws DatabaseException {
  531. assert(this.active);
  532. return getTable(tableName).blockIterator(this, block);
  533. }
  534.  
  535. public BacktrackingIterator<Record> getBlockIterator(String tableName, Iterator<Page> block,
  536. int maxPages) throws DatabaseException {
  537. assert(this.active);
  538. return getTable(tableName).blockIterator(this, block, maxPages);
  539. }
  540.  
  541. public RecordId runUpdateRecordWhere(String tableName, String targetColumnName, DataBox targetVaue,
  542. String predColumnName, DataBox predValue) throws DatabaseException {
  543. Table tab = getTable(tableName);
  544. Iterator<RecordId> recordIds = tab.ridIterator(this);
  545.  
  546. Schema s = tab.getSchema();
  547. int uindex = s.getFieldNames().indexOf(targetColumnName);
  548. int pindex = s.getFieldNames().indexOf(predColumnName);
  549.  
  550. while(recordIds.hasNext()) {
  551. RecordId curRID = recordIds.next();
  552. Record cur = getRecord(tableName, curRID);
  553. List<DataBox> record_copy = new ArrayList<DataBox>(cur.getValues());
  554.  
  555. if (record_copy.get(pindex).equals(predValue)) {
  556. record_copy.set(uindex, targetVaue);
  557. runUpdateRecord(tableName, record_copy, curRID);
  558. }
  559. }
  560. return null;
  561. }
  562.  
  563. private RecordId runUpdateRecord(String tableName, List<DataBox> values,
  564. RecordId rid) throws DatabaseException {
  565. assert(this.active);
  566. Table tab = getTable(tableName);
  567. Schema s = tab.getSchema();
  568.  
  569. Record rec = tab.updateRecord(this, values, rid);
  570.  
  571. List<DataBox> oldValues = rec.getValues();
  572. List<String> colNames = s.getFieldNames();
  573.  
  574. for (int i = 0; i < colNames.size(); i++) {
  575. String col = colNames.get(i);
  576. if (indexExists(tableName, col)) {
  577. BPlusTree tree = resolveIndexFromName(tableName, col).getSecond();
  578. tree.remove(this, oldValues.get(i));
  579. try {
  580. tree.put(this, values.get(i), rid);
  581. } catch (BPlusTreeException e) {
  582. throw new DatabaseException(e.getMessage());
  583. }
  584. }
  585. }
  586.  
  587. return rid;
  588. }
  589.  
  590. public TableStats getStats(String tableName) throws DatabaseException {
  591. assert(this.active);
  592. return getTable(tableName).getStats();
  593. }
  594.  
  595. public int getNumDataPages(String tableName) throws DatabaseException {
  596. assert(this.active);
  597. return getTable(tableName).getNumDataPages();
  598. }
  599.  
  600. public int getNumEntriesPerPage(String tableName) throws DatabaseException {
  601. assert(this.active);
  602. return getTable(tableName).getNumRecordsPerPage();
  603. }
  604.  
  605. public byte[] readPageHeader(String tableName, Page p) throws DatabaseException {
  606. assert(this.active);
  607. return getTable(tableName).getBitMap(this, p);
  608. }
  609.  
  610. public int getPageHeaderSize(String tableName) throws DatabaseException {
  611. assert(this.active);
  612. return getTable(tableName).getBitmapSizeInBytes();
  613. }
  614.  
  615. public int getEntrySize(String tableName) throws DatabaseException {
  616. assert(this.active);
  617. return getTable(tableName).getSchema().getSizeInBytes();
  618. }
  619.  
  620. public long getNumRecords(String tableName) throws DatabaseException {
  621. assert(this.active);
  622. return getTable(tableName).getNumRecords();
  623. }
  624.  
  625. public int getNumIndexPages(String tableName, String columnName) throws DatabaseException {
  626. assert(this.active);
  627. return this.resolveIndexFromName(tableName, columnName).getSecond().getNumPages();
  628. }
  629.  
  630. public Schema getSchema(String tableName) throws DatabaseException {
  631. assert(this.active);
  632. return getTable(tableName).getSchema();
  633. }
  634.  
  635. public Schema getFullyQualifiedSchema(String tableName) throws DatabaseException {
  636. assert(this.active);
  637.  
  638. Schema schema = getTable(tableName).getSchema();
  639. List<String> newColumnNames = new ArrayList<String>();
  640. for (String oldName : schema.getFieldNames()) {
  641. newColumnNames.add(tableName + "." + oldName);
  642. }
  643.  
  644. return new Schema(newColumnNames, schema.getFieldTypes());
  645. }
  646.  
  647. private Pair<String, BPlusTree> resolveIndexFromName(String tableName,
  648. String columnName) throws DatabaseException {
  649. while (aliasMaps.containsKey(tableName)) {
  650. tableName = aliasMaps.get(tableName);
  651. }
  652. if (columnName.contains(".")) {
  653. String columnPrefix = columnName.split("\\.")[0];
  654. while (aliasMaps.containsKey(columnPrefix)) {
  655. columnPrefix = aliasMaps.get(columnPrefix);
  656. }
  657. if (!tableName.equals(columnPrefix)) {
  658. throw new DatabaseException("Column: " + columnName + " is not a column of " + tableName);
  659. }
  660. columnName = columnName.split("\\.")[1];
  661. }
  662. String indexName = tableName + "," + columnName;
  663. if (Database.this.indexLookup.containsKey(indexName)) {
  664. return new Pair<>(indexName, Database.this.indexLookup.get(indexName));
  665. }
  666. throw new DatabaseException("Index does not exist");
  667. }
  668.  
  669. private Table getTable(String tableName) throws DatabaseException {
  670. if (this.tempTables.containsKey(tableName)) {
  671. return this.tempTables.get(tableName);
  672. }
  673.  
  674. while (aliasMaps.containsKey(tableName)) {
  675. tableName = aliasMaps.get(tableName);
  676. }
  677.  
  678. if (!Database.this.tableLookup.containsKey(tableName)) {
  679. throw new DatabaseException("Table: " + tableName + "does not exist");
  680. }
  681.  
  682. return Database.this.tableLookup.get(tableName);
  683. }
  684.  
  685. public void deleteTempTable(String tempTableName) {
  686. assert(this.active);
  687.  
  688. if (!this.tempTables.containsKey(tempTableName)) {
  689. return;
  690. }
  691.  
  692. this.tempTables.get(tempTableName).close();
  693. Database.this.tableLookup.remove(tempTableName);
  694.  
  695. File f = new File(Database.this.fileDir + "temp/" + tempTableName + Table.FILENAME_EXTENSION);
  696. f.delete();
  697. }
  698.  
  699. private void deleteAllTempTables() {
  700. Set<String> keys = tempTables.keySet();
  701.  
  702. for (String tableName : keys) {
  703. deleteTempTable(tableName);
  704. }
  705. }
  706.  
  707. public void block() {
  708. this.transactionLock.lock();
  709. try {
  710. this.blocked = true;
  711. while (this.blocked) {
  712. this.unblocked.awaitUninterruptibly();
  713. }
  714. } finally {
  715. this.transactionLock.unlock();
  716. }
  717. }
  718.  
  719. public void unblock() {
  720. this.transactionLock.lock();
  721. try {
  722. this.blocked = false;
  723. this.unblocked.signal();
  724. } finally {
  725. this.transactionLock.unlock();
  726. }
  727. }
  728.  
  729. public boolean getBlocked() {
  730. return this.blocked;
  731. }
  732. }
  733.  
  734. /* ******************************************************************************** */
  735. /* Every that follows is solely for the purpose of testing certain homeworks without
  736. requiring that previous homeworks be properly implemented. You should not change anything
  737. below. */
  738. /* ******************************************************************************** */
  739. protected Table newTable(String name, Schema schema, String filename, LockContext lockContext,
  740. BaseTransaction transaction) {
  741. return new Table(name, schema, filename, lockContext, transaction);
  742. }
  743.  
  744. protected Table newTable(String name, String filename, LockContext lockContext,
  745. BaseTransaction transaction) throws DatabaseException {
  746. return new Table(name, filename, lockContext, transaction);
  747. }
  748. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement