186 raise ValueError(prec) |
185 raise ValueError(prec) |
187 for succ in succs: |
186 for succ in succs: |
188 if len(succ) != 20: |
187 if len(succ) != 20: |
189 raise ValueError(succ) |
188 raise ValueError(succ) |
190 marker = (str(prec), tuple(succs), int(flag), encodemeta(metadata)) |
189 marker = (str(prec), tuple(succs), int(flag), encodemeta(metadata)) |
191 self.add(transaction, marker) |
190 self.add(transaction, [marker]) |
192 |
191 |
193 def add(self, transaction, marker): |
192 def add(self, transaction, markers): |
194 """Add a new marker to the store""" |
193 """Add new markers to the store |
195 if marker not in self._all: |
194 |
|
195 Take care of filtering duplicate. |
|
196 Return the number of new marker.""" |
|
197 new = [m for m in markers if m not in self._all] |
|
198 if new: |
196 f = self.sopener('obsstore', 'ab') |
199 f = self.sopener('obsstore', 'ab') |
197 try: |
200 try: |
198 # Whether the file's current position is at the begin or at |
201 # Whether the file's current position is at the begin or at |
199 # the end after opening a file for appending is implementation |
202 # the end after opening a file for appending is implementation |
200 # defined. So we must seek to the end before calling tell(), |
203 # defined. So we must seek to the end before calling tell(), |
202 # some platforms (issue3543). |
205 # some platforms (issue3543). |
203 f.seek(0, 2) # os.SEEK_END |
206 f.seek(0, 2) # os.SEEK_END |
204 offset = f.tell() |
207 offset = f.tell() |
205 transaction.add('obsstore', offset) |
208 transaction.add('obsstore', offset) |
206 # offset == 0: new file - add the version header |
209 # offset == 0: new file - add the version header |
207 for bytes in _encodemarkers([marker], offset == 0): |
210 for bytes in _encodemarkers(new, offset == 0): |
208 f.write(bytes) |
211 f.write(bytes) |
209 finally: |
212 finally: |
210 # XXX: f.close() == filecache invalidation == obsstore rebuilt. |
213 # XXX: f.close() == filecache invalidation == obsstore rebuilt. |
211 # call 'filecacheentry.refresh()' here |
214 # call 'filecacheentry.refresh()' here |
212 f.close() |
215 f.close() |
213 self._load(marker) |
216 self._load(new) |
|
217 return len(new) |
214 |
218 |
215 def mergemarkers(self, transation, data): |
219 def mergemarkers(self, transation, data): |
216 other = _readmarkers(data) |
220 markers = _readmarkers(data) |
217 local = set(self._all) |
221 self.add(transation, markers) |
218 new = [m for m in other if m not in local] |
222 |
219 for marker in new: |
223 def _load(self, markers): |
220 # XXX: N marker == N x (open, write, close) |
224 for mark in markers: |
221 # we should write them all at once |
225 self._all.append(mark) |
222 self.add(transation, marker) |
226 pre, sucs = mark[:2] |
223 |
227 self.precursors.setdefault(pre, set()).add(mark) |
224 def _load(self, marker): |
228 for suc in sucs: |
225 self._all.append(marker) |
229 self.successors.setdefault(suc, set()).add(mark) |
226 pre, sucs = marker[:2] |
|
227 self.precursors.setdefault(pre, set()).add(marker) |
|
228 for suc in sucs: |
|
229 self.successors.setdefault(suc, set()).add(marker) |
|
230 |
230 |
231 def _encodemarkers(markers, addheader=False): |
231 def _encodemarkers(markers, addheader=False): |
232 # Kept separate from flushmarkers(), it will be reused for |
232 # Kept separate from flushmarkers(), it will be reused for |
233 # markers exchange. |
233 # markers exchange. |
234 if addheader: |
234 if addheader: |