@@ -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
* Update the loose object cache to include the newly created
134
173
* object.
@@ -176,7 +215,7 @@ static void gh_client__update_packed_git(const char *line)
176
215
}
177
216
178
217
/*
179
- * Both CAP_OBJECTS verbs return the same format response:
218
+ * CAP_OBJECTS verbs return the same format response:
180
219
*
181
220
* <odb>
182
221
* <data>*
@@ -216,6 +255,8 @@ static int gh_client__objects__receive_response(
216
255
const char * v1 ;
217
256
char * line ;
218
257
int len ;
258
+ int nr_loose = 0 ;
259
+ int nr_packfile = 0 ;
219
260
int err = 0 ;
220
261
221
262
while (1 ) {
@@ -234,13 +275,13 @@ static int gh_client__objects__receive_response(
234
275
else if (starts_with (line , "packfile" )) {
235
276
gh_client__update_packed_git (line );
236
277
ghc |= GHC__CREATED__PACKFILE ;
237
- * p_nr_packfile += 1 ;
278
+ nr_packfile ++ ;
238
279
}
239
280
240
281
else if (starts_with (line , "loose" )) {
241
282
gh_client__update_loose_cache (line );
242
283
ghc |= GHC__CREATED__LOOSE ;
243
- * p_nr_loose += 1 ;
284
+ nr_loose ++ ;
244
285
}
245
286
246
287
else if (starts_with (line , "ok" ))
@@ -254,6 +295,8 @@ static int gh_client__objects__receive_response(
254
295
}
255
296
256
297
* p_ghc = ghc ;
298
+ * p_nr_loose = nr_loose ;
299
+ * p_nr_packfile = nr_packfile ;
257
300
258
301
return err ;
259
302
}
@@ -310,7 +353,7 @@ static struct gh_server__process *gh_client__find_long_running_process(
310
353
/*
311
354
* Find an existing long-running process with the above command
312
355
* line -or- create a new long-running process for this and
313
- * subsequent 'get' requests.
356
+ * subsequent requests.
314
357
*/
315
358
if (!gh_server__subprocess_map_initialized ) {
316
359
gh_server__subprocess_map_initialized = 1 ;
@@ -347,10 +390,14 @@ static struct gh_server__process *gh_client__find_long_running_process(
347
390
348
391
void gh_client__queue_oid (const struct object_id * oid )
349
392
{
350
- // TODO consider removing this trace2. it is useful for interactive
351
- // TODO debugging, but may generate way too much noise for a data
352
- // TODO event.
353
- trace2_printf ("gh_client__queue_oid: %s" , oid_to_hex (oid ));
393
+ /*
394
+ * Keep this trace as a printf only, so that it goes to the
395
+ * perf log, but not the event log. It is useful for interactive
396
+ * debugging, but generates way too much (unuseful) noise for the
397
+ * database.
398
+ */
399
+ if (trace2_is_enabled ())
400
+ trace2_printf ("gh_client__queue_oid: %s" , oid_to_hex (oid ));
354
401
355
402
if (!oidset_insert (& gh_client__oidset_queued , oid ))
356
403
gh_client__oidset_count ++ ;
@@ -431,10 +478,14 @@ int gh_client__get_immediate(const struct object_id *oid,
431
478
int nr_packfile = 0 ;
432
479
int err = 0 ;
433
480
434
- // TODO consider removing this trace2. it is useful for interactive
435
- // TODO debugging, but may generate way too much noise for a data
436
- // TODO event.
437
- trace2_printf ("gh_client__get_immediate: %s" , oid_to_hex (oid ));
481
+ /*
482
+ * Keep this trace as a printf only, so that it goes to the
483
+ * perf log, but not the event log. It is useful for interactive
484
+ * debugging, but generates way too much (unuseful) noise for the
485
+ * database.
486
+ */
487
+ if (trace2_is_enabled ())
488
+ trace2_printf ("gh_client__get_immediate: %s" , oid_to_hex (oid ));
438
489
439
490
entry = gh_client__find_long_running_process (CAP_OBJECTS );
440
491
if (!entry )
@@ -463,3 +514,55 @@ int gh_client__get_immediate(const struct object_id *oid,
463
514
464
515
return err ;
465
516
}
517
+
518
+ /*
519
+ * Ask gvfs-helper to prefetch commits-and-trees packfiles since a
520
+ * given timestamp.
521
+ *
522
+ * If seconds_since_epoch is zero, gvfs-helper will scan the ODB for
523
+ * the last received prefetch and ask for ones newer than that.
524
+ */
525
+ int gh_client__prefetch (timestamp_t seconds_since_epoch ,
526
+ int * nr_packfiles_received )
527
+ {
528
+ struct gh_server__process * entry ;
529
+ struct child_process * process ;
530
+ enum gh_client__created ghc ;
531
+ int nr_loose = 0 ;
532
+ int nr_packfile = 0 ;
533
+ int err = 0 ;
534
+
535
+ entry = gh_client__find_long_running_process (CAP_OBJECTS );
536
+ if (!entry )
537
+ return -1 ;
538
+
539
+ trace2_region_enter ("gh-client" , "objects/prefetch" , the_repository );
540
+ trace2_data_intmax ("gh-client" , the_repository , "prefetch/since" ,
541
+ seconds_since_epoch );
542
+
543
+ process = & entry -> subprocess .process ;
544
+
545
+ sigchain_push (SIGPIPE , SIG_IGN );
546
+
547
+ err = gh_client__send__objects_prefetch (process , seconds_since_epoch );
548
+ if (!err )
549
+ err = gh_client__objects__receive_response (
550
+ process , & ghc , & nr_loose , & nr_packfile );
551
+
552
+ sigchain_pop (SIGPIPE );
553
+
554
+ if (err ) {
555
+ subprocess_stop (& gh_server__subprocess_map ,
556
+ (struct subprocess_entry * )entry );
557
+ FREE_AND_NULL (entry );
558
+ }
559
+
560
+ trace2_data_intmax ("gh-client" , the_repository ,
561
+ "prefetch/packfile_count" , nr_packfile );
562
+ trace2_region_leave ("gh-client" , "objects/prefetch" , the_repository );
563
+
564
+ if (nr_packfiles_received )
565
+ * nr_packfiles_received = nr_packfile ;
566
+
567
+ return err ;
568
+ }
0 commit comments