revlog: only build the nodemap on demand

This commit is contained in:
Matt Mackall 2011-01-11 17:01:04 -06:00
parent efaaee2894
commit 846d35e24f
4 changed files with 39 additions and 66 deletions

View File

@ -81,8 +81,9 @@ def perfmanifest(ui, repo):
def perfindex(ui, repo):
import mercurial.changelog
n = repo["tip"].node()
def d():
t = repo.changelog.tip()
repo[n]
repo.invalidate()
timer(d)

View File

@ -244,41 +244,6 @@ quit:
const char nullid[20];
const int nullrev = -1;
/* create an index tuple, insert into the nodemap */
static PyObject * _build_idx_entry(PyObject *nodemap, int n, uint64_t offset_flags,
int comp_len, int uncomp_len, int base_rev,
int link_rev, int parent_1, int parent_2,
const char *c_node_id)
{
int err;
PyObject *entry, *node_id, *n_obj;
node_id = PyBytes_FromStringAndSize(c_node_id, 20);
n_obj = PyInt_FromLong(n);
if (!node_id || !n_obj)
err = -1;
else
err = PyDict_SetItem(nodemap, node_id, n_obj);
Py_XDECREF(n_obj);
if (err)
goto error_dealloc;
entry = Py_BuildValue("LiiiiiiN", offset_flags, comp_len,
uncomp_len, base_rev, link_rev,
parent_1, parent_2, node_id);
if (!entry)
goto error_dealloc;
PyObject_GC_UnTrack(entry); /* don't waste time with this */
return entry;
error_dealloc:
Py_XDECREF(node_id);
return NULL;
}
/* RevlogNG format (all in big endian, data may be inlined):
* 6 bytes: offset
* 2 bytes: flags
@ -290,8 +255,8 @@ error_dealloc:
* 4 bytes: parent 2 revision
* 32 bytes: nodeid (only 20 bytes used)
*/
static int _parse_index_ng (const char *data, int size, int inlined,
PyObject *index, PyObject *nodemap)
static int _parse_index_ng(const char *data, int size, int inlined,
PyObject *index)
{
PyObject *entry;
int n = 0, err;
@ -321,13 +286,15 @@ static int _parse_index_ng (const char *data, int size, int inlined,
parent_2 = ntohl(*((uint32_t *)(decode + 28)));
c_node_id = decode + 32;
entry = _build_idx_entry(nodemap, n, offset_flags,
comp_len, uncomp_len, base_rev,
link_rev, parent_1, parent_2,
c_node_id);
entry = Py_BuildValue("Liiiiiis#", offset_flags, comp_len,
uncomp_len, base_rev, link_rev,
parent_1, parent_2, c_node_id, 20);
if (!entry)
return 0;
PyObject_GC_UnTrack(entry); /* don't waste time with this */
if (inlined) {
err = PyList_Append(index, entry);
Py_DECREF(entry);
@ -348,12 +315,14 @@ static int _parse_index_ng (const char *data, int size, int inlined,
return 0;
}
/* create the nullid/nullrev entry in the nodemap and the
* magic nullid entry in the index at [-1] */
entry = _build_idx_entry(nodemap,
nullrev, 0, 0, 0, -1, -1, -1, -1, nullid);
/* create the magic nullid entry in the index at [-1] */
entry = Py_BuildValue("Liiiiiis#", (uint64_t)0, 0, 0, -1, -1, -1, -1, nullid, 20);
if (!entry)
return 0;
PyObject_GC_UnTrack(entry); /* don't waste time with this */
if (inlined) {
err = PyList_Append(index, entry);
Py_DECREF(entry);
@ -366,17 +335,16 @@ static int _parse_index_ng (const char *data, int size, int inlined,
}
/* This function parses a index file and returns a Python tuple of the
* following format: (index, nodemap, cache)
* following format: (index, cache)
*
* index: a list of tuples containing the RevlogNG records
* nodemap: a dict mapping node ids to indices in the index list
* cache: if data is inlined, a tuple (index_file_content, 0) else None
*/
static PyObject *parse_index(PyObject *self, PyObject *args)
static PyObject *parse_index2(PyObject *self, PyObject *args)
{
const char *data;
int size, inlined;
PyObject *rval = NULL, *index = NULL, *nodemap = NULL, *cache = NULL;
PyObject *rval = NULL, *index = NULL, *cache = NULL;
PyObject *data_obj = NULL, *inlined_obj;
if (!PyArg_ParseTuple(args, "s#O", &data, &size, &inlined_obj))
@ -390,10 +358,6 @@ static PyObject *parse_index(PyObject *self, PyObject *args)
if (!index)
goto quit;
nodemap = PyDict_New();
if (!nodemap)
goto quit;
/* set up the cache return value */
if (inlined) {
/* Note that the reference to data_obj is only borrowed */
@ -406,18 +370,17 @@ static PyObject *parse_index(PyObject *self, PyObject *args)
Py_INCREF(Py_None);
}
/* actually populate the index and the nodemap with data */
if (!_parse_index_ng (data, size, inlined, index, nodemap))
/* actually populate the index with data */
if (!_parse_index_ng(data, size, inlined, index))
goto quit;
rval = Py_BuildValue("NNN", index, nodemap, cache);
rval = Py_BuildValue("NN", index, cache);
if (!rval)
goto quit;
return rval;
quit:
Py_XDECREF(index);
Py_XDECREF(nodemap);
Py_XDECREF(cache);
Py_XDECREF(rval);
return NULL;
@ -429,7 +392,7 @@ static char parsers_doc[] = "Efficient content parsing.";
static PyMethodDef methods[] = {
{"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
{"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
{"parse_index", parse_index, METH_VARARGS, "parse a revlog index\n"},
{"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
{NULL, NULL}
};

View File

@ -172,8 +172,8 @@ class revlogio(object):
def parseindex(self, fp, data, inline):
# call the C implementation to parse the index data
index, nodemap, cache = parsers.parse_index(data, inline)
return index, nodemap, cache
index, cache = parsers.parse_index2(data, inline)
return index, None, cache
def packentry(self, entry, node, version, rev):
p = _pack(indexformatng, *entry)
@ -218,7 +218,6 @@ class revlog(object):
self.opener = opener
self._cache = None
self._chunkcache = (0, '')
self.nodemap = {nullid: nullrev}
self.index = []
self._shallowroot = shallowroot
self._parentdelta = 0
@ -267,7 +266,9 @@ class revlog(object):
d = self._io.parseindex(f, i, self._inline)
except (ValueError, IndexError):
raise RevlogError(_("index %s is corrupted") % (self.indexfile))
self.index, self.nodemap, self._chunkcache = d
self.index, n, self._chunkcache = d
if n:
self.nodemap = n
if not self._chunkcache:
self._chunkclear()
@ -275,6 +276,14 @@ class revlog(object):
if self.index == [] or self.index[-1][7] != nullid:
self.index.append((0, 0, 0, -1, -1, -1, -1, nullid))
@util.propertycache
def nodemap(self):
n = {nullid: nullrev}
i = self.index
for r in xrange(len(i) - 1):
n[i[r][7]] = r
return n
def tip(self):
return self.node(len(self.index) - 2)
def __len__(self):

View File

@ -50,7 +50,7 @@ def py_parseindex(data, inline) :
# add the magic null revision at -1
index.append((0, 0, 0, -1, -1, -1, -1, nullid))
return index, nodemap, cache
return index, cache
data_inlined = '\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x01\x8c' \
@ -97,10 +97,10 @@ data_non_inlined = '\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01D\x19' \
def runtest() :
py_res_1 = py_parseindex(data_inlined, True)
c_res_1 = parsers.parse_index(data_inlined, True)
c_res_1 = parsers.parse_index2(data_inlined, True)
py_res_2 = py_parseindex(data_non_inlined, False)
c_res_2 = parsers.parse_index(data_non_inlined, False)
c_res_2 = parsers.parse_index2(data_non_inlined, False)
if py_res_1 != c_res_1:
print "Parse index result (with inlined data) differs!"