<style> .text-center { text-align: center } h1{ border :none!important } </style> <h1 class="text-center"> Assignment 5 Report 1 </h1> <p class="text-center">110062143, 110062207, 110062208, 110062214</p> ## Implementation ### Primary Key We implement primary key with `ItemID` and `hashcode`, `hashcode` will be calculated in the constructor. ```java public class PrimaryKey { private Constant ItmeID; private int hashcode; ``` ### Stored Procedure ***StoreProcedure.java:*** Declare readSet and writeSet to record the primary key of the item. The lock declared here is used to block other transactions when the current transaction is entering the phase of acquiring locks, ensuring the preservation of atomicity. ```java public abstract class StoredProcedure<H extends ... protected HashSet<PrimaryKey> readSet = new HashSet<PrimaryKey>(); protected HashSet<PrimaryKey> writeSet = new HashSet<PrimaryKey>(); private ReentrantLock lock = new ReentrantLock(); ``` ***MicroTxnProc.java:*** We implement a new function, getReadWriteKeys(). This function will add the primary key of the item to readSet and writeSet. ```java protected void getReadWriteKeys(){ MicroTxnProcParamHelper paramHelper = getParamHelper(); for (int idx = 0; idx < paramHelper.getReadCount(); idx++) { readSet.add(new PrimaryKey(new IntegerConstant(paramHelper.getReadItemId(idx)))); } for (int idx = 0; idx < paramHelper.getWriteCount(); idx++) { writeSet.add(new PrimaryKey(new IntegerConstant(paramHelper.getWriteItemId(idx)))); } } ``` Then back to ***StoreProcedure.java***, all the locks needed by the transaction will be obtained here. ```java public void prepare(Object... pars) { ... tx = VanillaDb.txMgr().newTransaction( Connection.TRANSACTION_SERIALIZABLE, isReadOnly); lock.lock(); // if mgr is ConservativeConcurrencyMgr class then do prepareSp if(tx.concurrencyMgr() instanceof ConservativeConcurrencyMgr) { ConservativeConcurrencyMgr Mgr = (ConservativeConcurrencyMgr) tx.concurrencyMgr(); getReadWriteKeys(); Mgr.prepareSp(readSet, writeSet); } lock.unlock(); } ``` ### ConservativeConcurrencyMgr The function `prepareSp` will be called in StoreProcdure, which is mentioned above. The usage of this function is to lock read and write key with `xlock()` and `slock()`. ```java public void prepareSp(HashSet<PrimaryKey> readSet, HashSet<PrimaryKey> writeSet) { for (Object key : writeSet) { lockTbl.xLock(key, txNum); } for (Object key : readSet) { if (!writeSet.contains(key)) { lockTbl.sLock(key, txNum); } } } ``` We release all the lock when transaction finished or when rollback was called. ```java @Override public void onTxCommit(Transaction tx) { lockTbl.releaseAll(txNum, false); } @Override public void onTxRollback(Transaction tx) { lockTbl.releaseAll(txNum, false); } ``` ## Challenges of TPC-C Benchmarks: In micro benchmark, we can easily gather all the locks needed because all the transaction targets can be pre-determined by param-helper when parsing the sql command. In TPC-C, some transactions target id cannot be determined in the same manner. For example, when placing a new order into the ***new_order*** table, we need the ***next order id***, which cannot be known before we read the record from table ***district***. This quantity is needed to uniquely identify a record in the table ***new_order***. Hence, we won't be able to gather the corresponding lock of the record, unless we lock the whole ***new_order*** table. Or we'll have to pre-calculate the number of this type of transaction and remember all the current new order id of each district, and store it in param-helper to help locking the record. Which can be very cumbersome. The same situation arise in the later sql update command where the table ***order_line*** also require ***next order id*** to uniquely identify a record. In addition, in Payment Procedure, the queries to be executed to update the table ***customer*** depends on a field value ***cCredit***, If this value is unknown before reading the database, we'll have to lock all the possible record to which those queries may access. ## Experiments ### Environment Intel Core i5-12400 CPU @ 2.5GHz, 32 GB RAM, 1 TB SSD, Windows 10 ### Parameters | Param. name | Param. value | | -------- | -------- | | RW_TX_RATE | 0.2 | | TOTAL_READ_COUNT | 10 | | LOCAL_HOT_COUNT | 1 | | WRITE_RATIO_IN_RW_TX | 0.5 | | HOT_CONFLICT_RATE | 0.001 | ### Results - With different RTES ![image](https://hackmd.io/_uploads/HyoW0i_MC.png =500x) ![image](https://hackmd.io/_uploads/rJ3rjkYzC.png =500x) 1. The graph shows that our conservative concurrency manager correctly works since there's no abort. 2. The data shows that as the number of RTEs increases, the total number of committed transactions also increases. This is consistent with the understanding that more RTEs can handle more operations concurrently, which in turn can lead to a higher transaction throughput. - With different Buffer Pool Size ![image](https://hackmd.io/_uploads/SyMfs1YzA.png =500x) We thought the bigger size will lead to larger total commited txs numbers. ***However***, after testing with different BUFFER_POOL_SIZE the outcome seems roughly the same. We think that because there're no too much deadlock originally, so the buffer pool size didn't real help. Moreover, giving more size to buffer pool means some other internal spaces will decrease