예제 #1
0
 def handle_L(self, s):
     # load
     oid = recv(s, 8)
     if oid in self._find_client(s).invalid:
         s.sendall(STATUS_INVALID)
     else:
         try:
             record = self.storage.load(oid)
         except KeyError:
             log(10, 'KeyError %s', u64(oid))
             s.sendall(STATUS_KEYERROR)
         else:
             if is_logging(5):
                 log(5, 'Load %-7s %s', u64(oid), extract_class_name(record))
             s.sendall(STATUS_OKAY + p32(len(record)) + record)
예제 #2
0
 def handle_C(self, s):
     # commit
     client = self._find_client(s)
     s.sendall(p32(len(client.invalid)) + ''.join(client.invalid))
     client.invalid.clear()
     tlen = u32(recv(s, 4))
     if tlen == 0:
         return # client decided not to commit (e.g. conflict)
     tdata = recv(s, tlen)
     logging_debug = is_logging(10)
     logging_debug and log(10, 'Committing %s bytes', tlen)
     self.storage.begin()
     i = 0
     oids = []
     while i < len(tdata):
         rlen = u32(tdata[i:i+4])
         i += 4
         oid = tdata[i:i+8]
         record = tdata[i+8:i+rlen]
         i += rlen
         if logging_debug:
             class_name = extract_class_name(record)
             log(10, '  oid=%-6s rlen=%-6s %s', u64(oid), rlen, class_name)
         self.storage.store(oid, record)
         oids.append(oid)
     assert i == len(tdata)
     self.storage.end()
     log(20, 'Committed %3s objects %s bytes at %s',
         len(oids), tlen, datetime.now())
     s.sendall(STATUS_OKAY)
     for c in self.clients:
         if c is not client:
             c.invalid.update(oids)
예제 #3
0
 def gen_oid_record(self):
     """() -> sequence([oid:str, record:str])
     A FileStorage will do a better job of this.
     """
     for oid_num in xrange(u64(self.new_oid())):
         try:
             oid = p64(oid_num)
             record = self.load(oid)
             yield oid, record
         except DurusKeyError:
             pass
예제 #4
0
 def _build_index(self):
     self.fp.seek(0)
     if self.fp.read(len(self.MAGIC)) != self.MAGIC:
         raise IOError, "invalid storage (missing magic in %r)" % self.fp
     index_offset = u64(self.fp.read(8))
     assert index_offset > 0
     self.fp.seek(index_offset)
     index_size = u64(self.fp.read(8))
     self.index = loads(decompress(self.fp.read(index_size)))
     while 1:
         # Read one transaction each time here.
         oids = {}
         transaction_offset = self.fp.tell()
         try:
             while 1:
                 object_record_offset = self.fp.tell()
                 record = self._read_block()
                 if len(record) == 0:
                     break # normal termination
                 if len(record) < 12:
                     raise ValueError("Bad record size")
                 oid = record[0:8]
                 oids[oid] = object_record_offset
             # We've reached the normal end of a transaction.
             self.index.update(oids)
             oids.clear()
         except (ValueError, IOError), exc:
             if self.fp.tell() > transaction_offset:
                 if not self.repair:
                     raise
                 # The transaction was malformed. Attempt repair.
                 if self.fp.mode == 'r':
                     raise RuntimeError(
                         "Can't repair readonly file.\n%s" % exc)
                 self.fp.seek(transaction_offset)
                 self.fp.truncate()
             break
예제 #5
0
 def __init__(self, filename=None, readonly=False, repair=False):
     """(filename:str=None, readonly:bool=False, repair:bool=False)
     If filename is empty (or None), a temporary file will be used.
     """
     self.oid = 0
     self.filename = filename
     if readonly:
         if not filename:
             raise ValueError(
                 "A filename is required for a readonly storage.")
         if repair:
             raise ValueError("A readonly storage can't be repaired.")
         self.fp = open(self.filename, 'rb')
     else:
         if not filename:
             self.fp = NamedTemporaryFile(suffix=".durus", mode="w+b")
         elif os.path.exists(self.filename):
             self.fp = open(self.filename, 'a+b')
         else:
             self.fp = open(self.filename, 'w+b')
         try:
             lock_file(self.fp)
         except IOError:
             self.fp.close()
             raise RuntimeError(
                 "\n  %s is locked."
                 "\n  There is probably a Durus storage server (or a client)"
                 "\n  using it.\n" % self.get_filename())
     self.pending_records = {}
     self.pack_extra = None
     self.repair = repair
     self._set_concrete_class_for_magic()
     self.index = {}
     self._build_index()
     max_oid = 0
     for oid in self.index:
         max_oid = max(max_oid, u64(oid))
     self.oid = max_oid
예제 #6
0
 def _build_index(self):
     self.index = {}
     self.fp.seek(0)
     if self.fp.read(len(self.MAGIC)) != self.MAGIC:
         raise IOError, "invalid storage (missing magic in %r)" % self.fp
     max_tid = 0
     while 1:
         # Read one transaction each time here.
         transaction_offset = self.fp.tell()
         oids = {}
         try:
             while 1:
                 object_record_offset = self.fp.tell()
                 trecord = self._read_block()
                 if len(trecord) == 0:
                     break # normal termination
                 if len(trecord) < 16:
                     raise ValueError("Bad record size")
                 tid = trecord[0:8]
                 oid = trecord[8:16]
                 max_tid = max(max_tid, u64(tid))
                 oids[oid] = object_record_offset
             # We've reached the normal end of a transaction.
             self.index.update(oids)
             oids.clear()
         except (ValueError, IOError), exc:
             if self.fp.tell() > transaction_offset:
                 if not self.repair:
                     raise
                 # The transaction was malformed. Attempt repair.
                 if self.fp.mode == 'r':
                     raise RuntimeError(
                         "Can't repair readonly file.\n%s" % exc)
                 self.fp.seek(transaction_offset)
                 self.fp.truncate()
             break