This is an archive of the discontinued Mercurial Phabricator instance.

index: embed nodetree in index object to avoid reference cycle
ClosedPublic

Authored by martinvonz on Aug 24 2018, 12:23 PM.

Details

Summary

Since the index has a reference to a nodetree and the nodetree has a
reference back to the index, there is a reference cycle, so the index
(and its nodetree) can never be freed. This patch fixes that by making
"nodetree" a plan C struct that the index can embed, and also
introduces a new "nodetreeObject" that is a Python type wrapping the
nodetree struct.

Thanks to Yuya for noticing this and for suggesting the solution.

All tests passed on the first attempt once it compiled (I guess C is
like Haskell in this regard?).

Diff Detail

Repository
rHG Mercurial
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.

Event Timeline

martinvonz created this revision.Aug 24 2018, 12:23 PM
yuja added a subscriber: yuja.Aug 25 2018, 5:35 AM

-static int nt_init_py(nodetree *self, PyObject *args)
+static int ntobj_init(nodetreeObject *self, PyObject *args)
{

	PyObject *index;
	unsigned capacity;

+ int ret;

	if (!PyArg_ParseTuple(args, "O!I", &indexType, &index, &capacity))
		return -1;
  • return nt_init(self, (indexObject*)index, capacity);

+ ret = nt_init(&self->nt, (indexObject*)index, capacity);
+ if (ret == 0) {
+ Py_INCREF(index);
+ }

Perhaps index should be increfed no matter if nt_init() succeeds or not,
since the self is ntobj_dealloc()-ed anyway.

martinvonz updated this revision to Diff 10601.Aug 27 2018, 1:12 PM
In D4372#67157, @yuja wrote:

-static int nt_init_py(nodetree *self, PyObject *args)
+static int ntobj_init(nodetreeObject *self, PyObject *args)
{

	PyObject *index;
	unsigned capacity;

+ int ret;

	if (!PyArg_ParseTuple(args, "O!I", &indexType, &index, &capacity))
		return -1;
  • return nt_init(self, (indexObject*)index, capacity);

+ ret = nt_init(&self->nt, (indexObject*)index, capacity);
+ if (ret == 0) {
+ Py_INCREF(index);
+ }

Perhaps index should be increfed no matter if nt_init() succeeds or not,
since the self is ntobj_dealloc()-ed anyway.

Good catch. Fixed.

This revision was automatically updated to reflect the committed changes.

I haven't had time to dig into this, but I bisected a hard crash back to here on Windows.

--- c:/Users/Matt/projects/hg/tests/test-revisions.t
+++ c:/Users/Matt/projects/hg/tests/test-revisions.t.err
@@ -40,6 +40,6 @@
   [255]
 7b is no longer ambiguous
   $ hg l -r 7b
-  3:7b
+  [5]

   $ cd ..

@ has an earlier failure too, so possibly it's random-ish.

--- c:/Users/Matt/projects/hg/tests/test-revisions.t
+++ c:/Users/Matt/projects/hg/tests/test-revisions.t.err
@@ -31,6 +31,7 @@
   2:72
   1:9
   0:b
+  [5]
 9 was unambiguous and still is
   $ hg l -r 9
   1:9
@@ -40,6 +41,6 @@
   [255]
 7b is no longer ambiguous
   $ hg l -r 7b
-  3:7b
+  [5]

   $ cd ..