-
Notifications
You must be signed in to change notification settings - Fork 2
/
site_class.py
206 lines (149 loc) · 6.12 KB
/
site_class.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
from config_params import *
from util import *
from transaction_manager import *
import main
class Data:
def __init__(self, dataId, value, oldCommitedCopies):
self.dataId = dataId
self.name = "x"+str(dataId)
self.value = value
self.commited = main.time_tick
def __init__(self, dataId, value):
self.dataId = dataId
self.name = "x"+str(dataId)
self.value = value
def copy(self):
return Data(self.dataId, self.value)
def toString(self):
return self.name+": "+str(self.value)
def __str__(self):
return self.toString()
class Lock:
def __init__(self, lockType, transactionID, data):
# lockType = {READ, WRITE, READ_ONLY}
self.lockType = lockType
self.transactions = {transactionID}
self.dataInMemory = data
class Site:
def __init__(self, siteId):
self.failTimes = [-1]
# enum states {AVAILABLE, FAILED}
self.state = "AVAILABLE"
# int siteId
self.siteId = siteId
# Hash map dataId -> Lock
self.lockTable = {}
# Hash map dataId -> Data
self.data = {}
# timestamp -> value
self.oldCommitedCopies = {}
for dataId in range(1, NUM_DATA+1):
if (dataId % 2 != 0):
# x1 -> site 2, x3 -> site 4, x11 -> site 2, x15 -> site 6, etc.
if 1 + (dataId % NUM_SITES) == siteId:
self.data[dataId] = Data(dataId, 10 * dataId)
self.oldCommitedCopies[dataId] = [(main.time_tick, self.data[dataId])]
else:
self.data[dataId] = Data(dataId, 10 * dataId)
self.oldCommitedCopies[dataId] = [(main.time_tick, self.data[dataId])]
def flattenData(self):
res = []
for dataId in range(1, NUM_DATA+1):
if dataId in self.data:
d = self.data[dataId]
res.append(d.name+": "+str(d.value))
return ", ".join(res)
# returns set of transactionIds must be waited for
def checkLock(self, lockType, transactionID, dataId):
if dataId not in self.data:
return None
if dataId not in self.lockTable:
return set()
presentLock = self.lockTable[dataId]
if (lockType == "WRITE"):
trans = presentLock.transactions.copy()
trans.discard(transactionID)
return trans
elif (lockType == "READ"):
if (presentLock.lockType == "WRITE"):
trans = presentLock.transactions.copy()
trans.discard(transactionID)
return trans
elif (presentLock.lockType == "READ"):
return set()
def lock(self, lockType, transactionID, dataId):
if dataId not in self.data:
return
# Transaction has already got same type of lock on this data
if dataId in self.lockTable and lockType == self.lockTable[dataId].lockType and transactionID in self.lockTable[dataId].transactions:
return
# dataId has to be in self.data and we are adding copy of the data to lock table
self.lockTable[dataId] = Lock(lockType, transactionID, self.data[dataId].copy())
def update(self, transactionID, dataId, newValue):
if dataId not in self.data:
return
if transactionID not in self.lockTable[dataId].transactions or self.lockTable[dataId].lockType != "WRITE":
print(transactionID, "tries to update a data", dataId,"which it either does not have WRITE access or not any access at all")
self.lockTable[dataId].dataInMemory.value = newValue
def commit(self, transactionID, dataId):
if dataId not in self.data:
return
if dataId not in self.lockTable:
print(transactionID, "has passed commit command to data", dataId, "which is not locked")
return
lock = self.lockTable[dataId]
if (lock.lockType == "WRITE"):
if transactionID not in lock.transactions:
print(transactionID, "tries to commit a data", dataId, "which it does not lock access at all")
else:
self.data[dataId] = lock.dataInMemory
self.oldCommitedCopies[dataId].append((main.time_tick, self.data[dataId].copy()))
def releaseLocks(self, transactionID, lockedDataIds):
for dId in lockedDataIds:
if dId not in self.data:
continue
if dId in self.lockTable:
self.lockTable[dId].transactions.discard(transactionID)
if len(self.lockTable[dId].transactions) == 0:
del self.lockTable[dId]
def checkReadOnly(self, dataId, transTimestemp):
if dataId not in self.data:
None
for oldCopy in self.oldCommitedCopies[dataId][::-1]:
commitTime = oldCopy[0]
if commitTime == -1:
return False
if commitTime < transTimestemp:
return True
return False
def getDataReadOnly(self, dataId, transTimestemp):
if dataId not in self.data:
return None
for oldCopy in self.oldCommitedCopies[dataId][::-1]:
commitTime = oldCopy[0]
if commitTime == -1:
return None
if commitTime < transTimestemp:
return oldCopy[1]
return None
def checkDataExists(self, dataId):
return dataId in self.data
def checkReadAllowed(self, dataId, isDataReplicated):
if dataId not in self.data:
return None
if isDataReplicated == False:
return True
return self.oldCommitedCopies[dataId][-1][0] != -1
def getData(self, dataId):
if dataId not in self.data:
return
return self.data[dataId]
def fail(self):
self.state = "FAILED"
self.failTimes.append(main.time_tick)
def recover(self):
# make all data commited = False
self.state = "AVAILABLE"
for dataId, data in self.data.items():
self.oldCommitedCopies[dataId].append((-1, None))
self.lockTable = {}