Compare commits

...
2 Commits
Author SHA1 Message Date
izatwin 637009abf8 hw5 start 2024-04-18 20:29:22 -04:00
izatwin e391687a2e project 4 2024-04-18 20:29:15 -04:00
5 changed files with 433 additions and 17 deletions
Binary file not shown.
Binary file not shown.
@@ -6,7 +6,7 @@
\usepackage[a4paper, total={6in, 8in}]{geometry}
\usepackage{graphicx}
\title{CS 448 Spring 2024 Homework 1}
\title{CS 448 Spring 2024 Homework 5}
\author{Sean Rettig}
\begin{document}
+23
View File
@@ -0,0 +1,23 @@
bin/
.DS_Store
sean.minibase
# ---> Maven
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
# Eclipse m2e generated files
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
+409 -16
View File
@@ -1,25 +1,418 @@
package CC;
import java.util.List;
public class CC
{
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
enum LockState {
NONE,
SHARED,
EXCLUSIVE
}
class Lock {
private ArrayList<Integer> transactionIds;
private LockState type;
private int noReads;
public Lock() {
this.transactionIds = new ArrayList<Integer>();
this.noReads = 0;
this.type = LockState.NONE;
}
public ArrayList<Integer> getTransactionIds() {
return transactionIds;
}
public void addTransactionId(int transactionId) {
if (!transactionIds.contains(Integer.valueOf(transactionId))) {
transactionIds.add(transactionId);
noReads++;
}
}
public LockState getType() {
return type;
}
public void setType(LockState type) {
this.type = type;
}
public int getNoReads() {
return noReads;
}
public boolean hasLock(int transactionId) {
return transactionIds.contains(Integer.valueOf(transactionId));
}
public void release(int releaseTransactionId) {
transactionIds.remove(Integer.valueOf(releaseTransactionId));
noReads--;
if (noReads == 0) {
this.type = LockState.NONE;
}
}
}
class LockTable {
private Lock[] locks;
private static final int NUM_RECORDS = 10;
public LockTable() {
this.locks = new Lock[NUM_RECORDS];
// initialize the locktable
for (int recordId = 0; recordId < NUM_RECORDS; recordId++) {
locks[recordId] = new Lock();
}
}
public Lock getLock(int recordId) {
if (recordId >= 0 && recordId < locks.length) {
return locks[recordId];
} else {
throw new IllegalArgumentException("Invalid recordId: " + recordId);
}
}
public void releaseLocksForTransaction(int[] recordIds, int transactionId) {
for (int recordId : recordIds) {
if (recordId >= 0 && recordId < locks.length) {
locks[recordId].release(transactionId);
} else {
throw new IllegalArgumentException("Invalid recordId: " + recordId);
}
}
}
}
interface Operation {
int getRecordId();
int getValue();
}
class WriteOp implements Operation {
private int recordId;
private int value;
public WriteOp(int recordId, int value) {
this.recordId = recordId;
this.value = value;
}
public int getRecordId() {
return recordId;
}
public int getValue() {
return value;
}
}
class ReadOp implements Operation {
private int recordId;
public ReadOp(int recordId) {
this.recordId = recordId;
}
public int getRecordId() {
return recordId;
}
public int getValue() {
return -1;
}
}
class CommitOp implements Operation {
public int getRecordId() {
return -1;
}
public int getValue() {
return -1;
}
}
class Transaction {
private int currentOperationIndex;
private Operation[] operations;
private int transactionId;
private ArrayList<Integer> recordLocks;
private int prevTimestamp;
private boolean aborted;
public Transaction(String[] operations, int transactionId) {
this.currentOperationIndex = 0;
this.operations = new Operation[operations.length];
this.transactionId = transactionId;
this.recordLocks = new ArrayList<Integer>();
this.prevTimestamp = -1;
this.aborted = false;
int OpIndex = 0;
for (String operation : operations) {
if (operation.charAt(0) == 'W') {
this.operations[OpIndex] = new WriteOp(Character.getNumericValue(operation.charAt(2)),
Character.getNumericValue(operation.charAt(4)));
} else if (operation.charAt(0) == 'R') {
this.operations[OpIndex] = new ReadOp(Character.getNumericValue(operation.charAt(2)));
} else {
this.operations[OpIndex] = new CommitOp();
}
OpIndex++;
}
}
public int getCurrentOperationIndex() {
return currentOperationIndex;
}
public int getTransactionId() {
return transactionId;
}
public void setCurrentOperationIndex(int currentOperationIndex) {
this.currentOperationIndex = currentOperationIndex;
}
public Operation[] getOperations() {
return operations;
}
public boolean hasNextOperation() {
return (currentOperationIndex < operations.length) && !aborted;
}
public int doNextOperation(LockTable lockTable, int[] database, ArrayList<String[]> systemLog, int timestamp,
LinkedList<Integer>[] adj) {
if (hasNextOperation() && !aborted) {
Operation nextOp = operations[currentOperationIndex];
Lock nextLock = null;
if (!(nextOp instanceof CommitOp)) {
nextLock = lockTable.getLock(nextOp.getRecordId());
}
currentOperationIndex++;
if (nextOp instanceof ReadOp) {
if (!(nextLock.hasLock(transactionId))) {
// The current transaction doesn't already have the lock.
if (nextLock.getType() == LockState.EXCLUSIVE) {
currentOperationIndex--;
for (int adjTransactionId : nextLock.getTransactionIds()) {
if (adjTransactionId != transactionId
&& !adj[transactionId].contains(Integer.valueOf(adjTransactionId))) {
adj[transactionId].add(adjTransactionId);
}
}
return timestamp;
// The lock on the record is exclusive.
} else {
nextLock.setType(LockState.SHARED);
nextLock.addTransactionId(transactionId);
recordLocks.add(nextOp.getRecordId());
}
}
String[] log = { "R", Integer.toString(timestamp), "T" + Integer.toString(transactionId),
Integer.toString(nextOp.getRecordId()), Integer.toString(database[nextOp.getRecordId()]),
Integer.toString(prevTimestamp) };
systemLog.add(log);
} else if (nextOp instanceof WriteOp) {
int prevValue = database[nextOp.getRecordId()];
if ((nextLock.hasLock(transactionId) && nextLock.getNoReads() == 1)
|| nextLock.getType() == LockState.NONE) {
nextLock.setType(LockState.EXCLUSIVE);
database[nextOp.getRecordId()] = nextOp.getValue();
nextLock.addTransactionId(transactionId);
if (!recordLocks.contains(Integer.valueOf(nextOp.getRecordId()))) {
recordLocks.add(nextOp.getRecordId());
}
} else {
currentOperationIndex--;
for (int adjTransactionId : nextLock.getTransactionIds()) {
if (adjTransactionId != transactionId
&& !adj[transactionId].contains(Integer.valueOf(adjTransactionId))) {
adj[transactionId].add(adjTransactionId);
}
}
return timestamp;
}
String[] log = { "W", Integer.toString(timestamp), "T" + Integer.toString(transactionId),
Integer.toString(nextOp.getRecordId()), Integer.toString(prevValue),
Integer.toString(database[nextOp.getRecordId()]),
Integer.toString(prevTimestamp) };
systemLog.add(log);
} else {
for (int recordLock : recordLocks) {
lockTable.getLock(recordLock).release(transactionId);
}
recordLocks = new ArrayList<Integer>();
String[] log = { "C", Integer.toString(timestamp), "T" + Integer.toString(transactionId),
Integer.toString(prevTimestamp) };
systemLog.add(log);
}
prevTimestamp = timestamp;
timestamp++;
}
return timestamp;
}
public void reset() {
currentOperationIndex = 0;
recordLocks = new ArrayList<Integer>();
}
public int abortTransaction(LockTable lockTable, int[] database, ArrayList<String[]> systemLog, int timestamp,
LinkedList<Integer>[] adj) {
aborted = true;
int pastTransaction = prevTimestamp;
do {
String[] lastLog = systemLog.get(pastTransaction);
if (lastLog[0] == "W") {
database[Integer.parseInt(lastLog[3])] = Integer.parseInt(lastLog[4]);
}
pastTransaction = Integer.parseInt(lastLog[lastLog.length - 1]);
} while (pastTransaction != -1);
for (int recordLock : recordLocks) {
lockTable.getLock(recordLock).release(transactionId);
}
recordLocks = new ArrayList<Integer>();
adj[transactionId] = new LinkedList<Integer>();
String[] log = { "A", Integer.toString(timestamp), "T" + Integer.toString(transactionId),
Integer.toString(prevTimestamp) };
systemLog.add(log);
return -1;
}
}
public class CC {
private static final int NUM_RECORDS = 10;
/**
* Notes:
* - Execute all given transactions, using locking.
* - Each element in the transactions List represents all operations performed by one transaction, in order.
* - No operation in a transaction can be executed out of order, but operations may be interleaved with other
* transactions if allowed by the locking.
* - The index of the transaction in the list is equivalent to the transaction ID.
* - Print the log to the console at the end of the method.
* - Return the new db state after executing the transactions.
* @param db the initial status of the db
* @param transactions the schedule, which basically is a {@link List} of transactions.
* - Execute all given transactions, using locking.
* - Each element in the transactions List represents all operations performed
* by one transaction, in order.
* - No operation in a transaction can be executed out of order, but operations
* may be interleaved with other
* transactions if allowed by the locking.
* - The index of the transaction in the list is equivalent to the transaction
* ID.
* - Print the log to the console at the end of the method.
* - Return the new db state after executing the transactions.
*
* @param db the initial status of the db
* @param transactions the schedule, which basically is a {@link List} of
* transactions.
* @return the final status of the db
*/
public static int[] executeSchedule(int[] db, List<String> transactions)
{
//TODO
return null ;
public static int[] executeSchedule(int[] db, List<String> transactions) {
LockTable lockTable = new LockTable();
Queue<Transaction> transactionQueue = new LinkedList<>();
Transaction[] transactionsArray = new Transaction[transactions.size() + 1];
int newTransactionId = 1;
int[] database = new int[NUM_RECORDS];
ArrayList<String[]> systemLog = new ArrayList<>();
int timestamp = 0;
LinkedList<Integer>[] adj;
for (int i = 0; i < NUM_RECORDS; i++) {
database[i] = i;
}
for (String transaction : transactions) {
Transaction newTransaction = new Transaction(transaction.split(";"), newTransactionId);
transactionQueue.add(newTransaction);
transactionsArray[newTransactionId] = newTransaction;
newTransactionId++;
}
adj = new LinkedList[transactions.size() + 1];
for (int i = 0; i < transactions.size() + 1; ++i) {
adj[i] = new LinkedList<Integer>();
}
while (!transactionQueue.isEmpty()) {
Transaction curTransaction = transactionQueue.remove();
if (curTransaction.hasNextOperation()) {
timestamp = curTransaction.doNextOperation(lockTable, database, systemLog, timestamp, adj);
// Here is where we check if there are deadlocks. We run DFS.
boolean[] visited = new boolean[transactions.size() + 1];
int[] predecessor = new int[transactions.size() + 1];
ArrayList<Integer> nodesInCycle = DFS(curTransaction.getTransactionId(), visited, adj, predecessor);
if (nodesInCycle != null) {
Collections.sort(nodesInCycle);
transactionsArray[nodesInCycle.get(nodesInCycle.size() - 1)].abortTransaction(lockTable, database,
systemLog, timestamp,
adj);
timestamp++;
}
transactionQueue.add(curTransaction);
}
}
for (String[] log : systemLog) {
StringBuilder sb = new StringBuilder(log[0] + ":" + log[1]);
for (int k = 2; k < log.length; k++) {
sb.append("," + log[k]);
}
System.out.println(sb.toString());
}
System.out.println();
return database;
}
public static ArrayList<Integer> DFS(int v, boolean visited[], LinkedList<Integer> adj[], int predecessor[]) {
visited[v] = true;
Iterator<Integer> i = adj[v].listIterator();
while (i.hasNext()) {
int n = i.next();
if (!visited[n]) {
predecessor[n] = v;
return DFS(n, visited, adj, predecessor);
} else {
return returnNodesInCycle(predecessor, v, n);
}
}
return null;
}
public static ArrayList<Integer> returnNodesInCycle(int[] predecessor, int parent, int start) {
ArrayList<Integer> nodesInCycle = new ArrayList<>();
nodesInCycle.add(parent);
nodesInCycle.add(start);
while (predecessor[start] != parent && predecessor[start] != 0) {
nodesInCycle.add(predecessor[start]);
start = predecessor[start];
}
return nodesInCycle;
}
}