13
13
14
14
static struct oidset gh_client__oidset_queued = OIDSET_INIT ;
15
15
static unsigned long gh_client__oidset_count ;
16
- static int gh_client__includes_immediate ;
17
16
18
17
struct gh_server__process {
19
18
struct subprocess_entry subprocess ; /* must be first */
@@ -24,13 +23,20 @@ static int gh_server__subprocess_map_initialized;
24
23
static struct hashmap gh_server__subprocess_map ;
25
24
static struct object_directory * gh_client__chosen_odb ;
26
25
27
- #define CAP_GET (1u<<1)
26
+ /*
27
+ * The "objects" capability has 2 verbs: "get" and "post".
28
+ */
29
+ #define CAP_OBJECTS (1u<<1)
30
+ #define CAP_OBJECTS_NAME "objects"
31
+
32
+ #define CAP_OBJECTS__VERB_GET1_NAME "get"
33
+ #define CAP_OBJECTS__VERB_POST_NAME "post"
28
34
29
35
static int gh_client__start_fn (struct subprocess_entry * subprocess )
30
36
{
31
37
static int versions [] = {1 , 0 };
32
38
static struct subprocess_capability capabilities [] = {
33
- { "get" , CAP_GET },
39
+ { CAP_OBJECTS_NAME , CAP_OBJECTS },
34
40
{ NULL , 0 }
35
41
};
36
42
@@ -42,14 +48,16 @@ static int gh_client__start_fn(struct subprocess_entry *subprocess)
42
48
}
43
49
44
50
/*
45
- * Send:
51
+ * Send the queued OIDs in the OIDSET to gvfs-helper for it to
52
+ * fetch from the cache-server or main Git server using "/gvfs/objects"
53
+ * POST semantics.
46
54
*
47
- * get LF
55
+ * objects.post LF
48
56
* (<hex-oid> LF)*
49
57
* <flush>
50
58
*
51
59
*/
52
- static int gh_client__get__send_command (struct child_process * process )
60
+ static int gh_client__send__objects_post (struct child_process * process )
53
61
{
54
62
struct oidset_iter iter ;
55
63
struct object_id * oid ;
@@ -60,7 +68,9 @@ static int gh_client__get__send_command(struct child_process *process)
60
68
* so that we don't have to.
61
69
*/
62
70
63
- err = packet_write_fmt_gently (process -> in , "get\n" );
71
+ err = packet_write_fmt_gently (
72
+ process -> in ,
73
+ (CAP_OBJECTS_NAME "." CAP_OBJECTS__VERB_POST_NAME "\n" ));
64
74
if (err )
65
75
return err ;
66
76
@@ -79,6 +89,46 @@ static int gh_client__get__send_command(struct child_process *process)
79
89
return 0 ;
80
90
}
81
91
92
+ /*
93
+ * Send the given OID to gvfs-helper for it to fetch from the
94
+ * cache-server or main Git server using "/gvfs/objects" GET
95
+ * semantics.
96
+ *
97
+ * This ignores any queued OIDs.
98
+ *
99
+ * objects.get LF
100
+ * <hex-oid> LF
101
+ * <flush>
102
+ *
103
+ */
104
+ static int gh_client__send__objects_get (struct child_process * process ,
105
+ const struct object_id * oid )
106
+ {
107
+ int err ;
108
+
109
+ /*
110
+ * We assume that all of the packet_ routines call error()
111
+ * so that we don't have to.
112
+ */
113
+
114
+ err = packet_write_fmt_gently (
115
+ process -> in ,
116
+ (CAP_OBJECTS_NAME "." CAP_OBJECTS__VERB_GET1_NAME "\n" ));
117
+ if (err )
118
+ return err ;
119
+
120
+ err = packet_write_fmt_gently (process -> in , "%s\n" ,
121
+ oid_to_hex (oid ));
122
+ if (err )
123
+ return err ;
124
+
125
+ err = packet_flush_gently (process -> in );
126
+ if (err )
127
+ return err ;
128
+
129
+ return 0 ;
130
+ }
131
+
82
132
/*
83
133
* Verify that the pathname found in the "odb" response line matches
84
134
* what we requested.
@@ -148,7 +198,7 @@ static void gh_client__update_packed_git(const char *line)
148
198
}
149
199
150
200
/*
151
- * We expect :
201
+ * Both CAP_OBJECTS verbs return the same format response :
152
202
*
153
203
* <odb>
154
204
* <data>*
@@ -179,7 +229,7 @@ static void gh_client__update_packed_git(const char *line)
179
229
* grouped with a queued request for a blob. The tree-walk *might* be
180
230
* able to continue and let the 404 blob be handled later.
181
231
*/
182
- static int gh_client__get__receive_response (
232
+ static int gh_client__objects__receive_response (
183
233
struct child_process * process ,
184
234
enum gh_client__created * p_ghc ,
185
235
int * p_nr_loose , int * p_nr_packfile )
@@ -259,17 +309,12 @@ static void gh_client__choose_odb(void)
259
309
}
260
310
}
261
311
262
- static int gh_client__get (enum gh_client__created * p_ghc )
312
+ static struct gh_server__process * gh_client__find_long_running_process (
313
+ unsigned int cap_needed )
263
314
{
264
315
struct gh_server__process * entry ;
265
- struct child_process * process ;
266
316
struct argv_array argv = ARGV_ARRAY_INIT ;
267
317
struct strbuf quoted = STRBUF_INIT ;
268
- int nr_loose = 0 ;
269
- int nr_packfile = 0 ;
270
- int err = 0 ;
271
-
272
- trace2_region_enter ("gh-client" , "get" , the_repository );
273
318
274
319
gh_client__choose_odb ();
275
320
@@ -285,6 +330,11 @@ static int gh_client__get(enum gh_client__created *p_ghc)
285
330
286
331
sq_quote_argv_pretty (& quoted , argv .argv );
287
332
333
+ /*
334
+ * Find an existing long-running process with the above command
335
+ * line -or- create a new long-running process for this and
336
+ * subsequent 'get' requests.
337
+ */
288
338
if (!gh_server__subprocess_map_initialized ) {
289
339
gh_server__subprocess_map_initialized = 1 ;
290
340
hashmap_init (& gh_server__subprocess_map ,
@@ -298,70 +348,24 @@ static int gh_client__get(enum gh_client__created *p_ghc)
298
348
entry = xmalloc (sizeof (* entry ));
299
349
entry -> supported_capabilities = 0 ;
300
350
301
- err = subprocess_start_argv (
302
- & gh_server__subprocess_map , & entry -> subprocess , 1 ,
303
- & argv , gh_client__start_fn );
304
- if (err ) {
305
- free (entry );
306
- goto leave_region ;
307
- }
351
+ if (subprocess_start_argv (& gh_server__subprocess_map ,
352
+ & entry -> subprocess , 1 ,
353
+ & argv , gh_client__start_fn ))
354
+ FREE_AND_NULL (entry );
308
355
}
309
356
310
- process = & entry -> subprocess .process ;
311
-
312
- if (!(CAP_GET & entry -> supported_capabilities )) {
313
- error ("gvfs-helper: does not support GET" );
357
+ if (entry &&
358
+ (entry -> supported_capabilities & cap_needed ) != cap_needed ) {
359
+ error ("gvfs-helper: does not support needed capabilities" );
314
360
subprocess_stop (& gh_server__subprocess_map ,
315
361
(struct subprocess_entry * )entry );
316
- free (entry );
317
- err = -1 ;
318
- goto leave_region ;
362
+ FREE_AND_NULL (entry );
319
363
}
320
364
321
- sigchain_push (SIGPIPE , SIG_IGN );
322
-
323
- err = gh_client__get__send_command (process );
324
- if (!err )
325
- err = gh_client__get__receive_response (process , p_ghc ,
326
- & nr_loose , & nr_packfile );
327
-
328
- sigchain_pop (SIGPIPE );
329
-
330
- if (err ) {
331
- subprocess_stop (& gh_server__subprocess_map ,
332
- (struct subprocess_entry * )entry );
333
- free (entry );
334
- }
335
-
336
- leave_region :
337
365
argv_array_clear (& argv );
338
366
strbuf_release (& quoted );
339
367
340
- trace2_data_intmax ("gh-client" , the_repository ,
341
- "get/immediate" , gh_client__includes_immediate );
342
-
343
- trace2_data_intmax ("gh-client" , the_repository ,
344
- "get/nr_objects" , gh_client__oidset_count );
345
-
346
- if (nr_loose )
347
- trace2_data_intmax ("gh-client" , the_repository ,
348
- "get/nr_loose" , nr_loose );
349
-
350
- if (nr_packfile )
351
- trace2_data_intmax ("gh-client" , the_repository ,
352
- "get/nr_packfile" , nr_packfile );
353
-
354
- if (err )
355
- trace2_data_intmax ("gh-client" , the_repository ,
356
- "get/error" , err );
357
-
358
- trace2_region_leave ("gh-client" , "get" , the_repository );
359
-
360
- oidset_clear (& gh_client__oidset_queued );
361
- gh_client__oidset_count = 0 ;
362
- gh_client__includes_immediate = 0 ;
363
-
364
- return err ;
368
+ return entry ;
365
369
}
366
370
367
371
void gh_client__queue_oid (const struct object_id * oid )
@@ -388,28 +392,97 @@ void gh_client__queue_oid_array(const struct object_id *oids, int oid_nr)
388
392
gh_client__queue_oid (& oids [k ]);
389
393
}
390
394
395
+ /*
396
+ * Bulk fetch all of the queued OIDs in the OIDSET.
397
+ */
391
398
int gh_client__drain_queue (enum gh_client__created * p_ghc )
392
399
{
400
+ struct gh_server__process * entry ;
401
+ struct child_process * process ;
402
+ int nr_loose = 0 ;
403
+ int nr_packfile = 0 ;
404
+ int err = 0 ;
405
+
393
406
* p_ghc = GHC__CREATED__NOTHING ;
394
407
395
408
if (!gh_client__oidset_count )
396
409
return 0 ;
397
410
398
- return gh_client__get (p_ghc );
411
+ entry = gh_client__find_long_running_process (CAP_OBJECTS );
412
+ if (!entry )
413
+ return -1 ;
414
+
415
+ trace2_region_enter ("gh-client" , "objects/post" , the_repository );
416
+
417
+ process = & entry -> subprocess .process ;
418
+
419
+ sigchain_push (SIGPIPE , SIG_IGN );
420
+
421
+ err = gh_client__send__objects_post (process );
422
+ if (!err )
423
+ err = gh_client__objects__receive_response (
424
+ process , p_ghc , & nr_loose , & nr_packfile );
425
+
426
+ sigchain_pop (SIGPIPE );
427
+
428
+ if (err ) {
429
+ subprocess_stop (& gh_server__subprocess_map ,
430
+ (struct subprocess_entry * )entry );
431
+ FREE_AND_NULL (entry );
432
+ }
433
+
434
+ trace2_data_intmax ("gh-client" , the_repository ,
435
+ "objects/post/nr_objects" , gh_client__oidset_count );
436
+ trace2_region_leave ("gh-client" , "objects/post" , the_repository );
437
+
438
+ oidset_clear (& gh_client__oidset_queued );
439
+ gh_client__oidset_count = 0 ;
440
+
441
+ return err ;
399
442
}
400
443
444
+ /*
445
+ * Get exactly 1 object immediately.
446
+ * Ignore any queued objects.
447
+ */
401
448
int gh_client__get_immediate (const struct object_id * oid ,
402
449
enum gh_client__created * p_ghc )
403
450
{
404
- gh_client__includes_immediate = 1 ;
451
+ struct gh_server__process * entry ;
452
+ struct child_process * process ;
453
+ int nr_loose = 0 ;
454
+ int nr_packfile = 0 ;
455
+ int err = 0 ;
405
456
406
457
// TODO consider removing this trace2. it is useful for interactive
407
458
// TODO debugging, but may generate way too much noise for a data
408
459
// TODO event.
409
460
trace2_printf ("gh_client__get_immediate: %s" , oid_to_hex (oid ));
410
461
411
- if (!oidset_insert (& gh_client__oidset_queued , oid ))
412
- gh_client__oidset_count ++ ;
462
+ entry = gh_client__find_long_running_process (CAP_OBJECTS );
463
+ if (!entry )
464
+ return -1 ;
465
+
466
+ trace2_region_enter ("gh-client" , "objects/get" , the_repository );
413
467
414
- return gh_client__drain_queue (p_ghc );
468
+ process = & entry -> subprocess .process ;
469
+
470
+ sigchain_push (SIGPIPE , SIG_IGN );
471
+
472
+ err = gh_client__send__objects_get (process , oid );
473
+ if (!err )
474
+ err = gh_client__objects__receive_response (
475
+ process , p_ghc , & nr_loose , & nr_packfile );
476
+
477
+ sigchain_pop (SIGPIPE );
478
+
479
+ if (err ) {
480
+ subprocess_stop (& gh_server__subprocess_map ,
481
+ (struct subprocess_entry * )entry );
482
+ FREE_AND_NULL (entry );
483
+ }
484
+
485
+ trace2_region_leave ("gh-client" , "objects/get" , the_repository );
486
+
487
+ return err ;
415
488
}
0 commit comments