@@ -28,13 +28,14 @@ static struct hashmap gh_server__subprocess_map;
28
28
static struct object_directory * gh_client__chosen_odb ;
29
29
30
30
/*
31
- * The "objects" capability has 2 verbs: "get" and "post".
31
+ * The "objects" capability has verbs: "get" and "post" and "prefetch ".
32
32
*/
33
33
#define CAP_OBJECTS (1u<<1)
34
34
#define CAP_OBJECTS_NAME "objects"
35
35
36
36
#define CAP_OBJECTS__VERB_GET1_NAME "get"
37
37
#define CAP_OBJECTS__VERB_POST_NAME "post"
38
+ #define CAP_OBJECTS__VERB_PREFETCH_NAME "prefetch"
38
39
39
40
static int gh_client__start_fn (struct subprocess_entry * subprocess )
40
41
{
@@ -133,6 +134,44 @@ static int gh_client__send__objects_get(struct child_process *process,
133
134
return 0 ;
134
135
}
135
136
137
+ /*
138
+ * Send a request to gvfs-helper to prefetch packfiles from either the
139
+ * cache-server or the main Git server using "/gvfs/prefetch".
140
+ *
141
+ * objects.prefetch LF
142
+ * [<seconds-since_epoch> LF]
143
+ * <flush>
144
+ */
145
+ static int gh_client__send__objects_prefetch (struct child_process * process ,
146
+ timestamp_t seconds_since_epoch )
147
+ {
148
+ int err ;
149
+
150
+ /*
151
+ * We assume that all of the packet_ routines call error()
152
+ * so that we don't have to.
153
+ */
154
+
155
+ err = packet_write_fmt_gently (
156
+ process -> in ,
157
+ (CAP_OBJECTS_NAME "." CAP_OBJECTS__VERB_PREFETCH_NAME "\n" ));
158
+ if (err )
159
+ return err ;
160
+
161
+ if (seconds_since_epoch ) {
162
+ err = packet_write_fmt_gently (process -> in , "%" PRItime "\n" ,
163
+ seconds_since_epoch );
164
+ if (err )
165
+ return err ;
166
+ }
167
+
168
+ err = packet_flush_gently (process -> in );
169
+ if (err )
170
+ return err ;
171
+
172
+ return 0 ;
173
+ }
174
+
136
175
/*
137
176
* Update the loose object cache to include the newly created
138
177
* object.
@@ -181,7 +220,7 @@ static void gh_client__update_packed_git(const char *line)
181
220
}
182
221
183
222
/*
184
- * Both CAP_OBJECTS verbs return the same format response:
223
+ * CAP_OBJECTS verbs return the same format response:
185
224
*
186
225
* <odb>
187
226
* <data>*
@@ -221,6 +260,8 @@ static int gh_client__objects__receive_response(
221
260
const char * v1 ;
222
261
char * line ;
223
262
int len ;
263
+ int nr_loose = 0 ;
264
+ int nr_packfile = 0 ;
224
265
int err = 0 ;
225
266
226
267
while (1 ) {
@@ -239,13 +280,13 @@ static int gh_client__objects__receive_response(
239
280
else if (starts_with (line , "packfile" )) {
240
281
gh_client__update_packed_git (line );
241
282
ghc |= GHC__CREATED__PACKFILE ;
242
- * p_nr_packfile += 1 ;
283
+ nr_packfile ++ ;
243
284
}
244
285
245
286
else if (starts_with (line , "loose" )) {
246
287
gh_client__update_loose_cache (line );
247
288
ghc |= GHC__CREATED__LOOSE ;
248
- * p_nr_loose += 1 ;
289
+ nr_loose ++ ;
249
290
}
250
291
251
292
else if (starts_with (line , "ok" ))
@@ -259,6 +300,8 @@ static int gh_client__objects__receive_response(
259
300
}
260
301
261
302
* p_ghc = ghc ;
303
+ * p_nr_loose = nr_loose ;
304
+ * p_nr_packfile = nr_packfile ;
262
305
263
306
return err ;
264
307
}
@@ -315,7 +358,7 @@ static struct gh_server__process *gh_client__find_long_running_process(
315
358
/*
316
359
* Find an existing long-running process with the above command
317
360
* line -or- create a new long-running process for this and
318
- * subsequent 'get' requests.
361
+ * subsequent requests.
319
362
*/
320
363
if (!gh_server__subprocess_map_initialized ) {
321
364
gh_server__subprocess_map_initialized = 1 ;
@@ -352,10 +395,14 @@ static struct gh_server__process *gh_client__find_long_running_process(
352
395
353
396
void gh_client__queue_oid (const struct object_id * oid )
354
397
{
355
- // TODO consider removing this trace2. it is useful for interactive
356
- // TODO debugging, but may generate way too much noise for a data
357
- // TODO event.
358
- trace2_printf ("gh_client__queue_oid: %s" , oid_to_hex (oid ));
398
+ /*
399
+ * Keep this trace as a printf only, so that it goes to the
400
+ * perf log, but not the event log. It is useful for interactive
401
+ * debugging, but generates way too much (unuseful) noise for the
402
+ * database.
403
+ */
404
+ if (trace2_is_enabled ())
405
+ trace2_printf ("gh_client__queue_oid: %s" , oid_to_hex (oid ));
359
406
360
407
if (!oidset_insert (& gh_client__oidset_queued , oid ))
361
408
gh_client__oidset_count ++ ;
@@ -436,10 +483,14 @@ int gh_client__get_immediate(const struct object_id *oid,
436
483
int nr_packfile = 0 ;
437
484
int err = 0 ;
438
485
439
- // TODO consider removing this trace2. it is useful for interactive
440
- // TODO debugging, but may generate way too much noise for a data
441
- // TODO event.
442
- trace2_printf ("gh_client__get_immediate: %s" , oid_to_hex (oid ));
486
+ /*
487
+ * Keep this trace as a printf only, so that it goes to the
488
+ * perf log, but not the event log. It is useful for interactive
489
+ * debugging, but generates way too much (unuseful) noise for the
490
+ * database.
491
+ */
492
+ if (trace2_is_enabled ())
493
+ trace2_printf ("gh_client__get_immediate: %s" , oid_to_hex (oid ));
443
494
444
495
entry = gh_client__find_long_running_process (CAP_OBJECTS );
445
496
if (!entry )
@@ -468,3 +519,55 @@ int gh_client__get_immediate(const struct object_id *oid,
468
519
469
520
return err ;
470
521
}
522
+
523
+ /*
524
+ * Ask gvfs-helper to prefetch commits-and-trees packfiles since a
525
+ * given timestamp.
526
+ *
527
+ * If seconds_since_epoch is zero, gvfs-helper will scan the ODB for
528
+ * the last received prefetch and ask for ones newer than that.
529
+ */
530
+ int gh_client__prefetch (timestamp_t seconds_since_epoch ,
531
+ int * nr_packfiles_received )
532
+ {
533
+ struct gh_server__process * entry ;
534
+ struct child_process * process ;
535
+ enum gh_client__created ghc ;
536
+ int nr_loose = 0 ;
537
+ int nr_packfile = 0 ;
538
+ int err = 0 ;
539
+
540
+ entry = gh_client__find_long_running_process (CAP_OBJECTS );
541
+ if (!entry )
542
+ return -1 ;
543
+
544
+ trace2_region_enter ("gh-client" , "objects/prefetch" , the_repository );
545
+ trace2_data_intmax ("gh-client" , the_repository , "prefetch/since" ,
546
+ seconds_since_epoch );
547
+
548
+ process = & entry -> subprocess .process ;
549
+
550
+ sigchain_push (SIGPIPE , SIG_IGN );
551
+
552
+ err = gh_client__send__objects_prefetch (process , seconds_since_epoch );
553
+ if (!err )
554
+ err = gh_client__objects__receive_response (
555
+ process , & ghc , & nr_loose , & nr_packfile );
556
+
557
+ sigchain_pop (SIGPIPE );
558
+
559
+ if (err ) {
560
+ subprocess_stop (& gh_server__subprocess_map ,
561
+ (struct subprocess_entry * )entry );
562
+ FREE_AND_NULL (entry );
563
+ }
564
+
565
+ trace2_data_intmax ("gh-client" , the_repository ,
566
+ "prefetch/packfile_count" , nr_packfile );
567
+ trace2_region_leave ("gh-client" , "objects/prefetch" , the_repository );
568
+
569
+ if (nr_packfiles_received )
570
+ * nr_packfiles_received = nr_packfile ;
571
+
572
+ return err ;
573
+ }
0 commit comments