]> arthur.barton.de Git - bup.git/blob - hashsplit.py
Clean up buffering to reduce number of buffer copies.
[bup.git] / hashsplit.py
1 #!/usr/bin/env python
2 import sys, os, subprocess, errno, zlib, time
3 import hashsplit
4 from sha import sha
5
6 # FIXME: duplicated in C module.  This shouldn't really be here at all...
7 BLOBBITS = 14
8 BLOBSIZE = 1 << (BLOBBITS-1)
9
10
11 def log(s):
12     sys.stderr.write('%s\n' % s)
13
14
15 class Buf:
16     def __init__(self):
17         self.data = ''
18         self.start = 0
19
20     def put(self, s):
21         #log('oldsize=%d+%d adding=%d' % (len(self.data), self.start, len(s)))
22         if s:
23             self.data = buffer(self.data, self.start) + s
24             self.start = 0
25             
26     def peek(self, count):
27         return buffer(self.data, self.start, count)
28     
29     def eat(self, count):
30         self.start += count
31
32     def get(self, count):
33         v = buffer(self.data, self.start, count)
34         self.start += count
35         return v
36
37     def used(self):
38         return len(self.data) - self.start
39
40
41 def splitbuf(buf):
42     #return buf.get(BLOBSIZE)
43     b = buf.peek(buf.used())
44     ofs = hashsplit.splitbuf(b)
45     if ofs:
46         buf.eat(ofs)
47         return buffer(b, 0, ofs)
48     return None
49
50
51 def save_blob(blob):
52     header = 'blob %d\0' % len(blob)
53     sum = sha(header)
54     sum.update(blob)
55     hex = sum.hexdigest()
56     dir = '.git/objects/%s' % hex[0:2]
57     fn = '%s/%s' % (dir, hex[2:])
58     try:
59         os.mkdir(dir)
60     except OSError, e:
61         if e.errno != errno.EEXIST:
62             raise
63     if not os.path.exists(fn):
64         #log('creating %s' % fn)
65         tfn = '%s.%d' % (fn, os.getpid())
66         f = open(tfn, 'w')
67         z = zlib.compressobj(1)
68         f.write(z.compress(header))
69         f.write(z.compress(blob))
70         f.write(z.flush())
71         f.close()
72         os.rename(tfn, fn)
73     else:
74         #log('exists %s' % fn)
75         pass
76     print hex
77     return hex
78
79
80 def do_main():
81     start_time = time.time()
82     ofs = 0
83     buf = Buf()
84     blob = 1
85
86     eof = 0
87     lv = 0
88     while blob or not eof:
89         if not eof and (buf.used() < BLOBSIZE*2 or not blob):
90             bnew = sys.stdin.read(1024*1024)
91             if not len(bnew): eof = 1
92             #log('got %d, total %d' % (len(bnew), buf.used()))
93             buf.put(bnew)
94
95         blob = splitbuf(buf)
96         if eof and not blob:
97             blob = buf.get(buf.used())
98         if not blob and buf.used() >= BLOBSIZE*8:
99             blob = buf.get(BLOBSIZE*4)  # limit max blob size
100         if not blob and not eof:
101             continue
102
103         if blob:
104             ofs += len(blob)
105             #log('SPLIT @ %-8d size=%-8d (blobsize=%d)'
106             #    % (ofs, len(blob), BLOBSIZE))
107             save_blob(blob)
108           
109         nv = (ofs + buf.used())/1000000
110         if nv != lv:
111             log(nv)
112             lv = nv
113     secs = time.time() - start_time
114     log('\n%.2fkbytes in %.2f secs = %.2f kbytes/sec' 
115         % (ofs/1024., secs, ofs/1024./secs))
116
117
118 assert(BLOBSIZE >= 32)
119 do_main()