mercurial/cext/revlog.c
changeset 47140 c55afa35a5c8
parent 47078 223b47235d1c
child 47141 ac72eee94035
equal deleted inserted replaced
47139:f58a13c52726 47140:c55afa35a5c8
    97 	int ntinitialized;      /* 0 or 1 */
    97 	int ntinitialized;      /* 0 or 1 */
    98 	int ntrev;              /* last rev scanned */
    98 	int ntrev;              /* last rev scanned */
    99 	int ntlookups;          /* # lookups */
    99 	int ntlookups;          /* # lookups */
   100 	int ntmisses;           /* # lookups that miss the cache */
   100 	int ntmisses;           /* # lookups that miss the cache */
   101 	int inlined;
   101 	int inlined;
   102 	long hdrsize; /* size of index headers. Differs in v1 v.s. v2 format */
   102 	long entry_size; /* size of index headers. Differs in v1 v.s. v2 format
       
   103 	                  */
   103 };
   104 };
   104 
   105 
   105 static Py_ssize_t index_length(const indexObject *self)
   106 static Py_ssize_t index_length(const indexObject *self)
   106 {
   107 {
   107 	return self->length + self->new_length;
   108 	return self->length + self->new_length;
   121 static const char *const v1_tuple_format = PY23("kiiiiiis#", "kiiiiiiy#");
   122 static const char *const v1_tuple_format = PY23("kiiiiiis#", "kiiiiiiy#");
   122 static const char *const v2_tuple_format = PY23("kiiiiiis#ki", "kiiiiiiy#ki");
   123 static const char *const v2_tuple_format = PY23("kiiiiiis#ki", "kiiiiiiy#ki");
   123 #endif
   124 #endif
   124 
   125 
   125 /* A RevlogNG v1 index entry is 64 bytes long. */
   126 /* A RevlogNG v1 index entry is 64 bytes long. */
   126 static const long v1_hdrsize = 64;
   127 static const long v1_entry_size = 64;
   127 
   128 
   128 /* A Revlogv2 index entry is 96 bytes long. */
   129 /* A Revlogv2 index entry is 96 bytes long. */
   129 static const long v2_hdrsize = 96;
   130 static const long v2_entry_size = 96;
   130 
   131 
   131 static void raise_revlog_error(void)
   132 static void raise_revlog_error(void)
   132 {
   133 {
   133 	PyObject *mod = NULL, *dict = NULL, *errclass = NULL;
   134 	PyObject *mod = NULL, *dict = NULL, *errclass = NULL;
   134 
   135 
   162  * Return a pointer to the beginning of a RevlogNG record.
   163  * Return a pointer to the beginning of a RevlogNG record.
   163  */
   164  */
   164 static const char *index_deref(indexObject *self, Py_ssize_t pos)
   165 static const char *index_deref(indexObject *self, Py_ssize_t pos)
   165 {
   166 {
   166 	if (pos >= self->length)
   167 	if (pos >= self->length)
   167 		return self->added + (pos - self->length) * self->hdrsize;
   168 		return self->added + (pos - self->length) * self->entry_size;
   168 
   169 
   169 	if (self->inlined && pos > 0) {
   170 	if (self->inlined && pos > 0) {
   170 		if (self->offsets == NULL) {
   171 		if (self->offsets == NULL) {
   171 			Py_ssize_t ret;
   172 			Py_ssize_t ret;
   172 			self->offsets =
   173 			self->offsets =
   179 			};
   180 			};
   180 		}
   181 		}
   181 		return self->offsets[pos];
   182 		return self->offsets[pos];
   182 	}
   183 	}
   183 
   184 
   184 	return (const char *)(self->buf.buf) + pos * self->hdrsize;
   185 	return (const char *)(self->buf.buf) + pos * self->entry_size;
   185 }
   186 }
   186 
   187 
   187 /*
   188 /*
   188  * Get parents of the given rev.
   189  * Get parents of the given rev.
   189  *
   190  *
   326 	link_rev = getbe32(data + 20);
   327 	link_rev = getbe32(data + 20);
   327 	parent_1 = getbe32(data + 24);
   328 	parent_1 = getbe32(data + 24);
   328 	parent_2 = getbe32(data + 28);
   329 	parent_2 = getbe32(data + 28);
   329 	c_node_id = data + 32;
   330 	c_node_id = data + 32;
   330 
   331 
   331 	if (self->hdrsize == v1_hdrsize) {
   332 	if (self->entry_size == v1_entry_size) {
   332 		return Py_BuildValue(v1_tuple_format, offset_flags, comp_len,
   333 		return Py_BuildValue(v1_tuple_format, offset_flags, comp_len,
   333 		                     uncomp_len, base_rev, link_rev, parent_1,
   334 		                     uncomp_len, base_rev, link_rev, parent_1,
   334 		                     parent_2, c_node_id, self->nodelen);
   335 		                     parent_2, c_node_id, self->nodelen);
   335 	} else {
   336 	} else {
   336 		sidedata_offset = getbe64(data + 64);
   337 		sidedata_offset = getbe64(data + 64);
   376 	data = index_deref(self, rev);
   377 	data = index_deref(self, rev);
   377 	if (data == NULL)
   378 	if (data == NULL)
   378 		return NULL;
   379 		return NULL;
   379 	if (rev == 0) {
   380 	if (rev == 0) {
   380 		/* the header is eating the start of the first entry */
   381 		/* the header is eating the start of the first entry */
   381 		return PyBytes_FromStringAndSize(data + 4, self->hdrsize - 4);
   382 		return PyBytes_FromStringAndSize(data + 4,
   382 	}
   383 		                                 self->entry_size - 4);
   383 	return PyBytes_FromStringAndSize(data, self->hdrsize);
   384 	}
       
   385 	return PyBytes_FromStringAndSize(data, self->entry_size);
   384 }
   386 }
   385 
   387 
   386 /*
   388 /*
   387  * Return the hash of node corresponding to the given rev.
   389  * Return the hash of node corresponding to the given rev.
   388  */
   390  */
   435 	int rev, comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
   437 	int rev, comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
   436 	Py_ssize_t c_node_id_len, sidedata_comp_len;
   438 	Py_ssize_t c_node_id_len, sidedata_comp_len;
   437 	const char *c_node_id;
   439 	const char *c_node_id;
   438 	char *data;
   440 	char *data;
   439 
   441 
   440 	if (self->hdrsize == v1_hdrsize) {
   442 	if (self->entry_size == v1_entry_size) {
   441 		if (!PyArg_ParseTuple(obj, v1_tuple_format, &offset_flags,
   443 		if (!PyArg_ParseTuple(obj, v1_tuple_format, &offset_flags,
   442 		                      &comp_len, &uncomp_len, &base_rev,
   444 		                      &comp_len, &uncomp_len, &base_rev,
   443 		                      &link_rev, &parent_1, &parent_2,
   445 		                      &link_rev, &parent_1, &parent_2,
   444 		                      &c_node_id, &c_node_id_len)) {
   446 		                      &c_node_id, &c_node_id_len)) {
   445 			PyErr_SetString(PyExc_TypeError, "8-tuple required");
   447 			PyErr_SetString(PyExc_TypeError, "8-tuple required");
   462 	}
   464 	}
   463 
   465 
   464 	if (self->new_length == self->added_length) {
   466 	if (self->new_length == self->added_length) {
   465 		size_t new_added_length =
   467 		size_t new_added_length =
   466 		    self->added_length ? self->added_length * 2 : 4096;
   468 		    self->added_length ? self->added_length * 2 : 4096;
   467 		void *new_added = PyMem_Realloc(self->added, new_added_length *
   469 		void *new_added = PyMem_Realloc(
   468 		                                                 self->hdrsize);
   470 		    self->added, new_added_length * self->entry_size);
   469 		if (!new_added)
   471 		if (!new_added)
   470 			return PyErr_NoMemory();
   472 			return PyErr_NoMemory();
   471 		self->added = new_added;
   473 		self->added = new_added;
   472 		self->added_length = new_added_length;
   474 		self->added_length = new_added_length;
   473 	}
   475 	}
   474 	rev = self->length + self->new_length;
   476 	rev = self->length + self->new_length;
   475 	data = self->added + self->hdrsize * self->new_length++;
   477 	data = self->added + self->entry_size * self->new_length++;
   476 	putbe32(offset_flags >> 32, data);
   478 	putbe32(offset_flags >> 32, data);
   477 	putbe32(offset_flags & 0xffffffffU, data + 4);
   479 	putbe32(offset_flags & 0xffffffffU, data + 4);
   478 	putbe32(comp_len, data + 8);
   480 	putbe32(comp_len, data + 8);
   479 	putbe32(uncomp_len, data + 12);
   481 	putbe32(uncomp_len, data + 12);
   480 	putbe32(base_rev, data + 16);
   482 	putbe32(base_rev, data + 16);
   482 	putbe32(parent_1, data + 24);
   484 	putbe32(parent_1, data + 24);
   483 	putbe32(parent_2, data + 28);
   485 	putbe32(parent_2, data + 28);
   484 	memcpy(data + 32, c_node_id, c_node_id_len);
   486 	memcpy(data + 32, c_node_id, c_node_id_len);
   485 	/* Padding since SHA-1 is only 20 bytes for now */
   487 	/* Padding since SHA-1 is only 20 bytes for now */
   486 	memset(data + 32 + c_node_id_len, 0, 32 - c_node_id_len);
   488 	memset(data + 32 + c_node_id_len, 0, 32 - c_node_id_len);
   487 	if (self->hdrsize != v1_hdrsize) {
   489 	if (self->entry_size != v1_entry_size) {
   488 		putbe64(sidedata_offset, data + 64);
   490 		putbe64(sidedata_offset, data + 64);
   489 		putbe32(sidedata_comp_len, data + 72);
   491 		putbe32(sidedata_comp_len, data + 72);
   490 		/* Padding for 96 bytes alignment */
   492 		/* Padding for 96 bytes alignment */
   491 		memset(data + 76, 0, self->hdrsize - 76);
   493 		memset(data + 76, 0, self->entry_size - 76);
   492 	}
   494 	}
   493 
   495 
   494 	if (self->ntinitialized)
   496 	if (self->ntinitialized)
   495 		nt_insert(&self->nt, c_node_id, rev);
   497 		nt_insert(&self->nt, c_node_id, rev);
   496 
   498 
   511 	const char *const sidedata_format = PY23("nKiK", "nKiK");
   513 	const char *const sidedata_format = PY23("nKiK", "nKiK");
   512 #else
   514 #else
   513 	const char *const sidedata_format = PY23("nkik", "nkik");
   515 	const char *const sidedata_format = PY23("nkik", "nkik");
   514 #endif
   516 #endif
   515 
   517 
   516 	if (self->hdrsize == v1_hdrsize || self->inlined) {
   518 	if (self->entry_size == v1_entry_size || self->inlined) {
   517 		/*
   519 		/*
   518 		 There is a bug in the transaction handling when going from an
   520 		 There is a bug in the transaction handling when going from an
   519 	   inline revlog to a separate index and data file. Turn it off until
   521 	   inline revlog to a separate index and data file. Turn it off until
   520 	   it's fixed, since v2 revlogs sometimes get rewritten on exchange.
   522 	   it's fixed, since v2 revlogs sometimes get rewritten on exchange.
   521 	   See issue6485.
   523 	   See issue6485.
   539 		return NULL;
   541 		return NULL;
   540 	}
   542 	}
   541 
   543 
   542 	/* Find the newly added node, offset from the "already on-disk" length
   544 	/* Find the newly added node, offset from the "already on-disk" length
   543 	 */
   545 	 */
   544 	data = self->added + self->hdrsize * (rev - self->length);
   546 	data = self->added + self->entry_size * (rev - self->length);
   545 	putbe64(offset_flags, data);
   547 	putbe64(offset_flags, data);
   546 	putbe64(sidedata_offset, data + 64);
   548 	putbe64(sidedata_offset, data + 64);
   547 	putbe32(sidedata_comp_len, data + 72);
   549 	putbe32(sidedata_comp_len, data + 72);
   548 
   550 
   549 	Py_RETURN_NONE;
   551 	Py_RETURN_NONE;
  2690 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
  2692 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
  2691 {
  2693 {
  2692 	const char *data = (const char *)self->buf.buf;
  2694 	const char *data = (const char *)self->buf.buf;
  2693 	Py_ssize_t pos = 0;
  2695 	Py_ssize_t pos = 0;
  2694 	Py_ssize_t end = self->buf.len;
  2696 	Py_ssize_t end = self->buf.len;
  2695 	long incr = self->hdrsize;
  2697 	long incr = self->entry_size;
  2696 	Py_ssize_t len = 0;
  2698 	Py_ssize_t len = 0;
  2697 
  2699 
  2698 	while (pos + self->hdrsize <= end && pos >= 0) {
  2700 	while (pos + self->entry_size <= end && pos >= 0) {
  2699 		uint32_t comp_len, sidedata_comp_len = 0;
  2701 		uint32_t comp_len, sidedata_comp_len = 0;
  2700 		/* 3rd element of header is length of compressed inline data */
  2702 		/* 3rd element of header is length of compressed inline data */
  2701 		comp_len = getbe32(data + pos + 8);
  2703 		comp_len = getbe32(data + pos + 8);
  2702 		if (self->hdrsize == v2_hdrsize) {
  2704 		if (self->entry_size == v2_entry_size) {
  2703 			sidedata_comp_len = getbe32(data + pos + 72);
  2705 			sidedata_comp_len = getbe32(data + pos + 72);
  2704 		}
  2706 		}
  2705 		incr = self->hdrsize + comp_len + sidedata_comp_len;
  2707 		incr = self->entry_size + comp_len + sidedata_comp_len;
  2706 		if (offsets)
  2708 		if (offsets)
  2707 			offsets[len] = data + pos;
  2709 			offsets[len] = data + pos;
  2708 		len++;
  2710 		len++;
  2709 		pos += incr;
  2711 		pos += incr;
  2710 	}
  2712 	}
  2753 		PyErr_SetString(PyExc_RuntimeError, "unsupported node size");
  2755 		PyErr_SetString(PyExc_RuntimeError, "unsupported node size");
  2754 		return -1;
  2756 		return -1;
  2755 	}
  2757 	}
  2756 
  2758 
  2757 	if (revlogv2 && PyObject_IsTrue(revlogv2)) {
  2759 	if (revlogv2 && PyObject_IsTrue(revlogv2)) {
  2758 		self->hdrsize = v2_hdrsize;
  2760 		self->entry_size = v2_entry_size;
  2759 	} else {
  2761 	} else {
  2760 		self->hdrsize = v1_hdrsize;
  2762 		self->entry_size = v1_entry_size;
  2761 	}
  2763 	}
  2762 
  2764 
  2763 	if (self->hdrsize == v1_hdrsize) {
  2765 	if (self->entry_size == v1_entry_size) {
  2764 		self->nullentry =
  2766 		self->nullentry =
  2765 		    Py_BuildValue(PY23("iiiiiiis#", "iiiiiiiy#"), 0, 0, 0, -1,
  2767 		    Py_BuildValue(PY23("iiiiiiis#", "iiiiiiiy#"), 0, 0, 0, -1,
  2766 		                  -1, -1, -1, nullid, self->nodelen);
  2768 		                  -1, -1, -1, nullid, self->nodelen);
  2767 	} else {
  2769 	} else {
  2768 		self->nullentry =
  2770 		self->nullentry =
  2789 		Py_ssize_t len = inline_scan(self, NULL);
  2791 		Py_ssize_t len = inline_scan(self, NULL);
  2790 		if (len == -1)
  2792 		if (len == -1)
  2791 			goto bail;
  2793 			goto bail;
  2792 		self->length = len;
  2794 		self->length = len;
  2793 	} else {
  2795 	} else {
  2794 		if (size % self->hdrsize) {
  2796 		if (size % self->entry_size) {
  2795 			PyErr_SetString(PyExc_ValueError, "corrupt index file");
  2797 			PyErr_SetString(PyExc_ValueError, "corrupt index file");
  2796 			goto bail;
  2798 			goto bail;
  2797 		}
  2799 		}
  2798 		self->length = size / self->hdrsize;
  2800 		self->length = size / self->entry_size;
  2799 	}
  2801 	}
  2800 
  2802 
  2801 	return 0;
  2803 	return 0;
  2802 bail:
  2804 bail:
  2803 	return -1;
  2805 	return -1;
  2911     {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
  2913     {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
  2912     {NULL} /* Sentinel */
  2914     {NULL} /* Sentinel */
  2913 };
  2915 };
  2914 
  2916 
  2915 static PyMemberDef index_members[] = {
  2917 static PyMemberDef index_members[] = {
  2916     {"entry_size", T_LONG, offsetof(indexObject, hdrsize), 0,
  2918     {"entry_size", T_LONG, offsetof(indexObject, entry_size), 0,
  2917      "size of an index entry"},
  2919      "size of an index entry"},
  2918     {NULL} /* Sentinel */
  2920     {NULL} /* Sentinel */
  2919 };
  2921 };
  2920 
  2922 
  2921 PyTypeObject HgRevlogIndex_Type = {
  2923 PyTypeObject HgRevlogIndex_Type = {