| 489 | HttpTunnelProducer::HttpTunnelProducer() : consumer_list() {} |
| 490 | |
| 491 | uint64_t |
| 492 | HttpTunnelProducer::backlog(uint64_t limit) |
| 493 | { |
| 494 | uint64_t zret = 0; |
| 495 | // Calculate the total backlog, the # of bytes inside ATS for this producer. |
| 496 | // We go all the way through each chain to the ending sink and take the maximum |
| 497 | // over those paths. Do need to be careful about loops which can occur. |
| 498 | for (HttpTunnelConsumer *c = consumer_list.head; c; c = c->link.next) { |
| 499 | if (c->alive && c->write_vio) { |
| 500 | uint64_t n = 0; |
| 501 | if (HT_TRANSFORM == c->vc_type) { |
| 502 | n += static_cast<TransformVCChain *>(c->vc)->backlog(limit); |
| 503 | } else { |
| 504 | IOBufferReader *r = c->write_vio->get_reader(); |
| 505 | if (r) { |
| 506 | n += static_cast<uint64_t>(r->read_avail()); |
| 507 | } |
| 508 | } |
| 509 | if (n >= limit) { |
| 510 | return n; |
| 511 | } |
| 512 | |
| 513 | if (!c->is_sink()) { |
| 514 | HttpTunnelProducer *dsp = c->self_producer; |
| 515 | if (dsp) { |
| 516 | n += dsp->backlog(); |
| 517 | } |
| 518 | } |
| 519 | if (n >= limit) { |
| 520 | return n; |
| 521 | } |
| 522 | if (n > zret) { |
| 523 | zret = n; |
| 524 | } |
| 525 | } |
| 526 | } |
| 527 | |
| 528 | if (chunked_handler.chunked_reader) { |
| 529 | zret += static_cast<uint64_t>(chunked_handler.chunked_reader->read_avail()); |
| 530 | } |
| 531 | |
| 532 | return zret; |
| 533 | } |
| 534 | |
| 535 | /* We set the producers in a flow chain specifically rather than |
| 536 | using a tunnel level variable in order to handle bi-directional |
no test coverage detected