@@ -24,13 +24,14 @@ static struct hashmap gh_server__subprocess_map;
24
24
static struct object_directory * gh_client__chosen_odb ;
25
25
26
26
/*
27
- * The "objects" capability has 2 verbs: "get" and "post".
27
+ * The "objects" capability has verbs: "get" and "post" and "prefetch ".
28
28
*/
29
29
#define CAP_OBJECTS (1u<<1)
30
30
#define CAP_OBJECTS_NAME "objects"
31
31
32
32
#define CAP_OBJECTS__VERB_GET1_NAME "get"
33
33
#define CAP_OBJECTS__VERB_POST_NAME "post"
34
+ #define CAP_OBJECTS__VERB_PREFETCH_NAME "prefetch"
34
35
35
36
static int gh_client__start_fn (struct subprocess_entry * subprocess )
36
37
{
@@ -129,6 +130,44 @@ static int gh_client__send__objects_get(struct child_process *process,
129
130
return 0 ;
130
131
}
131
132
133
+ /*
134
+ * Send a request to gvfs-helper to prefetch packfiles from either the
135
+ * cache-server or the main Git server using "/gvfs/prefetch".
136
+ *
137
+ * objects.prefetch LF
138
+ * [<seconds-since_epoch> LF]
139
+ * <flush>
140
+ */
141
+ static int gh_client__send__objects_prefetch (struct child_process * process ,
142
+ timestamp_t seconds_since_epoch )
143
+ {
144
+ int err ;
145
+
146
+ /*
147
+ * We assume that all of the packet_ routines call error()
148
+ * so that we don't have to.
149
+ */
150
+
151
+ err = packet_write_fmt_gently (
152
+ process -> in ,
153
+ (CAP_OBJECTS_NAME "." CAP_OBJECTS__VERB_PREFETCH_NAME "\n" ));
154
+ if (err )
155
+ return err ;
156
+
157
+ if (seconds_since_epoch ) {
158
+ err = packet_write_fmt_gently (process -> in , "%" PRItime "\n" ,
159
+ seconds_since_epoch );
160
+ if (err )
161
+ return err ;
162
+ }
163
+
164
+ err = packet_flush_gently (process -> in );
165
+ if (err )
166
+ return err ;
167
+
168
+ return 0 ;
169
+ }
170
+
132
171
/*
133
172
* Verify that the pathname found in the "odb" response line matches
134
173
* what we requested.
@@ -198,7 +237,7 @@ static void gh_client__update_packed_git(const char *line)
198
237
}
199
238
200
239
/*
201
- * Both CAP_OBJECTS verbs return the same format response:
240
+ * CAP_OBJECTS verbs return the same format response:
202
241
*
203
242
* <odb>
204
243
* <data>*
@@ -238,6 +277,8 @@ static int gh_client__objects__receive_response(
238
277
const char * v1 ;
239
278
char * line ;
240
279
int len ;
280
+ int nr_loose = 0 ;
281
+ int nr_packfile = 0 ;
241
282
int err = 0 ;
242
283
243
284
while (1 ) {
@@ -256,13 +297,13 @@ static int gh_client__objects__receive_response(
256
297
else if (starts_with (line , "packfile" )) {
257
298
gh_client__update_packed_git (line );
258
299
ghc |= GHC__CREATED__PACKFILE ;
259
- * p_nr_packfile += 1 ;
300
+ nr_packfile ++ ;
260
301
}
261
302
262
303
else if (starts_with (line , "loose" )) {
263
304
gh_client__update_loose_cache (line );
264
305
ghc |= GHC__CREATED__LOOSE ;
265
- * p_nr_loose += 1 ;
306
+ nr_loose ++ ;
266
307
}
267
308
268
309
else if (starts_with (line , "ok" ))
@@ -276,6 +317,8 @@ static int gh_client__objects__receive_response(
276
317
}
277
318
278
319
* p_ghc = ghc ;
320
+ * p_nr_loose = nr_loose ;
321
+ * p_nr_packfile = nr_packfile ;
279
322
280
323
return err ;
281
324
}
@@ -333,7 +376,7 @@ static struct gh_server__process *gh_client__find_long_running_process(
333
376
/*
334
377
* Find an existing long-running process with the above command
335
378
* line -or- create a new long-running process for this and
336
- * subsequent 'get' requests.
379
+ * subsequent requests.
337
380
*/
338
381
if (!gh_server__subprocess_map_initialized ) {
339
382
gh_server__subprocess_map_initialized = 1 ;
@@ -370,10 +413,14 @@ static struct gh_server__process *gh_client__find_long_running_process(
370
413
371
414
void gh_client__queue_oid (const struct object_id * oid )
372
415
{
373
- // TODO consider removing this trace2. it is useful for interactive
374
- // TODO debugging, but may generate way too much noise for a data
375
- // TODO event.
376
- trace2_printf ("gh_client__queue_oid: %s" , oid_to_hex (oid ));
416
+ /*
417
+ * Keep this trace as a printf only, so that it goes to the
418
+ * perf log, but not the event log. It is useful for interactive
419
+ * debugging, but generates way too much (unuseful) noise for the
420
+ * database.
421
+ */
422
+ if (trace2_is_enabled ())
423
+ trace2_printf ("gh_client__queue_oid: %s" , oid_to_hex (oid ));
377
424
378
425
if (!oidset_insert (& gh_client__oidset_queued , oid ))
379
426
gh_client__oidset_count ++ ;
@@ -454,10 +501,14 @@ int gh_client__get_immediate(const struct object_id *oid,
454
501
int nr_packfile = 0 ;
455
502
int err = 0 ;
456
503
457
- // TODO consider removing this trace2. it is useful for interactive
458
- // TODO debugging, but may generate way too much noise for a data
459
- // TODO event.
460
- trace2_printf ("gh_client__get_immediate: %s" , oid_to_hex (oid ));
504
+ /*
505
+ * Keep this trace as a printf only, so that it goes to the
506
+ * perf log, but not the event log. It is useful for interactive
507
+ * debugging, but generates way too much (unuseful) noise for the
508
+ * database.
509
+ */
510
+ if (trace2_is_enabled ())
511
+ trace2_printf ("gh_client__get_immediate: %s" , oid_to_hex (oid ));
461
512
462
513
entry = gh_client__find_long_running_process (CAP_OBJECTS );
463
514
if (!entry )
@@ -486,3 +537,55 @@ int gh_client__get_immediate(const struct object_id *oid,
486
537
487
538
return err ;
488
539
}
540
+
541
+ /*
542
+ * Ask gvfs-helper to prefetch commits-and-trees packfiles since a
543
+ * given timestamp.
544
+ *
545
+ * If seconds_since_epoch is zero, gvfs-helper will scan the ODB for
546
+ * the last received prefetch and ask for ones newer than that.
547
+ */
548
+ int gh_client__prefetch (timestamp_t seconds_since_epoch ,
549
+ int * nr_packfiles_received )
550
+ {
551
+ struct gh_server__process * entry ;
552
+ struct child_process * process ;
553
+ enum gh_client__created ghc ;
554
+ int nr_loose = 0 ;
555
+ int nr_packfile = 0 ;
556
+ int err = 0 ;
557
+
558
+ entry = gh_client__find_long_running_process (CAP_OBJECTS );
559
+ if (!entry )
560
+ return -1 ;
561
+
562
+ trace2_region_enter ("gh-client" , "objects/prefetch" , the_repository );
563
+ trace2_data_intmax ("gh-client" , the_repository , "prefetch/since" ,
564
+ seconds_since_epoch );
565
+
566
+ process = & entry -> subprocess .process ;
567
+
568
+ sigchain_push (SIGPIPE , SIG_IGN );
569
+
570
+ err = gh_client__send__objects_prefetch (process , seconds_since_epoch );
571
+ if (!err )
572
+ err = gh_client__objects__receive_response (
573
+ process , & ghc , & nr_loose , & nr_packfile );
574
+
575
+ sigchain_pop (SIGPIPE );
576
+
577
+ if (err ) {
578
+ subprocess_stop (& gh_server__subprocess_map ,
579
+ (struct subprocess_entry * )entry );
580
+ FREE_AND_NULL (entry );
581
+ }
582
+
583
+ trace2_data_intmax ("gh-client" , the_repository ,
584
+ "prefetch/packfile_count" , nr_packfile );
585
+ trace2_region_leave ("gh-client" , "objects/prefetch" , the_repository );
586
+
587
+ if (nr_packfiles_received )
588
+ * nr_packfiles_received = nr_packfile ;
589
+
590
+ return err ;
591
+ }
0 commit comments