-
Notifications
You must be signed in to change notification settings - Fork 2
/
fastsimplexordatastore.py
258 lines (181 loc) · 6.75 KB
/
fastsimplexordatastore.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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
"""
<Author>
Justin Cappos
<Start Date>
May 25th, 2011
<Description>
A wrapper for a C-based datastore. This uses objects, etc. to make
the C interface more Pythonic...
This is really just a version of the Python datastore with the Python code
replaced with the C extension. I left in all of the error checking.
"""
import fastsimplexordatastore_c
import mmapxordatastore_c
import math
def do_xor(bytes_a, bytes_b):
if type(bytes_a) != bytes or type(bytes_b) != bytes:
raise TypeError("do_xor must be called with bytes")
if len(bytes_a) != len(bytes_b):
raise ValueError("do_xor requires byte types of the same length")
return fastsimplexordatastore_c.do_xor(bytes_a, bytes_b)
class XORDatastore(object):
"""
<Purpose>
Class that has information for an XORdatastore. This data structure can
quickly XOR blocks of data that it stores. The real work is done in a
C extension
<Side Effects>
None.
"""
# this is the private, internal storage area for data...
ds = None
dsobj = None
# these are public so that a caller can read information about a created
# datastore. They should not be changed.
numberofblocks = None
sizeofblocks = None
dstype = ""
use_precomputed_data = 0
def __init__(self, block_size, num_blocks, dstype, dbname, use_precomputed_data=False): # allocate
"""
<Purpose>
Allocate a place to store data for efficient XOR.
<Arguments>
block_size: the size of each block. This must be a positive int / long.
The value must be a multiple of 64
num_blocks: the number of blocks. This must be a positive integer
use_precomputed_data: Use the precomputed 4R data
<Exceptions>
TypeError is raised if invalid parameters are given.
"""
if type(block_size) != int and type(block_size) != int:
raise TypeError("Block size must be an integer")
if block_size <= 0:
raise TypeError("Block size must be positive")
if block_size % 64 != 0:
raise TypeError("Block size must be a multiple of 64 bytes")
if type(num_blocks) != int and type(num_blocks) != int:
raise TypeError("Number of blocks must be an integer")
if num_blocks <= 0:
raise TypeError("Number of blocks must be positive")
self.numberofblocks = num_blocks
self.sizeofblocks = block_size #in byte
self.use_precomputed_data = int(use_precomputed_data)
self.dstype = dstype
if dstype == "mmap":
self.ds = mmapxordatastore_c.Initialize(block_size, num_blocks, dbname)
self.dsobj = mmapxordatastore_c
else: # RAM
self.ds = fastsimplexordatastore_c.Allocate(block_size, num_blocks)
self.dsobj = fastsimplexordatastore_c
def produce_xor_from_bitstring(self, bitstring):
"""
<Purpose>
Returns an XORed block from an XORdatastore. It will always return
a string of the size of the datastore blocks
<Arguments>
bitstring: bytes that indicates what to XOR. The length
of this string must be ceil(numberofblocks / 8.0). Extra
bits are ignored (e.g. if there are 10 blocks, the last
six bits are ignored).
<Exceptions>
TypeError is raised if the bitstring is invalid
<Returns>
The XORed block.
"""
if type(bitstring) != bytes:
raise TypeError("bitstring must be of type bytes")
if len(bitstring) != math.ceil(self.numberofblocks/8.0):
raise TypeError("bitstring is not of the correct length")
return self.dsobj.Produce_Xor_From_Bitstring(self.ds, bitstring, self.use_precomputed_data)
def produce_xor_from_multiple_bitstrings(self, bitstring, num_strings):
"""
<Purpose>
Returns multiple XORed block from an XORdatastore. It will always return
a string of the size of the datastore blocks times num_strings
<Arguments>
bitstring: concatenated string of bits that indicates what to XOR. The length
of this string must be numberofblocks * num_strings / 8. Extra
bits are ignored (e.g. if there are 10 blocks, the last
six bits are ignored).
num_strings: the number of requests in bitstring
<Exceptions>
TypeError is raised if the bitstring is invalid
<Returns>
The XORed block.
"""
if type(bitstring) != bytes:
raise TypeError("bitstring must be of type bytes")
if len(bitstring) != math.ceil(self.numberofblocks / 8.0)*num_strings :
raise TypeError("bitstring is not of the correct length")
return self.dsobj.Produce_Xor_From_Bitstrings(self.ds, bitstring, num_strings, self.use_precomputed_data)
def set_data(self, offset, data_to_add):
"""
<Purpose>
Sets the raw data in an XORdatastore. It ignores block layout, etc.
<Arguments>
offset: this is a non-negative integer that must be less than the
numberofblocks * blocksize.
data_to_add: the string that should be added. offset + len(data_to_add)
must be less than the numberofblocks * blocksize.
<Exceptions>
TypeError if the arguments are the wrong type or have invalid values.
<Returns>
None
"""
if type(offset) != int and type(offset) != int:
raise TypeError("Offset must be an integer")
if offset < 0:
raise TypeError("Offset must be non-negative")
if type(data_to_add) != bytes:
raise TypeError("Data_to_add to XORdatastore must be bytes.")
if offset + len(data_to_add) > self.numberofblocks * self.sizeofblocks:
raise TypeError("Offset + added data overflows the XORdatastore")
return self.dsobj.SetData(self.ds, offset, data_to_add)
def get_data(self, offset, quantity):
"""
<Purpose>
Returns raw data from an XORdatastore. It ignores block layout, etc.
<Arguments>
offset: this is a non-negative integer that must be less than the numberofblocks * blocksize.
quantity: quantity must be a positive integer. offset + quantity must be less than the numberofblocks * blocksize.
<Exceptions>
TypeError if the arguments are the wrong type or have invalid values.
<Returns>
A string containing the data.
"""
if type(offset) != int and type(offset) != int:
raise TypeError("Offset must be an integer")
if offset < 0:
raise TypeError("Offset must be non-negative")
if type(quantity) != int and type(quantity) != int:
raise TypeError("Quantity must be an integer")
if quantity <= 0:
raise TypeError("Quantity must be positive")
if offset + quantity > self.numberofblocks * self.sizeofblocks:
raise TypeError("Quantity + offset is larger than XORdatastore")
return self.dsobj.GetData(self.ds, offset, quantity)
def finalize(self):
"""
<Purpose>
Does the preprocessing
<Arguments>
None
<Exceptions>
None
<Returns>
None
"""
self.dsobj.DoPreprocessing(self.ds)
def __del__(self): # deallocate
"""
<Purpose>
Deallocate the XORdatastore
<Arguments>
None
<Exceptions>
None
"""
# if there is an error, this might be an uninitialized object...
if self.ds != None:
self.dsobj.Deallocate(self.ds)