@@ -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.
@@ -180,7 +219,7 @@ static void gh_client__update_packed_git(const char *line)
180
219
}
181
220
182
221
/*
183
- * Both CAP_OBJECTS verbs return the same format response:
222
+ * CAP_OBJECTS verbs return the same format response:
184
223
*
185
224
* <odb>
186
225
* <data>*
@@ -220,6 +259,8 @@ static int gh_client__objects__receive_response(
220
259
const char * v1 ;
221
260
char * line ;
222
261
int len ;
262
+ int nr_loose = 0 ;
263
+ int nr_packfile = 0 ;
223
264
int err = 0 ;
224
265
225
266
while (1 ) {
@@ -238,13 +279,13 @@ static int gh_client__objects__receive_response(
238
279
else if (starts_with (line , "packfile" )) {
239
280
gh_client__update_packed_git (line );
240
281
ghc |= GHC__CREATED__PACKFILE ;
241
- * p_nr_packfile += 1 ;
282
+ nr_packfile ++ ;
242
283
}
243
284
244
285
else if (starts_with (line , "loose" )) {
245
286
gh_client__update_loose_cache (line );
246
287
ghc |= GHC__CREATED__LOOSE ;
247
- * p_nr_loose += 1 ;
288
+ nr_loose ++ ;
248
289
}
249
290
250
291
else if (starts_with (line , "ok" ))
@@ -258,6 +299,8 @@ static int gh_client__objects__receive_response(
258
299
}
259
300
260
301
* p_ghc = ghc ;
302
+ * p_nr_loose = nr_loose ;
303
+ * p_nr_packfile = nr_packfile ;
261
304
262
305
return err ;
263
306
}
@@ -314,7 +357,7 @@ static struct gh_server__process *gh_client__find_long_running_process(
314
357
/*
315
358
* Find an existing long-running process with the above command
316
359
* line -or- create a new long-running process for this and
317
- * subsequent 'get' requests.
360
+ * subsequent requests.
318
361
*/
319
362
if (!gh_server__subprocess_map_initialized ) {
320
363
gh_server__subprocess_map_initialized = 1 ;
@@ -351,10 +394,14 @@ static struct gh_server__process *gh_client__find_long_running_process(
351
394
352
395
void gh_client__queue_oid (const struct object_id * oid )
353
396
{
354
- // TODO consider removing this trace2. it is useful for interactive
355
- // TODO debugging, but may generate way too much noise for a data
356
- // TODO event.
357
- trace2_printf ("gh_client__queue_oid: %s" , oid_to_hex (oid ));
397
+ /*
398
+ * Keep this trace as a printf only, so that it goes to the
399
+ * perf log, but not the event log. It is useful for interactive
400
+ * debugging, but generates way too much (unuseful) noise for the
401
+ * database.
402
+ */
403
+ if (trace2_is_enabled ())
404
+ trace2_printf ("gh_client__queue_oid: %s" , oid_to_hex (oid ));
358
405
359
406
if (!oidset_insert (& gh_client__oidset_queued , oid ))
360
407
gh_client__oidset_count ++ ;
@@ -435,10 +482,14 @@ int gh_client__get_immediate(const struct object_id *oid,
435
482
int nr_packfile = 0 ;
436
483
int err = 0 ;
437
484
438
- // TODO consider removing this trace2. it is useful for interactive
439
- // TODO debugging, but may generate way too much noise for a data
440
- // TODO event.
441
- trace2_printf ("gh_client__get_immediate: %s" , oid_to_hex (oid ));
485
+ /*
486
+ * Keep this trace as a printf only, so that it goes to the
487
+ * perf log, but not the event log. It is useful for interactive
488
+ * debugging, but generates way too much (unuseful) noise for the
489
+ * database.
490
+ */
491
+ if (trace2_is_enabled ())
492
+ trace2_printf ("gh_client__get_immediate: %s" , oid_to_hex (oid ));
442
493
443
494
entry = gh_client__find_long_running_process (CAP_OBJECTS );
444
495
if (!entry )
@@ -467,3 +518,55 @@ int gh_client__get_immediate(const struct object_id *oid,
467
518
468
519
return err ;
469
520
}
521
+
522
+ /*
523
+ * Ask gvfs-helper to prefetch commits-and-trees packfiles since a
524
+ * given timestamp.
525
+ *
526
+ * If seconds_since_epoch is zero, gvfs-helper will scan the ODB for
527
+ * the last received prefetch and ask for ones newer than that.
528
+ */
529
+ int gh_client__prefetch (timestamp_t seconds_since_epoch ,
530
+ int * nr_packfiles_received )
531
+ {
532
+ struct gh_server__process * entry ;
533
+ struct child_process * process ;
534
+ enum gh_client__created ghc ;
535
+ int nr_loose = 0 ;
536
+ int nr_packfile = 0 ;
537
+ int err = 0 ;
538
+
539
+ entry = gh_client__find_long_running_process (CAP_OBJECTS );
540
+ if (!entry )
541
+ return -1 ;
542
+
543
+ trace2_region_enter ("gh-client" , "objects/prefetch" , the_repository );
544
+ trace2_data_intmax ("gh-client" , the_repository , "prefetch/since" ,
545
+ seconds_since_epoch );
546
+
547
+ process = & entry -> subprocess .process ;
548
+
549
+ sigchain_push (SIGPIPE , SIG_IGN );
550
+
551
+ err = gh_client__send__objects_prefetch (process , seconds_since_epoch );
552
+ if (!err )
553
+ err = gh_client__objects__receive_response (
554
+ process , & ghc , & nr_loose , & nr_packfile );
555
+
556
+ sigchain_pop (SIGPIPE );
557
+
558
+ if (err ) {
559
+ subprocess_stop (& gh_server__subprocess_map ,
560
+ (struct subprocess_entry * )entry );
561
+ FREE_AND_NULL (entry );
562
+ }
563
+
564
+ trace2_data_intmax ("gh-client" , the_repository ,
565
+ "prefetch/packfile_count" , nr_packfile );
566
+ trace2_region_leave ("gh-client" , "objects/prefetch" , the_repository );
567
+
568
+ if (nr_packfiles_received )
569
+ * nr_packfiles_received = nr_packfile ;
570
+
571
+ return err ;
572
+ }
0 commit comments