-
Notifications
You must be signed in to change notification settings - Fork 1
/
bitcask_file.py
66 lines (59 loc) · 2.13 KB
/
bitcask_file.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
import time
import uuid
import codec
from collections import namedtuple
"""
Represents a single record in a bitcask file
_____________________________________________________________
| | | | | |
| timestamp | key size | value size | key | value |
|_____________|____________|____________|___________|_________|
"""
Record = namedtuple(
'Record', ['timestamp', 'keysize', 'valuesize', 'key', 'value'])
class File:
"""
Class representing a bitcask file, which is an append-only log
of key, value pairs and their associated metadata
"""
def __init__(self, dir, filename=str(uuid.uuid4()), offset=0):
self.filename = '/'.join([dir, filename])
self.offset = offset
def _load_next_record(self):
read_bytes = 0
with open(self.filename, 'rb') as f:
f.seek(self.offset, 0)
meta_bytes = f.read(codec.METADATA_BYTE_SIZE)
if meta_bytes:
(tstamp, ksize, vsize) = codec.decode_metadata(meta_bytes)
key_bytes = f.read(ksize)
value_bytes = f.read(vsize)
key = key_bytes.decode()
value = value_bytes.decode()
read_bytes += len(meta_bytes) + ksize + vsize
self.offset += read_bytes
return Record(tstamp, ksize, vsize, key, value)
def write(self, key, value):
"""
encode the data and append to the file
"""
keysize = len(key)
valuesize = len(value)
timestamp = time.time()
record = Record(timestamp, keysize, valuesize, key, value)
data = codec.encode(record)
count = 0
with open(self.filename, 'ab') as f:
count = f.write(data)
curr_offset = self.offset
self.offset += count
return (timestamp, curr_offset, count)
def read(self, pos, size):
"""
read bytes from the file and decode into record
"""
data = b''
with open(self.filename, 'rb') as f:
f.seek(pos, 0)
data = f.read(size)
return codec.decode(data).value