{"thread":{"id":"44","subject":"[PATCH] Cache of hardlinked blobs","startedAt":"2005-04-16T04:43:00Z","lastAt":"2005-04-16T04:43:00Z","messageCount":1,"participants":["Daniel Barkalow"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"283","messageId":"Pine.LNX.4.21.0504160019240.30848-100000@iabervon.org","threadId":"44","inReplyTo":null,"subject":"[PATCH] Cache of hardlinked blobs","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-04-16T04:43:00Z","receivedAt":"2005-04-16T04:43:00Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"I wrote a quick and dirty patch to check out blobs into .git/blobs, and\nhardlink them into the working directory; if you symlink .git/blobs\ntogether for a number of trees, this should save a lot of space if you\nhave a lot of working directories. It also seems to speed up and save\nspace in \"git fork\" (or whatever it ends up being called) if the symlink\nis added to the list of symlinks. It seems effective from trying it with a\ngit tree. Ingo: do you want to try it with a kernel tree? I think you said\nyou wanted good performance for that sort of thing.\n\nPatch follows:\n\nMake a cache of expanded blobs, and hardlink against them instead of\ncreating more files. This is useful if the cache is shared between\ndifferent working directories and your editor breaks hard links\nappropriately.\n\nSigned-Off-By: Daniel Barkalow <barkalow@iabervon.org>\n\nIndex: checkout-cache.c\n===================================================================\n--- e4d994ccc556a50f89297c6dbcf22e484a344cf8/checkout-cache.c  (mode:100664 sha1:431b7032576f40d93a08be801e26f76c168ed57b)\n+++ 2ee21d9b73c81d51f6c0e8ff35a92a4f11105fc4/checkout-cache.c  (mode:100664 sha1:9624b3c783c482c9f6da8bf8b2cf45b316107776)\n@@ -34,6 +34,8 @@\n  */\n #include \"cache.h\"\n \n+#define HARDLINK_CACHE \".git/blobs\"\n+\n static int force = 0, quiet = 0;\n \n static void create_directories(const char *path)\n@@ -64,6 +66,80 @@\n \treturn fd;\n }\n \n+#ifdef HARDLINK_CACHE\n+\n+/*\n+ * NOTE! This returns a statically allocated buffer, so you have to be\n+ * careful about using it. Do a \"strdup()\" if you need to save the\n+ * filename.\n+ */\n+char *sha1_blob_cache_file_name(const unsigned char *sha1)\n+{\n+\tint i;\n+\tstatic char *name, *base;\n+\n+\tif (!base) {\n+\t\tchar *sha1_file_directory = HARDLINK_CACHE;\n+\t\tint len = strlen(sha1_file_directory);\n+\t\tbase = malloc(len + 60);\n+\t\tmemcpy(base, sha1_file_directory, len);\n+\t\tmemset(base+len, 0, 60);\n+\t\tbase[len] = '/';\n+\t\tbase[len+3] = '/';\n+\t\tname = base + len + 1;\n+\t}\n+\tfor (i = 0; i < 20; i++) {\n+\t\tstatic char hex[] = \"0123456789abcdef\";\n+\t\tunsigned int val = sha1[i];\n+\t\tchar *pos = name + i*2 + (i > 0);\n+\t\t*pos++ = hex[val >> 4];\n+\t\t*pos = hex[val & 0xf];\n+\t}\n+\treturn base;\n+}\n+\n+static int write_entry(struct cache_entry *ce)\n+{\n+\tint fd;\n+\tvoid *new;\n+\tunsigned long size;\n+\tlong wrote;\n+\tchar type[20];\n+\tchar *cache_name;\n+\tstruct stat st;\n+\n+\tcache_name = sha1_blob_cache_file_name(ce->sha1);\n+\n+\tif (stat(cache_name, &st)) {\n+\t\tnew = read_sha1_file(ce->sha1, type, &size);\n+\t\tif (!new || strcmp(type, \"blob\")) {\n+\t\t\treturn error(\"checkout-cache: unable to read sha1 file of %s (%s)\",\n+\t\t\t\t     ce->name, sha1_to_hex(ce->sha1));\n+\t\t}\n+\t\tfd = create_file(cache_name, ntohl(ce->ce_mode));\n+\t\tif (fd < 0) {\n+\t\t\tfree(new);\n+\t\t\treturn error(\"checkout-cache: unable to create %s (%s)\",\n+\t\t\t\t     ce->name, strerror(errno));\n+\t\t}\n+\t\twrote = write(fd, new, size);\n+\t\tclose(fd);\n+\t\tfree(new);\n+\t\tif (wrote != size)\n+\t\t\treturn error(\"checkout-cache: unable to write %s\", \n+\t\t\t\t     ce->name);\n+\t}\n+\tif (link(cache_name, ce->name)) {\n+\t\tif (errno == ENOENT) {\n+\t\t\tcreate_directories(ce->name);\n+\t\t\tlink(cache_name, ce->name);\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+#else\n+\n static int write_entry(struct cache_entry *ce)\n {\n \tint fd;\n@@ -91,6 +167,8 @@\n \treturn 0;\n }\n \n+#endif\n+\n static int checkout_entry(struct cache_entry *ce)\n {\n \tstruct stat st;\n\n"}]}