128 vfsmap = vfsmap.copy() |
128 vfsmap = vfsmap.copy() |
129 vfsmap[''] = opener # set default value |
129 vfsmap[''] = opener # set default value |
130 self._vfsmap = vfsmap |
130 self._vfsmap = vfsmap |
131 self._after = after |
131 self._after = after |
132 self.entries = [] |
132 self.entries = [] |
133 self.map = {} |
133 self._map = {} |
134 self._journal = journalname |
134 self._journal = journalname |
135 self._undoname = undoname |
135 self._undoname = undoname |
136 self._queue = [] |
136 self._queue = [] |
137 # A callback to validate transaction content before closing it. |
137 # A callback to validate transaction content before closing it. |
138 # should raise exception is anything is wrong. |
138 # should raise exception is anything is wrong. |
216 self._addentry(f, o, data) |
216 self._addentry(f, o, data) |
217 |
217 |
218 @active |
218 @active |
219 def add(self, file, offset, data=None): |
219 def add(self, file, offset, data=None): |
220 """record the state of an append-only file before update""" |
220 """record the state of an append-only file before update""" |
221 if file in self.map or file in self._backupmap: |
221 if file in self._map or file in self._backupmap: |
222 return |
222 return |
223 if self._queue: |
223 if self._queue: |
224 self._queue[-1].append((file, offset, data)) |
224 self._queue[-1].append((file, offset, data)) |
225 return |
225 return |
226 |
226 |
227 self._addentry(file, offset, data) |
227 self._addentry(file, offset, data) |
228 |
228 |
229 def _addentry(self, file, offset, data): |
229 def _addentry(self, file, offset, data): |
230 """add a append-only entry to memory and on-disk state""" |
230 """add a append-only entry to memory and on-disk state""" |
231 if file in self.map or file in self._backupmap: |
231 if file in self._map or file in self._backupmap: |
232 return |
232 return |
233 self.entries.append((file, offset, data)) |
233 self.entries.append((file, offset, data)) |
234 self.map[file] = len(self.entries) - 1 |
234 self._map[file] = len(self.entries) - 1 |
235 # add enough data to the journal to do the truncate |
235 # add enough data to the journal to do the truncate |
236 self._file.write("%s\0%d\n" % (file, offset)) |
236 self._file.write("%s\0%d\n" % (file, offset)) |
237 self._file.flush() |
237 self._file.flush() |
238 |
238 |
239 @active |
239 @active |
249 """ |
249 """ |
250 if self._queue: |
250 if self._queue: |
251 msg = 'cannot use transaction.addbackup inside "group"' |
251 msg = 'cannot use transaction.addbackup inside "group"' |
252 raise error.ProgrammingError(msg) |
252 raise error.ProgrammingError(msg) |
253 |
253 |
254 if file in self.map or file in self._backupmap: |
254 if file in self._map or file in self._backupmap: |
255 return |
255 return |
256 vfs = self._vfsmap[location] |
256 vfs = self._vfsmap[location] |
257 dirname, filename = vfs.split(file) |
257 dirname, filename = vfs.split(file) |
258 backupfilename = "%s.backup.%s" % (self._journal, filename) |
258 backupfilename = "%s.backup.%s" % (self._journal, filename) |
259 backupfile = vfs.reljoin(dirname, backupfilename) |
259 backupfile = vfs.reljoin(dirname, backupfilename) |
362 ''' |
362 ''' |
363 replace can only replace already committed entries |
363 replace can only replace already committed entries |
364 that are not pending in the queue |
364 that are not pending in the queue |
365 ''' |
365 ''' |
366 |
366 |
367 if file not in self.map: |
367 if file not in self._map: |
368 raise KeyError(file) |
368 raise KeyError(file) |
369 index = self.map[file] |
369 index = self._map[file] |
370 self.entries[index] = (file, offset, data) |
370 self.entries[index] = (file, offset, data) |
371 self._file.write("%s\0%d\n" % (file, offset)) |
371 self._file.write("%s\0%d\n" % (file, offset)) |
372 self._file.flush() |
372 self._file.flush() |
373 |
373 |
374 @active |
374 @active |