High performance cache for git repository status. Clients can retrieve information via named pipe.
Useful for scenarios that frequently access status information (ex. shell prompts like posh-git) that don't want to pay the cost of a "git status" (significantly more expensive with large repositories) when nothing has changed.
- PowerShell: git-status-cache-posh-client
Clients connect to the "GitStatusCache" named pipe hosted by GitStatusCache.exe. All messages sent over the pipe must be UTF-8 encoded JSON.
All requests must specify "Version" and "Action". The only currently available version is 1. Should the protocol change in the future the version number will be incremented to avoid breaking existing clients. The following operations may be specified in "Action".
Retrieves current status information for the requested "Path".
{
"Path": "D:\\git-status-cache-posh-client",
"Version": 1,
"Action": "GetStatus"
}
{
"Version": 1,
"Path": "D:\\git-status-cache-posh-client",
"RepoPath": "D:/git-status-cache-posh-client/.git/",
"WorkingDir": "D:/git-status-cache-posh-client/",
"State" : "",
"Branch" : "master",
"Upstream": "origin/master",
"UpstreamGone": false,
"AheadBy": 0,
"BehindBy": 0,
"IndexAdded": [],
"IndexModified": [],
"IndexDeleted": [],
"IndexTypeChange": [],
"IndexRenamed": [],
"WorkingAdded": [],
"WorkingModified": ["GitStatusCachePoshClient.ps1", "GitStatusCachePoshClient.psm1"],
"WorkingDeleted": [],
"WorkingTypeChange": [],
"WorkingRenamed": [],
"WorkingUnreadable": [],
"Ignored": [],
"Conflicted": []
"Stashes" : [{
"Name" : "stash@{0}",
"Sha1Id" : "e24d59d0d03a3f680def647a7bb62f027d8671c",
"Message" : "On master: Second stash!"
}, {
"Name" : "stash@{1}",
"Sha1Id" : "0cbabd043bae55a76c3c041e6db2b129a0a4872",
"Message" : "On master: My stash."
}
]
}
Reports information about the cache's performance.
{
"Version": 1,
"Action": "GetCacheStatistics"
}
{
"Version": 1,
"Uptime": "01:47:20",
"TotalGetStatusRequests": 541,
"AverageMillisecondsInGetStatus": 12.452925,
"MinimumMillisecondsInGetStatus": 0.098923,
"MaximumMillisecondsInGetStatus": 213.08858,
"CacheHits": 383,
"CacheMisses": 156,
"EffectiveCachePrimes": 26,
"TotalCachePrimes": 58,
"EffectiveCacheInvalidations": 175,
"TotalCacheInvalidations": 662,
"FullCacheInvalidations": 0
}
Instructs the cache process to terminate itself.
{
"Version": 1,
"Action": "Shutdown"
}
{
"Version": 1,
"Result": "Shutting down."
}
Any errors with the request will be reported back with a "Version" and a human-readable "Error" message. For example:
{
"Version": 1,
"Error": "Requested 'Path' is not part of a git repository."
}
Cost for serving a cache hit in the cache process is generally between 0.1-0.3 ms, but this metric doesn't include the overhead involved in a full request.
The following measurements were taken on git repositories containing the specified file count. Each file was a text file containing a single sentence of text. Each case was run 5 times and the numbers reported below are averages. Each individual measurement was taken with a high resolution timer at 1 ms precision.
The measurements below capture:
- Serializing a request to JSON in PowerShell.
- Sending the JSON request over the named pipe.
- Compute the current git status (cache miss) or retrieving it from the cache (cache hit) int the cache process.
- Sending the JSON response over the named pipe back to the PowerShell client.
- Deserializing the JSON response into a PSCustomObject
cache miss | cache hit | |
---|---|---|
10 file repository | 3.0 ms | 1.0 ms |
100 file respository | 3.0 ms | 1.0 ms |
1,000 file respository | 5.2 ms | 1.0 ms |
10,000 file respository | 22.4 ms | 1.0 ms |
100,000 file repository | 176.6 ms | 1.0 ms |
cache miss | cache hit | |
---|---|---|
10 file repository | 2.8 ms | 1.0 ms |
100 file respository | 2.8 ms | 1.0 ms |
1,000 file respository | 4.4 ms | 1.0 ms |
10,000 file respository | 20.6 ms | 1.0 ms |
100,000 file repository | 176.6 ms | 1.0 ms |
The measurements below capture all the steps from the git-status-cache-posh-client section as well as the cost for posh-git to render the prompt. This extra step has a fixed cost of around 7-10 ms.
Costs were gathered using timestamps from posh-git's debug output. Timings for posh-git without git-status-cache and git-status-cache-posh-client are included for in the "posh-git without cache" column for reference.
cache miss | cache hit | posh-git without cache | |
---|---|---|---|
10 file repository | 11.8 ms | 8.6 ms | 57.0 ms |
100 file respository | 11.8 ms | 8.6 ms | 62.2 ms |
1,000 file respository | 14.2 ms | 8.6 ms | 68.2 ms |
10,000 file respository | 30.8 ms | 8.0 ms | 133.8 ms |
100,000 file repository | 181.6 ms | 9.6 ms | 754.4 ms |
cache miss | cache hit | posh-git without cache | |
---|---|---|---|
10 file repository | 12.2 ms | 9.4 ms | 63.2 ms |
100 file respository | 12.2 ms | 9.4 ms | 65.0 ms |
1,000 file respository | 14.4 ms | 9.4 ms | 72.8 ms |
10,000 file respository | 31.0 ms | 9.4 ms | 134.0 ms |
100,000 file repository | 179.6 ms | 9.0 ms | 763.6 ms |
Build through Visual Studio using the solution after configuring required dependencies.
Project includes libgit2 as a submodule. Initial build of libgit2 requires CMake.
Visual Studio project requires BOOST_ROOT variable be set to the location of Boost's root directory. Boost can be built using the Simplified Build From Source instructions on Boost's getting started page:
If you wish to build from source with Visual C++, you can use a simple build procedure described in this section. Open the command prompt and change your current directory to the Boost root directory. Then, type the following commands:
bootstrap
.\b2 runtime-link=static
libgit2 is included as a submodule. To pull locally:
git submodule update --init --recursive
CMake is required to build. See libgit2 build instructions for details. Use the following options to generate Visual Studio project and perform initial build:
cd .\ext\libgit2
mkdir build
cd build
cmake .. -DBUILD_SHARED_LIBS=OFF -DSTATIC_CRT=ON -DTHREADSAFE=ON -DBUILD_CLAR=OFF
cmake --build . --config Debug
cmake --build . --config Release
rapidjson headers are included as a submodule. To pull locally:
git submodule update --init --recursive