@@ -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
}
@@ -332,7 +375,7 @@ static struct gh_server__process *gh_client__find_long_running_process(
332
375
/*
333
376
* Find an existing long-running process with the above command
334
377
* line -or- create a new long-running process for this and
335
- * subsequent 'get' requests.
378
+ * subsequent requests.
336
379
*/
337
380
if (!gh_server__subprocess_map_initialized ) {
338
381
gh_server__subprocess_map_initialized = 1 ;
@@ -369,10 +412,14 @@ static struct gh_server__process *gh_client__find_long_running_process(
369
412
370
413
void gh_client__queue_oid (const struct object_id * oid )
371
414
{
372
- // TODO consider removing this trace2. it is useful for interactive
373
- // TODO debugging, but may generate way too much noise for a data
374
- // TODO event.
375
- trace2_printf ("gh_client__queue_oid: %s" , oid_to_hex (oid ));
415
+ /*
416
+ * Keep this trace as a printf only, so that it goes to the
417
+ * perf log, but not the event log. It is useful for interactive
418
+ * debugging, but generates way too much (unuseful) noise for the
419
+ * database.
420
+ */
421
+ if (trace2_is_enabled ())
422
+ trace2_printf ("gh_client__queue_oid: %s" , oid_to_hex (oid ));
376
423
377
424
if (!oidset_insert (& gh_client__oidset_queued , oid ))
378
425
gh_client__oidset_count ++ ;
@@ -453,10 +500,14 @@ int gh_client__get_immediate(const struct object_id *oid,
453
500
int nr_packfile = 0 ;
454
501
int err = 0 ;
455
502
456
- // TODO consider removing this trace2. it is useful for interactive
457
- // TODO debugging, but may generate way too much noise for a data
458
- // TODO event.
459
- trace2_printf ("gh_client__get_immediate: %s" , oid_to_hex (oid ));
503
+ /*
504
+ * Keep this trace as a printf only, so that it goes to the
505
+ * perf log, but not the event log. It is useful for interactive
506
+ * debugging, but generates way too much (unuseful) noise for the
507
+ * database.
508
+ */
509
+ if (trace2_is_enabled ())
510
+ trace2_printf ("gh_client__get_immediate: %s" , oid_to_hex (oid ));
460
511
461
512
entry = gh_client__find_long_running_process (CAP_OBJECTS );
462
513
if (!entry )
@@ -485,3 +536,55 @@ int gh_client__get_immediate(const struct object_id *oid,
485
536
486
537
return err ;
487
538
}
539
+
540
+ /*
541
+ * Ask gvfs-helper to prefetch commits-and-trees packfiles since a
542
+ * given timestamp.
543
+ *
544
+ * If seconds_since_epoch is zero, gvfs-helper will scan the ODB for
545
+ * the last received prefetch and ask for ones newer than that.
546
+ */
547
+ int gh_client__prefetch (timestamp_t seconds_since_epoch ,
548
+ int * nr_packfiles_received )
549
+ {
550
+ struct gh_server__process * entry ;
551
+ struct child_process * process ;
552
+ enum gh_client__created ghc ;
553
+ int nr_loose = 0 ;
554
+ int nr_packfile = 0 ;
555
+ int err = 0 ;
556
+
557
+ entry = gh_client__find_long_running_process (CAP_OBJECTS );
558
+ if (!entry )
559
+ return -1 ;
560
+
561
+ trace2_region_enter ("gh-client" , "objects/prefetch" , the_repository );
562
+ trace2_data_intmax ("gh-client" , the_repository , "prefetch/since" ,
563
+ seconds_since_epoch );
564
+
565
+ process = & entry -> subprocess .process ;
566
+
567
+ sigchain_push (SIGPIPE , SIG_IGN );
568
+
569
+ err = gh_client__send__objects_prefetch (process , seconds_since_epoch );
570
+ if (!err )
571
+ err = gh_client__objects__receive_response (
572
+ process , & ghc , & nr_loose , & nr_packfile );
573
+
574
+ sigchain_pop (SIGPIPE );
575
+
576
+ if (err ) {
577
+ subprocess_stop (& gh_server__subprocess_map ,
578
+ (struct subprocess_entry * )entry );
579
+ FREE_AND_NULL (entry );
580
+ }
581
+
582
+ trace2_data_intmax ("gh-client" , the_repository ,
583
+ "prefetch/packfile_count" , nr_packfile );
584
+ trace2_region_leave ("gh-client" , "objects/prefetch" , the_repository );
585
+
586
+ if (nr_packfiles_received )
587
+ * nr_packfiles_received = nr_packfile ;
588
+
589
+ return err ;
590
+ }
0 commit comments