diff --git a/04/src/PersistenceManager.java b/04/src/PersistenceManager.java index 6164cd1..a7a0e0f 100644 --- a/04/src/PersistenceManager.java +++ b/04/src/PersistenceManager.java @@ -1,63 +1,147 @@ import org.jetbrains.annotations.Contract; +import java.util.*; + /** * Persistence manager using the Singleton pattern. */ -public class PersistenceManager -{ - private final static PersistenceManager instance; +public class PersistenceManager { + private final static PersistenceManager instance; + private Hashtable _pageBuffer; + private Hashtable> _transactionPageBuffer; + private Hashtable _transactions; + private Hashtable _pageLSN; + private int _nextTransactionNumber; + private int _nextLogSequenceNumber; static { try { instance = new PersistenceManager(); - } - catch (Throwable e) { + } catch (Throwable e) { throw new RuntimeException(e.getMessage()); } } /** * Returns an instance of the persistence manager. + * * @return instance */ @Contract(pure = true) - public static PersistenceManager getInstance() - { + public static PersistenceManager getInstance() { return instance; } /** * private constructor */ - private PersistenceManager() - {} + private PersistenceManager() { + _pageBuffer = new Hashtable<>(); + _transactionPageBuffer = new Hashtable<>(); + _transactions = new Hashtable<>(); + _pageLSN = new Hashtable<>(); + _nextTransactionNumber = 1; + _nextLogSequenceNumber = 1; + } /** * Begins the transaction and returns the transaction ID. + * * @return transaction ID */ - public int beginTransaction() - { - return 0; + public int beginTransaction() { + _transactions.put(_nextTransactionNumber, false); + // return the next transaction number and increase it by one afterwards + return _nextTransactionNumber++; } /** * Commits the transaction specified by given ID. - * @param taid transaction ID + * + * @param taid + * transaction ID */ - public void commit(int taid) - { - + public void commit(int taid) { + if (!_transactions.containsKey(taid)) { + throw new IllegalArgumentException("No transaction with given ID exists."); + } + // only perform commit actions if transaction isn't commited yet + if (!_transactions.get(taid)) { + _transactions.replace(taid, true); + } } /** * Writes given data into given page in given transaction. - * @param taid transaction ID - * @param pageid page ID - * @param data data + * + * @param taid + * transaction ID + * @param pageid + * page ID + * @param data + * data */ - public void write(int taid, int pageid, String data) - { + public void write(int taid, int pageid, String data) { + if (!_transactions.containsKey(taid)) { + throw new IllegalArgumentException("No transaction with given ID exists."); + } + if (_transactions.get(taid)) { + throw new IllegalArgumentException("Write operations cannot be performed for committed transactions."); + } + Set pageIDs = _transactionPageBuffer.getOrDefault(taid, new HashSet<>()); + pageIDs.add(pageid); + _transactionPageBuffer.put(taid, pageIDs); + _pageBuffer.put(pageid, data); + // log changes + int lsn = log(taid, pageid, data); + _pageLSN.put(pageid, lsn); + // call persist + persist(); + } + /** + * Logs the necessary information to the log file. + * + * @param taid + * affected transaction + * @param pageid + * modified page + * @param data + * written data + * @return log sequence number + */ + private int log(int taid, int pageid, String data) { + return _nextLogSequenceNumber++; + } + + /** + * Checks for full buffer and persists data of committed transactions to storage if buffer is full. + */ + private void persist() { + if (_pageBuffer.size() <= 5) { + return; + } + + // TODO persist the data of committed transactions + Enumeration transactionIDs = _transactions.keys(); + List commitedTransactions = new ArrayList<>(); + while (transactionIDs.hasMoreElements()) { + Integer taid = transactionIDs.nextElement(); + boolean committed = _transactions.get(taid); + if (committed) { + commitedTransactions.add(taid); + } + } + + for (int taid : commitedTransactions) { + // TODO persist data of committed transaction + Set pageIDs = _transactionPageBuffer.get(taid); + for (int pageid : pageIDs) { + // TODO persist data of pageID + _pageBuffer.remove(pageid); + } + _transactionPageBuffer.remove(taid); + _transactions.remove(taid); + } } }