Details
Details
- Reviewers
- None
- Group Reviewers
hg-reviewers - Commits
- rHGf28e64bbdd29: index: drop now-redundant "nt" prefix of fields in nodetree struct
Diff Detail
Diff Detail
- Repository
- rHG Mercurial
- Lint
Lint Skipped - Unit
Unit Tests Skipped
( )
| hg-reviewers |
| Lint Skipped |
| Unit Tests Skipped |
| Path | Packages | |||
|---|---|---|---|---|
| M | mercurial/cext/revlog.c (46 lines) |
| Commit | Parents | Author | Summary | Date |
|---|---|---|---|---|
| Martin von Zweigbergk | May 16 2018, 4:57 PM |
| Status | Author | Revision | |
|---|---|---|---|
| Closed | martinvonz | ||
| Closed | martinvonz | ||
| Closed | martinvonz | ||
| Closed | martinvonz | ||
| Closed | martinvonz |
| * A base-16 trie for fast node->rev mapping. | * A base-16 trie for fast node->rev mapping. | ||||
| * | * | ||||
| * Positive value is index of the next node in the trie | * Positive value is index of the next node in the trie | ||||
| * Negative value is a leaf: -(rev + 2) | * Negative value is a leaf: -(rev + 2) | ||||
| * Zero is empty | * Zero is empty | ||||
| */ | */ | ||||
| typedef struct { | typedef struct { | ||||
| nodetreenode *nodes; | nodetreenode *nodes; | ||||
| unsigned ntlength; /* # nodes in use */ | unsigned length; /* # nodes in use */ | ||||
| unsigned ntcapacity; /* # nodes allocated */ | unsigned capacity; /* # nodes allocated */ | ||||
| int ntdepth; /* maximum depth of tree */ | int depth; /* maximum depth of tree */ | ||||
| int ntsplits; /* # splits performed */ | int splits; /* # splits performed */ | ||||
| } nodetree; | } nodetree; | ||||
| /* | /* | ||||
| * This class has two behaviors. | * This class has two behaviors. | ||||
| * | * | ||||
| * When used in a list-like way (with integer keys), we decode an | * When used in a list-like way (with integer keys), we decode an | ||||
| * entry in a RevlogNG index file on demand. Our last entry is a | * entry in a RevlogNG index file on demand. Our last entry is a | ||||
| * sentinel, always a nullid. We have limited support for | * sentinel, always a nullid. We have limited support for | ||||
| if (self->raw_length != self->length - 1) | if (self->raw_length != self->length - 1) | ||||
| istat(raw_length, "revs on disk"); | istat(raw_length, "revs on disk"); | ||||
| istat(length, "revs in memory"); | istat(length, "revs in memory"); | ||||
| istat(ntlookups, "node trie lookups"); | istat(ntlookups, "node trie lookups"); | ||||
| istat(ntmisses, "node trie misses"); | istat(ntmisses, "node trie misses"); | ||||
| istat(ntrev, "node trie last rev scanned"); | istat(ntrev, "node trie last rev scanned"); | ||||
| if (self->nt) { | if (self->nt) { | ||||
| istat(nt->ntcapacity, "node trie capacity"); | istat(nt->capacity, "node trie capacity"); | ||||
| istat(nt->ntdepth, "node trie depth"); | istat(nt->depth, "node trie depth"); | ||||
| istat(nt->ntlength, "node trie count"); | istat(nt->length, "node trie count"); | ||||
| istat(nt->ntsplits, "node trie splits"); | istat(nt->splits, "node trie splits"); | ||||
| } | } | ||||
| #undef istat | #undef istat | ||||
| return obj; | return obj; | ||||
| bail: | bail: | ||||
| Py_XDECREF(obj); | Py_XDECREF(obj); | ||||
| } | } | ||||
| /* multiple matches against an ambiguous prefix */ | /* multiple matches against an ambiguous prefix */ | ||||
| return -4; | return -4; | ||||
| } | } | ||||
| static int nt_new(indexObject *self) | static int nt_new(indexObject *self) | ||||
| { | { | ||||
| nodetree *nt = self->nt; | nodetree *nt = self->nt; | ||||
| if (nt->ntlength == nt->ntcapacity) { | if (nt->length == nt->capacity) { | ||||
| if (nt->ntcapacity >= INT_MAX / (sizeof(nodetreenode) * 2)) { | if (nt->capacity >= INT_MAX / (sizeof(nodetreenode) * 2)) { | ||||
| PyErr_SetString(PyExc_MemoryError, | PyErr_SetString(PyExc_MemoryError, | ||||
| "overflow in nt_new"); | "overflow in nt_new"); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| nt->ntcapacity *= 2; | nt->capacity *= 2; | ||||
| nt->nodes = realloc(nt->nodes, | nt->nodes = realloc(nt->nodes, | ||||
| nt->ntcapacity * sizeof(nodetreenode)); | nt->capacity * sizeof(nodetreenode)); | ||||
| if (nt->nodes == NULL) { | if (nt->nodes == NULL) { | ||||
| PyErr_SetString(PyExc_MemoryError, "out of memory"); | PyErr_SetString(PyExc_MemoryError, "out of memory"); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| memset(&nt->nodes[nt->ntlength], 0, | memset(&nt->nodes[nt->length], 0, | ||||
| sizeof(nodetreenode) * (nt->ntcapacity - nt->ntlength)); | sizeof(nodetreenode) * (nt->capacity - nt->length)); | ||||
| } | } | ||||
| return nt->ntlength++; | return nt->length++; | ||||
| } | } | ||||
| static int nt_insert(indexObject *self, const char *node, int rev) | static int nt_insert(indexObject *self, const char *node, int rev) | ||||
| { | { | ||||
| int level = 0; | int level = 0; | ||||
| int off = 0; | int off = 0; | ||||
| while (level < 40) { | while (level < 40) { | ||||
| noff = nt_new(self); | noff = nt_new(self); | ||||
| if (noff == -1) | if (noff == -1) | ||||
| return -1; | return -1; | ||||
| /* self->nt->nodes may have been changed by realloc */ | /* self->nt->nodes may have been changed by realloc */ | ||||
| self->nt->nodes[off].children[k] = noff; | self->nt->nodes[off].children[k] = noff; | ||||
| off = noff; | off = noff; | ||||
| n = &self->nt->nodes[off]; | n = &self->nt->nodes[off]; | ||||
| n->children[nt_level(oldnode, ++level)] = v; | n->children[nt_level(oldnode, ++level)] = v; | ||||
| if (level > self->nt->ntdepth) | if (level > self->nt->depth) | ||||
| self->nt->ntdepth = level; | self->nt->depth = level; | ||||
| self->nt->ntsplits += 1; | self->nt->splits += 1; | ||||
| } else { | } else { | ||||
| level += 1; | level += 1; | ||||
| off = v; | off = v; | ||||
| } | } | ||||
| } | } | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| if (self->nt == NULL) { | if (self->nt == NULL) { | ||||
| PyErr_NoMemory(); | PyErr_NoMemory(); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| if ((size_t)self->raw_length > INT_MAX / sizeof(nodetreenode)) { | if ((size_t)self->raw_length > INT_MAX / sizeof(nodetreenode)) { | ||||
| PyErr_SetString(PyExc_ValueError, "overflow in nt_init"); | PyErr_SetString(PyExc_ValueError, "overflow in nt_init"); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| self->nt->ntcapacity = self->raw_length < 4 | self->nt->capacity = self->raw_length < 4 | ||||
| ? 4 : (int)self->raw_length / 2; | ? 4 : (int)self->raw_length / 2; | ||||
| self->nt->nodes = calloc(self->nt->ntcapacity, sizeof(nodetreenode)); | self->nt->nodes = calloc(self->nt->capacity, sizeof(nodetreenode)); | ||||
| if (self->nt->nodes == NULL) { | if (self->nt->nodes == NULL) { | ||||
| free(self->nt); | free(self->nt); | ||||
| self->nt = NULL; | self->nt = NULL; | ||||
| PyErr_NoMemory(); | PyErr_NoMemory(); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| self->ntrev = (int)index_length(self); | self->ntrev = (int)index_length(self); | ||||
| self->ntlookups = 1; | self->ntlookups = 1; | ||||
| self->ntmisses = 0; | self->ntmisses = 0; | ||||
| self->nt->ntdepth = 0; | self->nt->depth = 0; | ||||
| self->nt->ntsplits = 0; | self->nt->splits = 0; | ||||
| self->nt->ntlength = 1; | self->nt->length = 1; | ||||
| if (nt_insert(self, nullid, -1) == -1) { | if (nt_insert(self, nullid, -1) == -1) { | ||||
| free(self->nt->nodes); | free(self->nt->nodes); | ||||
| free(self->nt); | free(self->nt); | ||||
| self->nt = NULL; | self->nt = NULL; | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| } | } | ||||
| return 0; | return 0; | ||||