Compare commits
2
Commits
3cad683e98
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
637009abf8 | ||
|
|
e391687a2e |
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}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user