mercurial/transaction.py
changeset 0 9117c6561b0b
child 12 8b64243ee17b
equal deleted inserted replaced
-1:000000000000 0:9117c6561b0b
       
     1 # transaction.py - simple journalling scheme for mercurial
       
     2 #
       
     3 # This transaction scheme is intended to gracefully handle program
       
     4 # errors and interruptions. More serious failures like system crashes
       
     5 # can be recovered with an fsck-like tool. As the whole repository is
       
     6 # effectively log-structured, this should amount to simply truncating
       
     7 # anything that isn't referenced in the changelog.
       
     8 #
       
     9 # Copyright 2005 Matt Mackall <mpm@selenic.com>
       
    10 #
       
    11 # This software may be used and distributed according to the terms
       
    12 # of the GNU General Public License, incorporated herein by reference.
       
    13 
       
    14 import os
       
    15 
       
    16 class transaction:
       
    17     def __init__(self, opener, journal):
       
    18         self.opener = opener
       
    19         self.entries = []
       
    20         self.journal = journal
       
    21 
       
    22         # abort here if the journal already exists
       
    23         if os.path.exists(self.journal):
       
    24             raise "Journal already exists!"
       
    25         self.file = open(self.journal, "w")
       
    26 
       
    27     def __del__(self):
       
    28         if self.entries: self.abort()
       
    29 
       
    30     def add(self, file, offset):
       
    31         self.entries.append((file, offset))
       
    32         # add enough data to the journal to do the truncate
       
    33         self.file.write("%s\0%d\n" % (file, offset))
       
    34         self.file.flush()
       
    35 
       
    36     def close(self):
       
    37         self.file.close()
       
    38         self.entries = []
       
    39         os.unlink(self.journal)
       
    40 
       
    41     def abort(self):
       
    42         if not self.entries: return
       
    43 
       
    44         print "transaction abort!"
       
    45 
       
    46         for f, o in self.entries:
       
    47             self.opener(f, "a").truncate(o)
       
    48 
       
    49         self.entries = []
       
    50 
       
    51         try:
       
    52             os.unlink(self.journal)
       
    53             self.file.close()
       
    54         except: pass
       
    55 
       
    56         print "rollback completed"
       
    57         
       
    58     def recover(self):
       
    59         for l in open(self.journal).readlines():
       
    60             f, o = l.split('\0')
       
    61             self.opener(f, "a").truncate(int(o))
       
    62