##// END OF EJS Templates
parsers: add a C function to pack the dirstate...
Bryan O'Sullivan -
r16955:92e1c64b default
parent child Browse files
Show More
@@ -498,12 +498,24 b' class dirstate(object):'
498 498 return
499 499 st = self._opener("dirstate", "w", atomictemp=True)
500 500
501 def finish(s):
502 st.write(s)
503 st.close()
504 self._lastnormaltime = 0
505 self._dirty = self._dirtypl = False
506
501 507 # use the modification time of the newly created temporary file as the
502 508 # filesystem's notion of 'now'
503 now = int(util.fstat(st).st_mtime)
509 now = util.fstat(st).st_mtime
510 copymap = self._copymap
511 try:
512 finish(parsers.pack_dirstate(self._map, copymap, self._pl, now))
513 return
514 except AttributeError:
515 pass
504 516
517 now = int(now)
505 518 cs = cStringIO.StringIO()
506 copymap = self._copymap
507 519 pack = struct.pack
508 520 write = cs.write
509 521 write("".join(self._pl))
@@ -526,10 +538,7 b' class dirstate(object):'
526 538 e = pack(_format, e[0], e[1], e[2], e[3], len(f))
527 539 write(e)
528 540 write(f)
529 st.write(cs.getvalue())
530 st.close()
531 self._lastnormaltime = 0
532 self._dirty = self._dirtypl = False
541 finish(cs.getvalue())
533 542
534 543 def _dirignore(self, f):
535 544 if f == '.':
@@ -214,6 +214,154 b' quit:'
214 214 return ret;
215 215 }
216 216
217 static inline int getintat(PyObject *tuple, int off, uint32_t *v)
218 {
219 PyObject *o = PyTuple_GET_ITEM(tuple, off);
220 long val;
221
222 if (PyInt_Check(o))
223 val = PyInt_AS_LONG(o);
224 else if (PyLong_Check(o)) {
225 val = PyLong_AsLong(o);
226 if (val == -1 && PyErr_Occurred())
227 return -1;
228 } else {
229 PyErr_SetString(PyExc_TypeError, "expected an int or long");
230 return -1;
231 }
232 if (LONG_MAX > INT_MAX && (val > INT_MAX || val < INT_MIN)) {
233 PyErr_SetString(PyExc_OverflowError,
234 "Python value to large to convert to uint32_t");
235 return -1;
236 }
237 *v = (uint32_t)val;
238 return 0;
239 }
240
241 static PyObject *dirstate_unset;
242
243 /*
244 * Efficiently pack a dirstate object into its on-disk format.
245 */
246 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
247 {
248 PyObject *packobj = NULL;
249 PyObject *map, *copymap, *pl;
250 Py_ssize_t nbytes, pos, l;
251 PyObject *k, *v, *pn;
252 char *p, *s;
253 double now;
254
255 if (!PyArg_ParseTuple(args, "O!O!Od:pack_dirstate",
256 &PyDict_Type, &map, &PyDict_Type, &copymap,
257 &pl, &now))
258 return NULL;
259
260 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
261 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
262 return NULL;
263 }
264
265 /* Figure out how much we need to allocate. */
266 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
267 PyObject *c;
268 if (!PyString_Check(k)) {
269 PyErr_SetString(PyExc_TypeError, "expected string key");
270 goto bail;
271 }
272 nbytes += PyString_GET_SIZE(k) + 17;
273 c = PyDict_GetItem(copymap, k);
274 if (c) {
275 if (!PyString_Check(c)) {
276 PyErr_SetString(PyExc_TypeError,
277 "expected string key");
278 goto bail;
279 }
280 nbytes += PyString_GET_SIZE(c) + 1;
281 }
282 }
283
284 packobj = PyString_FromStringAndSize(NULL, nbytes);
285 if (packobj == NULL)
286 goto bail;
287
288 p = PyString_AS_STRING(packobj);
289
290 pn = PySequence_ITEM(pl, 0);
291 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
292 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
293 goto bail;
294 }
295 memcpy(p, s, l);
296 p += 20;
297 pn = PySequence_ITEM(pl, 1);
298 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
299 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
300 goto bail;
301 }
302 memcpy(p, s, l);
303 p += 20;
304
305 for (pos = 0; PyDict_Next(map, &pos, &k, &v); ) {
306 uint32_t mode, size, mtime;
307 Py_ssize_t len, l;
308 PyObject *o;
309 char *s, *t;
310 int err;
311
312 if (!PyTuple_Check(v) || PyTuple_GET_SIZE(v) != 4) {
313 PyErr_SetString(PyExc_TypeError, "expected a 4-tuple");
314 goto bail;
315 }
316 o = PyTuple_GET_ITEM(v, 0);
317 if (PyString_AsStringAndSize(o, &s, &l) == -1 || l != 1) {
318 PyErr_SetString(PyExc_TypeError, "expected one byte");
319 goto bail;
320 }
321 *p++ = *s;
322 err = getintat(v, 1, &mode);
323 err |= getintat(v, 2, &size);
324 err |= getintat(v, 3, &mtime);
325 if (err)
326 goto bail;
327 if (*s == 'n' && mtime == (uint32_t)now) {
328 /* See dirstate.py:write for why we do this. */
329 if (PyDict_SetItem(map, k, dirstate_unset) == -1)
330 goto bail;
331 mode = 0, size = -1, mtime = -1;
332 }
333 putbe32(mode, p);
334 putbe32(size, p + 4);
335 putbe32(mtime, p + 8);
336 t = p + 12;
337 p += 16;
338 len = PyString_GET_SIZE(k);
339 memcpy(p, PyString_AS_STRING(k), len);
340 p += len;
341 o = PyDict_GetItem(copymap, k);
342 if (o) {
343 *p++ = '\0';
344 l = PyString_GET_SIZE(o);
345 memcpy(p, PyString_AS_STRING(o), l);
346 p += l;
347 len += l + 1;
348 }
349 putbe32((uint32_t)len, t);
350 }
351
352 pos = p - PyString_AS_STRING(packobj);
353 if (pos != nbytes) {
354 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
355 (long)pos, (long)nbytes);
356 goto bail;
357 }
358
359 return packobj;
360 bail:
361 Py_XDECREF(packobj);
362 return NULL;
363 }
364
217 365 /*
218 366 * A base-16 trie for fast node->rev mapping.
219 367 *
@@ -1356,6 +1504,7 b' bail:'
1356 1504 static char parsers_doc[] = "Efficient content parsing.";
1357 1505
1358 1506 static PyMethodDef methods[] = {
1507 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
1359 1508 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
1360 1509 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
1361 1510 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
@@ -1375,6 +1524,8 b' static void module_init(PyObject *mod)'
1375 1524 -1, -1, -1, -1, nullid, 20);
1376 1525 if (nullentry)
1377 1526 PyObject_GC_UnTrack(nullentry);
1527
1528 dirstate_unset = Py_BuildValue("ciii", 'n', 0, -1, -1);
1378 1529 }
1379 1530
1380 1531 #ifdef IS_PY3K
General Comments 0
You need to be logged in to leave comments. Login now