|
@@ -48,6 +48,25 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
48
|
48
|
*/
|
49
|
49
|
#define PEERBLK_DECRYPT_CHUNKSIZE 2048
|
50
|
50
|
|
|
51
|
+/** PeerDist maximum number of concurrent raw block downloads
|
|
52
|
+ *
|
|
53
|
+ * Raw block downloads are expensive if the origin server uses HTTPS,
|
|
54
|
+ * since each concurrent download will require local TLS resources
|
|
55
|
+ * (including potentially large received encrypted data buffers).
|
|
56
|
+ *
|
|
57
|
+ * Raw block downloads may also be prohibitively slow to initiate when
|
|
58
|
+ * the origin server is using HTTPS and client certificates. Origin
|
|
59
|
+ * servers for PeerDist downloads are likely to be running IIS, which
|
|
60
|
+ * has a bug that breaks session resumption and requires each
|
|
61
|
+ * connection to go through the full client certificate verification.
|
|
62
|
+ *
|
|
63
|
+ * Limit the total number of concurrent raw block downloads to
|
|
64
|
+ * ameliorate these problems.
|
|
65
|
+ *
|
|
66
|
+ * This is a policy decision.
|
|
67
|
+ */
|
|
68
|
+#define PEERBLK_RAW_MAX 2
|
|
69
|
+
|
51
|
70
|
/** PeerDist raw block download attempt initial progress timeout
|
52
|
71
|
*
|
53
|
72
|
* This is a policy decision.
|
|
@@ -107,6 +126,8 @@ static struct profiler peerblk_discovery_success_profiler __profiler =
|
107
|
126
|
static struct profiler peerblk_discovery_timeout_profiler __profiler =
|
108
|
127
|
{ .name = "peerblk.discovery.timeout" };
|
109
|
128
|
|
|
129
|
+static void peerblk_dequeue ( struct peerdist_block *peerblk );
|
|
130
|
+
|
110
|
131
|
/**
|
111
|
132
|
* Get profiling timestamp
|
112
|
133
|
*
|
|
@@ -154,6 +175,10 @@ static void peerblk_reset ( struct peerdist_block *peerblk, int rc ) {
|
154
|
175
|
intf_restart ( &peerblk->raw, rc );
|
155
|
176
|
intf_restart ( &peerblk->retrieval, rc );
|
156
|
177
|
|
|
178
|
+ /* Remove from download queue, if applicable */
|
|
179
|
+ if ( peerblk->queue )
|
|
180
|
+ peerblk_dequeue ( peerblk );
|
|
181
|
+
|
157
|
182
|
/* Empty received data buffer */
|
158
|
183
|
xferbuf_free ( &peerblk->buffer );
|
159
|
184
|
peerblk->pos = 0;
|
|
@@ -439,6 +464,109 @@ static void peerblk_raw_close ( struct peerdist_block *peerblk, int rc ) {
|
439
|
464
|
peerblk_done ( peerblk, rc );
|
440
|
465
|
}
|
441
|
466
|
|
|
467
|
+/******************************************************************************
|
|
468
|
+ *
|
|
469
|
+ * Block download queue
|
|
470
|
+ *
|
|
471
|
+ ******************************************************************************
|
|
472
|
+ */
|
|
473
|
+
|
|
474
|
+/**
|
|
475
|
+ * PeerDist block download queue process
|
|
476
|
+ *
|
|
477
|
+ * @v queue Block download queue
|
|
478
|
+ */
|
|
479
|
+static void peerblk_step ( struct peerdist_block_queue *queue ) {
|
|
480
|
+ struct peerdist_block *peerblk;
|
|
481
|
+ int rc;
|
|
482
|
+
|
|
483
|
+ /* Do nothing yet if we have too many open block downloads */
|
|
484
|
+ if ( queue->count >= queue->max )
|
|
485
|
+ return;
|
|
486
|
+
|
|
487
|
+ /* Do nothing unless there are queued block downloads */
|
|
488
|
+ peerblk = list_first_entry ( &queue->list, struct peerdist_block,
|
|
489
|
+ queued );
|
|
490
|
+ if ( ! peerblk )
|
|
491
|
+ return;
|
|
492
|
+
|
|
493
|
+ /* Reschedule queue process */
|
|
494
|
+ process_add ( &queue->process );
|
|
495
|
+
|
|
496
|
+ /* Remove block from queue */
|
|
497
|
+ list_del ( &peerblk->queued );
|
|
498
|
+ INIT_LIST_HEAD ( &peerblk->queued );
|
|
499
|
+
|
|
500
|
+ /* Attempt download */
|
|
501
|
+ if ( ( rc = queue->open ( peerblk ) ) != 0 ) {
|
|
502
|
+ peerblk_close ( peerblk, rc );
|
|
503
|
+ return;
|
|
504
|
+ }
|
|
505
|
+
|
|
506
|
+ /* Increment open block download count */
|
|
507
|
+ queue->count++;
|
|
508
|
+}
|
|
509
|
+
|
|
510
|
+/**
|
|
511
|
+ * Add block to download queue
|
|
512
|
+ *
|
|
513
|
+ * @v peerblk PeerDist block download
|
|
514
|
+ * @v queue Block download queue
|
|
515
|
+ */
|
|
516
|
+static void peerblk_enqueue ( struct peerdist_block *peerblk,
|
|
517
|
+ struct peerdist_block_queue *queue ) {
|
|
518
|
+
|
|
519
|
+ /* Sanity checks */
|
|
520
|
+ assert ( peerblk->queue == NULL );
|
|
521
|
+ assert ( list_empty ( &peerblk->queued ) );
|
|
522
|
+
|
|
523
|
+ /* Add block to queue */
|
|
524
|
+ peerblk->queue = queue;
|
|
525
|
+ list_add_tail ( &peerblk->queued, &queue->list );
|
|
526
|
+
|
|
527
|
+ /* Schedule queue process */
|
|
528
|
+ process_add ( &queue->process );
|
|
529
|
+}
|
|
530
|
+
|
|
531
|
+/**
|
|
532
|
+ * Remove block from download queue
|
|
533
|
+ *
|
|
534
|
+ * @v peerblk PeerDist block download
|
|
535
|
+ */
|
|
536
|
+static void peerblk_dequeue ( struct peerdist_block *peerblk ) {
|
|
537
|
+ struct peerdist_block_queue *queue = peerblk->queue;
|
|
538
|
+
|
|
539
|
+ /* Sanity checks */
|
|
540
|
+ assert ( queue != NULL );
|
|
541
|
+
|
|
542
|
+ /* Remove block from queue */
|
|
543
|
+ peerblk->queue = NULL;
|
|
544
|
+ if ( list_empty ( &peerblk->queued ) ) {
|
|
545
|
+
|
|
546
|
+ /* Open download: decrement count and reschedule queue */
|
|
547
|
+ queue->count--;
|
|
548
|
+ process_add ( &queue->process );
|
|
549
|
+
|
|
550
|
+ } else {
|
|
551
|
+
|
|
552
|
+ /* Queued download: remove from queue */
|
|
553
|
+ list_del ( &peerblk->queued );
|
|
554
|
+ INIT_LIST_HEAD ( &peerblk->queued );
|
|
555
|
+ }
|
|
556
|
+}
|
|
557
|
+
|
|
558
|
+/** PeerDist block download queue process descriptor */
|
|
559
|
+static struct process_descriptor peerblk_queue_desc =
|
|
560
|
+ PROC_DESC_ONCE ( struct peerdist_block_queue, process, peerblk_step );
|
|
561
|
+
|
|
562
|
+/** Raw block download queue */
|
|
563
|
+static struct peerdist_block_queue peerblk_raw_queue = {
|
|
564
|
+ .process = PROC_INIT ( peerblk_raw_queue.process, &peerblk_queue_desc ),
|
|
565
|
+ .list = LIST_HEAD_INIT ( peerblk_raw_queue.list ),
|
|
566
|
+ .max = PEERBLK_RAW_MAX,
|
|
567
|
+ .open = peerblk_raw_open,
|
|
568
|
+};
|
|
569
|
+
|
442
|
570
|
/******************************************************************************
|
443
|
571
|
*
|
444
|
572
|
* Retrieval protocol block download attempts (using HTTP POST)
|
|
@@ -1213,9 +1341,8 @@ static void peerblk_expired ( struct retry_timer *timer, int over __unused ) {
|
1213
|
1341
|
return;
|
1214
|
1342
|
}
|
1215
|
1343
|
|
1216
|
|
- /* Attempt raw download */
|
1217
|
|
- if ( ( rc = peerblk_raw_open ( peerblk ) ) != 0 )
|
1218
|
|
- goto err;
|
|
1344
|
+ /* Add to raw download queue */
|
|
1345
|
+ peerblk_enqueue ( peerblk, &peerblk_raw_queue );
|
1219
|
1346
|
|
1220
|
1347
|
return;
|
1221
|
1348
|
|
|
@@ -1338,6 +1465,7 @@ int peerblk_open ( struct interface *xfer, struct uri *uri,
|
1338
|
1465
|
process_init_stopped ( &peerblk->process, &peerblk_process_desc,
|
1339
|
1466
|
&peerblk->refcnt );
|
1340
|
1467
|
peerdisc_init ( &peerblk->discovery, &peerblk_discovery_operations );
|
|
1468
|
+ INIT_LIST_HEAD ( &peerblk->queued );
|
1341
|
1469
|
timer_init ( &peerblk->timer, peerblk_expired, &peerblk->refcnt );
|
1342
|
1470
|
DBGC2 ( peerblk, "PEERBLK %p %d.%d id %02x%02x%02x%02x%02x..."
|
1343
|
1471
|
"%02x%02x%02x [%08zx,%08zx)", peerblk, peerblk->segment,
|