==== Механизм слежения за асинхронными путями исполнения (Branch layers) ====


=== Зачем это нужно ===

Рассмотрим асинхронный сервер, обрабатывающий запросы от клиентов. Поставим
перед собой задачу оградить этот сервер от исчерпания ресурсов из-за слишком
большого количества одновременно обрабатываемых запросов. Для этого установим
лимит на кол-во запросов, одновременно находящихся в обработке. При превышении
этого лимита приостанавливаем приём новых запросов. Постараемся построить
механизм, позволяющий одновременно и независимо ограничивать различные множества
операций (например, "не более 5 операций получения тяжёлого контента, и не более
50 - лёгкого").

Для того, чтобы реализовать такие лимиты, нужно знать количество запросов,
которые обрабатываются в данный момент. Если сервер обрабатывает запросы
асинхронно, то потребуется специальный механизм слежения за путями исполнения.
Branch layers (BL) - механизм слежения, предлагаемый библиотекой MyCpp.

Определим моменты начала и окончания асинхронной обработки запроса. Начало
обработки - это момент, когда, разобрав содержание клиентского запроса, сервер
принимает решение о начале обработки и переходит к первому шагу в цепочке
обработки. Завершение обработки - момент, когда освобождаются все ресурсы,
связанные с процессом обработки запроса.

Поясним определение момента завершения на примере. Допустим, обработка запроса
состоит из четырёх этапов: A, B, C, D. Этапы B и C выполняются последовательно:

          /--> B ---\
    A ---+           +---> D
          \--> C ---/

Допустим, на этапе "B" произошла ошибка, и мы прерываем цепочку обработки.
В этот момент обработку запроса ещё нельзя считать завершённой, т.к. ещё
не завершён этап "C". После завершения этапа "C" все ресурсы, связанные с
обработкой запроса, будут освобождены, т.к. больше не останется активных этапов.
С этого момента обработку можно будет считать завершённой.

Механизм BL предоставляет обобщённые средства для отслеживания завершения таких
цепочек обработки.


=== Как работает механизм Branch layers ===

Описание текущей реализации в MyCpp.

(также см. комментарий в mycpp/mycpp_thread_local.h)

"Branch" представляется в виде объекта SimplyReferenced. Считается, что ветвь
закончилась, когда соответствующий branch удаляется. Пользователь помещает
действия, которые необходимо совершить по окончании ветви, в деструктор объекта,
порождённого от SimplyReferenced.

class BranchLayer - набор объектов Branch (пользовательских объектов),
описывающих слой исполнения.

class BranchLayerKey - ключ, через который пользователь задаёт конкретный
слой исполнения.

beginNewBranch() - создаём новую группу сохранения, добавляем в неё новый слой
исполнения, и добавляем в этот слой ветвь. На данный момент используется только
в классе BranchHolder.

mergeNewBranch() - добавляем новый слой исполнения в текущую группу сохранения
и добавляем в этот слой ветвь. На данный момент используется только в классе
BranchMerger.

saveCurrentBranchLayer() - создаём новый объект BranchLayer, содержащий все
ветви из текущей группы сохранения, и возвращаем этот объект пользователю.
Используется, когда нужно сохранить описание текущего слоя исполнения для
последующего слияния при вызове отложенной процедуры обработки. Широко
применяется в пользовательском коде в MyNC.

pushBranchLayer() - создаём новую группу сохранения, в ней - новый слой, и
наполняем этот слой ветвями из заданного слоя. На данный момент используется
только в классе BranchLayerHolder, который, в свою очередь, нигде
не используется.

mergeBranchLayer() - то же, что и pushBranchLayer, но добавляем новый слой к
текущей группе сохранения. На данный момент используется только в классе
BranchLayerMerger.

endTopmostBranchLayer() - удаляем текущий слой в текущей группе сохранения. Если
в результате группа сохранения оказывается пустой, то удаляем её. На данный
момент используется только в реализации механизма BL в MyCpp.

class BranchHolder - пара beginNewBranch/endTopmostBranchLayer. Сейчас
единственное место, где используется BranchHolder - это метод
MyRelay::MessageCollector::report(). Полагаю, что в этом месте следует
использовать BranchMerger.

class BranchMerger - пара mergeNewBranch/endTopmostBranchLayer. Сейчас
единственное место, где используется BranchMerger - это метод
MyRelay::LoadBarrier::lineCallback().

class BranchLayerHolder - пара pushBranchLayer/endTopmostBranchLayer. На данный
момент нигде не используется.

class BranchLayerMerger - пара mergeBranchLayer/endTopmostBranchLayer. Широко
используется в коде MyNC в связке с saveCurrentBranchLayer().


=== Схема использования механизма BL ===

1. В момент начала асинхронной цепочки обработки создаём объект Branch,
   представляющий эту цепочку в механизме BL. Удаление объекта Branch будет
   означать завершение цепочки. Создаём объект BranchMerger, чтобы присоединить
   нашу новую цепочку к текущей группе сохранения. Если код, инициировавший
   начало асинхронной цепочки, не хочет, чтобы существующие ветви попадали
   в зависимость от новой, он может предварительно создать пустую группу
   сохранения.

2. Перед выполнением асинхронного вызова делаем saveCurrentBranchLayer(),
   результат помещаем в структуру состояния вызова.

3. При входе в обработчик результата асинхронного вызова используем
   BranchLayerHolder, чтобы задать текущую активную цепочку обработки.


=== Замечания по текущей реализации ===

* Считаю, что повсеместно вместо BranchLayerMerger следует использовать
  BranchLayerHolder, чтобы не наводить некорректных зависимостей между ветвями
  обработки. Ветвь обработки ответа от бэкэнда не должна сливаться с ветвью
  обработки клиентского запроса.

* Можно было бы сделать более эффективную реализацию BL (меньше new), усилив
  абстракцию.


=== Выводы применительно к momentvideo ===

Механизм заслуживает включения в libmymt и обобщённого использования в Mt.
Реализация должна быть предельно эффективной (thread-local storage, grow-only
slab, intrusive lists). Нужно подробно описать семантику всех операций (что для
чего можно использовать; что можно сделать, а что нельзя). API должен быть
минималистским. Текущий API в MyCpp избыточен.

