read-cache: load cache extensions on a worker thread
[gitweb.git] / read-cache.c
index 4781515252771a15f8eeaadbb4f7c00a4fcc1b79..2214b3153df1ff276233d77e184e0291c66e7b12 100644 (file)
@@ -23,6 +23,7 @@
 #include "split-index.h"
 #include "utf8.h"
 #include "fsmonitor.h"
+#include "thread-utils.h"
 
 /* Mask for the name length in ce_flags in the on-disk index */
 
@@ -1890,6 +1891,44 @@ static size_t estimate_cache_size(size_t ondisk_size, unsigned int entries)
 static size_t read_eoie_extension(const char *mmap, size_t mmap_size);
 static void write_eoie_extension(struct strbuf *sb, git_hash_ctx *eoie_context, size_t offset);
 
+struct load_index_extensions
+{
+#ifndef NO_PTHREADS
+       pthread_t pthread;
+#endif
+       struct index_state *istate;
+       const char *mmap;
+       size_t mmap_size;
+       unsigned long src_offset;
+};
+
+static void *load_index_extensions(void *_data)
+{
+       struct load_index_extensions *p = _data;
+       unsigned long src_offset = p->src_offset;
+
+       while (src_offset <= p->mmap_size - the_hash_algo->rawsz - 8) {
+               /* After an array of active_nr index entries,
+                * there can be arbitrary number of extended
+                * sections, each of which is prefixed with
+                * extension name (4-byte) and section length
+                * in 4-byte network byte order.
+                */
+               uint32_t extsize = get_be32(p->mmap + src_offset + 4);
+               if (read_index_extension(p->istate,
+                                        p->mmap + src_offset,
+                                        p->mmap + src_offset + 8,
+                                        extsize) < 0) {
+                       munmap((void *)p->mmap, p->mmap_size);
+                       die(_("index file corrupt"));
+               }
+               src_offset += 8;
+               src_offset += extsize;
+       }
+
+       return NULL;
+}
+
 /* remember to discard_cache() before reading a different cache! */
 int do_read_index(struct index_state *istate, const char *path, int must_exist)
 {
@@ -1900,6 +1939,11 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
        const char *mmap;
        size_t mmap_size;
        const struct cache_entry *previous_ce = NULL;
+       struct load_index_extensions p;
+       size_t extension_offset = 0;
+#ifndef NO_PTHREADS
+       int nr_threads;
+#endif
 
        if (istate->initialized)
                return istate->cache_nr;
@@ -1936,6 +1980,30 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
        istate->cache = xcalloc(istate->cache_alloc, sizeof(*istate->cache));
        istate->initialized = 1;
 
+       p.istate = istate;
+       p.mmap = mmap;
+       p.mmap_size = mmap_size;
+
+#ifndef NO_PTHREADS
+       nr_threads = git_config_get_index_threads();
+       if (!nr_threads)
+               nr_threads = online_cpus();
+
+       if (nr_threads > 1) {
+               extension_offset = read_eoie_extension(mmap, mmap_size);
+               if (extension_offset) {
+                       int err;
+
+                       p.src_offset = extension_offset;
+                       err = pthread_create(&p.pthread, NULL, load_index_extensions, &p);
+                       if (err)
+                               die(_("unable to create load_index_extensions thread: %s"), strerror(err));
+
+                       nr_threads--;
+               }
+       }
+#endif
+
        if (istate->version == 4) {
                mem_pool_init(&istate->ce_mem_pool,
                              estimate_cache_size_from_compressed(istate->cache_nr));
@@ -1960,22 +2028,17 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
        istate->timestamp.sec = st.st_mtime;
        istate->timestamp.nsec = ST_MTIME_NSEC(st);
 
-       while (src_offset <= mmap_size - the_hash_algo->rawsz - 8) {
-               /* After an array of active_nr index entries,
-                * there can be arbitrary number of extended
-                * sections, each of which is prefixed with
-                * extension name (4-byte) and section length
-                * in 4-byte network byte order.
-                */
-               uint32_t extsize;
-               extsize = get_be32(mmap + src_offset + 4);
-               if (read_index_extension(istate,
-                                        mmap + src_offset,
-                                        mmap + src_offset + 8,
-                                        extsize) < 0)
-                       goto unmap;
-               src_offset += 8;
-               src_offset += extsize;
+       /* if we created a thread, join it otherwise load the extensions on the primary thread */
+#ifndef NO_PTHREADS
+       if (extension_offset) {
+               int ret = pthread_join(p.pthread, NULL);
+               if (ret)
+                       die(_("unable to join load_index_extensions thread: %s"), strerror(ret));
+       }
+#endif
+       if (!extension_offset) {
+               p.src_offset = src_offset;
+               load_index_extensions(&p);
        }
        munmap((void *)mmap, mmap_size);
        return istate->cache_nr;