##// END OF EJS Templates
exchangev2: fetch manifest revisions...
exchangev2: fetch manifest revisions Now that the server has support for retrieving manifest data, we can implement the client bits to call it. We teach the changeset fetching code to capture the manifest revisions that are encountered on incoming changesets. We then feed this into a new function which filters out known manifests and then batches up manifest data requests to the server. This is different from the previous wire protocol in a few notable ways. First, the client fetches manifest data separately and explicitly. Before, we'd ask the server for data pertaining to some changesets (via a "getbundle" command) and manifests (and files) would be sent automatically. Providing an API for looking up just manifest data separately gives clients much more flexibility for manifest management. For example, a client may choose to only fetch manifest data on demand instead of prefetching it (i.e. partial clone). Second, we send N commands to the server for manifest retrieval instead of 1. This property has a few nice side-effects. One is that the deterministic nature of the requests lends itself to server-side caching. For example, say the remote has 50,000 manifests. If the server is configured to cache responses, each time a new commit arrives, you will have a cache miss and need to regenerate all outgoing data. But if you makes N requests requesting 10,000 manifests each, a new commit will still yield cache hits on the initial, unchanged manifest batches/requests. A derived benefit from these properties is that resumable clone is conceptually simpler to implement. When making a monolithic request for all of the repository data, recovering from an interrupted clone is hard because the server was in the driver's seat and was maintaining state about all the data that needed transferred. With the client driving fetching, the client can persist the set of unfetched entities and retry/resume a fetch if something goes wrong. Or we can fetch all data N changesets at a time and slowly build up a repository. This approach is drastically easier to implement when we have server APIs exposing low-level repository primitives (such as manifests and files). We don't yet support tree manifests. But it should be possible to implement that with the existing wire protocol command. Differential Revision: https://phab.mercurial-scm.org/D4489

File last commit:

r34637:31c6c4d2 default
r39674:d292328e default
Show More
exewrapper.c
159 lines | 3.9 KiB | text/x-c | CLexer
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 /*
exewrapper.c - wrapper for calling a python script on Windows
Copyright 2012 Adrian Buehlmann <adrian@cadifra.com> and others
This software may be used and distributed according to the terms of the
GNU General Public License version 2 or any later version.
*/
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 #include <stdio.h>
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 #include <windows.h>
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 #include "hgpythonlib.h"
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058
#ifdef __GNUC__
int strcat_s(char *d, size_t n, const char *s)
{
return !strncat(d, s, n);
}
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 int strcpy_s(char *d, size_t n, const char *s)
{
return !strncpy(d, s, n);
}
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 #endif
static char pyscript[MAX_PATH + 10];
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 static char pyhome[MAX_PATH + 10];
static char envpyhome[MAX_PATH + 10];
static char pydllfile[MAX_PATH + 10];
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058
int main(int argc, char *argv[])
{
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 char *p;
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 int ret;
int i;
int n;
char **pyargv;
WIN32_FIND_DATA fdata;
HANDLE hfind;
const char *err;
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 HMODULE pydll;
Augie Fackler
exewrapper: format with clang-format...
r34637 void(__cdecl * Py_SetPythonHome)(char *home);
int(__cdecl * Py_Main)(int argc, char *argv[]);
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058
Augie Fackler
exewrapper: format with clang-format...
r34637 if (GetModuleFileName(NULL, pyscript, sizeof(pyscript)) == 0) {
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 err = "GetModuleFileName failed";
goto bail;
}
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 p = strrchr(pyscript, '.');
if (p == NULL) {
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 err = "malformed module filename";
goto bail;
}
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 *p = 0; /* cut trailing ".exe" */
strcpy_s(pyhome, sizeof(pyhome), pyscript);
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058
hfind = FindFirstFile(pyscript, &fdata);
if (hfind != INVALID_HANDLE_VALUE) {
/* pyscript exists, close handle */
FindClose(hfind);
} else {
/* file pyscript isn't there, take <pyscript>exe.py */
strcat_s(pyscript, sizeof(pyscript), "exe.py");
}
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 pydll = NULL;
Kostia Balytskyi
exewrapper: prefer HackableMercurial python if availbale...
r31443
p = strrchr(pyhome, '\\');
if (p == NULL) {
err = "can't find backslash in module filename";
goto bail;
}
*p = 0; /* cut at directory */
/* check for private Python of HackableMercurial */
strcat_s(pyhome, sizeof(pyhome), "\\hg-python");
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732
Kostia Balytskyi
exewrapper: prefer HackableMercurial python if availbale...
r31443 hfind = FindFirstFile(pyhome, &fdata);
if (hfind != INVALID_HANDLE_VALUE) {
/* Path .\hg-python exists. We are probably in HackableMercurial
scenario, so let's load python dll from this dir. */
FindClose(hfind);
strcpy_s(pydllfile, sizeof(pydllfile), pyhome);
strcat_s(pydllfile, sizeof(pydllfile), "\\" HGPYTHONLIB ".dll");
pydll = LoadLibrary(pydllfile);
if (pydll == NULL) {
Augie Fackler
exewrapper: format with clang-format...
r34637 err = "failed to load private Python DLL " HGPYTHONLIB
".dll";
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 goto bail;
}
Augie Fackler
exewrapper: format with clang-format...
r34637 Py_SetPythonHome =
(void *)GetProcAddress(pydll, "Py_SetPythonHome");
Kostia Balytskyi
exewrapper: prefer HackableMercurial python if availbale...
r31443 if (Py_SetPythonHome == NULL) {
err = "failed to get Py_SetPythonHome";
goto bail;
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 }
Kostia Balytskyi
exewrapper: prefer HackableMercurial python if availbale...
r31443 Py_SetPythonHome(pyhome);
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 }
if (pydll == NULL) {
Gregory Szorc
exewrapper: add .dll to LoadLibrary() argument...
r29019 pydll = LoadLibrary(HGPYTHONLIB ".dll");
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 if (pydll == NULL) {
Adrian Buehlmann
exewrapper: report name of failed DLL in error message...
r26662 err = "failed to load Python DLL " HGPYTHONLIB ".dll";
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 goto bail;
}
}
Augie Fackler
exewrapper: format with clang-format...
r34637 Py_Main = (void *)GetProcAddress(pydll, "Py_Main");
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 if (Py_Main == NULL) {
err = "failed to get Py_Main";
goto bail;
}
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 /*
Only add the pyscript to the args, if it's not already there. It may
Adrian Buehlmann
exewrapper: use generic term script...
r17063 already be there, if the script spawned a child process of itself, in
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 the same way as it got called, that is, with the pyscript already in
place. So we optionally accept the pyscript as the first argument
(argv[1]), letting our exe taking the role of the python interpreter.
*/
if (argc >= 2 && strcmp(argv[1], pyscript) == 0) {
/*
pyscript is already in the args, so there is no need to copy
the args and we can directly call the python interpreter with
the original args.
*/
return Py_Main(argc, argv);
}
/*
Start assembling the args for the Python interpreter call. We put the
name of our exe (argv[0]) in the position where the python.exe
canonically is, and insert the pyscript next.
*/
Augie Fackler
exewrapper: format with clang-format...
r34637 pyargv = malloc((argc + 5) * sizeof(char *));
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 if (pyargv == NULL) {
err = "not enough memory";
goto bail;
}
n = 0;
pyargv[n++] = argv[0];
pyargv[n++] = pyscript;
/* copy remaining args from the command line */
for (i = 1; i < argc; i++)
pyargv[n++] = argv[i];
/* argv[argc] is guaranteed to be NULL, so we forward that guarantee */
pyargv[n] = NULL;
ret = Py_Main(n, pyargv); /* The Python interpreter call */
free(pyargv);
return ret;
bail:
fprintf(stderr, "abort: %s\n", err);
return 255;
}