@@ -1720,7 +1720,8 @@ int read_index(struct index_state *istate)
1720
1720
return read_index_from (istate , get_index_file (), get_git_dir ());
1721
1721
}
1722
1722
1723
- static struct cache_entry * create_from_disk (struct index_state * istate ,
1723
+ static struct cache_entry * create_from_disk (struct mem_pool * ce_mem_pool ,
1724
+ unsigned int version ,
1724
1725
struct ondisk_cache_entry * ondisk ,
1725
1726
unsigned long * ent_size ,
1726
1727
const struct cache_entry * previous_ce )
@@ -1737,7 +1738,7 @@ static struct cache_entry *create_from_disk(struct index_state *istate,
1737
1738
* number of bytes to be stripped from the end of the previous name,
1738
1739
* and the bytes to append to the result, to come up with its name.
1739
1740
*/
1740
- int expand_name_field = istate -> version == 4 ;
1741
+ int expand_name_field = version == 4 ;
1741
1742
1742
1743
/* On-disk flags are just 16 bits */
1743
1744
flags = get_be16 (& ondisk -> flags );
@@ -1761,16 +1762,17 @@ static struct cache_entry *create_from_disk(struct index_state *istate,
1761
1762
const unsigned char * cp = (const unsigned char * )name ;
1762
1763
size_t strip_len , previous_len ;
1763
1764
1764
- previous_len = previous_ce ? previous_ce -> ce_namelen : 0 ;
1765
+ /* If we're at the begining of a block, ignore the previous name */
1765
1766
strip_len = decode_varint (& cp );
1766
- if (previous_len < strip_len ) {
1767
- if (previous_ce )
1767
+ if (previous_ce ) {
1768
+ previous_len = previous_ce -> ce_namelen ;
1769
+ if (previous_len < strip_len )
1768
1770
die (_ ("malformed name field in the index, near path '%s'" ),
1769
- previous_ce -> name );
1770
- else
1771
- die (_ ("malformed name field in the index in the first path" ));
1771
+ previous_ce -> name );
1772
+ copy_len = previous_len - strip_len ;
1773
+ } else {
1774
+ copy_len = 0 ;
1772
1775
}
1773
- copy_len = previous_len - strip_len ;
1774
1776
name = (const char * )cp ;
1775
1777
}
1776
1778
@@ -1780,7 +1782,7 @@ static struct cache_entry *create_from_disk(struct index_state *istate,
1780
1782
len += copy_len ;
1781
1783
}
1782
1784
1783
- ce = mem_pool__ce_alloc (istate -> ce_mem_pool , len );
1785
+ ce = mem_pool__ce_alloc (ce_mem_pool , len );
1784
1786
1785
1787
ce -> ce_stat_data .sd_ctime .sec = get_be32 (& ondisk -> ctime .sec );
1786
1788
ce -> ce_stat_data .sd_mtime .sec = get_be32 (& ondisk -> mtime .sec );
@@ -1948,6 +1950,52 @@ static void *load_index_extensions(void *_data)
1948
1950
return NULL ;
1949
1951
}
1950
1952
1953
+ /*
1954
+ * A helper function that will load the specified range of cache entries
1955
+ * from the memory mapped file and add them to the given index.
1956
+ */
1957
+ static unsigned long load_cache_entry_block (struct index_state * istate ,
1958
+ struct mem_pool * ce_mem_pool , int offset , int nr , const char * mmap ,
1959
+ unsigned long start_offset , const struct cache_entry * previous_ce )
1960
+ {
1961
+ int i ;
1962
+ unsigned long src_offset = start_offset ;
1963
+
1964
+ for (i = offset ; i < offset + nr ; i ++ ) {
1965
+ struct ondisk_cache_entry * disk_ce ;
1966
+ struct cache_entry * ce ;
1967
+ unsigned long consumed ;
1968
+
1969
+ disk_ce = (struct ondisk_cache_entry * )(mmap + src_offset );
1970
+ ce = create_from_disk (ce_mem_pool , istate -> version , disk_ce , & consumed , previous_ce );
1971
+ set_index_entry (istate , i , ce );
1972
+
1973
+ src_offset += consumed ;
1974
+ previous_ce = ce ;
1975
+ }
1976
+ return src_offset - start_offset ;
1977
+ }
1978
+
1979
+ static unsigned long load_all_cache_entries (struct index_state * istate ,
1980
+ const char * mmap , size_t mmap_size , unsigned long src_offset )
1981
+ {
1982
+ unsigned long consumed ;
1983
+
1984
+ if (istate -> version == 4 ) {
1985
+ mem_pool_init (& istate -> ce_mem_pool ,
1986
+ estimate_cache_size_from_compressed (istate -> cache_nr ));
1987
+ } else {
1988
+ mem_pool_init (& istate -> ce_mem_pool ,
1989
+ estimate_cache_size (mmap_size , istate -> cache_nr ));
1990
+ }
1991
+
1992
+ consumed = load_cache_entry_block (istate , istate -> ce_mem_pool ,
1993
+ 0 , istate -> cache_nr , mmap , src_offset , NULL );
1994
+ return consumed ;
1995
+ }
1996
+
1997
+ #ifndef NO_PTHREADS
1998
+
1951
1999
/*
1952
2000
* Mostly randomly chosen maximum thread counts: we
1953
2001
* cap the parallelism to online_cpus() threads, and we want
@@ -1957,20 +2005,123 @@ static void *load_index_extensions(void *_data)
1957
2005
1958
2006
#define THREAD_COST (10000)
1959
2007
2008
+ struct load_cache_entries_thread_data
2009
+ {
2010
+ pthread_t pthread ;
2011
+ struct index_state * istate ;
2012
+ struct mem_pool * ce_mem_pool ;
2013
+ int offset ;
2014
+ const char * mmap ;
2015
+ struct index_entry_offset_table * ieot ;
2016
+ int ieot_start ; /* starting index into the ieot array */
2017
+ int ieot_blocks ; /* count of ieot entries to process */
2018
+ unsigned long consumed ; /* return # of bytes in index file processed */
2019
+ };
2020
+
2021
+ /*
2022
+ * A thread proc to run the load_cache_entries() computation
2023
+ * across multiple background threads.
2024
+ */
2025
+ static void * load_cache_entries_thread (void * _data )
2026
+ {
2027
+ struct load_cache_entries_thread_data * p = _data ;
2028
+ int i ;
2029
+
2030
+ /* iterate across all ieot blocks assigned to this thread */
2031
+ for (i = p -> ieot_start ; i < p -> ieot_start + p -> ieot_blocks ; i ++ ) {
2032
+ p -> consumed += load_cache_entry_block (p -> istate , p -> ce_mem_pool ,
2033
+ p -> offset , p -> ieot -> entries [i ].nr , p -> mmap , p -> ieot -> entries [i ].offset , NULL );
2034
+ p -> offset += p -> ieot -> entries [i ].nr ;
2035
+ }
2036
+ return NULL ;
2037
+ }
2038
+
2039
+ static unsigned long load_cache_entries_threaded (struct index_state * istate , const char * mmap , size_t mmap_size ,
2040
+ unsigned long src_offset , int nr_threads , struct index_entry_offset_table * ieot )
2041
+ {
2042
+ int i , offset , ieot_blocks , ieot_start , err ;
2043
+ struct load_cache_entries_thread_data * data ;
2044
+ unsigned long consumed = 0 ;
2045
+
2046
+ /* a little sanity checking */
2047
+ if (istate -> name_hash_initialized )
2048
+ BUG ("the name hash isn't thread safe" );
2049
+
2050
+ mem_pool_init (& istate -> ce_mem_pool , 0 );
2051
+
2052
+ /* ensure we have no more threads than we have blocks to process */
2053
+ if (nr_threads > ieot -> nr )
2054
+ nr_threads = ieot -> nr ;
2055
+ data = xcalloc (nr_threads , sizeof (* data ));
2056
+
2057
+ offset = ieot_start = 0 ;
2058
+ ieot_blocks = DIV_ROUND_UP (ieot -> nr , nr_threads );
2059
+ for (i = 0 ; i < nr_threads ; i ++ ) {
2060
+ struct load_cache_entries_thread_data * p = & data [i ];
2061
+ int nr , j ;
2062
+
2063
+ if (ieot_start + ieot_blocks > ieot -> nr )
2064
+ ieot_blocks = ieot -> nr - ieot_start ;
2065
+
2066
+ p -> istate = istate ;
2067
+ p -> offset = offset ;
2068
+ p -> mmap = mmap ;
2069
+ p -> ieot = ieot ;
2070
+ p -> ieot_start = ieot_start ;
2071
+ p -> ieot_blocks = ieot_blocks ;
2072
+
2073
+ /* create a mem_pool for each thread */
2074
+ nr = 0 ;
2075
+ for (j = p -> ieot_start ; j < p -> ieot_start + p -> ieot_blocks ; j ++ )
2076
+ nr += p -> ieot -> entries [j ].nr ;
2077
+ if (istate -> version == 4 ) {
2078
+ mem_pool_init (& p -> ce_mem_pool ,
2079
+ estimate_cache_size_from_compressed (nr ));
2080
+ } else {
2081
+ mem_pool_init (& p -> ce_mem_pool ,
2082
+ estimate_cache_size (mmap_size , nr ));
2083
+ }
2084
+
2085
+ err = pthread_create (& p -> pthread , NULL , load_cache_entries_thread , p );
2086
+ if (err )
2087
+ die (_ ("unable to create load_cache_entries thread: %s" ), strerror (err ));
2088
+
2089
+ /* increment by the number of cache entries in the ieot block being processed */
2090
+ for (j = 0 ; j < ieot_blocks ; j ++ )
2091
+ offset += ieot -> entries [ieot_start + j ].nr ;
2092
+ ieot_start += ieot_blocks ;
2093
+ }
2094
+
2095
+ for (i = 0 ; i < nr_threads ; i ++ ) {
2096
+ struct load_cache_entries_thread_data * p = & data [i ];
2097
+
2098
+ err = pthread_join (p -> pthread , NULL );
2099
+ if (err )
2100
+ die (_ ("unable to join load_cache_entries thread: %s" ), strerror (err ));
2101
+ mem_pool_combine (istate -> ce_mem_pool , p -> ce_mem_pool );
2102
+ consumed += p -> consumed ;
2103
+ }
2104
+
2105
+ free (data );
2106
+
2107
+ return consumed ;
2108
+ }
2109
+ #endif
2110
+
1960
2111
/* remember to discard_cache() before reading a different cache! */
1961
2112
int do_read_index (struct index_state * istate , const char * path , int must_exist )
1962
2113
{
1963
- int fd , i ;
2114
+ int fd ;
1964
2115
struct stat st ;
1965
2116
unsigned long src_offset ;
1966
2117
const struct cache_header * hdr ;
1967
2118
const char * mmap ;
1968
2119
size_t mmap_size ;
1969
- const struct cache_entry * previous_ce = NULL ;
1970
2120
struct load_index_extensions p ;
1971
2121
size_t extension_offset = 0 ;
1972
2122
#ifndef NO_PTHREADS
1973
- int nr_threads ;
2123
+ int nr_threads , cpus ;
2124
+ struct index_entry_offset_table * ieot = NULL ;
1974
2125
#endif
1975
2126
1976
2127
if (istate -> initialized )
@@ -2012,10 +2163,18 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
2012
2163
p .mmap = mmap ;
2013
2164
p .mmap_size = mmap_size ;
2014
2165
2166
+ src_offset = sizeof (* hdr );
2167
+
2015
2168
#ifndef NO_PTHREADS
2016
2169
nr_threads = git_config_get_index_threads ();
2017
- if (!nr_threads )
2018
- nr_threads = online_cpus ();
2170
+
2171
+ /* TODO: does creating more threads than cores help? */
2172
+ if (!nr_threads ) {
2173
+ nr_threads = istate -> cache_nr / THREAD_COST ;
2174
+ cpus = online_cpus ();
2175
+ if (nr_threads > cpus )
2176
+ nr_threads = cpus ;
2177
+ }
2019
2178
2020
2179
if (nr_threads > 1 ) {
2021
2180
extension_offset = read_eoie_extension (mmap , mmap_size );
@@ -2030,29 +2189,24 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
2030
2189
nr_threads -- ;
2031
2190
}
2032
2191
}
2033
- #endif
2034
2192
2035
- if (istate -> version == 4 ) {
2036
- mem_pool_init (& istate -> ce_mem_pool ,
2037
- estimate_cache_size_from_compressed (istate -> cache_nr ));
2193
+ /*
2194
+ * Locate and read the index entry offset table so that we can use it
2195
+ * to multi-thread the reading of the cache entries.
2196
+ */
2197
+ if (extension_offset && nr_threads > 1 )
2198
+ ieot = read_ieot_extension (mmap , mmap_size , extension_offset );
2199
+
2200
+ if (ieot ) {
2201
+ src_offset += load_cache_entries_threaded (istate , mmap , mmap_size , src_offset , nr_threads , ieot );
2202
+ free (ieot );
2038
2203
} else {
2039
- mem_pool_init (& istate -> ce_mem_pool ,
2040
- estimate_cache_size (mmap_size , istate -> cache_nr ));
2204
+ src_offset += load_all_cache_entries (istate , mmap , mmap_size , src_offset );
2041
2205
}
2206
+ #else
2207
+ src_offset += load_all_cache_entries (istate , mmap , mmap_size , src_offset );
2208
+ #endif
2042
2209
2043
- src_offset = sizeof (* hdr );
2044
- for (i = 0 ; i < istate -> cache_nr ; i ++ ) {
2045
- struct ondisk_cache_entry * disk_ce ;
2046
- struct cache_entry * ce ;
2047
- unsigned long consumed ;
2048
-
2049
- disk_ce = (struct ondisk_cache_entry * )(mmap + src_offset );
2050
- ce = create_from_disk (istate , disk_ce , & consumed , previous_ce );
2051
- set_index_entry (istate , i , ce );
2052
-
2053
- src_offset += consumed ;
2054
- previous_ce = ce ;
2055
- }
2056
2210
istate -> timestamp .sec = st .st_mtime ;
2057
2211
istate -> timestamp .nsec = ST_MTIME_NSEC (st );
2058
2212
@@ -2549,7 +2703,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
2549
2703
struct strbuf previous_name_buf = STRBUF_INIT , * previous_name ;
2550
2704
int drop_cache_tree = istate -> drop_cache_tree ;
2551
2705
off_t offset ;
2552
- int ieot_blocks = 1 ;
2706
+ int ieot_entries = 1 ;
2553
2707
struct index_entry_offset_table * ieot = NULL ;
2554
2708
int nr , nr_threads ;
2555
2709
@@ -2602,6 +2756,8 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
2602
2756
ieot_blocks = cpus - 1 ;
2603
2757
} else {
2604
2758
ieot_blocks = nr_threads ;
2759
+ if (ieot_blocks > istate -> cache_nr )
2760
+ ieot_blocks = istate -> cache_nr ;
2605
2761
}
2606
2762
2607
2763
/*
@@ -2611,7 +2767,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
2611
2767
if (ieot_blocks > 1 ) {
2612
2768
ieot = xcalloc (1 , sizeof (struct index_entry_offset_table )
2613
2769
+ (ieot_blocks * sizeof (struct index_entry_offset )));
2614
- ieot_blocks = DIV_ROUND_UP (entries , ieot_blocks );
2770
+ ieot_entries = DIV_ROUND_UP (entries , ieot_blocks );
2615
2771
}
2616
2772
}
2617
2773
#endif
@@ -2644,7 +2800,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
2644
2800
2645
2801
drop_cache_tree = 1 ;
2646
2802
}
2647
- if (ieot && i && (i % ieot_blocks == 0 )) {
2803
+ if (ieot && i && (i % ieot_entries == 0 )) {
2648
2804
ieot -> entries [ieot -> nr ].nr = nr ;
2649
2805
ieot -> entries [ieot -> nr ].offset = offset ;
2650
2806
ieot -> nr ++ ;
0 commit comments