##// END OF EJS Templates
tests: add test-remotefilelog-strip.t to demonstrate an issue with linknodes...
tests: add test-remotefilelog-strip.t to demonstrate an issue with linknodes ### Background Every time a commit is modified, remotefilelog updates the metadata for the file object to point to the new commit (I believe that this is different from non-remotefilelog hg, which leaves the linkrevs pointing to the obsolete commits; doing otherwise would involve changing data in the middle of revlogs). With `hg strip` (or other things that use repair.strip()), when you strip a commit that's not the tip of the revlog, there may be commits after it in revnum order that aren't descended from it and don't need to be (and shouldn't be) stripped. These are "saved" by strip in a bundle, and that bundle is reapplied after truncating the relevant revlogs. ### The problem Remotefilelog generally avoids being involved at all in strip. Currently, that includes even providing file contents to this backup bundle. This can cause the linknode to point to a changeset that is no longer in the repository. Example: ``` @ 3 df91f74b871e | | x 2 70494d7ec5ef |/ | x 1 1e423846dde0 |/ o 0 b292c1e3311f ``` Commits 1, 2, and 3 are related via obsolescence, and are description-only changes. The linknode for the file in these commits changed each time we updated the description, so it's currently df91f7. If I strip commits 1 and 3, however, the linknode *remains* df91f7, which no longer exists in the repository. Commit 70494d was "saved", stripped, and then reapplied, so it is in the repository (as revision 1 instead of 2 now), and was unobsoleted since the obsmarker was stripped as well. The linknode for the file should point to 70494d, the most recent commit that is in the repository that modified the file. Remotefilelog has some logic to handle broken linknodes, but it can be slow. We have actually disabled it internally because it's too slow for our purposes. Differential Revision: https://phab.mercurial-scm.org/D10319

File last commit:

r40634:fa331960 default
r47605:2819df46 default
Show More
util.h
74 lines | 2.0 KiB | text/x-c | CLexer
/*
util.h - utility functions for interfacing with the various python APIs.
This software may be used and distributed according to the terms of
the GNU General Public License, incorporated herein by reference.
*/
#ifndef _HG_UTIL_H_
#define _HG_UTIL_H_
#include "compat.h"
#if PY_MAJOR_VERSION >= 3
#define IS_PY3K
#endif
/* helper to switch things like string literal depending on Python version */
#ifdef IS_PY3K
#define PY23(py2, py3) py3
#else
#define PY23(py2, py3) py2
#endif
/* clang-format off */
typedef struct {
PyObject_HEAD
char state;
int mode;
int size;
int mtime;
} dirstateTupleObject;
/* clang-format on */
extern PyTypeObject dirstateTupleType;
#define dirstate_tuple_check(op) (Py_TYPE(op) == &dirstateTupleType)
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
/* VC9 doesn't include bool and lacks stdbool.h based on my searching */
#if defined(_MSC_VER) || __STDC_VERSION__ < 199901L
#define true 1
#define false 0
typedef unsigned char bool;
#else
#include <stdbool.h>
#endif
static inline PyObject *_dict_new_presized(Py_ssize_t expected_size)
{
/* _PyDict_NewPresized expects a minused parameter, but it actually
creates a dictionary that's the nearest power of two bigger than the
parameter. For example, with the initial minused = 1000, the
dictionary created has size 1024. Of course in a lot of cases that
can be greater than the maximum load factor Python's dict object
expects (= 2/3), so as soon as we cross the threshold we'll resize
anyway. So create a dictionary that's at least 3/2 the size. */
return _PyDict_NewPresized(((1 + expected_size) / 2) * 3);
}
/* Convert a PyInt or PyLong to a long. Returns false if there is an
error, in which case an exception will already have been set. */
static inline bool pylong_to_long(PyObject *pylong, long *out)
{
*out = PyLong_AsLong(pylong);
/* Fast path to avoid hitting PyErr_Occurred if the value was obviously
* not an error. */
if (*out != -1) {
return true;
}
return PyErr_Occurred() == NULL;
}
#endif /* _HG_UTIL_H_ */