diff options
author | robot-piglet <robot-piglet@yandex-team.com> | 2023-12-04 15:32:14 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2023-12-05 01:22:50 +0300 |
commit | c21ed9eedf73010bc81342518177dfdfb0d56bd7 (patch) | |
tree | 72f8fde4463080cfe5a38eb0babc051cfe32c51e /library/cpp | |
parent | ec1311bf2e8cc231723b8b5e484ca576663a1309 (diff) | |
download | ydb-c21ed9eedf73010bc81342518177dfdfb0d56bd7.tar.gz |
Intermediate changes
Diffstat (limited to 'library/cpp')
651 files changed, 0 insertions, 84412 deletions
diff --git a/library/cpp/CMakeLists.darwin-arm64.txt b/library/cpp/CMakeLists.darwin-arm64.txt index 58a86cdbb5..918b7e4c77 100644 --- a/library/cpp/CMakeLists.darwin-arm64.txt +++ b/library/cpp/CMakeLists.darwin-arm64.txt @@ -7,7 +7,6 @@ add_subdirectory(accurate_accumulate) -add_subdirectory(actors) add_subdirectory(archive) add_subdirectory(balloc) add_subdirectory(binsaver) diff --git a/library/cpp/CMakeLists.darwin-x86_64.txt b/library/cpp/CMakeLists.darwin-x86_64.txt index 5692463e65..4656f580ad 100644 --- a/library/cpp/CMakeLists.darwin-x86_64.txt +++ b/library/cpp/CMakeLists.darwin-x86_64.txt @@ -7,7 +7,6 @@ add_subdirectory(accurate_accumulate) -add_subdirectory(actors) add_subdirectory(archive) add_subdirectory(balloc) add_subdirectory(binsaver) diff --git a/library/cpp/CMakeLists.linux-aarch64.txt b/library/cpp/CMakeLists.linux-aarch64.txt index 58a86cdbb5..918b7e4c77 100644 --- a/library/cpp/CMakeLists.linux-aarch64.txt +++ b/library/cpp/CMakeLists.linux-aarch64.txt @@ -7,7 +7,6 @@ add_subdirectory(accurate_accumulate) -add_subdirectory(actors) add_subdirectory(archive) add_subdirectory(balloc) add_subdirectory(binsaver) diff --git a/library/cpp/CMakeLists.linux-x86_64.txt b/library/cpp/CMakeLists.linux-x86_64.txt index 5692463e65..4656f580ad 100644 --- a/library/cpp/CMakeLists.linux-x86_64.txt +++ b/library/cpp/CMakeLists.linux-x86_64.txt @@ -7,7 +7,6 @@ add_subdirectory(accurate_accumulate) -add_subdirectory(actors) add_subdirectory(archive) add_subdirectory(balloc) add_subdirectory(binsaver) diff --git a/library/cpp/CMakeLists.windows-x86_64.txt b/library/cpp/CMakeLists.windows-x86_64.txt index d8d81b3185..7867eb1061 100644 --- a/library/cpp/CMakeLists.windows-x86_64.txt +++ b/library/cpp/CMakeLists.windows-x86_64.txt @@ -7,7 +7,6 @@ add_subdirectory(accurate_accumulate) -add_subdirectory(actors) add_subdirectory(archive) add_subdirectory(balloc) add_subdirectory(binsaver) diff --git a/library/cpp/actors/CMakeLists.txt b/library/cpp/actors/CMakeLists.txt deleted file mode 100644 index becd73cd24..0000000000 --- a/library/cpp/actors/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(actor_type) -add_subdirectory(core) -add_subdirectory(cppcoro) -add_subdirectory(dnscachelib) -add_subdirectory(dnsresolver) -add_subdirectory(examples) -add_subdirectory(helpers) -add_subdirectory(http) -add_subdirectory(interconnect) -add_subdirectory(log_backend) -add_subdirectory(memory_log) -add_subdirectory(prof) -add_subdirectory(protos) -add_subdirectory(testlib) -add_subdirectory(util) -add_subdirectory(wilson) diff --git a/library/cpp/actors/README.md b/library/cpp/actors/README.md deleted file mode 100644 index 22502c391a..0000000000 --- a/library/cpp/actors/README.md +++ /dev/null @@ -1,107 +0,0 @@ -## Actor library - -### Часть первая, вводная. -Иногда приходится разрабатывать асинхронные, существенно параллельные, местами распределённые программы. Иногда еще и внутренняя логика нетривиальна, разнородна, пишется разными командами не один год. Всё как мы любим. Человечеством придумано не так много способов внутренней организации структуры и кода таких программ. Большинство из них плохие (и именно из-за плохих подходов разработка асинхронных, многопоточных программ приобрела дурную славу). Некоторые получше. А серебряной пули как обычно нет. - -Когда мы начинали разработку Yandex Database (тогда еще KiKiMR), сразу было понятно что простыми наколеночными поделиями обойтись (и сделать при этом хорошо, так что бы не было стыдно) не получится. В качестве базиса мы выбрали мессадж-пассинг и модель акторов. И не пожалели. Постепенно этот подход распространился на смежные проекты. - -### Базовые концепции. -Если отбросить шелуху – представляем сервис (программу в случае запуска изолированного бинарника) как ансамбль независимых агентов, взаимодействующих через отправку асинхронных сообщений внутри общего окружения. Тут все слова важны: - -Независимых – не разделяют состояние и поток выполнения. -Передача сообщений – формализуем протоколы, а не интерфейсы. - -Асинхронная – не блокируемся на отправке сообщений. -Общее окружение – все агенты разделяют общий пул ресурсов и каждый из них, зная адрес, может послать сообщение каждому. - -В более хайповых терминах – очень похоже на колокейтед микросервисы, только уровнем ниже. И да, мы заведомо не хотели прятать асинхронщину и параллелизм от разработчика, показывая прям самое мясо. - -### IActor. -https://a.yandex-team.ru/arcadia/library/cpp/actors/core/actor.h?rev=r11291267#L310 -Базовый класс всех агентов, напрямую обычно не используется. Инстанцируется либо TActor, либо TActorBootstrapped. Фактически весь полезный код программы размещается в акторах. -(важное замечание – в коде увидите ручки с TActorContext и без него, схожие по названию и назначению. На данный момент вариант с TActorContext является устаревшим, новый код стоит писать без его использования). -Важные методы: - -PassAway – единственный корректный способ зарегистрированному актору умереть. Может вызываться только находясь внутри обработчика сообщения. -Send – отправка сообщения, зная адрес получателя. В акторе доступен хелпер, принимающий непосредственно сообщение. Базовый вызов, принимающий полный event handle – доступен в контексте. - -Become – установить функцию-обработчик сообщений, которая будет использована при получении следующего сообщения. - -Register – зарегистрировать новый актор в акторсистеме, с выделением нового мейлбокса. Важно – с момента вызова владение актором передается акторсистеме, т.е. уже к моменту выхода актор может начать выполняться на другом потоке, нельзя к нему ни обращаться прямыми вызовами, ни даже предполагать что он еще жив. - -Schedule – зарегистрировать сообщение, которое будет отправлено не менее чем через запрошенную задержку. В акторе доступен хелпер, декорирующий сообщение хендлом отправки самому себе, в контексте можно передать полный хендл. - -SelfId – узнать собственный адрес. Возвращаемый объект TActorIdentity можно передавать если требуется делегировать отправку сообщений от имени актора (например если пишете полезный код пользуясь пассивными объектами). -Посылка сообщений дешёвая, не нужно на ней чрезмерно экономить (но не бесплатная – поэтому посылать сообщения только ради посылки сообщений то же не стоит). - -Инстанцирование акторов так же дёшево, актор на запрос или фазу запроса – вполне нормальная практика. Мультиплексировать обработку разных запросов в одном акторе – так же вполне нормально. В нашем коде много примеров и первого, и второго. Пользуйтесь здравым смыслов и собственным вкусом. -Т.к. на время обработки сообщения актор занимает тред из пула акторсистемы – уходить в длинные вычисления лучше на отдельном отселённом акторе (и либо отселять в отдельный пол акторсистемы, либо контролировать параллельность брокером ресурсов), блокирующие вызовы делать почти всегда ошибка. Стремление написать мютекс - ересь и от лукавого. -Идентифицируются акторы своим TActorID-ом, который уникален и вы не должны его придумывать из воздуха, а только получить из регистрации (для порождённых акторов) или его вам должен рассказать кто-то, законно его знающий. - -Отправка на несуществующий актор (уже умерший) безопасна, сообщение будет просто выброшено в момент обработки (как обрабатывать недоставку сообщений в протоколах расскажу ниже). - -Кроме нормальных TActorID существуют еще и сервисные (составленные из строчки и номера ноды). Под ними может быть зарегистрирован реальный актор и фактически при получении сообщения по сервисному адресу – попробует переправить его текущему фактическому. Это позволяет размещать хорошо известные сервисы по хорошо известному адресу, не выстраивая параллельную машинерию поиска. - -Строить из актора конечный автомат при помощи переключений функции-обработчика – выбор в каждом конкретном случае, иногда удобнее да, иногда сваливать всё в одно состояние, а иногда – применять гибридное решение (когда часть жизненного цикла – обычно инициализации и завершение – выражены в переходах, а часть – нет). -Меньше слов, больше дела – этого уже достаточно что бы прочитать самый простой пример. https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/actors/examples/01_ping_pong -Здесь можно увидеть образец самого простого актора, занимающегося переброской сообщений и использующего все основные вызовы. Заодно покрутив за разные ручки (количество тредов в тредпуле, количество пар перебрасывающихся акторов) можно посмотреть на изменение поведения системы (hint: в таких простых сценариях максимум перфоманса достигается при одном треде в тредпулах). - -### Event и Event Handle. -Полезную нагрузку сообщений заворачиваем в наследника IEventBase, у которого два важных метода – сериализация и загрузка. Сериализация виртуальная, а вот загрузка – нет, и для разбора сообщения из байтовой последовательности – необходимо на стороне получателя сматчить число-идентификатор типа ивента с С++ типом. Именно это делают макросы из hfunc.h. На практике ивенты создаются либо как наследник TEventLocal<> (для строго локальных сообщений) либо как наследник TEventPB<> (для потенциально пересылаемых по сети сообщений, типизируются protobuf-мессаджем). - -Кроме непосредственно ивента (в виде структуры либо в виде байтовой строки) для пересылки сообщения необходим набор дополнительных полей - -Адресат - -Отправитель - -Тип сообщения - -Кука - -Флаги - -Сообщение + дополнительные поля = IEventHandle. Именно хендлами акторсистема и оперирует. <event-type>::TPtr – в примере выше – это и есть указатель на типизированный хендл. - -Технически типом сообщения может быть любое число, которое получатель и отправитель договорились понимать как идентификатор сообщения. Сложившаяся практика – выделять диапазон идентификаторов макросом EventSpaceBegin (фактически блоками по 64к), начиная с блока ES_USERSPACE. -Кука – неинтерпретируемое ui64 число, передаваемое с хендлом. Хорошей практикой является в ответе сервиса на сообщение выставлять куку в куку исходного сообщения, особенно для сервисов, потенциально используемых конкурентно. - -В флагах несколько бит зарезервировано под флаги, декларирующие как необходимо обрабатывать особые ситуации и 12 бит – под номер канала интерконнекта, в котором будет пересылаться сообщение (для локальных сообщений в имеющихся реализациях номер канала не имеет значения - хотя можно представить реализацию где для каналов будут независимые очереди). - -### Тредпулы и мейлбоксы. -В рамках одной акторсистемы может сосуществовать несколько независимых тредпулов, каждый актор регистрируется на конкретном и в процессе жизни не может мигрировать (но может создавать новые акторы на произвольном тредпуле). Используется для крупноблочного разделения ресурсов, либо между разными активностями (вот здесь – обрабатываем один класс запросов, а вот здесь - другой), либо между разными профилями активности (вот здесь обрабатываем быстрые запросы, здесь – медленные, а вот там – вообще батчёвые). Например в YDB работает системный тредпул (в котором запускаются акторы, необходимые для функционирования YDB, и для которого мы следим что бы не было длительной блокировки в обработчиках), пользовательский тредпул (в котором обрабатываются запросы и потенциально обработчики могут уходить в себя подольше, но это не повлияет на инфраструктуру), батчёвый тредпул (куда отгружается длительная обработка – компакшены дисков, сканы таблиц и подобное) и, в жирных нодах – тредпул интерконнекта (как наиболее чувствительного к задержкам). -Пересылка сообщений между акторами разных тредпулов но одной локальной акторсистемы остаётся локальной, принудительной сериализации сообщения не происходит. - -При регистрации актор прикрепляется к мейлбоксу (в типичном случае на собственном мейлбоксе, но по особой нужде можно находясь внутри обработки сообщения прикрепить порождённый актор к текущему активному мейлбоксу – см. RegisterWithSameMailbox (ранее RegisterLocal) – в этом случае будет гарантироваться отсутствие конкурентной обработки сообщений). Собственно Send – это и есть заворачивание ивента в хендл, помещение хендла в очередь мейлбокса и добавление мейлбокса в очередь активации тредпула. В рамках одного мейлбокса – обработка FIFO, между мейлбоксами таких гарантий нет, хотя и стараемся активировать мейлбоксы примерно в порядке появления в них сообщений. - -При регистрации актора можно выбрать тип мейлбокса, они немного отличаются стоимость добавления – либо дёшево, но похуже под контеншеном, либо почти wait-free, но подороже. См. комментарии к TMailboxType за актуальными подсказками что-как. - -Полезные хелперы. - -STFUNC – декларация стейт-функции, рекомендую всегда использовать именно такую форму для декларации, т.к. потом проще искать. - -hFunc – макрос выбора хендлера, передающий ивент в обработчик. - -cFunc – макрос выбора хендлера, не передающий ивент в обработчик. - -### Обработка сбоев. -В рамках локальной акторсистемы доставка сообщений гарантирована, если по какой-то причине сообщение не доставлено (важно! Именно не доставлено, факт обработанности сообщения уже на совести принимающего актора) – то произойдёт одно из: - -Если выставлен флаг FlagForwardOnNondelivery – сообщение будет переправлено на актор, переданный как forwardOnNondelivery при конструировании хендла. Полезно например если какие-то сервисы создаются по требованию и для несозданных сервисов – желаем зароутить в роутер. Работает только в рамках локальной акторсистемы. - -Иначе при выставленном флаге FlagTrackDelivery – для отправителя будет сгенерирован ивент TEvUndelivered от имени недоступного актора. Получение такого сообщения гарантирует что исходный ивент не был обработан и никакие эффекты не произошли. Генерация и доставка нотификации в рамках локальной акторсистемы гарантирована, в распределённой – как повезёт, может и потеряться. - -Иначе, если никакие флаги не выставлены – сообщение будет выброшено. - -Т.к. в распределённой системе доставка нотификаций о недоставке не гарантируется, то для надёжной обработки сбоев необходим дополнительный механизм – по флагу FlagSubscribeOnSession при пересечении границ ноды происходит подписка отправителя на нотификацию о разрыве сетевой сессии, в рамках которой сообщение было отправлено. Теперь при разрыве сетевой сессии отправитель узнает что сообщение могло быть недоставлено (а могло и быть доставлено – мы не знаем) и сможет отреагировать. Нужно не забывать отписываться от нотификации о разрыве сессий – иначе будут копиться вплоть до ближайшего разрыва (который может и не скоро произойти). - -Резюмируя: при необходимости контролировать доставку внутри локальной акторсистемы – выставляем флаг FlagTrackDelivery и обрабатываем TEvUndelivered. Для распределённой – добавляем FlagSubscribeOnSession и дополнительно обрабатываем TEvNodeDisconnected не забывая отписываться от более не нужных подписок. - -### Интерконнект. -Локальная акторсистема – это только половина пирога, возможность объединить их в распределённую – вторая половина. Реализация интерконнекта доступна из коробки и умеет -Передавать сообщения через одно tcp-соединение -Мультиплексировать разные потоки (ака каналы) в рамках одного соединения, гарантируя порядок в рамках канала -Старается делать это хорошо. -В рамках распределённой системы требуется каждой локальной акторсистеме назначить уникальный номер (например табличкой или реализовав динамическую раздачу номеров ноды) и запустить в рамках каждой локальной акторсистемы локальный неймсервис (например по табличке ремапинга номера ноды в сетевой адрес либо как кеш опорного неймсервиса). -Смотрим на второй пример https://a.yandex-team.ru/arcadia/library/cpp/actors/examples/02_discovery -Тут у нас конфигурируется распределённая акторсистема (в примере все пять запускаются в одном бинарнике, но точно так же – можно запускать и частями) на пять нод. На каждой ноде запускается реплика для паблишинга строчек и актор-эндпоинт (каждый со своим портом). Эндпоинты с помощью актора-паблишера публикуют свои явки/пароли на распределённый сторадж (с обработкой нештатных ситауций и поддержанием в актуальном состоянии). И рядом лежит реализация запроса к стораджу на листинг опубликованого по мажорити. Собственно это упрощённый и почищенный от специфики код, используемый в YDB для публикации и нахождения актуальных эндпоинтов пользовательской базы. diff --git a/library/cpp/actors/actor_type/CMakeLists.darwin-arm64.txt b/library/cpp/actors/actor_type/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 825e96d2d8..0000000000 --- a/library/cpp/actors/actor_type/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,33 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) - -add_library(cpp-actors-actor_type) -target_link_libraries(cpp-actors-actor_type PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-util - cpp-actors-prof - tools-enum_parser-enum_serialization_runtime -) -target_sources(cpp-actors-actor_type PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/common.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/indexes.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/index_constructor.cpp -) -generate_enum_serilization(cpp-actors-actor_type - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/common.h - INCLUDE_HEADERS - library/cpp/actors/actor_type/common.h -) diff --git a/library/cpp/actors/actor_type/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/actor_type/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 825e96d2d8..0000000000 --- a/library/cpp/actors/actor_type/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,33 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) - -add_library(cpp-actors-actor_type) -target_link_libraries(cpp-actors-actor_type PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-util - cpp-actors-prof - tools-enum_parser-enum_serialization_runtime -) -target_sources(cpp-actors-actor_type PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/common.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/indexes.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/index_constructor.cpp -) -generate_enum_serilization(cpp-actors-actor_type - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/common.h - INCLUDE_HEADERS - library/cpp/actors/actor_type/common.h -) diff --git a/library/cpp/actors/actor_type/CMakeLists.linux-aarch64.txt b/library/cpp/actors/actor_type/CMakeLists.linux-aarch64.txt deleted file mode 100644 index dc1ebb7a22..0000000000 --- a/library/cpp/actors/actor_type/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,34 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) - -add_library(cpp-actors-actor_type) -target_link_libraries(cpp-actors-actor_type PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-actors-util - cpp-actors-prof - tools-enum_parser-enum_serialization_runtime -) -target_sources(cpp-actors-actor_type PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/common.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/indexes.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/index_constructor.cpp -) -generate_enum_serilization(cpp-actors-actor_type - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/common.h - INCLUDE_HEADERS - library/cpp/actors/actor_type/common.h -) diff --git a/library/cpp/actors/actor_type/CMakeLists.linux-x86_64.txt b/library/cpp/actors/actor_type/CMakeLists.linux-x86_64.txt deleted file mode 100644 index dc1ebb7a22..0000000000 --- a/library/cpp/actors/actor_type/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,34 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) - -add_library(cpp-actors-actor_type) -target_link_libraries(cpp-actors-actor_type PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-actors-util - cpp-actors-prof - tools-enum_parser-enum_serialization_runtime -) -target_sources(cpp-actors-actor_type PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/common.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/indexes.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/index_constructor.cpp -) -generate_enum_serilization(cpp-actors-actor_type - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/common.h - INCLUDE_HEADERS - library/cpp/actors/actor_type/common.h -) diff --git a/library/cpp/actors/actor_type/CMakeLists.txt b/library/cpp/actors/actor_type/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/actor_type/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/actor_type/CMakeLists.windows-x86_64.txt b/library/cpp/actors/actor_type/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 825e96d2d8..0000000000 --- a/library/cpp/actors/actor_type/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,33 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) - -add_library(cpp-actors-actor_type) -target_link_libraries(cpp-actors-actor_type PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-util - cpp-actors-prof - tools-enum_parser-enum_serialization_runtime -) -target_sources(cpp-actors-actor_type PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/common.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/indexes.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/index_constructor.cpp -) -generate_enum_serilization(cpp-actors-actor_type - ${CMAKE_SOURCE_DIR}/library/cpp/actors/actor_type/common.h - INCLUDE_HEADERS - library/cpp/actors/actor_type/common.h -) diff --git a/library/cpp/actors/actor_type/common.cpp b/library/cpp/actors/actor_type/common.cpp deleted file mode 100644 index be8569b7f5..0000000000 --- a/library/cpp/actors/actor_type/common.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "common.h" - -namespace NActors { - -} diff --git a/library/cpp/actors/actor_type/common.h b/library/cpp/actors/actor_type/common.h deleted file mode 100644 index cfda827c3f..0000000000 --- a/library/cpp/actors/actor_type/common.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -namespace NActors { - -struct TActorActivityTag {}; - -} - -namespace NActors { -enum class EInternalActorType { - OTHER = 0, - INCORRECT_ACTOR_TYPE_INDEX, - ACTOR_SYSTEM, - ACTORLIB_COMMON, - ACTORLIB_STATS, - LOG_ACTOR, - INTERCONNECT_PROXY_TCP, - INTERCONNECT_SESSION_TCP, - INTERCONNECT_COMMON, - SELF_PING_ACTOR, - TEST_ACTOR_RUNTIME, - INTERCONNECT_HANDSHAKE, - INTERCONNECT_POLLER, - INTERCONNECT_SESSION_KILLER, - ACTOR_SYSTEM_SCHEDULER_ACTOR, - ACTOR_FUTURE_CALLBACK, - INTERCONNECT_MONACTOR, - INTERCONNECT_LOAD_ACTOR, - INTERCONNECT_LOAD_RESPONDER, - NAMESERVICE, - DNS_RESOLVER, - INTERCONNECT_PROXY_WRAPPER, - ACTOR_COROUTINE -}; -} diff --git a/library/cpp/actors/actor_type/index_constructor.cpp b/library/cpp/actors/actor_type/index_constructor.cpp deleted file mode 100644 index 667d3617c3..0000000000 --- a/library/cpp/actors/actor_type/index_constructor.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "index_constructor.h" - -namespace NActors { - -} diff --git a/library/cpp/actors/actor_type/index_constructor.h b/library/cpp/actors/actor_type/index_constructor.h deleted file mode 100644 index b533643a61..0000000000 --- a/library/cpp/actors/actor_type/index_constructor.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "common.h" -#include <library/cpp/actors/util/local_process_key.h> -#include <library/cpp/actors/prof/tag.h> - -template <> -class TLocalProcessKeyStateIndexConstructor<NActors::TActorActivityTag> { -public: - static ui32 BuildCurrentIndex(const TStringBuf name, const ui32 /*currentNamesCount*/) { - return NProfiling::MakeTag(name.data()); - } -}; diff --git a/library/cpp/actors/actor_type/indexes.cpp b/library/cpp/actors/actor_type/indexes.cpp deleted file mode 100644 index 628eae08d8..0000000000 --- a/library/cpp/actors/actor_type/indexes.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "indexes.h" - -namespace NActors { - -} diff --git a/library/cpp/actors/actor_type/indexes.h b/library/cpp/actors/actor_type/indexes.h deleted file mode 100644 index a971847056..0000000000 --- a/library/cpp/actors/actor_type/indexes.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include "common.h" -#include "index_constructor.h" -#include <library/cpp/actors/util/local_process_key.h> - -namespace NActors { - -class TActorTypeOperator { -public: - static constexpr ui32 GetMaxAvailableActorsCount() { - return TLocalProcessKeyStateIndexLimiter::GetMaxKeysCount(); - } - - template <class TEnum> - static ui32 GetEnumActivityType(const TEnum enumValue) { - return TEnumProcessKey<TActorActivityTag, TEnum>::GetIndex(enumValue); - } - - static ui32 GetActorSystemIndex() { - return TEnumProcessKey<TActorActivityTag, EInternalActorType>::GetIndex(EInternalActorType::ACTOR_SYSTEM); - } - - static ui32 GetOtherActivityIndex() { - return TEnumProcessKey<TActorActivityTag, EInternalActorType>::GetIndex(EInternalActorType::OTHER); - } - - static ui32 GetActorActivityIncorrectIndex() { - return TEnumProcessKey<TActorActivityTag, EInternalActorType>::GetIndex(EInternalActorType::INCORRECT_ACTOR_TYPE_INDEX); - } -}; -} diff --git a/library/cpp/actors/actor_type/ya.make b/library/cpp/actors/actor_type/ya.make deleted file mode 100644 index 736e99cf49..0000000000 --- a/library/cpp/actors/actor_type/ya.make +++ /dev/null @@ -1,16 +0,0 @@ -LIBRARY() - -SRCS( - common.cpp - indexes.cpp - index_constructor.cpp -) - -PEERDIR( - library/cpp/actors/util - library/cpp/actors/prof -) - -GENERATE_ENUM_SERIALIZATION(common.h) - -END() diff --git a/library/cpp/actors/core/CMakeLists.darwin-arm64.txt b/library/cpp/actors/core/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 2090b64ba1..0000000000 --- a/library/cpp/actors/core/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,101 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) -add_subdirectory(ut_fat) -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) - -add_library(cpp-actors-core) -target_link_libraries(cpp-actors-core PUBLIC - contrib-libs-cxxsupp - yutil - tools-enum_parser-enum_serialization_runtime - cpp-actors-actor_type - cpp-actors-memory_log - cpp-actors-prof - cpp-actors-protos - cpp-actors-util - library-cpp-execprofile - cpp-json-writer - library-cpp-logger - library-cpp-lwtrace - cpp-monlib-dynamic_counters - library-cpp-svnversion - library-cpp-time_provider - cpp-threading-future -) -target_sources(cpp-actors-core PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_bootstrapped.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_coroutine.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_virtual.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actorid.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actorsystem.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/ask.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/av_bootstrapped.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/balancer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/buffer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/callstack.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/cpu_manager.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_load.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_pb.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/events_undelivered.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_base.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_basic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_io.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_united.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_thread.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/harmonizer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/interconnect.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/io_dispatcher.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_settings.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_buffer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/mailbox.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/monotonic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/monotonic_provider.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/worker_context.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/probes.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/process_stats.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_basic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_cookie.cpp -) -generate_enum_serilization(cpp-actors-core - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/defs.h - INCLUDE_HEADERS - library/cpp/actors/core/defs.h -) -generate_enum_serilization(cpp-actors-core - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor.h - INCLUDE_HEADERS - library/cpp/actors/core/actor.h -) -generate_enum_serilization(cpp-actors-core - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_iface.h - INCLUDE_HEADERS - library/cpp/actors/core/log_iface.h -) diff --git a/library/cpp/actors/core/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/core/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 2090b64ba1..0000000000 --- a/library/cpp/actors/core/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,101 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) -add_subdirectory(ut_fat) -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) - -add_library(cpp-actors-core) -target_link_libraries(cpp-actors-core PUBLIC - contrib-libs-cxxsupp - yutil - tools-enum_parser-enum_serialization_runtime - cpp-actors-actor_type - cpp-actors-memory_log - cpp-actors-prof - cpp-actors-protos - cpp-actors-util - library-cpp-execprofile - cpp-json-writer - library-cpp-logger - library-cpp-lwtrace - cpp-monlib-dynamic_counters - library-cpp-svnversion - library-cpp-time_provider - cpp-threading-future -) -target_sources(cpp-actors-core PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_bootstrapped.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_coroutine.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_virtual.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actorid.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actorsystem.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/ask.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/av_bootstrapped.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/balancer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/buffer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/callstack.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/cpu_manager.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_load.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_pb.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/events_undelivered.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_base.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_basic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_io.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_united.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_thread.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/harmonizer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/interconnect.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/io_dispatcher.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_settings.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_buffer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/mailbox.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/monotonic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/monotonic_provider.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/worker_context.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/probes.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/process_stats.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_basic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_cookie.cpp -) -generate_enum_serilization(cpp-actors-core - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/defs.h - INCLUDE_HEADERS - library/cpp/actors/core/defs.h -) -generate_enum_serilization(cpp-actors-core - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor.h - INCLUDE_HEADERS - library/cpp/actors/core/actor.h -) -generate_enum_serilization(cpp-actors-core - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_iface.h - INCLUDE_HEADERS - library/cpp/actors/core/log_iface.h -) diff --git a/library/cpp/actors/core/CMakeLists.linux-aarch64.txt b/library/cpp/actors/core/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 24152462c9..0000000000 --- a/library/cpp/actors/core/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,102 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) -add_subdirectory(ut_fat) -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) - -add_library(cpp-actors-core) -target_link_libraries(cpp-actors-core PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - tools-enum_parser-enum_serialization_runtime - cpp-actors-actor_type - cpp-actors-memory_log - cpp-actors-prof - cpp-actors-protos - cpp-actors-util - library-cpp-execprofile - cpp-json-writer - library-cpp-logger - library-cpp-lwtrace - cpp-monlib-dynamic_counters - library-cpp-svnversion - library-cpp-time_provider - cpp-threading-future -) -target_sources(cpp-actors-core PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_bootstrapped.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_coroutine.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_virtual.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actorid.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actorsystem.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/ask.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/av_bootstrapped.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/balancer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/buffer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/callstack.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/cpu_manager.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_load.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_pb.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/events_undelivered.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_base.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_basic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_io.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_united.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_thread.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/harmonizer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/interconnect.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/io_dispatcher.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_settings.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_buffer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/mailbox.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/monotonic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/monotonic_provider.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/worker_context.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/probes.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/process_stats.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_basic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_cookie.cpp -) -generate_enum_serilization(cpp-actors-core - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/defs.h - INCLUDE_HEADERS - library/cpp/actors/core/defs.h -) -generate_enum_serilization(cpp-actors-core - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor.h - INCLUDE_HEADERS - library/cpp/actors/core/actor.h -) -generate_enum_serilization(cpp-actors-core - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_iface.h - INCLUDE_HEADERS - library/cpp/actors/core/log_iface.h -) diff --git a/library/cpp/actors/core/CMakeLists.linux-x86_64.txt b/library/cpp/actors/core/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 24152462c9..0000000000 --- a/library/cpp/actors/core/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,102 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) -add_subdirectory(ut_fat) -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) - -add_library(cpp-actors-core) -target_link_libraries(cpp-actors-core PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - tools-enum_parser-enum_serialization_runtime - cpp-actors-actor_type - cpp-actors-memory_log - cpp-actors-prof - cpp-actors-protos - cpp-actors-util - library-cpp-execprofile - cpp-json-writer - library-cpp-logger - library-cpp-lwtrace - cpp-monlib-dynamic_counters - library-cpp-svnversion - library-cpp-time_provider - cpp-threading-future -) -target_sources(cpp-actors-core PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_bootstrapped.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_coroutine.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_virtual.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actorid.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actorsystem.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/ask.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/av_bootstrapped.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/balancer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/buffer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/callstack.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/cpu_manager.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_load.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_pb.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/events_undelivered.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_base.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_basic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_io.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_united.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_thread.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/harmonizer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/interconnect.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/io_dispatcher.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_settings.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_buffer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/mailbox.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/monotonic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/monotonic_provider.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/worker_context.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/probes.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/process_stats.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_basic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_cookie.cpp -) -generate_enum_serilization(cpp-actors-core - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/defs.h - INCLUDE_HEADERS - library/cpp/actors/core/defs.h -) -generate_enum_serilization(cpp-actors-core - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor.h - INCLUDE_HEADERS - library/cpp/actors/core/actor.h -) -generate_enum_serilization(cpp-actors-core - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_iface.h - INCLUDE_HEADERS - library/cpp/actors/core/log_iface.h -) diff --git a/library/cpp/actors/core/CMakeLists.txt b/library/cpp/actors/core/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/core/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/core/CMakeLists.windows-x86_64.txt b/library/cpp/actors/core/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 2090b64ba1..0000000000 --- a/library/cpp/actors/core/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,101 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) -add_subdirectory(ut_fat) -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) -get_built_tool_path( - TOOL_enum_parser_bin - TOOL_enum_parser_dependency - tools/enum_parser/enum_parser - enum_parser -) - -add_library(cpp-actors-core) -target_link_libraries(cpp-actors-core PUBLIC - contrib-libs-cxxsupp - yutil - tools-enum_parser-enum_serialization_runtime - cpp-actors-actor_type - cpp-actors-memory_log - cpp-actors-prof - cpp-actors-protos - cpp-actors-util - library-cpp-execprofile - cpp-json-writer - library-cpp-logger - library-cpp-lwtrace - cpp-monlib-dynamic_counters - library-cpp-svnversion - library-cpp-time_provider - cpp-threading-future -) -target_sources(cpp-actors-core PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_bootstrapped.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_coroutine.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_virtual.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actorid.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actorsystem.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/ask.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/av_bootstrapped.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/balancer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/buffer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/callstack.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/cpu_manager.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_load.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_pb.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/events_undelivered.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_base.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_basic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_io.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_united.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_thread.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/harmonizer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/interconnect.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/io_dispatcher.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_settings.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_buffer.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/mailbox.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/monotonic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/monotonic_provider.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/worker_context.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/probes.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/process_stats.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_basic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_cookie.cpp -) -generate_enum_serilization(cpp-actors-core - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/defs.h - INCLUDE_HEADERS - library/cpp/actors/core/defs.h -) -generate_enum_serilization(cpp-actors-core - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor.h - INCLUDE_HEADERS - library/cpp/actors/core/actor.h -) -generate_enum_serilization(cpp-actors-core - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_iface.h - INCLUDE_HEADERS - library/cpp/actors/core/log_iface.h -) diff --git a/library/cpp/actors/core/README.md b/library/cpp/actors/core/README.md deleted file mode 100644 index cb5fb9dfbd..0000000000 --- a/library/cpp/actors/core/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# ActorSystem - -## Sending - -Обычная отправка (Send) сообщения проходит следующим образом: - -1) По получателю находится MailBox -2) Кладется сообщение в мейлбокс -3) Проверяется единсвенное ли это сообщение в мейлбоксе, если нет, то больше ничего не делаем -4) Иначе кладем сообщение в очередь активаций и в случае наличия спящих потоков, будим один из них - -Из этого следует, что мы всегда стараемся будить поток. -Например если 2 актора пересылают друг другу сообщение, то они будут по переменно работать в разных потоках. - -Но они вполне могли бы работать на одном потоке, и скорее всего это бы работало эффективней: - -* Кеши не теряются из перехода с одного потока на другой. -* Меньше затрат на пробуждение потоков. - -Для этого сделали два других способа отправки Send<ESendingType::Lazy> и Send<ESendingType::Tail> - -Send<ESendingType::Lazy> старается придержать мейлбокс в который отправили сообщение, до окончания обработки текущего мейлбокса и работае следующим образом: - -1) По получателю находится MailBox -2) Кладется сообщение в мейлбокс -3) Проверяется единсвенное ли это сообщение в мейлбоксе, если нет, то больше ничего не делаем -4) Захватываем мейлбокс -5) Если до этого уже захватили мейлбокс, то старый кладется в очередь активаций и пробуем разбудить спящий поток -6) После завершения обработки текущего мейлбокса проверяется, есть ли активация в очереди активаций. Если есть, то берем из очереди активаций мейлбокс, а захваченный кладем в очередь активаций, если же очередь активаций была пустая, то обрабатываем захваченный мейлбокс - -Из плюсов, может лишний раз не будить поток и обрабатывать сообщения в том же потоке. - -Из минусов, если после использования Send<ESendingType::Lazy> текущий мейлбокс будет долго обрабатываться, то это время добавиться к времени ожидания отправленного сообщения. Так как его мейлбокс захвачен потоком и не обрабатывается. Так же при сильной загрузки системы, когда очередь активаций всегда большая, отправленным сообщения будет добавляться летенси, так как мы не сразу отправляем сообщение, а ждем пока обработка мейлбокса закончится. И так как очередь акттиваций всегда не пустая, то мы с задержкой кладем мейлбокс в очередь активаций, хотя могли сделать это сразу. - -Стоит использоваться желательно перед смертью актора, когда известно что больше он ничего обрабатывать не будет. - -Для случаев, когда мы не хотим ждать окончания обработки мейлбокса или смерти актора, и хотим гарантировано обработать отправленное сообщение в том же потоке, следует использовать Send<ESendingType::Tail>. - -После обработки текущего сообщение, обработка мейлбокса прервется, и начнется обработка захваченного мейлбокса. При этом передается квота с которым обрабатывался первый мейлбокс. Благодаря этому не получится заблокировать поток двумя акторами пересылающими друг другу сообщения. В какой-то момент кончится квота по времени или по количеству обработанных сообщений. - -Send<ESendingType::Tail> работает следующим образом: - -1) По получателю находится MailBox -2) Кладется сообщение в мейлбокс -3) Проверяется единсвенное ли это сообщение в мейлбоксе, если нет, то больше ничего не делаем -4) Захватываем мейлбоксa -5) Все остальные отправки сообщений будут работать как обычный Send -6) После завершения обработки текущего сообщения, прерывается обработка мейлбокса и начинается обработка захваченного мейлбокса с квотой старого мейлбокса -7) При завершении квоты, захваченный мейлбокс обрабатывается как в Send<ESendingType::Lazy> - -Требуется когда важно продолжить цепочку работы в следующем акторе пока кеши сообщения еще прогреты. По сравнению с Send<ESendingType::Lazy> гарантировано продолжит обработку сообщения и не имеет проблем с задержкой обработки сообщения. diff --git a/library/cpp/actors/core/actor.cpp b/library/cpp/actors/core/actor.cpp deleted file mode 100644 index 6d6c92f431..0000000000 --- a/library/cpp/actors/core/actor.cpp +++ /dev/null @@ -1,250 +0,0 @@ -#include "actor.h" -#include "actor_virtual.h" -#include "actorsystem.h" -#include "executor_thread.h" -#include <library/cpp/actors/util/datetime.h> - -namespace NActors { - Y_POD_THREAD(TThreadContext*) TlsThreadContext(nullptr); - thread_local TActivationContext *TActivationContextHolder::Value = nullptr; - TActivationContextHolder TlsActivationContext; - - [[gnu::noinline]] TActivationContextHolder::operator bool() const { - asm volatile(""); - return Value != nullptr; - } - - [[gnu::noinline]] TActivationContextHolder::operator TActivationContext*() const { - asm volatile(""); - return Value; - } - - [[gnu::noinline]] TActivationContext *TActivationContextHolder::operator ->() { - asm volatile(""); - return Value; - } - - [[gnu::noinline]] TActivationContext& TActivationContextHolder::operator *() { - asm volatile(""); - return *Value; - } - - [[gnu::noinline]] TActivationContextHolder& TActivationContextHolder::operator =(TActivationContext *context) { - asm volatile(""); - Value = context; - return *this; - } - - template<i64 Increment> - static void UpdateQueueSizeAndTimestamp(TActorUsageImpl<true>& impl, ui64 time) { - ui64 usedTimeIncrement = 0; - using T = TActorUsageImpl<true>; - - for (;;) { - uint64_t value = impl.QueueSizeAndTimestamp.load(); - ui64 count = value >> T::TimestampBits; - - count += Increment; - Y_ABORT_UNLESS((count & ~T::CountMask) == 0); - - ui64 timestamp = value; - if (Increment == 1 && count == 1) { - timestamp = time; - } else if (Increment == -1 && count == 0) { - usedTimeIncrement = (static_cast<ui64>(time) - timestamp) & T::TimestampMask; - timestamp = 0; // reset timestamp to some zero value - } - - const ui64 updated = (timestamp & T::TimestampMask) | (count << T::TimestampBits); - if (impl.QueueSizeAndTimestamp.compare_exchange_weak(value, updated)) { - break; - } - } - - if (usedTimeIncrement && impl.LastUsageTimestamp <= time) { - impl.UsedTime += usedTimeIncrement; - } - } - - void TActorUsageImpl<true>::OnEnqueueEvent(ui64 time) { - UpdateQueueSizeAndTimestamp<+1>(*this, time); - } - - void TActorUsageImpl<true>::OnDequeueEvent() { - UpdateQueueSizeAndTimestamp<-1>(*this, GetCycleCountFast()); - } - - double TActorUsageImpl<true>::GetUsage(ui64 time) { - ui64 used = UsedTime.exchange(0); - if (const ui64 value = QueueSizeAndTimestamp.load(); value >> TimestampBits) { - used += (static_cast<ui64>(time) - value) & TimestampMask; - } - - Y_ABORT_UNLESS(LastUsageTimestamp <= time); - ui64 passed = time - LastUsageTimestamp; - LastUsageTimestamp = time; - - if (!passed) { - return 0; - } - - return (double)Min(passed, used) / passed; - } - - void IActor::Describe(IOutputStream &out) const noexcept { - SelfActorId.Out(out); - } - - bool IActor::Send(TAutoPtr<IEventHandle> ev) const noexcept { - return TActivationContext::Send(ev); - } - - bool IActor::Send(const TActorId& recipient, IEventBase* ev, ui32 flags, ui64 cookie, NWilson::TTraceId traceId) const noexcept { - return SelfActorId.Send(recipient, ev, flags, cookie, std::move(traceId)); - } - - void TActivationContext::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) { - TlsActivationContext->ExecutorThread.Schedule(deadline, ev, cookie); - } - - void TActivationContext::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) { - TlsActivationContext->ExecutorThread.Schedule(deadline, ev, cookie); - } - - void TActivationContext::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) { - TlsActivationContext->ExecutorThread.Schedule(delta, ev, cookie); - } - - void TActorIdentity::Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie) const { - return TActivationContext::Schedule(deadline, new IEventHandle(*this, {}, ev), cookie); - } - - void TActorIdentity::Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie) const { - return TActivationContext::Schedule(deadline, new IEventHandle(*this, {}, ev), cookie); - } - - void TActorIdentity::Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie) const { - return TActivationContext::Schedule(delta, new IEventHandle(*this, {}, ev), cookie); - } - - TActorId TActivationContext::RegisterWithSameMailbox(IActor* actor, TActorId parentId) { - Y_DEBUG_ABORT_UNLESS(parentId); - auto& ctx = *TlsActivationContext; - return ctx.ExecutorThread.RegisterActor(actor, &ctx.Mailbox, parentId.Hint(), parentId); - } - - TActorId TActorContext::RegisterWithSameMailbox(IActor* actor) const { - return ExecutorThread.RegisterActor(actor, &Mailbox, SelfID.Hint(), SelfID); - } - - TActorId IActor::RegisterWithSameMailbox(IActor* actor) const noexcept { - return TlsActivationContext->ExecutorThread.RegisterActor(actor, &TlsActivationContext->Mailbox, SelfActorId.Hint(), SelfActorId); - } - - TActorId TActivationContext::InterconnectProxy(ui32 destinationNodeId) { - return TlsActivationContext->ExecutorThread.ActorSystem->InterconnectProxy(destinationNodeId); - } - - TActorSystem* TActivationContext::ActorSystem() { - return TlsActivationContext->ExecutorThread.ActorSystem; - } - - i64 TActivationContext::GetCurrentEventTicks() { - return GetCycleCountFast() - TlsActivationContext->EventStart; - } - - double TActivationContext::GetCurrentEventTicksAsSeconds() { - return NHPTimer::GetSeconds(GetCurrentEventTicks()); - } - - TActorId IActor::Register(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId) const noexcept { - return TlsActivationContext->ExecutorThread.RegisterActor(actor, mailboxType, poolId, SelfActorId); - } - - void TActorContext::Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie) const { - ExecutorThread.Schedule(deadline, new IEventHandle(SelfID, TActorId(), ev), cookie); - } - - void TActorContext::Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie) const { - ExecutorThread.Schedule(deadline, new IEventHandle(SelfID, TActorId(), ev), cookie); - } - - void TActorContext::Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie) const { - ExecutorThread.Schedule(delta, new IEventHandle(SelfID, TActorId(), ev), cookie); - } - - void IActor::Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie) const noexcept { - TlsActivationContext->ExecutorThread.Schedule(deadline, new IEventHandle(SelfActorId, TActorId(), ev), cookie); - } - - void IActor::Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie) const noexcept { - TlsActivationContext->ExecutorThread.Schedule(deadline, new IEventHandle(SelfActorId, TActorId(), ev), cookie); - } - - void IActor::Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie) const noexcept { - TlsActivationContext->ExecutorThread.Schedule(delta, new IEventHandle(SelfActorId, TActorId(), ev), cookie); - } - - TInstant TActivationContext::Now() { - return TlsActivationContext->ExecutorThread.ActorSystem->Timestamp(); - } - - TMonotonic TActivationContext::Monotonic() { - return TlsActivationContext->ExecutorThread.ActorSystem->Monotonic(); - } - - TInstant TActorContext::Now() const { - return ExecutorThread.ActorSystem->Timestamp(); - } - - TMonotonic TActorContext::Monotonic() const { - return ExecutorThread.ActorSystem->Monotonic(); - } - - NLog::TSettings* TActivationContext::LoggerSettings() const { - return ExecutorThread.ActorSystem->LoggerSettings(); - } - - std::pair<ui32, ui32> TActorContext::CountMailboxEvents(ui32 maxTraverse) const { - return Mailbox.CountMailboxEvents(SelfID.LocalId(), maxTraverse); - } - - std::pair<ui32, ui32> IActor::CountMailboxEvents(ui32 maxTraverse) const { - return TlsActivationContext->Mailbox.CountMailboxEvents(SelfActorId.LocalId(), maxTraverse); - } - - void IActor::Die(const TActorContext& ctx) { - if (ctx.SelfID) - Y_ABORT_UNLESS(ctx.SelfID == SelfActorId); - PassAway(); - } - - void IActor::PassAway() { - auto& cx = *TlsActivationContext; - cx.ExecutorThread.UnregisterActor(&cx.Mailbox, SelfActorId); - } - - double IActor::GetElapsedTicksAsSeconds() const { - return NHPTimer::GetSeconds(ElapsedTicks); - } - - void TActorCallbackBehaviour::Receive(IActor* actor, TAutoPtr<IEventHandle>& ev) { - (actor->*StateFunc)(ev); - } - - void TActorVirtualBehaviour::Receive(IActor* actor, std::unique_ptr<IEventHandle> ev) { - Y_ABORT_UNLESS(!!ev && ev->GetBase()); - ev->GetBase()->Execute(actor, std::move(ev)); - } - - void IActor::Registered(TActorSystem* sys, const TActorId& owner) { - // fallback to legacy method, do not use it anymore - if (auto eh = AfterRegister(SelfId(), owner)) { - if (!TlsThreadContext || TlsThreadContext->SendingType == ESendingType::Common) { - sys->Send(eh); - } else { - sys->SpecificSend(eh); - } - } - } -} diff --git a/library/cpp/actors/core/actor.h b/library/cpp/actors/core/actor.h deleted file mode 100644 index 96a8f5d05a..0000000000 --- a/library/cpp/actors/core/actor.h +++ /dev/null @@ -1,999 +0,0 @@ -#pragma once - -#include "actorsystem.h" -#include "event.h" -#include "executor_thread.h" -#include "monotonic.h" -#include "thread_context.h" - -#include <library/cpp/actors/actor_type/indexes.h> -#include <library/cpp/actors/util/local_process_key.h> - -#include <util/system/tls.h> -#include <util/generic/noncopyable.h> - -namespace NActors { - class TActorSystem; - class TMailboxTable; - struct TMailboxHeader; - - class TExecutorThread; - class IActor; - class ISchedulerCookie; - class IExecutorPool; - - namespace NLog { - struct TSettings; - } - - struct TActorContext; - struct TActivationContext; - - class TActivationContextHolder { - static thread_local TActivationContext *Value; - - public: - [[gnu::noinline]] operator bool() const; - [[gnu::noinline]] operator TActivationContext*() const; - [[gnu::noinline]] TActivationContext *operator ->(); - [[gnu::noinline]] TActivationContext& operator *(); - [[gnu::noinline]] TActivationContextHolder& operator=(TActivationContext *context); - }; - - extern TActivationContextHolder TlsActivationContext; - - struct TActivationContext { - public: - TMailboxHeader& Mailbox; - TExecutorThread& ExecutorThread; - const NHPTimer::STime EventStart; - - protected: - explicit TActivationContext(TMailboxHeader& mailbox, TExecutorThread& executorThread, NHPTimer::STime eventStart) - : Mailbox(mailbox) - , ExecutorThread(executorThread) - , EventStart(eventStart) - { - } - - public: - template <ESendingType SendingType = ESendingType::Common> - static bool Send(TAutoPtr<IEventHandle> ev); - - template <ESendingType SendingType = ESendingType::Common> - static bool Send(std::unique_ptr<IEventHandle> &&ev); - - template <ESendingType SendingType = ESendingType::Common> - static bool Forward(TAutoPtr<IEventHandle>& ev, const TActorId& recipient); - - template <ESendingType SendingType = ESendingType::Common> - static bool Forward(THolder<IEventHandle>& ev, const TActorId& recipient); - - /** - * Schedule one-shot event that will be send at given time point in the future. - * - * @param deadline the wallclock time point in future when event must be send - * @param ev the event to send - * @param cookie cookie that will be piggybacked with event - */ - static void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr); - static void Schedule(TInstant deadline, std::unique_ptr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr) { - return Schedule(deadline, TAutoPtr<IEventHandle>(ev.release()), cookie); - } - - /** - * Schedule one-shot event that will be send at given time point in the future. - * - * @param deadline the monotonic time point in future when event must be send - * @param ev the event to send - * @param cookie cookie that will be piggybacked with event - */ - static void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr); - static void Schedule(TMonotonic deadline, std::unique_ptr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr) { - return Schedule(deadline, TAutoPtr<IEventHandle>(ev.release()), cookie); - } - - /** - * Schedule one-shot event that will be send after given delay. - * - * @param delta the time from now to delay event sending - * @param ev the event to send - * @param cookie cookie that will be piggybacked with event - */ - static void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr); - static void Schedule(TDuration delta, std::unique_ptr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr) { - return Schedule(delta, TAutoPtr<IEventHandle>(ev.release()), cookie); - } - - static TInstant Now(); - static TMonotonic Monotonic(); - NLog::TSettings* LoggerSettings() const; - - // register new actor in ActorSystem on new fresh mailbox. - template <ESendingType SendingType = ESendingType::Common> - static TActorId Register(IActor* actor, TActorId parentId = TActorId(), TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 poolId = Max<ui32>()); - - // Register new actor in ActorSystem on same _mailbox_ as current actor. - // There is one thread per mailbox to execute actor, which mean - // no _cpu core scalability_ for such actors. - // This method of registration can be usefull if multiple actors share - // some memory. - static TActorId RegisterWithSameMailbox(IActor* actor, TActorId parentId); - - static const TActorContext& AsActorContext(); - static TActorContext ActorContextFor(TActorId id); - - static TActorId InterconnectProxy(ui32 nodeid); - static TActorSystem* ActorSystem(); - - static i64 GetCurrentEventTicks(); - static double GetCurrentEventTicksAsSeconds(); - }; - - struct TActorContext: public TActivationContext { - const TActorId SelfID; - using TEventFlags = IEventHandle::TEventFlags; - explicit TActorContext(TMailboxHeader& mailbox, TExecutorThread& executorThread, NHPTimer::STime eventStart, const TActorId& selfID) - : TActivationContext(mailbox, executorThread, eventStart) - , SelfID(selfID) - { - } - - template <ESendingType SendingType = ESendingType::Common> - bool Send(const TActorId& recipient, IEventBase* ev, TEventFlags flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const; - template <ESendingType SendingType = ESendingType::Common> - bool Send(const TActorId& recipient, THolder<IEventBase> ev, TEventFlags flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const { - return Send<SendingType>(recipient, ev.Release(), flags, cookie, std::move(traceId)); - } - template <ESendingType SendingType = ESendingType::Common> - bool Send(const TActorId& recipient, std::unique_ptr<IEventBase> ev, TEventFlags flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const { - return Send<SendingType>(recipient, ev.release(), flags, cookie, std::move(traceId)); - } - template <ESendingType SendingType = ESendingType::Common> - bool Send(TAutoPtr<IEventHandle> ev) const; - template <ESendingType SendingType = ESendingType::Common> - bool Send(std::unique_ptr<IEventHandle> &&ev) const { - return Send<SendingType>(TAutoPtr<IEventHandle>(ev.release())); - } - template <ESendingType SendingType = ESendingType::Common> - bool Forward(TAutoPtr<IEventHandle>& ev, const TActorId& recipient) const; - template <ESendingType SendingType = ESendingType::Common> - bool Forward(THolder<IEventHandle>& ev, const TActorId& recipient) const; - - TInstant Now() const; - TMonotonic Monotonic() const; - - /** - * Schedule one-shot event that will be send at given time point in the future. - * - * @param deadline the wallclock time point in future when event must be send - * @param ev the event to send - * @param cookie cookie that will be piggybacked with event - */ - void Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const; - - /** - * Schedule one-shot event that will be send at given time point in the future. - * - * @param deadline the monotonic time point in future when event must be send - * @param ev the event to send - * @param cookie cookie that will be piggybacked with event - */ - void Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const; - - /** - * Schedule one-shot event that will be send after given delay. - * - * @param delta the time from now to delay event sending - * @param ev the event to send - * @param cookie cookie that will be piggybacked with event - */ - void Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const; - - TActorContext MakeFor(const TActorId& otherId) const { - return TActorContext(Mailbox, ExecutorThread, EventStart, otherId); - } - - // register new actor in ActorSystem on new fresh mailbox. - template <ESendingType SendingType = ESendingType::Common> - TActorId Register(IActor* actor, TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 poolId = Max<ui32>()) const; - - // Register new actor in ActorSystem on same _mailbox_ as current actor. - // There is one thread per mailbox to execute actor, which mean - // no _cpu core scalability_ for such actors. - // This method of registration can be usefull if multiple actors share - // some memory. - TActorId RegisterWithSameMailbox(IActor* actor) const; - - std::pair<ui32, ui32> CountMailboxEvents(ui32 maxTraverse = Max<ui32>()) const; - }; - - struct TActorIdentity: public TActorId { - using TEventFlags = IEventHandle::TEventFlags; - explicit TActorIdentity(TActorId actorId) - : TActorId(actorId) - { - } - - void operator=(TActorId actorId) { - *this = TActorIdentity(actorId); - } - - template <ESendingType SendingType = ESendingType::Common> - bool Send(const TActorId& recipient, IEventBase* ev, TEventFlags flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const; - bool SendWithContinuousExecution(const TActorId& recipient, IEventBase* ev, TEventFlags flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const; - void Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const; - void Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const; - void Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const; - }; - - class IActor; - - class IActorOps : TNonCopyable { - public: - virtual void Describe(IOutputStream&) const noexcept = 0; - virtual bool Send(const TActorId& recipient, IEventBase*, IEventHandle::TEventFlags flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const noexcept = 0; - - /** - * Schedule one-shot event that will be send at given time point in the future. - * - * @param deadline the wallclock time point in future when event must be send - * @param ev the event to send - * @param cookie cookie that will be piggybacked with event - */ - virtual void Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept = 0; - - /** - * Schedule one-shot event that will be send at given time point in the future. - * - * @param deadline the monotonic time point in future when event must be send - * @param ev the event to send - * @param cookie cookie that will be piggybacked with event - */ - virtual void Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept = 0; - - /** - * Schedule one-shot event that will be send after given delay. - * - * @param delta the time from now to delay event sending - * @param ev the event to send - * @param cookie cookie that will be piggybacked with event - */ - virtual void Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept = 0; - - virtual TActorId Register(IActor*, TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 poolId = Max<ui32>()) const noexcept = 0; - virtual TActorId RegisterWithSameMailbox(IActor*) const noexcept = 0; - }; - - class TDecorator; - - class TActorVirtualBehaviour { - public: - static void Receive(IActor* actor, std::unique_ptr<IEventHandle> ev); - public: - }; - - class TActorCallbackBehaviour { - private: - using TBase = IActor; - friend class TDecorator; - public: - using TReceiveFunc = void (IActor::*)(TAutoPtr<IEventHandle>& ev); - private: - TReceiveFunc StateFunc = nullptr; - public: - TActorCallbackBehaviour() = default; - TActorCallbackBehaviour(TReceiveFunc stateFunc) - : StateFunc(stateFunc) { - } - bool Initialized() const { - return !!StateFunc; - } - - // NOTE: exceptions must not escape state function but if an exception hasn't be caught - // by the actor then we want to crash an see the stack - void Receive(IActor* actor, TAutoPtr<IEventHandle>& ev); - - template <typename T> - void Become(T stateFunc) { - StateFunc = static_cast<TReceiveFunc>(stateFunc); - } - - template <typename T, typename... TArgs> - void Become(T stateFunc, const TActorContext& ctx, TArgs&&... args) { - StateFunc = static_cast<TReceiveFunc>(stateFunc); - ctx.Schedule(std::forward<TArgs>(args)...); - } - - TReceiveFunc CurrentStateFunc() const { - return StateFunc; - } - - }; - - template<bool> - struct TActorUsageImpl { - void OnEnqueueEvent(ui64 /*time*/) {} // called asynchronously when event is put in the mailbox - void OnDequeueEvent() {} // called when processed by Executor - double GetUsage(ui64 /*time*/) { return 0; } // called from collector thread - void DoActorInit() {} - }; - - template<> - struct TActorUsageImpl<true> { - static constexpr int TimestampBits = 40; - static constexpr int CountBits = 24; - static constexpr ui64 TimestampMask = ((ui64)1 << TimestampBits) - 1; - static constexpr ui64 CountMask = ((ui64)1 << CountBits) - 1; - - std::atomic_uint64_t QueueSizeAndTimestamp = 0; - std::atomic_uint64_t UsedTime = 0; // how much time did we consume since last GetUsage() call - ui64 LastUsageTimestamp = 0; // when GetUsage() was called the last time - - void OnEnqueueEvent(ui64 time); - void OnDequeueEvent(); - double GetUsage(ui64 time); - void DoActorInit() { LastUsageTimestamp = GetCycleCountFast(); } - }; - - class IActor - : protected IActorOps - , public TActorUsageImpl<ActorLibCollectUsageStats> - { - private: - TActorIdentity SelfActorId; - i64 ElapsedTicks; - friend void DoActorInit(TActorSystem*, IActor*, const TActorId&, const TActorId&); - friend class TDecorator; - - private: // stuck actor monitoring - TMonotonic LastReceiveTimestamp; - size_t StuckIndex = Max<size_t>(); - friend class TExecutorPoolBaseMailboxed; - friend class TExecutorThread; - - IActor(const ui32 activityType) - : SelfActorId(TActorId()) - , ElapsedTicks(0) - , ActivityType(activityType) - , HandledEvents(0) { - } - - protected: - TActorCallbackBehaviour CImpl; - public: - using TEventFlags = IEventHandle::TEventFlags; - using TReceiveFunc = TActorCallbackBehaviour::TReceiveFunc; - /// @sa services.proto NKikimrServices::TActivity::EType - using EActorActivity = EInternalActorType; - using EActivityType = EActorActivity; - ui32 ActivityType; - - protected: - ui64 HandledEvents; - - template <typename EEnum = EActivityType, typename std::enable_if<std::is_enum<EEnum>::value, bool>::type v = true> - IActor(const EEnum activityEnumType = EActivityType::OTHER) - : IActor(TEnumProcessKey<TActorActivityTag, EEnum>::GetIndex(activityEnumType)) { - } - - IActor(TActorCallbackBehaviour&& cImpl, const ui32 activityType) - : SelfActorId(TActorId()) - , ElapsedTicks(0) - , CImpl(std::move(cImpl)) - , ActivityType(activityType) - , HandledEvents(0) - { - } - - template <typename EEnum = EActivityType, typename std::enable_if<std::is_enum<EEnum>::value, bool>::type v = true> - IActor(TActorCallbackBehaviour&& cImpl, const EEnum activityEnumType = EActivityType::OTHER) - : IActor(std::move(cImpl), TEnumProcessKey<TActorActivityTag, EEnum>::GetIndex(activityEnumType)) { - } - - public: - template <class TEventBase> - class TEventSenderFromActor: ::TNonCopyable { - private: - TEventFlags Flags = 0; - ui64 Cookie = 0; - const TActorIdentity SenderId; - NWilson::TTraceId TraceId = {}; - std::unique_ptr<TEventBase> Event; - public: - template <class... Types> - TEventSenderFromActor(const IActor* owner, Types&&... args) - : SenderId(owner->SelfId()) - , Event(new TEventBase(std::forward<Types>(args)...)) { - - } - - TEventSenderFromActor& SetFlags(const TEventFlags flags) { - Flags = flags; - return *this; - } - - TEventSenderFromActor& SetCookie(const ui64 value) { - Cookie = value; - return *this; - } - - TEventSenderFromActor& SetTraceId(NWilson::TTraceId&& value) { - TraceId = std::move(value); - return *this; - } - - bool SendTo(const TActorId& recipient) { - return SenderId.Send(recipient, Event.release(), Flags, Cookie, std::move(TraceId)); - } - }; - - template <class TEvent, class... Types> - TEventSenderFromActor<TEvent> Sender(Types&&... args) const { - return TEventSenderFromActor<TEvent>(this, std::forward<Types>(args)...); - } - - virtual ~IActor() { - } // must not be called for registered actors, see Die method instead - - protected: - virtual void Die(const TActorContext& ctx); // would unregister actor so call exactly once and only from inside of message processing - virtual void PassAway(); - - protected: - void SetActivityType(ui32 activityType) { - ActivityType = activityType; - } - - public: - class TPassAwayGuard: TMoveOnly { - private: - IActor* Owner = nullptr; - public: - TPassAwayGuard(TPassAwayGuard&& item) { - Owner = item.Owner; - item.Owner = nullptr; - } - - TPassAwayGuard(IActor* owner) - : Owner(owner) - { - - } - - ~TPassAwayGuard() { - if (Owner) { - Owner->PassAway(); - } - } - }; - - TPassAwayGuard PassAwayGuard() { - return TPassAwayGuard(this); - } - - // must be called to wrap any call trasitions from one actor to another - template<typename TActor, typename TMethod, typename... TArgs> - static std::invoke_result_t<TMethod, TActor, TArgs...> InvokeOtherActor(TActor& actor, TMethod&& method, TArgs&&... args) { - struct TRecurseContext : TActorContext { - TActivationContext* const Prev; - - TRecurseContext(const TActorId& actorId) - : TActorContext(TActivationContext::ActorContextFor(actorId)) - , Prev(TlsActivationContext) - { - TlsActivationContext = this; - } - - ~TRecurseContext() { - Y_ABORT_UNLESS(TlsActivationContext == this, "TlsActivationContext mismatch; probably InvokeOtherActor was invoked from a coroutine"); - TlsActivationContext = Prev; - } - } context(actor.SelfId()); - - return std::invoke(std::forward<TMethod>(method), actor, std::forward<TArgs>(args)...); - } - - virtual void Registered(TActorSystem* sys, const TActorId& owner); - - virtual TAutoPtr<IEventHandle> AfterRegister(const TActorId& self, const TActorId& parentId) { - Y_UNUSED(self); - Y_UNUSED(parentId); - return TAutoPtr<IEventHandle>(); - } - - i64 GetElapsedTicks() const { - return ElapsedTicks; - } - double GetElapsedTicksAsSeconds() const; - void AddElapsedTicks(i64 ticks) { - ElapsedTicks += ticks; - } - ui32 GetActivityType() const { - return ActivityType; - } - ui64 GetHandledEvents() const { - return HandledEvents; - } - TActorIdentity SelfId() const { - return SelfActorId; - } - - void Receive(TAutoPtr<IEventHandle>& ev) { - ++HandledEvents; - LastReceiveTimestamp = TActivationContext::Monotonic(); - if (CImpl.Initialized()) { - CImpl.Receive(this, ev); - } else { - TActorVirtualBehaviour::Receive(this, std::unique_ptr<IEventHandle>(ev.Release())); - } - } - - TActorContext ActorContext() const { - return TActivationContext::ActorContextFor(SelfId()); - } - - protected: - void SetEnoughCpu(bool isEnough) { - if (TlsThreadContext) { - TlsThreadContext->IsEnoughCpu = isEnough; - } - } - - void Describe(IOutputStream&) const noexcept override; - bool Send(TAutoPtr<IEventHandle> ev) const noexcept; - bool Send(const TActorId& recipient, IEventBase* ev, TEventFlags flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const noexcept final; - bool Send(const TActorId& recipient, THolder<IEventBase> ev, TEventFlags flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const{ - return Send(recipient, ev.Release(), flags, cookie, std::move(traceId)); - } - bool Send(const TActorId& recipient, std::unique_ptr<IEventBase> ev, TEventFlags flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const { - return Send(recipient, ev.release(), flags, cookie, std::move(traceId)); - } - - template <class TEvent, class ... TEventArgs> - bool Send(TActorId recipient, TEventArgs&& ... args) const { - return Send(recipient, MakeHolder<TEvent>(std::forward<TEventArgs>(args)...)); - } - - template <ESendingType SendingType> - bool Send(const TActorId& recipient, IEventBase* ev, TEventFlags flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const; - template <ESendingType SendingType> - bool Send(const TActorId& recipient, THolder<IEventBase> ev, TEventFlags flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const { - return Send(recipient, ev.Release(), flags, cookie, std::move(traceId)); - } - template <ESendingType SendingType> - bool Send(const TActorId& recipient, std::unique_ptr<IEventBase> ev, TEventFlags flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const { - return Send(recipient, ev.release(), flags, cookie, std::move(traceId)); - } - - static bool Forward(TAutoPtr<IEventHandle>& ev, const TActorId& recipient) { - return TActivationContext::Forward(ev, recipient); - } - - static bool Forward(THolder<IEventHandle>& ev, const TActorId& recipient) { - return TActivationContext::Forward(ev, recipient); - } - - template <typename TEventHandle> - static bool Forward(TAutoPtr<TEventHandle>& ev, const TActorId& recipient) { - TAutoPtr<IEventHandle> evi(ev.Release()); - return TActivationContext::Forward(evi, recipient); - } - - void Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept final; - void Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept final; - void Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept final; - - // register new actor in ActorSystem on new fresh mailbox. - TActorId Register(IActor* actor, TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 poolId = Max<ui32>()) const noexcept final; - - template <ESendingType SendingType> - TActorId Register(IActor* actor, TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 poolId = Max<ui32>()) const noexcept; - - // Register new actor in ActorSystem on same _mailbox_ as current actor. - // There is one thread per mailbox to execute actor, which mean - // no _cpu core scalability_ for such actors. - // This method of registration can be useful if multiple actors share - // some memory. - TActorId RegisterWithSameMailbox(IActor* actor) const noexcept final; - - std::pair<ui32, ui32> CountMailboxEvents(ui32 maxTraverse = Max<ui32>()) const; - - private: - void ChangeSelfId(TActorId actorId) { - SelfActorId = actorId; - } - }; - - inline size_t GetActivityTypeCount() { - return TLocalProcessKeyState<TActorActivityTag>::GetInstance().GetCount(); - } - - inline TStringBuf GetActivityTypeName(size_t index) { - return TLocalProcessKeyState<TActorActivityTag>::GetInstance().GetNameByIndex(index); - } - - class IActorCallback: public IActor { - protected: - template <class TEnum = IActor::EActivityType> - IActorCallback(TReceiveFunc stateFunc, const TEnum activityType = IActor::EActivityType::OTHER) - : IActor(TActorCallbackBehaviour(stateFunc), activityType) { - - } - - IActorCallback(TReceiveFunc stateFunc, const ui32 activityType) - : IActor(TActorCallbackBehaviour(stateFunc), activityType) { - - } - - public: - template <typename T> - void Become(T stateFunc) { - CImpl.Become(stateFunc); - } - - template <typename T, typename... TArgs> - void Become(T stateFunc, const TActorContext& ctx, TArgs&&... args) { - CImpl.Become(stateFunc, ctx, std::forward<TArgs>(args)...); - } - - template <typename T, typename... TArgs> - void Become(T stateFunc, TArgs&&... args) { - CImpl.Become(stateFunc); - Schedule(std::forward<TArgs>(args)...); - } - - TReceiveFunc CurrentStateFunc() const { - return CImpl.CurrentStateFunc(); - } - }; - - template <typename TDerived> - class TActor: public IActorCallback { - private: - using TDerivedReceiveFunc = void (TDerived::*)(TAutoPtr<IEventHandle>& ev); - - template <typename T, typename = const char*> - struct HasActorName: std::false_type {}; - template <typename T> - struct HasActorName<T, decltype((void)T::ActorName, (const char*)nullptr)>: std::true_type {}; - - template <typename T, typename = const char*> - struct HasActorActivityType: std::false_type {}; - template <typename T> - struct HasActorActivityType<T, decltype((void)T::ActorActivityType, (const char*)nullptr)>: std::true_type {}; - - static ui32 GetActivityTypeIndexImpl() { - if constexpr(HasActorName<TDerived>::value) { - return TLocalProcessKey<TActorActivityTag, TDerived::ActorName>::GetIndex(); - } else if constexpr (HasActorActivityType<TDerived>::value) { - using TActorActivity = decltype(((TDerived*)nullptr)->ActorActivityType()); - static_assert(std::is_enum<TActorActivity>::value); - return TEnumProcessKey<TActorActivityTag, TActorActivity>::GetIndex(TDerived::ActorActivityType()); - } else { - // 200 characters is limit for solomon metric tag length - return TLocalProcessExtKey<TActorActivityTag, TDerived, 200>::GetIndex(); - } - } - - static ui32 GetActivityTypeIndex() { - static const ui32 result = GetActivityTypeIndexImpl(); - return result; - } - - protected: - // static constexpr char ActorName[] = "UNNAMED"; - - TActor(TDerivedReceiveFunc func) - : IActorCallback(static_cast<TReceiveFunc>(func), GetActivityTypeIndex()) { - } - - template <class TEnum = EActivityType> - TActor(TDerivedReceiveFunc func, const TEnum activityEnumType = EActivityType::OTHER) - : IActorCallback(static_cast<TReceiveFunc>(func), activityEnumType) { - } - - TActor(TDerivedReceiveFunc func, const TString& actorName) - : IActorCallback(static_cast<TReceiveFunc>(func), TLocalProcessKeyState<TActorActivityTag>::GetInstance().Register(actorName)) { - } - - public: - typedef TDerived TThis; - - // UnsafeBecome methods don't verify the bindings of the stateFunc to the TDerived - template <typename T> - void UnsafeBecome(T stateFunc) { - this->IActorCallback::Become(stateFunc); - } - - template <typename T, typename... TArgs> - void UnsafeBecome(T stateFunc, const TActorContext& ctx, TArgs&&... args) { - this->IActorCallback::Become(stateFunc, ctx, std::forward<TArgs>(args)...); - } - - template <typename T, typename... TArgs> - void UnsafeBecome(T stateFunc, TArgs&&... args) { - this->IActorCallback::Become(stateFunc, std::forward<TArgs>(args)...); - } - - template <typename T> - void Become(T stateFunc) { - // TODO(kruall): have to uncomment asserts after end of sync contrib/ydb - // static_assert(std::is_convertible_v<T, TDerivedReceiveFunc>); - this->IActorCallback::Become(stateFunc); - } - - template <typename T, typename... TArgs> - void Become(T stateFunc, const TActorContext& ctx, TArgs&&... args) { - // static_assert(std::is_convertible_v<T, TDerivedReceiveFunc>); - this->IActorCallback::Become(stateFunc, ctx, std::forward<TArgs>(args)...); - } - - template <typename T, typename... TArgs> - void Become(T stateFunc, TArgs&&... args) { - // static_assert(std::is_convertible_v<T, TDerivedReceiveFunc>); - this->IActorCallback::Become(stateFunc, std::forward<TArgs>(args)...); - } - }; - - -#define STFUNC_SIG TAutoPtr<::NActors::IEventHandle>& ev -#define STATEFN_SIG TAutoPtr<::NActors::IEventHandle>& ev -#define STFUNC(funcName) void funcName(TAutoPtr<::NActors::IEventHandle>& ev) -#define STATEFN(funcName) void funcName(TAutoPtr<::NActors::IEventHandle>& ev) - -#define STFUNC_STRICT_UNHANDLED_MSG_HANDLER Y_DEBUG_ABORT_UNLESS(false, "%s: unexpected message type 0x%08" PRIx32, __func__, etype); - -#define STFUNC_BODY(HANDLERS, UNHANDLED_MSG_HANDLER) \ - switch (const ui32 etype = ev->GetTypeRewrite()) { \ - HANDLERS \ - default: \ - UNHANDLED_MSG_HANDLER \ - } - -#define STRICT_STFUNC_BODY(HANDLERS) STFUNC_BODY(HANDLERS, STFUNC_STRICT_UNHANDLED_MSG_HANDLER) - -#define STRICT_STFUNC(NAME, HANDLERS) \ - void NAME(STFUNC_SIG) { \ - STRICT_STFUNC_BODY(HANDLERS) \ - } - -#define STRICT_STFUNC_EXC(NAME, HANDLERS, EXCEPTION_HANDLERS) \ - void NAME(STFUNC_SIG) { \ - try { \ - STRICT_STFUNC_BODY(HANDLERS) \ - } \ - EXCEPTION_HANDLERS \ - } - - inline const TActorContext& TActivationContext::AsActorContext() { - TActivationContext* tls = TlsActivationContext; - return *static_cast<TActorContext*>(tls); - } - - inline TActorContext TActivationContext::ActorContextFor(TActorId id) { - auto& tls = *TlsActivationContext; - return TActorContext(tls.Mailbox, tls.ExecutorThread, tls.EventStart, id); - } - - class TDecorator : public IActorCallback { - protected: - THolder<IActor> Actor; - - public: - TDecorator(THolder<IActor>&& actor) - : IActorCallback(static_cast<TReceiveFunc>(&TDecorator::State), actor->GetActivityType()) - , Actor(std::move(actor)) - { - } - - void Registered(TActorSystem* sys, const TActorId& owner) override { - Actor->ChangeSelfId(SelfId()); - Actor->Registered(sys, owner); - } - - virtual bool DoBeforeReceiving(TAutoPtr<IEventHandle>& /*ev*/, const TActorContext& /*ctx*/) { - return true; - } - - virtual void DoAfterReceiving(const TActorContext& /*ctx*/) - { - } - - STFUNC(State) { - auto ctx(ActorContext()); - if (DoBeforeReceiving(ev, ctx)) { - Actor->Receive(ev); - DoAfterReceiving(ctx); - } - } - }; - - // TTestDecorator doesn't work with the real actor system - struct TTestDecorator : public TDecorator { - TTestDecorator(THolder<IActor>&& actor) - : TDecorator(std::move(actor)) - { - } - - virtual ~TTestDecorator() = default; - - // This method must be called in the test actor system - bool BeforeSending(TAutoPtr<IEventHandle>& ev) - { - bool send = true; - TTestDecorator *decorator = dynamic_cast<TTestDecorator*>(Actor.Get()); - if (decorator) { - send = decorator->BeforeSending(ev); - } - return send && ev && DoBeforeSending(ev); - } - - virtual bool DoBeforeSending(TAutoPtr<IEventHandle>& /*ev*/) { - return true; - } - }; - - - template <ESendingType SendingType> - bool TExecutorThread::Send(TAutoPtr<IEventHandle> ev) { -#ifdef USE_ACTOR_CALLSTACK - do { - (ev)->Callstack = TCallstack::GetTlsCallstack(); - (ev)->Callstack.Trace(); - } while (false) -#endif - Ctx.IncrementSentEvents(); - return ActorSystem->Send<SendingType>(ev); - } - - template <ESendingType SendingType> - TActorId TExecutorThread::RegisterActor(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId, - TActorId parentId) - { - if (!parentId) { - parentId = CurrentRecipient; - } - if (poolId == Max<ui32>()) { - if constexpr (SendingType == ESendingType::Common) { - return Ctx.Executor->Register(actor, mailboxType, ++RevolvingWriteCounter, parentId); - } else if (!TlsThreadContext) { - return Ctx.Executor->Register(actor, mailboxType, ++RevolvingWriteCounter, parentId); - } else { - ESendingType previousType = std::exchange(TlsThreadContext->SendingType, SendingType); - TActorId id = Ctx.Executor->Register(actor, mailboxType, ++RevolvingWriteCounter, parentId); - TlsThreadContext->SendingType = previousType; - return id; - } - } else { - return ActorSystem->Register<SendingType>(actor, mailboxType, poolId, ++RevolvingWriteCounter, parentId); - } - } - - template <ESendingType SendingType> - TActorId TExecutorThread::RegisterActor(IActor* actor, TMailboxHeader* mailbox, ui32 hint, TActorId parentId) { - if (!parentId) { - parentId = CurrentRecipient; - } - if constexpr (SendingType == ESendingType::Common) { - return Ctx.Executor->Register(actor, mailbox, hint, parentId); - } else if (!TlsActivationContext) { - return Ctx.Executor->Register(actor, mailbox, hint, parentId); - } else { - ESendingType previousType = std::exchange(TlsThreadContext->SendingType, SendingType); - TActorId id = Ctx.Executor->Register(actor, mailbox, hint, parentId); - TlsThreadContext->SendingType = previousType; - return id; - } - } - - - template <ESendingType SendingType> - bool TActivationContext::Send(TAutoPtr<IEventHandle> ev) { - return TlsActivationContext->ExecutorThread.Send<SendingType>(ev); - } - - template <ESendingType SendingType> - bool TActivationContext::Send(std::unique_ptr<IEventHandle> &&ev) { - return TlsActivationContext->ExecutorThread.Send<SendingType>(ev.release()); - } - - template <ESendingType SendingType> - bool TActivationContext::Forward(TAutoPtr<IEventHandle>& ev, const TActorId& recipient) { - return Send(IEventHandle::Forward(ev, recipient)); - } - - template <ESendingType SendingType> - bool TActivationContext::Forward(THolder<IEventHandle>& ev, const TActorId& recipient) { - return Send(IEventHandle::Forward(ev, recipient)); - } - - template <ESendingType SendingType> - bool TActorContext::Send(const TActorId& recipient, IEventBase* ev, TEventFlags flags, ui64 cookie, NWilson::TTraceId traceId) const { - return Send<SendingType>(new IEventHandle(recipient, SelfID, ev, flags, cookie, nullptr, std::move(traceId))); - } - - template <ESendingType SendingType> - bool TActorContext::Send(TAutoPtr<IEventHandle> ev) const { - return ExecutorThread.Send<SendingType>(ev); - } - - template <ESendingType SendingType> - bool TActorContext::Forward(TAutoPtr<IEventHandle>& ev, const TActorId& recipient) const { - return ExecutorThread.Send<SendingType>(IEventHandle::Forward(ev, recipient)); - } - - template <ESendingType SendingType> - bool TActorContext::Forward(THolder<IEventHandle>& ev, const TActorId& recipient) const { - return ExecutorThread.Send<SendingType>(IEventHandle::Forward(ev, recipient)); - } - - template <ESendingType SendingType> - TActorId TActivationContext::Register(IActor* actor, TActorId parentId, TMailboxType::EType mailboxType, ui32 poolId) { - return TlsActivationContext->ExecutorThread.RegisterActor<SendingType>(actor, mailboxType, poolId, parentId); - } - - template <ESendingType SendingType> - TActorId TActorContext::Register(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId) const { - return ExecutorThread.RegisterActor<SendingType>(actor, mailboxType, poolId, SelfID); - } - - template <ESendingType SendingType> - bool TActorIdentity::Send(const TActorId& recipient, IEventBase* ev, TEventFlags flags, ui64 cookie, NWilson::TTraceId traceId) const { - return TActivationContext::Send<SendingType>(new IEventHandle(recipient, *this, ev, flags, cookie, nullptr, std::move(traceId))); - } - - template <ESendingType SendingType> - bool IActor::Send(const TActorId& recipient, IEventBase* ev, TEventFlags flags, ui64 cookie, NWilson::TTraceId traceId) const { - return SelfActorId.Send<SendingType>(recipient, ev, flags, cookie, std::move(traceId)); - } - - template <ESendingType SendingType> - TActorId IActor::Register(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId) const noexcept { - Y_ABORT_UNLESS(actor); - return TlsActivationContext->ExecutorThread.RegisterActor<SendingType>(actor, mailboxType, poolId, SelfActorId); - } - - - template <ESendingType SendingType> - TActorId TActorSystem::Register(IActor* actor, TMailboxType::EType mailboxType, ui32 executorPool, - ui64 revolvingCounter, const TActorId& parentId) { - Y_ABORT_UNLESS(actor); - Y_ABORT_UNLESS(executorPool < ExecutorPoolCount, "executorPool# %" PRIu32 ", ExecutorPoolCount# %" PRIu32, - (ui32)executorPool, (ui32)ExecutorPoolCount); - if constexpr (SendingType == ESendingType::Common) { - return CpuManager->GetExecutorPool(executorPool)->Register(actor, mailboxType, revolvingCounter, parentId); - } else if (!TlsThreadContext) { - return CpuManager->GetExecutorPool(executorPool)->Register(actor, mailboxType, revolvingCounter, parentId); - } else { - ESendingType previousType = std::exchange(TlsThreadContext->SendingType, SendingType); - TActorId id = CpuManager->GetExecutorPool(executorPool)->Register(actor, mailboxType, revolvingCounter, parentId); - TlsThreadContext->SendingType = previousType; - return id; - } - } - - template <ESendingType SendingType> - bool TActorSystem::Send(TAutoPtr<IEventHandle> ev) const { - if constexpr (SendingType == ESendingType::Common) { - return this->GenericSend< &IExecutorPool::Send>(ev); - } else { - return this->SpecificSend(ev, SendingType); - } - } - -} - -template <> -inline void Out<NActors::TActorIdentity>(IOutputStream& o, const NActors::TActorIdentity& x) { - return x.Out(o); -} - -template <> -struct THash<NActors::TActorIdentity> { - inline ui64 operator()(const NActors::TActorIdentity& x) const { - return x.Hash(); - } -}; - -template<> struct std::hash<NActors::TActorIdentity> : THash<NActors::TActorIdentity> {}; diff --git a/library/cpp/actors/core/actor_benchmark_helper.h b/library/cpp/actors/core/actor_benchmark_helper.h deleted file mode 100644 index 7e9651eb35..0000000000 --- a/library/cpp/actors/core/actor_benchmark_helper.h +++ /dev/null @@ -1,763 +0,0 @@ -#include "actor.h" -#include "events.h" -#include "actorsystem.h" -#include "executor_pool_basic.h" -#include "scheduler_basic.h" -#include "actor_bootstrapped.h" - -#include <library/cpp/actors/testlib/test_runtime.h> -#include <library/cpp/actors/util/threadparkpad.h> -#include <library/cpp/testing/unittest/registar.h> -#include <library/cpp/threading/chunk_queue/queue.h> - -#include <util/generic/algorithm.h> -#include <library/cpp/deprecated/atomic/atomic.h> -#include <util/system/rwlock.h> -#include <util/system/hp_timer.h> -#include <vector> - -namespace NActors::NTests { - -struct TTestEndDecorator : TDecorator { - TThreadParkPad* Pad; - TAtomic* ActorsAlive; - - TTestEndDecorator(THolder<IActor>&& actor, TThreadParkPad* pad, TAtomic* actorsAlive) - : TDecorator(std::move(actor)) - , Pad(pad) - , ActorsAlive(actorsAlive) - { - AtomicIncrement(*ActorsAlive); - } - - ~TTestEndDecorator() { - if (AtomicDecrement(*ActorsAlive) == 0) { - Pad->Unpark(); - } - } -}; - - -struct TActorBenchmarkSettings { - static constexpr bool DefaultNoRealtime = true; - static constexpr ui32 DefaultSpinThreshold = 1'000'000; - static constexpr ui32 TotalEventsAmountPerThread = 1'000; - - static constexpr auto MailboxTypes = { - TMailboxType::Simple, - TMailboxType::Revolving, - TMailboxType::HTSwap, - TMailboxType::ReadAsFilled, - TMailboxType::TinyReadAsFilled - }; -}; - - -template <typename TSettings_ = TActorBenchmarkSettings> -struct TActorBenchmark { - using TSettings = TSettings_; - - class TDummyActor : public TActor<TDummyActor> { - public: - TDummyActor() : TActor<TDummyActor>(&TDummyActor::StateFunc) {} - STFUNC(StateFunc) { - (void)ev; - } - }; - - enum class ERole { - Leader, - Follower - }; - - struct TEvOwnedPing : TEvents::TEvPing { - TEvOwnedPing(TActorId owner) - : TEvPing() - , Owner(owner) - {} - - TActorId Owner; - }; - - struct TEventSharedCounters { - TEventSharedCounters(ui32 count) - : NotStarted(count) - , Finished(0) - , Counters(count) - , StartedCounters(count) - , EndedCounters(count) - { - for (ui32 idx = 0; idx < count; ++idx) { - Counters[idx].store(0); - StartedCounters[idx].store(0); - EndedCounters[idx].store(0); - } - } - - std::atomic<ui64> NotStarted = 0; - std::atomic<ui64> Finished = 0; - std::vector<NThreading::TPadded<std::atomic<ui64>>> Counters; - std::vector<NThreading::TPadded<std::atomic<ui64>>> StartedCounters; - std::vector<NThreading::TPadded<std::atomic<ui64>>> EndedCounters; - std::atomic<ui64> StartTimeTs = 0; - std::atomic<ui64> EndTimeTs = 0; - std::atomic<bool> DoStop = false; - }; - - struct TSendReceiveActorParams { - ui64 OwnEvents = 0; - ui64 OtherEvents = 0; - bool EndlessSending = false; - double *ElapsedTime = nullptr; - std::vector<TActorId> Receivers; - bool Allocation = false; - ESendingType SendingType = ESendingType::Common; - ui32 Neighbours = 0; - TEventSharedCounters *SharedCounters; - ui32 InFlight = 1; - }; - - class TSendReceiveActor : public TActorBootstrapped<TSendReceiveActor> { - public: - static constexpr auto ActorActivityType() { - return IActorCallback::EActivityType::ACTORLIB_COMMON; - } - - TSendReceiveActor(const TSendReceiveActorParams ¶ms, ui32 idx=0) - : OwnEventsCounter(params.OwnEvents) - , OtherEventsCounter(params.OtherEvents) - , ElapsedTime(params.ElapsedTime) - , Receivers(params.Receivers) - , AllocatesMemory(params.Allocation) - , SendingType(params.SendingType) - , MailboxNeighboursCount(params.Neighbours) - , SharedCounters(params.SharedCounters) - , PairIdx(idx) - , EndlessSending(params.EndlessSending) - , IsLeader(OwnEventsCounter) - , InFlight(params.InFlight) - {} - - void StoreCounters(std::vector<NThreading::TPadded<std::atomic<ui64>>> &dest) { - for (ui32 idx = 0; idx < dest.size(); ++idx) { - dest[idx].store(SharedCounters->Counters[idx]); - } - } - - void Bootstrap(const TActorContext &ctx) { - if (SharedCounters && IsLeader) { - ui32 count = --SharedCounters->NotStarted; - if (!count) { - SharedCounters->StartTimeTs = GetCycleCountFast(); - StoreCounters(SharedCounters->StartedCounters); - } - } - if (Receivers.empty() && OwnEventsCounter) { - Receivers.push_back(this->SelfId()); - } - Timer.Reset(); - this->Become(&TSendReceiveActor::StateFunc); - for (ui32 i = 0; i < MailboxNeighboursCount; ++i) { - ctx.RegisterWithSameMailbox(new TDummyActor()); - } - for (TActorId receiver : Receivers) { - for (ui32 eventIdx = 0; eventIdx < InFlight; ++eventIdx) { - TAutoPtr<IEventHandle> ev = new IEventHandle(receiver, this->SelfId(), new TEvOwnedPing(this->SelfId())); - SpecialSend(ev, ctx, true); - } - } - } - - void SpecialSend(TAutoPtr<IEventHandle> ev, const TActorContext &ctx, bool own) { - EventsCounter++; - if (own) { - --OwnEventsCounter; - } - if (SendingType == ESendingType::Lazy) { - ctx.Send<ESendingType::Lazy>(ev); - } else if (SendingType == ESendingType::Tail) { - ctx.Send<ESendingType::Tail>(ev); - } else { - ctx.Send(ev); - } - } - - void Stop() { - if (SharedCounters && IsLeader) { - if (!SharedCounters->NotStarted++) { - StoreCounters(SharedCounters->EndedCounters); - SharedCounters->EndTimeTs = GetCycleCountFast(); - } - } - if (ElapsedTime != nullptr) { - if (Receivers.size() && Receivers[0] != this->SelfId()) { - *ElapsedTime = Timer.Passed() / EventsCounter; - } else { - *ElapsedTime = Timer.Passed() * 2 / EventsCounter; - } - } - this->PassAway(); - } - - bool CheckWorkIsDone() { - if (OwnEventsCounter || OtherEventsCounter || EndlessSending) { - return false; - } - Stop(); - return true; - } - - STFUNC(StateFunc) { - ++EventsCounter; - ui32 counter = ++ReceiveTurn; - if (SharedCounters) { - if (counter % 128 == 0) { - if (IsLeader) { - SharedCounters->Counters[PairIdx].store(EventsCounter); - } - if (SharedCounters->DoStop) { - Stop(); - return; - } - } - } - bool own = ev->Get<TEvOwnedPing>()->Owner == this->SelfId(); - if (!own) { - --OtherEventsCounter; - } - if (CheckWorkIsDone()) - return; - - auto ctx(this->ActorContext()); - if (AllocatesMemory) { - SpecialSend(new IEventHandle(ev->Sender, this->SelfId(), new TEvOwnedPing(ev->Get<TEvOwnedPing>()->Owner)), ctx, own); - } else { - std::swap(*const_cast<TActorId*>(&ev->Sender), *const_cast<TActorId*>(&ev->Recipient)); - ev->DropRewrite(); - SpecialSend(ev, ctx, own); - } - - CheckWorkIsDone(); - } - - private: - THPTimer Timer; - ui64 OwnEventsCounter; - ui64 OtherEventsCounter; - double* ElapsedTime; - std::vector<TActorId> Receivers; - bool AllocatesMemory; - ESendingType SendingType; - ui32 MailboxNeighboursCount; - ui32 EventsCounter = 0; - TEventSharedCounters *SharedCounters; - ui32 PairIdx = 0; - bool EndlessSending = false; - bool IsLeader = false; - ui32 InFlight = 1; - ui32 ReceiveTurn = 0; - }; - - static void AddBasicPool(THolder<TActorSystemSetup>& setup, ui32 threads, bool activateEveryEvent, i16 sharedExecutorsCount) { - TBasicExecutorPoolConfig basic; - basic.PoolId = setup->GetExecutorsCount(); - basic.PoolName = TStringBuilder() << "b" << basic.PoolId; - basic.Threads = threads; - basic.SpinThreshold = TSettings::DefaultSpinThreshold; - basic.TimePerMailbox = TDuration::Hours(1); - basic.SharedExecutorsCount = sharedExecutorsCount; - basic.SoftProcessingDurationTs = Us2Ts(100); - if (activateEveryEvent) { - basic.EventsPerMailbox = 1; - } - setup->CpuManager.Basic.emplace_back(std::move(basic)); - } - - static void AddUnitedPool(THolder<TActorSystemSetup>& setup, ui32 concurrency, bool activateEveryEvent) { - TUnitedExecutorPoolConfig united; - united.PoolId = setup->GetExecutorsCount(); - united.PoolName = TStringBuilder() << "u" << united.PoolId; - united.Concurrency = concurrency; - united.TimePerMailbox = TDuration::Hours(1); - if (activateEveryEvent) { - united.EventsPerMailbox = 1; - } else { - united.EventsPerMailbox = ::Max<ui32>(); - } - setup->CpuManager.United.emplace_back(std::move(united)); - } - - static THolder<TActorSystemSetup> GetActorSystemSetup(ui32 unitedCpuCount, bool preemption) { - auto setup = MakeHolder<NActors::TActorSystemSetup>(); - setup->NodeId = 1; - setup->CpuManager.UnitedWorkers.CpuCount = unitedCpuCount; - setup->CpuManager.UnitedWorkers.SpinThresholdUs = TSettings::DefaultSpinThreshold; - setup->CpuManager.UnitedWorkers.NoRealtime = TSettings::DefaultNoRealtime; - if (preemption) { - setup->CpuManager.UnitedWorkers.PoolLimitUs = 500; - setup->CpuManager.UnitedWorkers.EventLimitUs = 100; - setup->CpuManager.UnitedWorkers.LimitPrecisionUs = 100; - } else { - setup->CpuManager.UnitedWorkers.PoolLimitUs = 100'000'000'000; - setup->CpuManager.UnitedWorkers.EventLimitUs = 10'000'000'000; - setup->CpuManager.UnitedWorkers.LimitPrecisionUs = 10'000'000'000; - } - setup->Scheduler = new TBasicSchedulerThread(NActors::TSchedulerConfig(512, 0)); - return setup; - } - - enum class EPoolType { - Basic, - United - }; - - static THolder<TActorSystemSetup> InitActorSystemSetup(EPoolType poolType, ui32 poolsCount, ui32 threads, bool activateEveryEvent, bool preemption) { - if (poolType == EPoolType::Basic) { - THolder<TActorSystemSetup> setup = GetActorSystemSetup(0, false); - for (ui32 i = 0; i < poolsCount; ++i) { - AddBasicPool(setup, threads, activateEveryEvent, 0); - } - return setup; - } else if (poolType == EPoolType::United) { - THolder<TActorSystemSetup> setup = GetActorSystemSetup(poolsCount * threads, preemption); - for (ui32 i = 0; i < poolsCount; ++i) { - AddUnitedPool(setup, threads, activateEveryEvent); - } - return setup; - } - Y_ABORT(); - } - - static double BenchSendReceive(bool allocation, NActors::TMailboxType::EType mType, EPoolType poolType, ESendingType sendingType) { - THolder<TActorSystemSetup> setup = InitActorSystemSetup(poolType, 1, 1, false, false); - TActorSystem actorSystem(setup); - actorSystem.Start(); - - TThreadParkPad pad; - TAtomic actorsAlive = 0; - double elapsedTime = 0; - THolder<IActor> endActor{new TTestEndDecorator( - THolder(new TSendReceiveActor( - TSendReceiveActorParams{ - .OwnEvents=TSettings::TotalEventsAmountPerThread, - .OtherEvents=0, - .ElapsedTime=&elapsedTime, - .Allocation=allocation, - .SendingType=sendingType, - } - )), - &pad, - &actorsAlive - )}; - - actorSystem.Register(endActor.Release(), mType); - - pad.Park(); - actorSystem.Stop(); - - return 1e9 * elapsedTime; - } - - static double BenchSendActivateReceive(ui32 poolsCount, ui32 threads, bool allocation, EPoolType poolType, ESendingType sendingType) { - THolder<TActorSystemSetup> setup = InitActorSystemSetup(poolType, poolsCount, threads, true, false); - TActorSystem actorSystem(setup); - actorSystem.Start(); - - TThreadParkPad pad; - TAtomic actorsAlive = 0; - double elapsedTime = 0; - ui32 followerPoolId = 0; - - ui32 leaderPoolId = poolsCount == 1 ? 0 : 1; - ui64 eventsPerPair = TSettings::TotalEventsAmountPerThread; - - TActorId followerId = actorSystem.Register( - new TActorBenchmark::TSendReceiveActor( - TSendReceiveActorParams{.OtherEvents=eventsPerPair / 2, .Allocation=allocation} - ), - TMailboxType::HTSwap, - followerPoolId - ); - THolder<IActor> leader{ - new TTestEndDecorator( - THolder(new TActorBenchmark::TSendReceiveActor( - TSendReceiveActorParams{ - .OwnEvents=eventsPerPair / 2, - .ElapsedTime=&elapsedTime, - .Receivers={followerId}, - .Allocation=allocation, - .SendingType=sendingType, - } - )), - &pad, - &actorsAlive - ) - }; - actorSystem.Register(leader.Release(), TMailboxType::HTSwap, leaderPoolId); - - pad.Park(); - actorSystem.Stop(); - - return 1e9 * elapsedTime; - } - - static double BenchSendActivateReceiveWithMailboxNeighbours(ui32 MailboxNeighbourActors, EPoolType poolType, ESendingType sendingType) { - THolder<TActorSystemSetup> setup = InitActorSystemSetup(poolType, 1, 1, false, false); - TActorSystem actorSystem(setup); - actorSystem.Start(); - - TThreadParkPad pad; - TAtomic actorsAlive = 0; - double elapsedTime = 0; - - ui64 eventsPerPair = TSettings::TotalEventsAmountPerThread; - - TActorId followerId = actorSystem.Register( - new TActorBenchmark::TSendReceiveActor( - TSendReceiveActorParams{ - .OtherEvents=eventsPerPair / 2, - .Allocation=false, - .Neighbours=MailboxNeighbourActors, - } - ), - TMailboxType::HTSwap - ); - THolder<IActor> leader{ - new TTestEndDecorator( - THolder(new TActorBenchmark::TSendReceiveActor( - TSendReceiveActorParams{ - .OwnEvents=eventsPerPair / 2, - .ElapsedTime=&elapsedTime, - .Receivers={followerId}, - .Allocation=false, - .SendingType=sendingType, - .Neighbours=MailboxNeighbourActors, - } - )), - &pad, - &actorsAlive - ) - }; - actorSystem.Register(leader.Release(), TMailboxType::HTSwap); - - pad.Park(); - actorSystem.Stop(); - - return 1e9 * elapsedTime; - } - - struct TBenchResult { - double ElapsedTime; - ui64 SentEvents; - ui64 MinPairSentEvents; - ui64 MaxPairSentEvents; - }; - - static auto BenchContentedThreads(ui32 threads, ui32 actorsPairsCount, EPoolType poolType, ESendingType sendingType, TDuration testDuration = TDuration::Zero(), ui32 inFlight = 1) { - THolder<TActorSystemSetup> setup = InitActorSystemSetup(poolType, 1, threads, false, false); - TActorSystem actorSystem(setup); - actorSystem.Start(); - - TThreadParkPad pad; - TAtomic actorsAlive = 0; - - TEventSharedCounters sharedCounters(actorsPairsCount); - - ui64 totalEvents = TSettings::TotalEventsAmountPerThread * threads; - ui64 eventsPerPair = totalEvents / actorsPairsCount; - - for (ui32 i = 0; i < actorsPairsCount; ++i) { - ui32 followerPoolId = 0; - ui32 leaderPoolId = 0; - TActorId followerId = actorSystem.Register( - new TSendReceiveActor( - TSendReceiveActorParams{ - .OtherEvents = eventsPerPair / 2, - .EndlessSending = bool(testDuration), - .Allocation = false, - .SharedCounters = &sharedCounters, - } - ), - TMailboxType::HTSwap, - followerPoolId - ); - THolder<IActor> leader{ - new TTestEndDecorator( - THolder(new TSendReceiveActor(TSendReceiveActorParams{ - .OwnEvents = eventsPerPair / 2, - .EndlessSending = bool(testDuration), - .Receivers={followerId}, - .Allocation = false, - .SendingType=sendingType, - .SharedCounters=&sharedCounters, - .InFlight = inFlight - }, i)), - &pad, - &actorsAlive - ) - }; - actorSystem.Register(leader.Release(), TMailboxType::HTSwap, leaderPoolId); - } - - if (testDuration) { - Sleep(testDuration); - for (ui32 idx = 0; idx < actorsPairsCount; ++idx) { - sharedCounters.EndedCounters[idx].store(sharedCounters.Counters[idx]); - } - sharedCounters.EndTimeTs = GetCycleCountFast(); - } else { - pad.Park(); - } - actorSystem.Stop(); - - ui64 sentEvents = sharedCounters.EndedCounters[0] - sharedCounters.StartedCounters[0]; - ui64 minSentEvents = sentEvents; - ui64 maxSentEvents = sentEvents; - for (ui32 pairIdx = 1; pairIdx < actorsPairsCount; ++pairIdx) { - ui64 count = sharedCounters.EndedCounters[pairIdx] - sharedCounters.StartedCounters[pairIdx]; - sentEvents += count; - minSentEvents = ::Min(minSentEvents, count); - maxSentEvents = ::Max(maxSentEvents, count); - } - - return TBenchResult { - .ElapsedTime = 1000 * Ts2Us(sharedCounters.EndTimeTs - sharedCounters.StartTimeTs), - .SentEvents = sentEvents, - .MinPairSentEvents = minSentEvents, - .MaxPairSentEvents = maxSentEvents - }; - } - - static auto BenchStarContentedThreads(ui32 threads, ui32 actorsPairsCount, EPoolType poolType, ESendingType sendingType, TDuration testDuration = TDuration::Zero(), ui32 starMultiply=10) { - THolder<TActorSystemSetup> setup = InitActorSystemSetup(poolType, 1, threads, true, false); - TActorSystem actorSystem(setup); - actorSystem.Start(); - - TThreadParkPad pad; - TAtomic actorsAlive = 0; - - TEventSharedCounters sharedCounters(actorsPairsCount); - - ui64 totalEvents = TSettings::TotalEventsAmountPerThread * threads; - ui64 eventsPerPair = totalEvents / actorsPairsCount; - - for (ui32 i = 0; i < actorsPairsCount; ++i) { - ui32 followerPoolId = 0; - ui32 leaderPoolId = 0; - std::vector<TActorId> receivers; - for (ui32 idx = 0; idx < starMultiply; ++idx) { - TActorId followerId = actorSystem.Register( - new TSendReceiveActor( - TSendReceiveActorParams{ - .OtherEvents = eventsPerPair / 2 / starMultiply, - .EndlessSending = bool(testDuration), - .Allocation = false, - .SharedCounters = &sharedCounters, - } - ), - TMailboxType::HTSwap, - followerPoolId - ); - receivers.push_back(followerId); - } - THolder<IActor> leader{ - new TTestEndDecorator( - THolder(new TSendReceiveActor(TSendReceiveActorParams{ - .OwnEvents = eventsPerPair / 2, - .EndlessSending = bool(testDuration), - .Receivers=receivers, - .Allocation = false, - .SendingType=sendingType, - .SharedCounters=&sharedCounters, - }, i)), - &pad, - &actorsAlive - ) - }; - actorSystem.Register(leader.Release(), TMailboxType::HTSwap, leaderPoolId); - } - - if (testDuration) { - Sleep(testDuration); - for (ui32 idx = 0; idx < actorsPairsCount; ++idx) { - sharedCounters.EndedCounters[idx].store(sharedCounters.Counters[idx]); - } - sharedCounters.EndTimeTs = GetCycleCountFast(); - } else { - pad.Park(); - } - actorSystem.Stop(); - - ui64 sentEvents = sharedCounters.EndedCounters[0] - sharedCounters.StartedCounters[0]; - ui64 minSentEvents = sentEvents; - ui64 maxSentEvents = sentEvents; - for (ui32 pairIdx = 1; pairIdx < actorsPairsCount; ++pairIdx) { - ui64 count = sharedCounters.EndedCounters[pairIdx] - sharedCounters.StartedCounters[pairIdx]; - sentEvents += count; - minSentEvents = ::Min(minSentEvents, count); - maxSentEvents = ::Max(maxSentEvents, count); - } - - return TBenchResult { - .ElapsedTime = 1000 * Ts2Us(sharedCounters.EndTimeTs - sharedCounters.StartTimeTs), - .SentEvents = sentEvents, - .MinPairSentEvents = minSentEvents, - .MaxPairSentEvents = maxSentEvents - }; - } - - - static auto Mean(const std::vector<double>& data) { - return Accumulate(data.begin(), data.end(), 0.0) / data.size(); - } - - static auto Deviation(const std::vector<double>& data) { - auto mean = Mean(data); - double deviation = 0.0; - for (const auto& x : data) { - deviation += (x - mean) * (x - mean); - } - return std::sqrt(deviation / data.size()); - } - - static double Min(const std::vector<double>& data) { - return *std::min_element(data.begin(), data.end()); - } - - static double Max(const std::vector<double>& data) { - return *std::max_element(data.begin(), data.end()); - } - - template <auto Measurment> - struct TStats { - double Mean; - double Deviation; - double Min; - double Max; - - TStats(const std::vector<double> &data) - : Mean(TActorBenchmark::Mean(data)) - , Deviation(TActorBenchmark::Deviation(data)) - , Min(TActorBenchmark::Min(data)) - , Max(TActorBenchmark::Max(data)) - { - } - - TString ToString() { - return TStringBuilder() << Mean << " ± " << Deviation << " " << Measurment() - << " " << std::ceil(Deviation / Mean * 1000) / 10.0 << "%" - << " min " << Min << " " << Measurment() << " max " << Max << " " << Measurment(); - } - }; - - static constexpr auto EmptyMsr = []{return "";}; - static constexpr auto NsMsr = []{return "ns";}; - - struct TStatsBenchResult { - TStats<NsMsr> ElapsedTime; - TStats<EmptyMsr> SentEvents; - TStats<EmptyMsr> MinPairSentEvents; - TStats<EmptyMsr> MaxPairSentEvents; - - TString ToString() { - return TStringBuilder() << ElapsedTime.ToString() << Endl << SentEvents.ToString() << Endl << MinPairSentEvents.ToString() << Endl << MaxPairSentEvents.ToString(); - } - }; - - template <typename Func> - static auto CountStats(Func func, ui32 itersCount = 5) { - if constexpr (std::is_same_v<double, std::decay_t<decltype(func())>>) { - std::vector<double> elapsedTimes; - for (ui32 i = 0; i < itersCount; ++i) { - auto elapsedTime = func(); - elapsedTimes.push_back(elapsedTime); - } - return TStats<NsMsr>(elapsedTimes); - } else { - std::vector<double> elapsedTimes; - std::vector<double> sentEvents; - std::vector<double> minPairSentEvents; - std::vector<double> maxPairSentEvents; - for (ui32 i = 0; i < itersCount; ++i) { - TBenchResult result = func(); - elapsedTimes.push_back(result.ElapsedTime); - sentEvents.push_back(result.SentEvents); - minPairSentEvents.push_back(result.MinPairSentEvents); - maxPairSentEvents.push_back(result.MaxPairSentEvents); - } - return TStatsBenchResult { - .ElapsedTime = TStats<NsMsr>(elapsedTimes), - .SentEvents = TStats<EmptyMsr>(sentEvents), - .MinPairSentEvents = TStats<EmptyMsr>(minPairSentEvents), - .MaxPairSentEvents = TStats<EmptyMsr>(maxPairSentEvents), - }; - } - } - - static void RunBenchSendActivateReceive(ui32 poolsCount, ui32 threads, bool allocation, EPoolType poolType) { - auto stats = CountStats([=] { - return BenchSendActivateReceive(poolsCount, threads, allocation, poolType, ESendingType::Common); - }); - Cerr << stats.ToString() << Endl; - stats = CountStats([=] { - return BenchSendActivateReceive(poolsCount, threads, allocation, poolType, ESendingType::Lazy); - }); - Cerr << stats.ToString() << " Lazy" << Endl; - stats = CountStats([=] { - return BenchSendActivateReceive(poolsCount, threads, allocation, poolType, ESendingType::Tail); - }); - Cerr << stats.ToString() << " Tail" << Endl; - } - - static void RunBenchContentedThreads(ui32 threads, EPoolType poolType) { - for (ui32 actorPairs = 1; actorPairs <= 2 * threads; actorPairs++) { - auto stats = CountStats([threads, actorPairs, poolType] { - return BenchContentedThreads(threads, actorPairs, poolType, ESendingType::Common); - }); - Cerr << stats.ToString() << " actorPairs: " << actorPairs << Endl; - stats = CountStats([threads, actorPairs, poolType] { - return BenchContentedThreads(threads, actorPairs, poolType, ESendingType::Lazy); - }); - Cerr << stats.ToString() << " actorPairs: " << actorPairs << " Lazy"<< Endl; - stats = CountStats([threads, actorPairs, poolType] { - return BenchContentedThreads(threads, actorPairs, poolType, ESendingType::Tail); - }); - Cerr << stats.ToString() << " actorPairs: " << actorPairs << " Tail"<< Endl; - } - } - - static void RunSendActivateReceiveCSV(const std::vector<ui32> &threadsList, const std::vector<ui32> &actorPairsList, const std::vector<ui32> &inFlights, TDuration subtestDuration) { - Cout << "threads,actorPairs,in_flight,msgs_per_sec,elapsed_seconds,min_pair_sent_msgs,max_pair_sent_msgs" << Endl; - for (ui32 threads : threadsList) { - for (ui32 actorPairs : actorPairsList) { - for (ui32 inFlight : inFlights) { - auto stats = CountStats([threads, actorPairs, inFlight, subtestDuration] { - return BenchContentedThreads(threads, actorPairs, EPoolType::Basic, ESendingType::Common, subtestDuration, inFlight); - }, 3); - double elapsedSeconds = stats.ElapsedTime.Mean / 1e9; - ui64 eventsPerSecond = stats.SentEvents.Mean / elapsedSeconds; - Cout << threads << "," << actorPairs << "," << inFlight << "," << eventsPerSecond << "," << elapsedSeconds << "," << stats.MinPairSentEvents.Min << "," << stats.MaxPairSentEvents.Max << Endl; - } - } - } - } - - - static void RunStarSendActivateReceiveCSV(const std::vector<ui32> &threadsList, const std::vector<ui32> &actorPairsList, const std::vector<ui32> &starsList) { - Cout << "threads,actorPairs,star_multiply,msgs_per_sec,elapsed_seconds,min_pair_sent_msgs,max_pair_sent_msgs" << Endl; - for (ui32 threads : threadsList) { - for (ui32 actorPairs : actorPairsList) { - for (ui32 stars : starsList) { - auto stats = CountStats([threads, actorPairs, stars] { - return BenchStarContentedThreads(threads, actorPairs, EPoolType::Basic, ESendingType::Common, TDuration::Seconds(1), stars); - }, 3); - double elapsedSeconds = stats.ElapsedTime.Mean / 1e9; - ui64 eventsPerSecond = stats.SentEvents.Mean / elapsedSeconds; - Cout << threads << "," << actorPairs << "," << stars << "," << eventsPerSecond << "," << elapsedSeconds << "," << stats.MinPairSentEvents.Min << "," << stats.MaxPairSentEvents.Max << Endl; - } - } - } - } -}; - -} // NActors::NTests diff --git a/library/cpp/actors/core/actor_bootstrapped.cpp b/library/cpp/actors/core/actor_bootstrapped.cpp deleted file mode 100644 index 8c1effcd5d..0000000000 --- a/library/cpp/actors/core/actor_bootstrapped.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "actor_bootstrapped.h" - -namespace NActors { -} diff --git a/library/cpp/actors/core/actor_bootstrapped.h b/library/cpp/actors/core/actor_bootstrapped.h deleted file mode 100644 index 70a6163bc5..0000000000 --- a/library/cpp/actors/core/actor_bootstrapped.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include "actorsystem.h" -#include "actor.h" -#include "events.h" -#include <util/generic/noncopyable.h> - -namespace NActors { - template<typename T> struct dependent_false : std::false_type {}; - - template<typename TDerived> - class TActorBootstrapped: public TActor<TDerived> { - protected: - TAutoPtr<IEventHandle> AfterRegister(const TActorId& self, const TActorId& parentId) override { - return new IEventHandle(TEvents::TSystem::Bootstrap, 0, self, parentId, {}, 0); - } - - STFUNC(StateBootstrap) { - Y_ABORT_UNLESS(ev->GetTypeRewrite() == TEvents::TSystem::Bootstrap, "Unexpected bootstrap message"); - using T = decltype(&TDerived::Bootstrap); - TDerived& self = static_cast<TDerived&>(*this); - if constexpr (std::is_invocable_v<T, TDerived, const TActorContext&>) { - self.Bootstrap(TActivationContext::ActorContextFor(TActor<TDerived>::SelfId())); - } else if constexpr (std::is_invocable_v<T, TDerived, const TActorId&, const TActorContext&>) { - self.Bootstrap(ev->Sender, TActivationContext::ActorContextFor(TActor<TDerived>::SelfId())); - } else if constexpr (std::is_invocable_v<T, TDerived>) { - self.Bootstrap(); - } else if constexpr (std::is_invocable_v<T, TDerived, const TActorId&>) { - self.Bootstrap(ev->Sender); - } else { - static_assert(dependent_false<TDerived>::value, "No correct Bootstrap() signature"); - } - } - - TActorBootstrapped() - : TActor<TDerived>(&TDerived::StateBootstrap) { - } - - template <class TEnum> - TActorBootstrapped(const TEnum activityType) - : TActor<TDerived>(&TDerived::StateBootstrap, activityType) { - } - - TActorBootstrapped(const TString& activityName) - : TActor<TDerived>(&TDerived::StateBootstrap, activityName) { - } - }; -} diff --git a/library/cpp/actors/core/actor_coroutine.cpp b/library/cpp/actors/core/actor_coroutine.cpp deleted file mode 100644 index 32390eaae3..0000000000 --- a/library/cpp/actors/core/actor_coroutine.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include "actor_coroutine.h" -#include "executor_thread.h" - -#include <util/system/sanitizers.h> -#include <util/system/type_name.h> -#include <util/system/info.h> -#include <util/system/protect.h> - -namespace NActors { - static const size_t PageSize = NSystemInfo::GetPageSize(); - -#if !CORO_THROUGH_THREADS - static size_t AlignStackSize(size_t size) { - size += PageSize - (size & PageSize - 1) & PageSize - 1; -#ifndef NDEBUG - size += PageSize; -#endif - return size; - } -#endif - - TActorCoroImpl::TActorCoroImpl(size_t stackSize, bool allowUnhandledDtor) - : AllowUnhandledDtor(allowUnhandledDtor) -#if !CORO_THROUGH_THREADS - , Stack(AlignStackSize(stackSize)) - , FiberClosure{this, TArrayRef(Stack.Begin(), Stack.End())} - , FiberContext(FiberClosure) -#endif - { - Y_UNUSED(stackSize); -#if !CORO_THROUGH_THREADS && !defined(NDEBUG) - ProtectMemory(STACK_GROW_DOWN ? Stack.Begin() : Stack.End() - PageSize, PageSize, EProtectMemoryMode::PM_NONE); -#endif - } - - void TActorCoroImpl::Destroy() { - if (!Finished) { // only resume when we have bootstrapped and Run() was entered and not yet finished; in other case simply terminate - InvokedFromDtor = true; - Resume(nullptr); - } -#if CORO_THROUGH_THREADS - if (WorkerThread.joinable()) { - WorkerThread.join(); - } -#endif - } - - bool TActorCoroImpl::Send(TAutoPtr<IEventHandle> ev) { - return GetActorContext().ExecutorThread.Send(ev); - } - - THolder<IEventHandle> TActorCoroImpl::WaitForEvent(TMonotonic deadline) { - IEventHandle *timeoutEv = nullptr; - if (deadline != TMonotonic::Max()) { - TActivationContext::Schedule(deadline, timeoutEv = new IEventHandle(TEvents::TSystem::CoroTimeout, 0, - SelfActorId, {}, nullptr, 0)); - } - - // ensure we have no unprocessed event and return back to actor system to receive one - Y_ABORT_UNLESS(!Finished); - - // obtain pending event and ensure we've got one - while (THolder<IEventHandle> event = ReturnToActorSystem()) { - if (event->GetTypeRewrite() != TEvents::TSystem::CoroTimeout) { - return event; - } else if (event.Get() == timeoutEv) { - return nullptr; // it is not a race -- we've got timeout exactly for our current wait - } - } - Y_ABORT("no pending event"); - } - - bool TActorCoroImpl::ProcessEvent(THolder<IEventHandle> ev) { - if (!SelfActorId) { // process bootstrap message, extract actor ids - Y_ABORT_UNLESS(ev->GetTypeRewrite() == TEvents::TSystem::Bootstrap); - SelfActorId = ev->Recipient; - ParentActorId = ev->Sender; - ev.Reset(); -#if CORO_THROUGH_THREADS - WorkerThread = std::thread(std::bind(&TActorCoroImpl::DoRun, this)); -#endif - } - - // prepare actor context for in-coroutine use - TActivationContext *ac = TlsActivationContext; - TActorContext actorContext(ac->Mailbox, ac->ExecutorThread, ac->EventStart, SelfActorId); - TlsActivationContext = &actorContext; - - Resume(std::move(ev)); - - // drop actor context - TlsActivationContext = ac; - - return Finished; - } - - void TActorCoroImpl::Resume(THolder<IEventHandle> ev) { - BeforeResume(); - - Y_ABORT_UNLESS(!PendingEvent); - PendingEvent.Swap(ev); - -#if CORO_THROUGH_THREADS - ActivationContext = TlsActivationContext; - InEvent.Signal(); - OutEvent.Wait(); -#else - // save caller context for a later return - Y_ABORT_UNLESS(!ActorSystemContext); - TExceptionSafeContext actorSystemContext; - ActorSystemContext = &actorSystemContext; - - // go to actor coroutine - ActorSystemContext->SwitchTo(&FiberContext); -#endif - - Y_ABORT_UNLESS(!PendingEvent); - } - - void TActorCoroImpl::DoRun() { -#if CORO_THROUGH_THREADS - InEvent.Wait(); - TlsActivationContext = ActivationContext; -#endif - if (!InvokedFromDtor) { - try { - Run(); - } catch (const TDtorException& /*ex*/) { - if (!AllowUnhandledDtor) { - Y_ABORT("unhandled TDtorException"); - } - } catch (const std::exception& ex) { - Y_ABORT("unhandled exception of type %s", TypeName(ex).data()); - } catch (...) { - Y_ABORT("unhandled exception of type not derived from std::exception"); - } - } - Finished = true; - ReturnToActorSystem(); - } - - THolder<IEventHandle> TActorCoroImpl::ReturnToActorSystem() { -#if CORO_THROUGH_THREADS - OutEvent.Signal(); - if (Finished) { - return nullptr; - } else { - InEvent.Wait(); // wait for reentry - TlsActivationContext = ActivationContext; - } -#else - TExceptionSafeContext* returnContext = std::exchange(ActorSystemContext, nullptr); - Y_ABORT_UNLESS(returnContext); - if (StoreTlsState) { - StoreTlsState(this); - } - FiberContext.SwitchTo(returnContext); - if (RestoreTlsState) { - RestoreTlsState(this); - } -#endif - - if (THolder<IEventHandle> ev = std::exchange(PendingEvent, nullptr)) { - return ev; - } else { - // we have returned from the actor system and it kindly asks us to terminate the coroutine as it is being - // stopped - Y_ABORT_UNLESS(InvokedFromDtor); - throw TDtorException(); - } - } - - TActorCoro::~TActorCoro() { - Impl->Destroy(); - } - - STATEFN(TActorCoro::StateFunc) { - if (Impl->ProcessEvent(ev)) { - PassAway(); - } - } -} diff --git a/library/cpp/actors/core/actor_coroutine.h b/library/cpp/actors/core/actor_coroutine.h deleted file mode 100644 index a098c334cf..0000000000 --- a/library/cpp/actors/core/actor_coroutine.h +++ /dev/null @@ -1,230 +0,0 @@ -#pragma once - -#include <util/system/context.h> -#include <util/system/filemap.h> - -#include "actor_bootstrapped.h" -#include "executor_thread.h" -#include "event_local.h" - -#include <thread> - -namespace NActors { - - class TActorCoro; - -#ifndef CORO_THROUGH_THREADS -# ifdef _tsan_enabled_ -# define CORO_THROUGH_THREADS 1 -# else -# define CORO_THROUGH_THREADS 0 -# endif -#endif - - class TActorCoroImpl : public ITrampoLine { - const bool AllowUnhandledDtor; - bool Finished = false; - bool InvokedFromDtor = false; -#if CORO_THROUGH_THREADS - TAutoEvent InEvent; - TAutoEvent OutEvent; - TActivationContext *ActivationContext = nullptr; - std::thread WorkerThread; -#else - TMappedAllocation Stack; - TContClosure FiberClosure; - TExceptionSafeContext FiberContext; - TExceptionSafeContext* ActorSystemContext = nullptr; -#endif - THolder<IEventHandle> PendingEvent; - - protected: - TActorIdentity SelfActorId = TActorIdentity(TActorId()); - TActorId ParentActorId; - - // Pre-leave and pre-enter hook functions are called by coroutine actor code to conserve the state of required TLS - // variables. - // - // They are called in the following order: - // - // 1. coroutine executes WaitForEvent - // 2. StoreTlsState() is called - // 3. control is returned to the actor system - // 4. some event is received, handler called (now in different thread, unconserved TLS variables are changed!) - // 5. handler transfers control to the coroutine - // 6. RestoreTlsState() is called - // - // These hooks may be used in the following way: - // - // thread_local TMyClass *MyObject = nullptr; - // - // class TMyCoroImpl : public TActorCoroImpl { - // TMyClass *SavedMyObject; - // ... - // public: - // TMyCoroImpl() - // : TActorCoroImpl(...) - // { - // StoreTlsState = RestoreTlsState = &TMyCoroImpl::ConserveState; - // } - // - // static void ConserveState(TActorCoroImpl *p) { - // TMyCoroImpl *my = static_cast<TMyCoroImpl*>(p); - // std::swap(my->SavedMyObject, MyObject); - // } - // - // ... - // } - void (*StoreTlsState)(TActorCoroImpl*) = nullptr; - void (*RestoreTlsState)(TActorCoroImpl*) = nullptr; - - - private: - template <typename TFirstEvent, typename... TOtherEvents> - struct TIsOneOf: public TIsOneOf<TOtherEvents...> { - bool operator()(IEventHandle& ev) const { - return ev.GetTypeRewrite() == TFirstEvent::EventType || TIsOneOf<TOtherEvents...>()(ev); - } - }; - - template <typename TSingleEvent> - struct TIsOneOf<TSingleEvent> { - bool operator()(IEventHandle& ev) const { - return ev.GetTypeRewrite() == TSingleEvent::EventType; - } - }; - - protected: - struct TDtorException : yexception {}; - - public: - TActorCoroImpl(size_t stackSize, bool allowUnhandledDtor = false); - // specify stackSize explicitly for each actor; don't forget about overflow control gap - - virtual ~TActorCoroImpl() = default; - - virtual void Run() = 0; - - virtual void BeforeResume() {} - - // Release execution ownership and wait for some event to arrive. - THolder<IEventHandle> WaitForEvent(TMonotonic deadline = TMonotonic::Max()); - - // Wait for specific event set by filter functor. Function returns first event that matches filter. On any other - // - // kind of event processUnexpectedEvent() is called. - // Example: WaitForSpecificEvent([](IEventHandle& ev) { return ev.Cookie == 42; }); - template <typename TFunc, typename TCallback, typename = std::enable_if_t<std::is_invocable_v<TCallback, TAutoPtr<IEventHandle>>>> - THolder<IEventHandle> WaitForSpecificEvent(TFunc&& filter, TCallback processUnexpectedEvent, TMonotonic deadline = TMonotonic::Max()) { - for (;;) { - if (THolder<IEventHandle> event = WaitForEvent(deadline); !event) { - return nullptr; - } else if (filter(*event)) { - return event; - } else { - processUnexpectedEvent(event); - } - } - } - - template <typename TFunc, typename TDerived, typename = std::enable_if_t<std::is_base_of_v<TActorCoroImpl, TDerived>>> - THolder<IEventHandle> WaitForSpecificEvent(TFunc&& filter, void (TDerived::*processUnexpectedEvent)(TAutoPtr<IEventHandle>), - TMonotonic deadline = TMonotonic::Max()) { - auto callback = [&](TAutoPtr<IEventHandle> ev) { (static_cast<TDerived&>(*this).*processUnexpectedEvent)(ev); }; - return WaitForSpecificEvent(std::forward<TFunc>(filter), callback, deadline); - } - - // Wait for specific event or set of events. Function returns first event that matches enlisted type. On any other - // kind of event processUnexpectedEvent() is called. - // - // Example: WaitForSpecificEvent<TEvReadResult, TEvFinished>(); - template <typename TFirstEvent, typename TSecondEvent, typename... TOtherEvents, typename TCallback> - THolder<IEventHandle> WaitForSpecificEvent(TCallback&& callback, TMonotonic deadline = TMonotonic::Max()) { - TIsOneOf<TFirstEvent, TSecondEvent, TOtherEvents...> filter; - return WaitForSpecificEvent(filter, std::forward<TCallback>(callback), deadline); - } - - // Wait for single specific event. - template <typename TEventType, typename TCallback> - THolder<typename TEventType::THandle> WaitForSpecificEvent(TCallback&& callback, TMonotonic deadline = TMonotonic::Max()) { - auto filter = [](IEventHandle& ev) { - return ev.GetTypeRewrite() == TEventType::EventType; - }; - THolder<IEventHandle> event = WaitForSpecificEvent(filter, std::forward<TCallback>(callback), deadline); - return THolder<typename TEventType::THandle>(static_cast<typename TEventType::THandle*>(event ? event.Release() : nullptr)); - } - - protected: // Actor System compatibility section - const TActorContext& GetActorContext() const { return TActivationContext::AsActorContext(); } - TActorSystem *GetActorSystem() const { return GetActorContext().ExecutorThread.ActorSystem; } - TInstant Now() const { return GetActorContext().Now(); } - TMonotonic Monotonic() const { return GetActorContext().Monotonic(); } - - bool Send(const TActorId& recipient, IEventBase* ev, ui32 flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) { - return GetActorContext().Send(recipient, ev, flags, cookie, std::move(traceId)); - } - - bool Send(const TActorId& recipient, THolder<IEventBase> ev, ui32 flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) { - return GetActorContext().Send(recipient, ev.Release(), flags, cookie, std::move(traceId)); - } - - bool Send(TAutoPtr<IEventHandle> ev); - - bool Forward(THolder<IEventHandle>& ev, const TActorId& recipient) { - return Send(IEventHandle::Forward(ev, recipient).Release()); - } - - void Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie = nullptr) { - return GetActorContext().Schedule(delta, ev, cookie); - } - - void Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) { - return GetActorContext().Schedule(deadline, ev, cookie); - } - - void Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) { - return GetActorContext().Schedule(deadline, ev, cookie); - } - - TActorId Register(IActor* actor, TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 poolId = Max<ui32>()) { - return GetActorContext().Register(actor, mailboxType, poolId); - } - - TActorId RegisterWithSameMailbox(IActor* actor) { - return GetActorContext().RegisterWithSameMailbox(actor); - } - - private: - friend class TActorCoro; - bool ProcessEvent(THolder<IEventHandle> ev); - void Destroy(); - - private: - /* Resume() function goes to actor coroutine context and continues (or starts) to execute it until actor finishes - * his job or it is blocked on WaitForEvent. Then the function returns. */ - void Resume(THolder<IEventHandle> ev); - THolder<IEventHandle> ReturnToActorSystem(); - void DoRun() override final; - }; - - class TActorCoro : public IActorCallback { - THolder<TActorCoroImpl> Impl; - - public: - template <class TEnumActivityType = IActor::EActivityType> - TActorCoro(THolder<TActorCoroImpl> impl, const TEnumActivityType activityType = IActor::EActivityType::ACTOR_COROUTINE) - : IActorCallback(static_cast<TReceiveFunc>(&TActorCoro::StateFunc), activityType) - , Impl(std::move(impl)) - {} - - ~TActorCoro(); - - TAutoPtr<IEventHandle> AfterRegister(const TActorId& self, const TActorId& parent) override { - return new IEventHandle(TEvents::TSystem::Bootstrap, 0, self, parent, {}, 0); - } - - private: - STATEFN(StateFunc); - }; - -} diff --git a/library/cpp/actors/core/actor_coroutine_ut.cpp b/library/cpp/actors/core/actor_coroutine_ut.cpp deleted file mode 100644 index 4567cd142e..0000000000 --- a/library/cpp/actors/core/actor_coroutine_ut.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include "actor_coroutine.h" -#include "actorsystem.h" -#include "executor_pool_basic.h" -#include "scheduler_basic.h" -#include "events.h" -#include "event_local.h" -#include "hfunc.h" -#include <library/cpp/testing/unittest/registar.h> - -#include <util/system/sanitizers.h> - -using namespace NActors; - -Y_UNIT_TEST_SUITE(ActorCoro) { - enum { - Begin = EventSpaceBegin(TEvents::ES_USERSPACE), - Request, - Response, - Enough - }; - - struct TEvRequest: public TEventLocal<TEvRequest, Request> { - }; - - struct TEvResponse: public TEventLocal<TEvResponse, Response> { - }; - - struct TEvEnough: public TEventLocal<TEvEnough, Enough> { - }; - - class TBasicResponderActor: public TActorBootstrapped<TBasicResponderActor> { - TDeque<TActorId> RespondTo; - - public: - TBasicResponderActor() { - } - - void Bootstrap(const TActorContext& /*ctx*/) { - Become(&TBasicResponderActor::StateFunc); - } - - STFUNC(StateFunc) { - switch (ev->GetTypeRewrite()) { - HFunc(TEvRequest, Handle); - HFunc(TEvents::TEvWakeup, Handle); - HFunc(TEvents::TEvPoisonPill, Handle); - } - } - - void Handle(TEvRequest::TPtr& ev, const TActorContext& ctx) { - RespondTo.push_back(ev->Sender); - ctx.Schedule(TDuration::Seconds(1), new TEvents::TEvWakeup); - } - - void Handle(TEvents::TEvWakeup::TPtr& /*ev*/, const TActorContext& ctx) { - ctx.Send(RespondTo.front(), new TEvResponse()); - RespondTo.pop_front(); - } - - void Handle(TEvents::TEvPoisonPill::TPtr& /*ev*/, const TActorContext& ctx) { - Die(ctx); - } - }; - - class TCoroActor: public TActorCoroImpl { - TManualEvent& DoneEvent; - TAtomic& ItemsProcessed; - bool Finish; - - struct TPoisonPillException {}; - - public: - TCoroActor(TManualEvent& doneEvent, TAtomic& itemsProcessed) - : TActorCoroImpl(1 << 20) - , DoneEvent(doneEvent) - , ItemsProcessed(itemsProcessed) - , Finish(false) - { - } - - void Run() override { - TActorId child = GetActorContext().Register(new TBasicResponderActor); - ui32 itemsProcessed = 0; - try { - while (!Finish) { - GetActorContext().Send(child, new TEvRequest()); - THolder<IEventHandle> resp = WaitForSpecificEvent<TEvResponse>(&TCoroActor::ProcessUnexpectedEvent); - UNIT_ASSERT_EQUAL(resp->GetTypeRewrite(), TEvResponse::EventType); - ++itemsProcessed; - } - } catch (const TPoisonPillException& /*ex*/) { - } - GetActorContext().Send(child, new TEvents::TEvPoisonPill); - - AtomicSet(ItemsProcessed, itemsProcessed); - DoneEvent.Signal(); - } - - void ProcessUnexpectedEvent(TAutoPtr<IEventHandle> event) { - if (event->GetTypeRewrite() == Enough) { - Finish = true; - } else if (event->GetTypeRewrite() == TEvents::TSystem::Poison) { - throw TPoisonPillException(); - } - } - }; - - void Check(THolder<IEventBase> && message) { - THolder<TActorSystemSetup> setup = MakeHolder<TActorSystemSetup>(); - setup->NodeId = 0; - setup->ExecutorsCount = 1; - setup->Executors.Reset(new TAutoPtr<IExecutorPool>[setup->ExecutorsCount]); - for (ui32 i = 0; i < setup->ExecutorsCount; ++i) { - setup->Executors[i] = new TBasicExecutorPool(i, 5, 10, "basic"); - } - setup->Scheduler = new TBasicSchedulerThread; - - TActorSystem actorSystem(setup); - - actorSystem.Start(); - - TManualEvent doneEvent; - TAtomic itemsProcessed = 0; - TActorId actor = actorSystem.Register(new TActorCoro(MakeHolder<TCoroActor>(doneEvent, itemsProcessed))); - NanoSleep(3UL * 1000 * 1000 * 1000); - actorSystem.Send(actor, message.Release()); - doneEvent.WaitI(); - - UNIT_ASSERT(AtomicGet(itemsProcessed) >= 2); - - actorSystem.Stop(); - } - - Y_UNIT_TEST(Basic) { - if (NSan::TSanIsOn()) { - // TODO https://st.yandex-team.ru/DEVTOOLS-3154 - return; - } - Check(MakeHolder<TEvEnough>()); - } - - Y_UNIT_TEST(PoisonPill) { - Check(MakeHolder<TEvents::TEvPoisonPill>()); - } -} diff --git a/library/cpp/actors/core/actor_ut.cpp b/library/cpp/actors/core/actor_ut.cpp deleted file mode 100644 index 52d3cbad9c..0000000000 --- a/library/cpp/actors/core/actor_ut.cpp +++ /dev/null @@ -1,511 +0,0 @@ -#include "actor.h" -#include "events.h" -#include "actorsystem.h" -#include "executor_pool_basic.h" -#include "scheduler_basic.h" -#include "actor_bootstrapped.h" -#include "actor_benchmark_helper.h" - -#include <library/cpp/actors/testlib/test_runtime.h> -#include <library/cpp/actors/util/threadparkpad.h> -#include <library/cpp/testing/unittest/registar.h> - -#include <util/generic/algorithm.h> -#include <library/cpp/deprecated/atomic/atomic.h> -#include <util/system/rwlock.h> -#include <util/system/hp_timer.h> - -using namespace NActors; -using namespace NActors::NTests; - -Y_UNIT_TEST_SUITE(ActorBenchmark) { - - using TActorBenchmark = ::NActors::NTests::TActorBenchmark<>; - using TSettings = TActorBenchmark::TSettings; - using TSendReceiveActorParams = TActorBenchmark::TSendReceiveActorParams; - - Y_UNIT_TEST(WithSharedExecutors) { - THolder<TActorSystemSetup> setup = TActorBenchmark::GetActorSystemSetup(0, false); - TActorBenchmark::AddBasicPool(setup, 2, 1, 0); - TActorBenchmark::AddBasicPool(setup, 2, 1, 1); - - TActorSystem actorSystem(setup); - actorSystem.Start(); - - TThreadParkPad pad; - TAtomic actorsAlive = 0; - THPTimer Timer; - - ui64 eventsPerPair = TSettings::TotalEventsAmountPerThread * 4 / 60; - - Timer.Reset(); - for (ui32 i = 0; i < 50; ++i) { - ui32 followerPoolId = 0; - ui32 leaderPoolId = 0; - TActorId followerId = actorSystem.Register( - new TActorBenchmark::TSendReceiveActor( - TSendReceiveActorParams{.OtherEvents=eventsPerPair / 2, .Allocation=true} - ), - TMailboxType::HTSwap, - followerPoolId - ); - THolder<IActor> leader{ - new TTestEndDecorator(THolder(new TActorBenchmark::TSendReceiveActor( - TSendReceiveActorParams{.OwnEvents=eventsPerPair / 2, .Receivers={followerId}, .Allocation=true} - )), - &pad, - &actorsAlive) - }; - actorSystem.Register(leader.Release(), TMailboxType::HTSwap, leaderPoolId); - } - for (ui32 i = 0; i < 10; ++i) { - ui32 followerPoolId = 1; - ui32 leaderPoolId = 1; - TActorId followerId = actorSystem.Register( - new TActorBenchmark::TSendReceiveActor( - TSendReceiveActorParams{.OtherEvents=eventsPerPair / 2, .Allocation=true} - ), - TMailboxType::HTSwap, - followerPoolId - ); - THolder<IActor> leader{ - new TTestEndDecorator( - THolder(new TActorBenchmark::TSendReceiveActor( - TSendReceiveActorParams{.OwnEvents=eventsPerPair / 2, .Receivers={followerId}, .Allocation=true} - )), - &pad, - &actorsAlive - ) - }; - actorSystem.Register(leader.Release(), TMailboxType::HTSwap, leaderPoolId); - } - - pad.Park(); - auto elapsedTime = Timer.Passed() / (TSettings::TotalEventsAmountPerThread * 4); - actorSystem.Stop(); - - Cerr << "Completed " << 1e9 * elapsedTime << Endl; - } - - Y_UNIT_TEST(WithoutSharedExecutors) { - THolder<TActorSystemSetup> setup = TActorBenchmark::GetActorSystemSetup(0, false); - TActorBenchmark::AddBasicPool(setup, 2, 1, 0); - TActorBenchmark::AddBasicPool(setup, 2, 1, 0); - - TActorSystem actorSystem(setup); - actorSystem.Start(); - - TThreadParkPad pad; - TAtomic actorsAlive = 0; - THPTimer Timer; - - ui64 eventsPerPair = TSettings::TotalEventsAmountPerThread * 4 / 60; - - Timer.Reset(); - for (ui32 i = 0; i < 50; ++i) { - ui32 followerPoolId = 0; - ui32 leaderPoolId = 0; - TActorId followerId = actorSystem.Register( - new TActorBenchmark::TSendReceiveActor( - TSendReceiveActorParams{.OtherEvents=eventsPerPair / 2, .Allocation=true} - ), - TMailboxType::HTSwap, - followerPoolId - ); - THolder<IActor> leader{ - new TTestEndDecorator( - THolder(new TActorBenchmark::TSendReceiveActor( - TSendReceiveActorParams{.OwnEvents=eventsPerPair / 2, .Receivers={followerId}, .Allocation=true} - )), - &pad, - &actorsAlive - ) - }; - actorSystem.Register(leader.Release(), TMailboxType::HTSwap, leaderPoolId); - } - for (ui32 i = 0; i < 10; ++i) { - ui32 followerPoolId = 1; - ui32 leaderPoolId = 1; - TActorId followerId = actorSystem.Register( - new TActorBenchmark::TSendReceiveActor( - TSendReceiveActorParams{.OtherEvents=eventsPerPair / 2, .Allocation=true} - ), - TMailboxType::HTSwap, - followerPoolId - ); - THolder<IActor> leader{ - new TTestEndDecorator( - THolder(new TActorBenchmark::TSendReceiveActor( - TSendReceiveActorParams{.OwnEvents=eventsPerPair / 2, .Receivers={followerId}, .Allocation=true} - )), - &pad, - &actorsAlive - ) - }; - actorSystem.Register(leader.Release(), TMailboxType::HTSwap, leaderPoolId); - } - - pad.Park(); - auto elapsedTime = Timer.Passed() / (4 * TSettings::TotalEventsAmountPerThread); - actorSystem.Stop(); - - Cerr << "Completed " << 1e9 * elapsedTime << Endl; - } - - Y_UNIT_TEST(SendReceive1Pool1ThreadAlloc) { - for (const auto& mType : TSettings::MailboxTypes) { - auto stats = TActorBenchmark::CountStats([mType] { - return TActorBenchmark::BenchSendReceive(true, mType, TActorBenchmark::EPoolType::Basic, ESendingType::Common); - }); - Cerr << stats.ToString() << " " << mType << Endl; - stats = TActorBenchmark::CountStats([mType] { - return TActorBenchmark::BenchSendReceive(true, mType, TActorBenchmark::EPoolType::Basic, ESendingType::Lazy); - }); - Cerr << stats.ToString() << " " << mType << " Lazy" << Endl; - stats = TActorBenchmark::CountStats([mType] { - return TActorBenchmark::BenchSendReceive(true, mType, TActorBenchmark::EPoolType::Basic, ESendingType::Tail); - }); - Cerr << stats.ToString() << " " << mType << " Tail" << Endl; - } - } - - Y_UNIT_TEST(SendReceive1Pool1ThreadAllocUnited) { - for (const auto& mType : TSettings::MailboxTypes) { - auto stats = TActorBenchmark::CountStats([mType] { - return TActorBenchmark::BenchSendReceive(true, mType, TActorBenchmark::EPoolType::United, ESendingType::Common); - }); - Cerr << stats.ToString() << " " << mType << Endl; - stats = TActorBenchmark::CountStats([mType] { - return TActorBenchmark::BenchSendReceive(true, mType, TActorBenchmark::EPoolType::United, ESendingType::Lazy); - }); - Cerr << stats.ToString() << " " << mType << " Lazy" << Endl; - stats = TActorBenchmark::CountStats([mType] { - return TActorBenchmark::BenchSendReceive(true, mType, TActorBenchmark::EPoolType::United, ESendingType::Tail); - }); - Cerr << stats.ToString() << " " << mType << " Tail" << Endl; - } - } - - Y_UNIT_TEST(SendReceive1Pool1ThreadNoAlloc) { - for (const auto& mType : TSettings::MailboxTypes) { - auto stats = TActorBenchmark::CountStats([mType] { - return TActorBenchmark::BenchSendReceive(false, mType, TActorBenchmark::EPoolType::Basic, ESendingType::Common); - }); - Cerr << stats.ToString() << " " << mType << Endl; - stats = TActorBenchmark::CountStats([mType] { - return TActorBenchmark::BenchSendReceive(false, mType, TActorBenchmark::EPoolType::Basic, ESendingType::Lazy); - }); - Cerr << stats.ToString() << " " << mType << " Lazy" << Endl; - stats = TActorBenchmark::CountStats([mType] { - return TActorBenchmark::BenchSendReceive(false, mType, TActorBenchmark::EPoolType::Basic, ESendingType::Tail); - }); - Cerr << stats.ToString() << " " << mType << " Tail" << Endl; - } - } - - Y_UNIT_TEST(SendReceive1Pool1ThreadNoAllocUnited) { - for (const auto& mType : TSettings::MailboxTypes) { - auto stats = TActorBenchmark::CountStats([mType] { - return TActorBenchmark::BenchSendReceive(false, mType, TActorBenchmark::EPoolType::United, ESendingType::Common); - }); - Cerr << stats.ToString() << " " << mType << Endl; - stats = TActorBenchmark::CountStats([mType] { - return TActorBenchmark::BenchSendReceive(false, mType, TActorBenchmark::EPoolType::United, ESendingType::Lazy); - }); - Cerr << stats.ToString() << " " << mType << " Lazy" << Endl; - stats = TActorBenchmark::CountStats([mType] { - return TActorBenchmark::BenchSendReceive(false, mType, TActorBenchmark::EPoolType::United, ESendingType::Tail); - }); - Cerr << stats.ToString() << " " << mType << " Tail" << Endl; - } - } - - Y_UNIT_TEST(SendActivateReceive1Pool1ThreadAlloc) { - TActorBenchmark::RunBenchSendActivateReceive(1, 1, true, TActorBenchmark::EPoolType::Basic); - } - - Y_UNIT_TEST(SendActivateReceive1Pool1ThreadAllocUnited) { - TActorBenchmark::RunBenchSendActivateReceive(1, 1, true, TActorBenchmark::EPoolType::United); - } - - Y_UNIT_TEST(SendActivateReceive1Pool1ThreadNoAlloc) { - TActorBenchmark::RunBenchSendActivateReceive(1, 1, false, TActorBenchmark::EPoolType::Basic); - } - - Y_UNIT_TEST(SendActivateReceive1Pool1ThreadNoAllocUnited) { - TActorBenchmark::RunBenchSendActivateReceive(1, 1, false, TActorBenchmark::EPoolType::United); - } - - Y_UNIT_TEST(SendActivateReceive1Pool2ThreadsAlloc) { - TActorBenchmark::RunBenchSendActivateReceive(1, 2, true, TActorBenchmark::EPoolType::Basic); - } - - Y_UNIT_TEST(SendActivateReceive1Pool2ThreadsAllocUnited) { - TActorBenchmark::RunBenchSendActivateReceive(1, 2, true, TActorBenchmark::EPoolType::United); - } - - Y_UNIT_TEST(SendActivateReceive1Pool2ThreadsNoAlloc) { - TActorBenchmark::RunBenchSendActivateReceive(1, 2, false, TActorBenchmark::EPoolType::Basic); - } - - Y_UNIT_TEST(SendActivateReceive1Pool2ThreadsNoAllocUnited) { - TActorBenchmark::RunBenchSendActivateReceive(1, 2, false, TActorBenchmark::EPoolType::United); - } - - Y_UNIT_TEST(SendActivateReceive2Pool1ThreadAlloc) { - TActorBenchmark::RunBenchSendActivateReceive(2, 1, true, TActorBenchmark::EPoolType::Basic); - } - - Y_UNIT_TEST(SendActivateReceive2Pool1ThreadAllocUnited) { - TActorBenchmark::RunBenchSendActivateReceive(2, 1, true, TActorBenchmark::EPoolType::United); - } - - Y_UNIT_TEST(SendActivateReceive2Pool1ThreadNoAlloc) { - TActorBenchmark::RunBenchSendActivateReceive(2, 1, false, TActorBenchmark::EPoolType::Basic); - } - - Y_UNIT_TEST(SendActivateReceive2Pool1ThreadNoAllocUnited) { - TActorBenchmark::RunBenchSendActivateReceive(2, 1, false, TActorBenchmark::EPoolType::United); - } - - Y_UNIT_TEST(SendActivateReceive1Pool1Threads) { TActorBenchmark::RunBenchContentedThreads(1, TActorBenchmark::EPoolType::Basic); } - Y_UNIT_TEST(SendActivateReceive1Pool1ThreadsUnited) { TActorBenchmark::RunBenchContentedThreads(1, TActorBenchmark::EPoolType::United); } - Y_UNIT_TEST(SendActivateReceive1Pool2Threads) { TActorBenchmark::RunBenchContentedThreads(2, TActorBenchmark::EPoolType::Basic); } - Y_UNIT_TEST(SendActivateReceive1Pool2ThreadsUnited) { TActorBenchmark::RunBenchContentedThreads(2, TActorBenchmark::EPoolType::United); } - Y_UNIT_TEST(SendActivateReceive1Pool3Threads) { TActorBenchmark::RunBenchContentedThreads(3, TActorBenchmark::EPoolType::Basic); } - Y_UNIT_TEST(SendActivateReceive1Pool3ThreadsUnited) { TActorBenchmark::RunBenchContentedThreads(3, TActorBenchmark::EPoolType::United); } - Y_UNIT_TEST(SendActivateReceive1Pool4Threads) { TActorBenchmark::RunBenchContentedThreads(4, TActorBenchmark::EPoolType::Basic); } - Y_UNIT_TEST(SendActivateReceive1Pool4ThreadsUnited) { TActorBenchmark::RunBenchContentedThreads(4, TActorBenchmark::EPoolType::United); } - Y_UNIT_TEST(SendActivateReceive1Pool5Threads) { TActorBenchmark::RunBenchContentedThreads(5, TActorBenchmark::EPoolType::Basic); } - Y_UNIT_TEST(SendActivateReceive1Pool5ThreadsUnited) { TActorBenchmark::RunBenchContentedThreads(5, TActorBenchmark::EPoolType::United); } - Y_UNIT_TEST(SendActivateReceive1Pool6Threads) { TActorBenchmark::RunBenchContentedThreads(6, TActorBenchmark::EPoolType::Basic); } - Y_UNIT_TEST(SendActivateReceive1Pool6ThreadsUnited) { TActorBenchmark::RunBenchContentedThreads(6, TActorBenchmark::EPoolType::United); } - Y_UNIT_TEST(SendActivateReceive1Pool7Threads) { TActorBenchmark::RunBenchContentedThreads(7, TActorBenchmark::EPoolType::Basic); } - Y_UNIT_TEST(SendActivateReceive1Pool7ThreadsUnited) { TActorBenchmark::RunBenchContentedThreads(7, TActorBenchmark::EPoolType::United); } - Y_UNIT_TEST(SendActivateReceive1Pool8Threads) { TActorBenchmark::RunBenchContentedThreads(8, TActorBenchmark::EPoolType::Basic); } - Y_UNIT_TEST(SendActivateReceive1Pool8ThreadsUnited) { TActorBenchmark::RunBenchContentedThreads(8, TActorBenchmark::EPoolType::United); } - - Y_UNIT_TEST(SendActivateReceiveCSV) { - std::vector<ui32> threadsList; - for (ui32 threads = 1; threads <= 32; threads *= 2) { - threadsList.push_back(threads); - } - std::vector<ui32> actorPairsList; - for (ui32 actorPairs = 1; actorPairs <= 2 * 32; actorPairs *= 2) { - actorPairsList.push_back(actorPairs); - } - TActorBenchmark::RunSendActivateReceiveCSV(threadsList, actorPairsList, {1}, TDuration::MilliSeconds(100)); - } - - Y_UNIT_TEST(SendActivateReceiveWithMailboxNeighbours) { - TVector<ui32> NeighbourActors = {0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 32, 64, 128, 256}; - for (const auto& neighbour : NeighbourActors) { - auto stats = TActorBenchmark::CountStats([neighbour] { - return TActorBenchmark::BenchSendActivateReceiveWithMailboxNeighbours(neighbour, TActorBenchmark::EPoolType::Basic, ESendingType::Common); - }); - Cerr << stats.ToString() << " neighbourActors: " << neighbour << Endl; - stats = TActorBenchmark::CountStats([neighbour] { - return TActorBenchmark::BenchSendActivateReceiveWithMailboxNeighbours(neighbour, TActorBenchmark::EPoolType::Basic, ESendingType::Lazy); - }); - Cerr << stats.ToString() << " neighbourActors: " << neighbour << " Lazy" << Endl; - stats = TActorBenchmark::CountStats([neighbour] { - return TActorBenchmark::BenchSendActivateReceiveWithMailboxNeighbours(neighbour, TActorBenchmark::EPoolType::Basic, ESendingType::Tail); - }); - Cerr << stats.ToString() << " neighbourActors: " << neighbour << " Tail" << Endl; - } - } - - Y_UNIT_TEST(SendActivateReceiveWithMailboxNeighboursUnited) { - TVector<ui32> NeighbourActors = {0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 32, 64, 128, 256}; - for (const auto& neighbour : NeighbourActors) { - auto stats = TActorBenchmark::CountStats([neighbour] { - return TActorBenchmark::BenchSendActivateReceiveWithMailboxNeighbours(neighbour, TActorBenchmark::EPoolType::United, ESendingType::Common); - }); - Cerr << stats.ToString() << " neighbourActors: " << neighbour << Endl; - stats = TActorBenchmark::CountStats([neighbour] { - return TActorBenchmark::BenchSendActivateReceiveWithMailboxNeighbours(neighbour, TActorBenchmark::EPoolType::United, ESendingType::Lazy); - }); - Cerr << stats.ToString() << " neighbourActors: " << neighbour << " Lazy" << Endl; - stats = TActorBenchmark::CountStats([neighbour] { - return TActorBenchmark::BenchSendActivateReceiveWithMailboxNeighbours(neighbour, TActorBenchmark::EPoolType::United, ESendingType::Tail); - }); - Cerr << stats.ToString() << " neighbourActors: " << neighbour << " Tail" << Endl; - } - } -} - -Y_UNIT_TEST_SUITE(TestDecorator) { - struct TPingDecorator : TDecorator { - TAutoPtr<IEventHandle> SavedEvent = nullptr; - ui64* Counter; - - TPingDecorator(THolder<IActor>&& actor, ui64* counter) - : TDecorator(std::move(actor)) - , Counter(counter) - { - } - - bool DoBeforeReceiving(TAutoPtr<IEventHandle>& ev, const TActorContext&) override { - *Counter += 1; - if (ev->Type != TEvents::THelloWorld::Pong) { - TAutoPtr<IEventHandle> pingEv = new IEventHandle(SelfId(), SelfId(), new TEvents::TEvPing()); - SavedEvent = ev; - Actor->Receive(pingEv); - } else { - Actor->Receive(SavedEvent); - } - return false; - } - }; - - struct TPongDecorator : TDecorator { - ui64* Counter; - - TPongDecorator(THolder<IActor>&& actor, ui64* counter) - : TDecorator(std::move(actor)) - , Counter(counter) - { - } - - bool DoBeforeReceiving(TAutoPtr<IEventHandle>& ev, const TActorContext&) override { - *Counter += 1; - if (ev->Type == TEvents::THelloWorld::Ping) { - TAutoPtr<IEventHandle> pongEv = new IEventHandle(SelfId(), SelfId(), new TEvents::TEvPong()); - Send(SelfId(), new TEvents::TEvPong()); - return false; - } - return true; - } - }; - - struct TTestActor : TActorBootstrapped<TTestActor> { - static constexpr char ActorName[] = "TestActor"; - - void Bootstrap() - { - const auto& activityTypeIndex = GetActivityType(); - Y_ENSURE(activityTypeIndex < GetActivityTypeCount()); - Y_ENSURE(GetActivityTypeName(activityTypeIndex) == "TestActor"); - PassAway(); - } - }; - - Y_UNIT_TEST(Basic) { - THolder<TActorSystemSetup> setup = MakeHolder<TActorSystemSetup>(); - setup->NodeId = 0; - setup->ExecutorsCount = 1; - setup->Executors.Reset(new TAutoPtr<IExecutorPool>[setup->ExecutorsCount]); - - ui64 ts = GetCycleCountFast(); - THolder<IHarmonizer> harmonizer(MakeHarmonizer(ts)); - for (ui32 i = 0; i < setup->ExecutorsCount; ++i) { - setup->Executors[i] = new TBasicExecutorPool(i, 1, 10, "basic", harmonizer.Get()); - harmonizer->AddPool(setup->Executors[i].Get()); - } - setup->Scheduler = new TBasicSchedulerThread; - - TActorSystem actorSystem(setup); - actorSystem.Start(); - - THolder<IActor> innerActor = MakeHolder<TTestActor>(); - ui64 pongCounter = 0; - THolder<IActor> pongActor = MakeHolder<TPongDecorator>(std::move(innerActor), &pongCounter); - ui64 pingCounter = 0; - THolder<IActor> pingActor = MakeHolder<TPingDecorator>(std::move(pongActor), &pingCounter); - - TThreadParkPad pad; - TAtomic actorsAlive = 0; - - THolder<IActor> endActor = MakeHolder<TTestEndDecorator>(std::move(pingActor), &pad, &actorsAlive); - actorSystem.Register(endActor.Release(), TMailboxType::HTSwap); - - pad.Park(); - actorSystem.Stop(); - UNIT_ASSERT(pongCounter == 2 && pingCounter == 2); - } - - Y_UNIT_TEST(LocalProcessKey) { - static constexpr char ActorName[] = "TestActor"; - - UNIT_ASSERT((TEnumProcessKey<TActorActivityTag, IActor::EActorActivity>::GetName(IActor::EActivityType::INTERCONNECT_PROXY_TCP) == "INTERCONNECT_PROXY_TCP")); - UNIT_ASSERT((TLocalProcessKey<TActorActivityTag, ActorName>::GetName() == ActorName)); - } -} - -Y_UNIT_TEST_SUITE(TestStateFunc) { - struct TTestActorWithExceptionsStateFunc : TActor<TTestActorWithExceptionsStateFunc> { - static constexpr char ActorName[] = "TestActorWithExceptionsStateFunc"; - - TTestActorWithExceptionsStateFunc() - : TActor<TTestActorWithExceptionsStateFunc>(&TTestActorWithExceptionsStateFunc::StateFunc) - { - } - - STRICT_STFUNC_EXC(StateFunc, - hFunc(TEvents::TEvWakeup, Handle), - ExceptionFunc(yexception, HandleException) - ExceptionFuncEv(std::exception, HandleException) - AnyExceptionFunc(HandleException) - ) - - void Handle(TEvents::TEvWakeup::TPtr& ev) { - Owner = ev->Sender; - switch (ev->Get()->Tag) { - case ETag::NoException: - SendResponse(ETag::NoException); - break; - case ETag::YException: - Cerr << "Throw yexception" << Endl; - throw yexception(); - case ETag::StdException: - Cerr << "Throw std::exception" << Endl; - throw std::runtime_error("trololo"); - case ETag::OtherException: - Cerr << "Throw trash" << Endl; - throw TString("1"); - default: - UNIT_ASSERT(false); - } - } - - void HandleException(const yexception&) { - Cerr << "Handle yexception" << Endl; - SendResponse(ETag::YException); - } - - void HandleException(const std::exception&, TAutoPtr<::NActors::IEventHandle>& ev) { - Cerr << "Handle std::exception from event with type " << ev->Type << Endl; - SendResponse(ETag::StdException); - } - - void HandleException() { - Cerr << "Handle trash" << Endl; - SendResponse(ETag::OtherException); - } - - enum ETag : ui64 { - NoException, - YException, - StdException, - OtherException, - }; - - void SendResponse(ETag tag) { - Send(Owner, new TEvents::TEvWakeup(tag)); - } - - TActorId Owner; - }; - - Y_UNIT_TEST(StateFuncWithExceptions) { - TTestActorRuntimeBase runtime; - runtime.Initialize(); - auto sender = runtime.AllocateEdgeActor(); - auto testActor = runtime.Register(new TTestActorWithExceptionsStateFunc()); - for (ui64 tag = 0; tag < 4; ++tag) { - runtime.Send(new IEventHandle(testActor, sender, new TEvents::TEvWakeup(tag)), 0, true); - auto ev = runtime.GrabEdgeEventRethrow<TEvents::TEvWakeup>(sender); - UNIT_ASSERT_VALUES_EQUAL(ev->Get()->Tag, tag); - } - } -} diff --git a/library/cpp/actors/core/actor_virtual.cpp b/library/cpp/actors/core/actor_virtual.cpp deleted file mode 100644 index 709cd7be15..0000000000 --- a/library/cpp/actors/core/actor_virtual.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "actor_virtual.h" - -namespace NActors { -
-
-} diff --git a/library/cpp/actors/core/actor_virtual.h b/library/cpp/actors/core/actor_virtual.h deleted file mode 100644 index 78da45138d..0000000000 --- a/library/cpp/actors/core/actor_virtual.h +++ /dev/null @@ -1,88 +0,0 @@ -#pragma once -#include "event.h" -#include "actor.h" - -namespace NActors { - -template <class TEvent> -class TEventContext { -private: - TEvent* Event; - std::unique_ptr<IEventHandle> Handle; -public: - const TEvent* operator->() const { - return Event; - } - const IEventHandle& GetHandle() const { - return *Handle; - } - TEventContext(std::unique_ptr<IEventHandle> handle) - : Handle(std::move(handle)) - { - Y_DEBUG_ABORT_UNLESS(dynamic_cast<TEvent*>(Handle->GetBase())); - Event = static_cast<TEvent*>(Handle->GetBase()); - Y_ABORT_UNLESS(Event); - } -}; - -template <class TEvent, class TExpectedActor> -class IEventForActor: public IEventBase { -protected: - virtual bool DoExecute(IActor* actor, std::unique_ptr<IEventHandle> eventPtr) override { - Y_DEBUG_ABORT_UNLESS(dynamic_cast<TExpectedActor*>(actor)); - auto* actorCorrect = static_cast<TExpectedActor*>(actor); - TEventContext<TEvent> context(std::move(eventPtr)); - actorCorrect->ProcessEvent(context); - return true; - } -public: -}; - -template <class TBaseEvent, class TEvent, class TExpectedObject> -class IEventForAnything: public TBaseEvent { -protected: - virtual bool DoExecute(IActor* actor, std::unique_ptr<IEventHandle> eventPtr) override { - auto* objImpl = dynamic_cast<TExpectedObject*>(actor); - if (!objImpl) { - return false; - } - TEventContext<TEvent> context(std::move(eventPtr)); - objImpl->ProcessEvent(context); - return true; - } -public: -}; - -template <class TEvent, class TActor> -class TEventLocalForActor: public IEventForActor<TEvent, TActor> { -private: - using TBase = IEventForActor<TEvent, TActor>; - static TString GetClassTitle() { - return TStringBuilder() << typeid(TEvent).name() << "->" << typeid(TActor).name(); - } - static i64 LocalClassId; -public: - virtual ui32 Type() const override { - return LocalClassId; - } - virtual TString ToStringHeader() const override { - return GetClassTitle(); - } - - virtual bool SerializeToArcadiaStream(TChunkSerializer* /*serializer*/) const override { - Y_ABORT("Serialization of local event %s->%s", typeid(TEvent).name(), typeid(TActor).name()); - } - - virtual bool IsSerializable() const override { - return false; - } - - static IEventBase* Load(TEventSerializedData*) { - Y_ABORT("Loading of local event %s->%s", typeid(TEvent).name(), typeid(TActor).name()); - } -}; - -template <class TEvent, class TActor> -i64 TEventLocalForActor<TEvent, TActor>::LocalClassId = Singleton<TAtomicCounter>()->Inc(); - -} diff --git a/library/cpp/actors/core/actorid.cpp b/library/cpp/actors/core/actorid.cpp deleted file mode 100644 index ccda035eac..0000000000 --- a/library/cpp/actors/core/actorid.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "actorid.h" -#include <util/string/builder.h> -#include <util/string/cast.h> - -namespace NActors { - void TActorId::Out(IOutputStream& o) const { - o << "[" << NodeId() << ":" << LocalId() << ":" << Hint() << "]"; - } - - TString TActorId::ToString() const { - TString x; - TStringOutput o(x); - Out(o); - return x; - } - - bool TActorId::Parse(const char* buf, ui32 sz) { - if (sz < 4 || buf[0] != '[' || buf[sz - 1] != ']') - return false; - - size_t semicolons[2]; - TStringBuf str(buf, sz); - semicolons[0] = str.find(':', 1); - if (semicolons[0] == TStringBuf::npos) - return false; - semicolons[1] = str.find(':', semicolons[0] + 1); - if (semicolons[1] == TStringBuf::npos) - return false; - - bool success = TryFromString(buf + 1, semicolons[0] - 1, Raw.N.NodeId) && TryFromString(buf + semicolons[0] + 1, semicolons[1] - semicolons[0] - 1, Raw.N.LocalId) && TryFromString(buf + semicolons[1] + 1, sz - semicolons[1] - 2, Raw.N.Hint); - - return success; - } -} diff --git a/library/cpp/actors/core/actorid.h b/library/cpp/actors/core/actorid.h deleted file mode 100644 index 4e9a7bc3c3..0000000000 --- a/library/cpp/actors/core/actorid.h +++ /dev/null @@ -1,198 +0,0 @@ -#pragma once - -#include "defs.h" -#include <util/stream/output.h> // for IOutputStream -#include <util/generic/hash.h> - -namespace NActors { - // used as global uniq address of actor - // also could be used to transport service id (12 byte strings placed in hint-localid) - // highest 1 bit of node - mark of service id - // next 11 bits of node-id - pool id - // next 20 bits - node id itself - - struct TActorId { - static constexpr ui32 MaxServiceIDLength = 12; - static constexpr ui32 MaxPoolID = 0x000007FF; - static constexpr ui32 MaxNodeId = 0x000FFFFF; - static constexpr ui32 PoolIndexShift = 20; - static constexpr ui32 PoolIndexMask = MaxPoolID << PoolIndexShift; - static constexpr ui32 ServiceMask = 0x80000000; - static constexpr ui32 NodeIdMask = MaxNodeId; - - private: - union { - struct { - ui64 LocalId; - ui32 Hint; - ui32 NodeId; - } N; - - struct { - ui64 X1; - ui64 X2; - } X; - - ui8 Buf[16]; - } Raw; - - public: - TActorId() noexcept { - Raw.X.X1 = 0; - Raw.X.X2 = 0; - } - - explicit TActorId(ui32 nodeId, ui32 poolId, ui64 localId, ui32 hint) noexcept { - Y_DEBUG_ABORT_UNLESS(poolId <= MaxPoolID); - Raw.N.LocalId = localId; - Raw.N.Hint = hint; - Raw.N.NodeId = nodeId | (poolId << PoolIndexShift); - } - - explicit TActorId(ui32 nodeId, const TStringBuf& x) noexcept { - Y_ABORT_UNLESS(x.size() <= MaxServiceIDLength, "service id is too long"); - Raw.N.LocalId = 0; - Raw.N.Hint = 0; - Raw.N.NodeId = nodeId | ServiceMask; - memcpy(Raw.Buf, x.data(), x.size()); - } - - explicit TActorId(ui64 x1, ui64 x2) noexcept { - Raw.X.X1 = x1; - Raw.X.X2 = x2; - } - - explicit operator bool() const noexcept { - return Raw.X.X1 != 0 || Raw.X.X2 != 0; - } - - ui64 LocalId() const noexcept { - return Raw.N.LocalId; - } - - ui32 Hint() const noexcept { - return Raw.N.Hint; - } - - ui32 NodeId() const noexcept { - return Raw.N.NodeId & NodeIdMask; - } - - bool IsService() const noexcept { - return (Raw.N.NodeId & ServiceMask); - } - - TStringBuf ServiceId() const noexcept { - Y_DEBUG_ABORT_UNLESS(IsService()); - return TStringBuf((const char*)Raw.Buf, MaxServiceIDLength); - } - - static ui32 PoolIndex(ui32 nodeid) noexcept { - return ((nodeid & PoolIndexMask) >> PoolIndexShift); - } - - ui32 PoolID() const noexcept { - return PoolIndex(Raw.N.NodeId); - } - - ui64 RawX1() const noexcept { - return Raw.X.X1; - } - - ui64 RawX2() const noexcept { - return Raw.X.X2; - } - - bool operator<(const TActorId& x) const noexcept { - const ui64 s1 = Raw.X.X1; - const ui64 s2 = Raw.X.X2; - const ui64 x1 = x.Raw.X.X1; - const ui64 x2 = x.Raw.X.X2; - - return (s1 != x1) ? (s1 < x1) : (s2 < x2); - } - - bool operator!=(const TActorId& x) const noexcept { - return Raw.X.X1 != x.Raw.X.X1 || Raw.X.X2 != x.Raw.X.X2; - } - - bool operator==(const TActorId& x) const noexcept { - return !(x != *this); - } - - ui64 Hash() const noexcept { - const ui32* x = (const ui32*)Raw.Buf; - - const ui64 x1 = x[0] * 0x001DFF3D8DC48F5Dull; - const ui64 x2 = x[1] * 0x179CA10C9242235Dull; - const ui64 x3 = x[2] * 0x0F530CAD458B0FB1ull; - const ui64 x4 = x[3] * 0xB5026F5AA96619E9ull; - - const ui64 z1 = x1 + x2; - const ui64 z2 = x3 + x4; - - const ui64 sum = 0x5851F42D4C957F2D + z1 + z2; - - return (sum >> 32) | (sum << 32); - } - - ui32 Hash32() const noexcept { - const ui32* x = (const ui32*)Raw.Buf; - - const ui64 x1 = x[0] * 0x001DFF3D8DC48F5Dull; - const ui64 x2 = x[1] * 0x179CA10C9242235Dull; - const ui64 x3 = x[2] * 0x0F530CAD458B0FB1ull; - const ui64 x4 = x[3] * 0xB5026F5AA96619E9ull; - - const ui64 z1 = x1 + x2; - const ui64 z2 = x3 + x4; - - const ui64 sum = 0x5851F42D4C957F2D + z1 + z2; - - return sum >> 32; - } - - struct THash { - ui64 operator()(const TActorId& actorId) const noexcept { - return actorId.Hash(); - } - }; - - struct THash32 { - ui64 operator()(const TActorId& actorId) const noexcept { - return actorId.Hash(); - } - }; - - struct TOrderedCmp { - bool operator()(const TActorId &left, const TActorId &right) const noexcept { - Y_DEBUG_ABORT_UNLESS(!left.IsService() && !right.IsService(), "ordered compare works for plain actorids only"); - const ui32 n1 = left.NodeId(); - const ui32 n2 = right.NodeId(); - - return (n1 != n2) ? (n1 < n2) : left.LocalId() < right.LocalId(); - } - }; - - TString ToString() const; - void Out(IOutputStream& o) const; - bool Parse(const char* buf, ui32 sz); - }; - - static_assert(sizeof(TActorId) == 16, "expect sizeof(TActorId) == 16"); - static_assert(MaxPools < TActorId::MaxPoolID); // current implementation of united pool has limit MaxPools on pool id -} - -template <> -inline void Out<NActors::TActorId>(IOutputStream& o, const NActors::TActorId& x) { - return x.Out(o); -} - -template <> -struct THash<NActors::TActorId> { - inline ui64 operator()(const NActors::TActorId& x) const { - return x.Hash(); - } -}; - -template<> struct std::hash<NActors::TActorId> : THash<NActors::TActorId> {}; diff --git a/library/cpp/actors/core/actorsystem.cpp b/library/cpp/actors/core/actorsystem.cpp deleted file mode 100644 index c09a208ef5..0000000000 --- a/library/cpp/actors/core/actorsystem.cpp +++ /dev/null @@ -1,323 +0,0 @@ -#include "defs.h" -#include "actorsystem.h" -#include "callstack.h" -#include "cpu_manager.h" -#include "mailbox.h" -#include "events.h" -#include "interconnect.h" -#include "servicemap.h" -#include "scheduler_queue.h" -#include "scheduler_actor.h" -#include "log.h" -#include "probes.h" -#include "ask.h" -#include <library/cpp/actors/util/affinity.h> -#include <library/cpp/actors/util/datetime.h> -#include <util/generic/hash.h> -#include <util/system/rwlock.h> -#include <util/random/random.h> - -namespace NActors { - LWTRACE_USING(ACTORLIB_PROVIDER); - - TActorSetupCmd::TActorSetupCmd() - : MailboxType(TMailboxType::HTSwap) - , PoolId(0) - , Actor(nullptr) - { - } - - TActorSetupCmd::TActorSetupCmd(TActorSetupCmd&&) = default; - TActorSetupCmd& TActorSetupCmd::operator=(TActorSetupCmd&&) = default; - TActorSetupCmd::~TActorSetupCmd() = default; - - TActorSetupCmd::TActorSetupCmd(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId) - : MailboxType(mailboxType) - , PoolId(poolId) - , Actor(actor) - { - } - - TActorSetupCmd::TActorSetupCmd(std::unique_ptr<IActor> actor, TMailboxType::EType mailboxType, ui32 poolId) - : MailboxType(mailboxType) - , PoolId(poolId) - , Actor(std::move(actor)) - { - } - - void TActorSetupCmd::Set(std::unique_ptr<IActor> actor, TMailboxType::EType mailboxType, ui32 poolId) { - MailboxType = mailboxType; - PoolId = poolId; - Actor = std::move(actor); - } - - struct TActorSystem::TServiceMap : TNonCopyable { - NActors::TServiceMap<TActorId, TActorId, TActorId::THash> LocalMap; - TTicketLock Lock; - - TActorId RegisterLocalService(const TActorId& serviceId, const TActorId& actorId) { - TTicketLock::TGuard guard(&Lock); - const TActorId old = LocalMap.Update(serviceId, actorId); - return old; - } - - TActorId LookupLocal(const TActorId& x) { - return LocalMap.Find(x); - } - }; - - TActorSystem::TActorSystem(THolder<TActorSystemSetup>& setup, void* appData, - TIntrusivePtr<NLog::TSettings> loggerSettings) - : NodeId(setup->NodeId) - , CpuManager(new TCpuManager(setup)) - , ExecutorPoolCount(CpuManager->GetExecutorsCount()) - , Scheduler(setup->Scheduler) - , InterconnectCount((ui32)setup->Interconnect.ProxyActors.size()) - , CurrentTimestamp(0) - , CurrentMonotonic(0) - , CurrentIDCounter(RandomNumber<ui64>()) - , SystemSetup(setup.Release()) - , DefSelfID(NodeId, "actorsystem") - , AppData0(appData) - , LoggerSettings0(loggerSettings) - , StartExecuted(false) - , StopExecuted(false) - , CleanupExecuted(false) - { - ServiceMap.Reset(new TServiceMap()); - } - - TActorSystem::~TActorSystem() { - Cleanup(); - } - - template <TActorSystem::TEPSendFunction EPSpecificSend> - bool TActorSystem::GenericSend(TAutoPtr<IEventHandle> ev) const { - if (Y_UNLIKELY(!ev)) - return false; - -#ifdef USE_ACTOR_CALLSTACK - ev->Callstack.TraceIfEmpty(); -#endif - - TActorId recipient = ev->GetRecipientRewrite(); - const ui32 recpNodeId = recipient.NodeId(); - - if (recpNodeId != NodeId && recpNodeId != 0) { - // if recipient is not local one - rewrite with forward instruction - Y_DEBUG_ABORT_UNLESS(!ev->HasEvent() || ev->GetBase()->IsSerializable()); - Y_ABORT_UNLESS(ev->Recipient == recipient, - "Event rewrite from %s to %s would be lost via interconnect", - ev->Recipient.ToString().c_str(), - recipient.ToString().c_str()); - recipient = InterconnectProxy(recpNodeId); - ev->Rewrite(TEvInterconnect::EvForward, recipient); - } - if (recipient.IsService()) { - TActorId target = ServiceMap->LookupLocal(recipient); - if (!target && IsInterconnectProxyId(recipient) && ProxyWrapperFactory) { - const TActorId actorId = ProxyWrapperFactory(const_cast<TActorSystem*>(this), - GetInterconnectProxyNode(recipient)); - with_lock(ProxyCreationLock) { - target = ServiceMap->LookupLocal(recipient); - if (!target) { - target = actorId; - ServiceMap->RegisterLocalService(recipient, target); - } - } - if (target != actorId) { - // a race has occured, terminate newly created actor - Send(new IEventHandle(TEvents::TSystem::Poison, 0, actorId, {}, nullptr, 0)); - } - } - recipient = target; - ev->Rewrite(ev->GetTypeRewrite(), recipient); - } - - Y_DEBUG_ABORT_UNLESS(recipient == ev->GetRecipientRewrite()); - const ui32 recpPool = recipient.PoolID(); - if (recipient && recpPool < ExecutorPoolCount) { - if ((CpuManager->GetExecutorPool(recpPool)->*EPSpecificSend)(ev)) { - return true; - } - } - if (ev) { - Send(IEventHandle::ForwardOnNondelivery(ev, TEvents::TEvUndelivered::ReasonActorUnknown)); - } - return false; - } - - template - bool TActorSystem::GenericSend<&IExecutorPool::Send>(TAutoPtr<IEventHandle> ev) const; - template - bool TActorSystem::GenericSend<&IExecutorPool::SpecificSend>(TAutoPtr<IEventHandle> ev) const; - - bool TActorSystem::Send(const TActorId& recipient, IEventBase* ev, ui32 flags, ui64 cookie) const { - return this->Send(new IEventHandle(recipient, DefSelfID, ev, flags, cookie)); - } - - bool TActorSystem::SpecificSend(TAutoPtr<IEventHandle> ev) const { - return this->GenericSend<&IExecutorPool::SpecificSend>(ev); - } - - bool TActorSystem::SpecificSend(TAutoPtr<IEventHandle> ev, ESendingType sendingType) const { - if (!TlsThreadContext) { - return this->GenericSend<&IExecutorPool::Send>(ev); - } else { - ESendingType previousType = std::exchange(TlsThreadContext->SendingType, sendingType); - bool isSent = this->GenericSend<&IExecutorPool::SpecificSend>(ev); - TlsThreadContext->SendingType = previousType; - return isSent; - } - } - - void TActorSystem::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) const { - Schedule(deadline - Timestamp(), ev, cookie); - } - - void TActorSystem::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) const { - const auto current = Monotonic(); - if (deadline < current) - deadline = current; - - TTicketLock::TGuard guard(&ScheduleLock); - ScheduleQueue->Writer.Push(deadline.MicroSeconds(), ev.Release(), cookie); - } - - void TActorSystem::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) const { - const auto deadline = Monotonic() + delta; - - TTicketLock::TGuard guard(&ScheduleLock); - ScheduleQueue->Writer.Push(deadline.MicroSeconds(), ev.Release(), cookie); - } - - NThreading::TFuture<THolder<IEventBase>> TActorSystem::AskGeneric(TMaybe<ui32> expectedEventType, - TActorId recipient, THolder<IEventBase> event, - TDuration timeout) { - auto promise = NThreading::NewPromise<THolder<IEventBase>>(); - Register(MakeAskActor(expectedEventType, recipient, std::move(event), timeout, promise).Release()); - return promise.GetFuture(); - } - - ui64 TActorSystem::AllocateIDSpace(ui64 count) { - Y_DEBUG_ABORT_UNLESS(count < Max<ui32>() / 65536); - - static_assert(sizeof(TAtomic) == sizeof(ui64), "expect sizeof(TAtomic) == sizeof(ui64)"); - - // get high 32 bits as seconds from epoch - // it could wrap every century, but we don't expect any actor-reference to live this long so such wrap will do no harm - const ui64 timeFromEpoch = TInstant::MicroSeconds(RelaxedLoad(&CurrentTimestamp)).Seconds(); - - // get low 32 bits as counter value - ui32 lowPartEnd = (ui32)(AtomicAdd(CurrentIDCounter, count)); - while (lowPartEnd < count) // if our request crosses 32bit boundary - retry - lowPartEnd = (ui32)(AtomicAdd(CurrentIDCounter, count)); - - const ui64 lowPart = lowPartEnd - count; - const ui64 ret = (timeFromEpoch << 32) | lowPart; - - return ret; - } - - TActorId TActorSystem::InterconnectProxy(ui32 destinationNode) const { - if (destinationNode < InterconnectCount) - return Interconnect[destinationNode]; - else if (destinationNode != NodeId) - return MakeInterconnectProxyId(destinationNode); - else - return TActorId(); - } - - ui32 TActorSystem::BroadcastToProxies(const std::function<IEventHandle*(const TActorId&)>& eventFabric) { - // TODO: get rid of this method - for (ui32 i = 0; i < InterconnectCount; ++i) { - Send(eventFabric(Interconnect[i])); - } - return InterconnectCount; - } - - TActorId TActorSystem::LookupLocalService(const TActorId& x) const { - return ServiceMap->LookupLocal(x); - } - - TActorId TActorSystem::RegisterLocalService(const TActorId& serviceId, const TActorId& actorId) { - // TODO: notify old actor about demotion - return ServiceMap->RegisterLocalService(serviceId, actorId); - } - - void TActorSystem::GetPoolStats(ui32 poolId, TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const { - CpuManager->GetPoolStats(poolId, poolStats, statsCopy); - } - - THarmonizerStats TActorSystem::GetHarmonizerStats() const { - return CpuManager->GetHarmonizerStats(); - - } - - void TActorSystem::Start() { - Y_ABORT_UNLESS(StartExecuted == false); - StartExecuted = true; - - ScheduleQueue.Reset(new NSchedulerQueue::TQueueType()); - TVector<NSchedulerQueue::TReader*> scheduleReaders; - scheduleReaders.push_back(&ScheduleQueue->Reader); - CpuManager->PrepareStart(scheduleReaders, this); - Scheduler->Prepare(this, &CurrentTimestamp, &CurrentMonotonic); - Scheduler->PrepareSchedules(&scheduleReaders.front(), (ui32)scheduleReaders.size()); - - // setup interconnect proxies - { - TInterconnectSetup& setup = SystemSetup->Interconnect; - Interconnect.Reset(new TActorId[InterconnectCount + 1]); - for (ui32 i = 0, e = InterconnectCount; i != e; ++i) { - TActorSetupCmd& x = setup.ProxyActors[i]; - if (x.Actor) { - Interconnect[i] = Register(x.Actor.release(), x.MailboxType, x.PoolId, i); - Y_ABORT_UNLESS(!!Interconnect[i]); - } - } - ProxyWrapperFactory = std::move(SystemSetup->Interconnect.ProxyWrapperFactory); - } - - // setup local services - { - for (ui32 i = 0, e = (ui32)SystemSetup->LocalServices.size(); i != e; ++i) { - std::pair<TActorId, TActorSetupCmd>& x = SystemSetup->LocalServices[i]; - const TActorId xid = Register(x.second.Actor.release(), x.second.MailboxType, x.second.PoolId, i); - Y_ABORT_UNLESS(!!xid); - if (!!x.first) - RegisterLocalService(x.first, xid); - } - } - - Scheduler->PrepareStart(); - CpuManager->Start(); - Send(MakeSchedulerActorId(), new TEvSchedulerInitialize(scheduleReaders, &CurrentTimestamp, &CurrentMonotonic)); - Scheduler->Start(); - } - - void TActorSystem::Stop() { - if (StopExecuted || !StartExecuted) - return; - - StopExecuted = true; - - for (auto&& fn : std::exchange(DeferredPreStop, {})) { - fn(); - } - - Scheduler->PrepareStop(); - CpuManager->PrepareStop(); - Scheduler->Stop(); - CpuManager->Shutdown(); - } - - void TActorSystem::Cleanup() { - Stop(); - if (CleanupExecuted || !StartExecuted) - return; - CleanupExecuted = true; - CpuManager->Cleanup(); - Scheduler.Destroy(); - } -} diff --git a/library/cpp/actors/core/actorsystem.h b/library/cpp/actors/core/actorsystem.h deleted file mode 100644 index df5de39090..0000000000 --- a/library/cpp/actors/core/actorsystem.h +++ /dev/null @@ -1,311 +0,0 @@ -#pragma once - -#include "defs.h" - -#include "balancer.h" -#include "config.h" -#include "event.h" -#include "executor_pool.h" -#include "log_settings.h" -#include "scheduler_cookie.h" -#include "cpu_manager.h" -#include "executor_thread.h" - -#include <library/cpp/threading/future/future.h> -#include <library/cpp/actors/util/ticket_lock.h> - -#include <util/generic/vector.h> -#include <util/datetime/base.h> -#include <util/system/mutex.h> - -namespace NActors { - class IActor; - class TActorSystem; - class TCpuManager; - struct TWorkerContext; - - inline TActorId MakeInterconnectProxyId(ui32 destNodeId) { - char data[12]; - memcpy(data, "ICProxy@", 8); - memcpy(data + 8, &destNodeId, sizeof(ui32)); - return TActorId(0, TStringBuf(data, 12)); - } - - inline bool IsInterconnectProxyId(const TActorId& actorId) { - return actorId.IsService() && !memcmp(actorId.ServiceId().data(), "ICProxy@", 8); - } - - inline ui32 GetInterconnectProxyNode(const TActorId& actorId) { - ui32 nodeId; - memcpy(&nodeId, actorId.ServiceId().data() + 8, sizeof(ui32)); - return nodeId; - } - - namespace NSchedulerQueue { - class TReader; - struct TQueueType; - } - - // could be proxy to in-pool schedulers (for NUMA-aware executors) - class ISchedulerThread : TNonCopyable { - public: - virtual ~ISchedulerThread() { - } - - virtual void Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) = 0; - virtual void PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) = 0; - virtual void PrepareStart() { /* empty */ } - virtual void Start() = 0; - virtual void PrepareStop() = 0; - virtual void Stop() = 0; - }; - - struct TActorSetupCmd { - TMailboxType::EType MailboxType; - ui32 PoolId; - std::unique_ptr<IActor> Actor; - - TActorSetupCmd(); - TActorSetupCmd(const TActorSetupCmd&) = delete; - TActorSetupCmd(TActorSetupCmd&&); - TActorSetupCmd& operator=(const TActorSetupCmd&) = delete; - TActorSetupCmd& operator=(TActorSetupCmd&&); - TActorSetupCmd(std::unique_ptr<IActor> actor, TMailboxType::EType mailboxType, ui32 poolId); - ~TActorSetupCmd(); - - // For legacy code, please do not use - TActorSetupCmd(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId); - - void Set(std::unique_ptr<IActor> actor, TMailboxType::EType mailboxType, ui32 poolId); - }; - - using TProxyWrapperFactory = std::function<TActorId(TActorSystem*, ui32)>; - - struct TInterconnectSetup { - TVector<TActorSetupCmd> ProxyActors; - TProxyWrapperFactory ProxyWrapperFactory; - }; - - struct TActorSystemSetup { - ui32 NodeId = 0; - - // Either Executors or CpuManager must be initialized - ui32 ExecutorsCount = 0; - TArrayHolder<TAutoPtr<IExecutorPool>> Executors; - - TAutoPtr<IBalancer> Balancer; // main implementation will be implicitly created if not set - - TCpuManagerConfig CpuManager; - - TAutoPtr<ISchedulerThread> Scheduler; - - TInterconnectSetup Interconnect; - - bool MonitorStuckActors = false; - - using TLocalServices = TVector<std::pair<TActorId, TActorSetupCmd>>; - TLocalServices LocalServices; - - ui32 GetExecutorsCount() const { - return Executors ? ExecutorsCount : CpuManager.GetExecutorsCount(); - } - - TString GetPoolName(ui32 poolId) const { - return Executors ? Executors[poolId]->GetName() : CpuManager.GetPoolName(poolId); - } - - ui32 GetThreads(ui32 poolId) const { - auto result = GetThreadsOptional(poolId); - Y_ABORT_UNLESS(result, "undefined pool id: %" PRIu32, (ui32)poolId); - return *result; - } - - std::optional<ui32> GetThreadsOptional(const ui32 poolId) const { - if (Y_LIKELY(Executors)) { - if (Y_LIKELY(poolId < ExecutorsCount)) { - return Executors[poolId]->GetDefaultThreadCount(); - } else { - return {}; - } - } else { - return CpuManager.GetThreadsOptional(poolId); - } - } - }; - - class TActorSystem : TNonCopyable { - struct TServiceMap; - - public: - const ui32 NodeId; - - private: - THolder<TCpuManager> CpuManager; - const ui32 ExecutorPoolCount; - - TAutoPtr<ISchedulerThread> Scheduler; - THolder<TServiceMap> ServiceMap; - - const ui32 InterconnectCount; - TArrayHolder<TActorId> Interconnect; - - volatile ui64 CurrentTimestamp; - volatile ui64 CurrentMonotonic; - volatile ui64 CurrentIDCounter; - - THolder<NSchedulerQueue::TQueueType> ScheduleQueue; - mutable TTicketLock ScheduleLock; - - friend class TExecutorThread; - - THolder<TActorSystemSetup> SystemSetup; - TActorId DefSelfID; - void* AppData0; - TIntrusivePtr<NLog::TSettings> LoggerSettings0; - TProxyWrapperFactory ProxyWrapperFactory; - TMutex ProxyCreationLock; - - bool StartExecuted; - bool StopExecuted; - bool CleanupExecuted; - - std::deque<std::function<void()>> DeferredPreStop; - public: - TActorSystem(THolder<TActorSystemSetup>& setup, void* appData = nullptr, - TIntrusivePtr<NLog::TSettings> loggerSettings = TIntrusivePtr<NLog::TSettings>(nullptr)); - ~TActorSystem(); - - void Start(); - void Stop(); - void Cleanup(); - - template <ESendingType SendingType = ESendingType::Common> - TActorId Register(IActor* actor, TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 executorPool = 0, - ui64 revolvingCounter = 0, const TActorId& parentId = TActorId()); - - bool MonitorStuckActors() const { return SystemSetup->MonitorStuckActors; } - - private: - typedef bool (IExecutorPool::*TEPSendFunction)(TAutoPtr<IEventHandle>& ev); - - template <TEPSendFunction EPSpecificSend> - bool GenericSend(TAutoPtr<IEventHandle> ev) const; - - public: - template <ESendingType SendingType = ESendingType::Common> - bool Send(TAutoPtr<IEventHandle> ev) const; - - bool SpecificSend(TAutoPtr<IEventHandle> ev, ESendingType sendingType) const; - bool SpecificSend(TAutoPtr<IEventHandle> ev) const; - - bool Send(const TActorId& recipient, IEventBase* ev, ui32 flags = 0, ui64 cookie = 0) const; - - /** - * Schedule one-shot event that will be send at given time point in the future. - * - * @param deadline the wallclock time point in future when event must be send - * @param ev the event to send - * @param cookie cookie that will be piggybacked with event - */ - void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr) const; - - /** - * Schedule one-shot event that will be send at given time point in the future. - * - * @param deadline the monotonic time point in future when event must be send - * @param ev the event to send - * @param cookie cookie that will be piggybacked with event - */ - void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr) const; - - /** - * Schedule one-shot event that will be send after given delay. - * - * @param delta the time from now to delay event sending - * @param ev the event to send - * @param cookie cookie that will be piggybacked with event - */ - void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr) const; - - /** - * A way to interact with actors from non-actor context. - * - * This method will send the `event` to the `recipient` and then will wait for a response. When response arrives, - * it will be passed to the future. If response is not of type `T`, the future will resolve into an exception. - * - * @tparam T expected response type. Must be derived from `TEventBase`, - * or use `IEventBase` to catch any response. - * @param actorSystem actor system that will be used to register an actor that'll wait for response. - * @param recipient who will get a request. - * @param event a request message. - * @return future that will be resolved when a message from `recipient` arrives. - */ - template <typename T> - [[nodiscard]] - NThreading::TFuture<THolder<T>> Ask(TActorId recipient, THolder<IEventBase> event, TDuration timeout = TDuration::Max()) { - if constexpr (std::is_same_v<T, IEventBase>) { - return AskGeneric(Nothing(), recipient, std::move(event), timeout); - } else { - return AskGeneric(T::EventType, recipient, std::move(event), timeout) - .Apply([](const NThreading::TFuture<THolder<IEventBase>>& ev) { - return THolder<T>(static_cast<T*>(const_cast<THolder<IEventBase>&>(ev.GetValueSync()).Release())); // =( - }); - } - } - - [[nodiscard]] - NThreading::TFuture<THolder<IEventBase>> AskGeneric( - TMaybe<ui32> expectedEventType, - TActorId recipient, - THolder<IEventBase> event, - TDuration timeout); - - ui64 AllocateIDSpace(ui64 count); - - TActorId InterconnectProxy(ui32 destinationNode) const; - ui32 BroadcastToProxies(const std::function<IEventHandle*(const TActorId&)>&); - - void UpdateLinkStatus(ui8 status, ui32 destinationNode); - ui8 LinkStatus(ui32 destinationNode); - - TActorId LookupLocalService(const TActorId& x) const; - TActorId RegisterLocalService(const TActorId& serviceId, const TActorId& actorId); - - TInstant Timestamp() const { - return TInstant::MicroSeconds(RelaxedLoad(&CurrentTimestamp)); - } - - TMonotonic Monotonic() const { - return TMonotonic::MicroSeconds(RelaxedLoad(&CurrentMonotonic)); - } - - template <typename T> - T* AppData() const { - return (T*)AppData0; - } - - NLog::TSettings* LoggerSettings() const { - return LoggerSettings0.Get(); - } - - void GetPoolStats(ui32 poolId, TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const; - - THarmonizerStats GetHarmonizerStats() const; - - std::optional<ui32> GetPoolThreadsCount(const ui32 poolId) const { - if (!SystemSetup) { - return {}; - } - return SystemSetup->GetThreadsOptional(poolId); - } - - void DeferPreStop(std::function<void()> fn) { - DeferredPreStop.push_back(std::move(fn)); - } - - TVector<IExecutorPool*> GetBasicExecutorPools() const { - return CpuManager->GetBasicExecutorPools(); - } - - }; -} diff --git a/library/cpp/actors/core/actorsystem_ut.cpp b/library/cpp/actors/core/actorsystem_ut.cpp deleted file mode 100644 index 231d6f0ca1..0000000000 --- a/library/cpp/actors/core/actorsystem_ut.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "actorsystem.h" - -#include <library/cpp/actors/testlib/test_runtime.h> -#include <library/cpp/testing/unittest/registar.h> - -using namespace NActors; - -Y_UNIT_TEST_SUITE(TActorSystemTest) { - - class TTestActor: public TActor<TTestActor> { - public: - TTestActor() - : TActor{&TThis::Main} - { - } - - STATEFN(Main) { - Y_UNUSED(ev); - } - }; - - THolder<TTestActorRuntimeBase> CreateRuntime() { - auto runtime = MakeHolder<TTestActorRuntimeBase>(); - runtime->SetScheduledEventFilter([](auto&&, auto&&, auto&&, auto&&) { return false; }); - runtime->Initialize(); - return runtime; - } - - Y_UNIT_TEST(LocalService) { - THolder<TTestActorRuntimeBase> runtime = CreateRuntime(); - auto actorA = runtime->Register(new TTestActor); - auto actorB = runtime->Register(new TTestActor); - - TActorId myServiceId{0, TStringBuf{"my-service"}}; - - auto prevActorId = runtime->RegisterService(myServiceId, actorA); - UNIT_ASSERT(!prevActorId); - UNIT_ASSERT_EQUAL(runtime->GetLocalServiceId(myServiceId), actorA); - - prevActorId = runtime->RegisterService(myServiceId, actorB); - UNIT_ASSERT(prevActorId); - UNIT_ASSERT_EQUAL(prevActorId, actorA); - UNIT_ASSERT_EQUAL(runtime->GetLocalServiceId(myServiceId), actorB); - } -} diff --git a/library/cpp/actors/core/ask.cpp b/library/cpp/actors/core/ask.cpp deleted file mode 100644 index 40c6748d56..0000000000 --- a/library/cpp/actors/core/ask.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "ask.h" - -#include "actor_bootstrapped.h" -#include "actorid.h" -#include "event.h" -#include "hfunc.h" - -namespace NActors { - namespace { - class TAskActor: public TActorBootstrapped<TAskActor> { - enum { - Timeout = EventSpaceBegin(TEvents::ES_PRIVATE), - }; - - // We can't use the standard timeout event because recipient may send us one. - struct TTimeout: public TEventLocal<TTimeout, Timeout> { - }; - - public: - TAskActor( - TMaybe<ui32> expectedEventType, - TActorId recipient, - THolder<IEventBase> event, - TDuration timeout, - const NThreading::TPromise<THolder<IEventBase>>& promise) - : ExpectedEventType_(expectedEventType) - , Recipient_(recipient) - , Event_(std::move(event)) - , Timeout_(timeout) - , Promise_(promise) - { - } - - static constexpr char ActorName[] = "ASK_ACTOR"; - - public: - void Bootstrap() { - Send(Recipient_, std::move(Event_)); - Become(&TAskActor::Waiting); - - if (Timeout_ != TDuration::Max()) { - Schedule(Timeout_, new TTimeout); - } - } - - STATEFN(Waiting) { - if (ev->GetTypeRewrite() == TTimeout::EventType) { - Promise_.SetException(std::make_exception_ptr(yexception() << "ask timeout")); - } else if (!ExpectedEventType_ || ev->GetTypeRewrite() == ExpectedEventType_) { - Promise_.SetValue(ev.Get()->ReleaseBase()); - } else { - Promise_.SetException(std::make_exception_ptr(yexception() << "received unexpected response " << ev.Get()->GetBase()->ToString())); - } - - PassAway(); - } - - public: - TMaybe<ui32> ExpectedEventType_; - TActorId Recipient_; - THolder<IEventBase> Event_; - TDuration Timeout_; - NThreading::TPromise<THolder<IEventBase>> Promise_; - }; - } - - THolder<IActor> MakeAskActor( - TMaybe<ui32> expectedEventType, - TActorId recipient, - THolder<IEventBase> event, - TDuration timeout, - const NThreading::TPromise<THolder<IEventBase>>& promise) - { - return MakeHolder<TAskActor>(expectedEventType, std::move(recipient), std::move(event), timeout, promise); - } -} diff --git a/library/cpp/actors/core/ask.h b/library/cpp/actors/core/ask.h deleted file mode 100644 index 036f1833a4..0000000000 --- a/library/cpp/actors/core/ask.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "actor.h" -#include "event.h" - -#include <library/cpp/threading/future/future.h> - -namespace NActors { - /** - * See `TActorSystem::Ask`. - */ - THolder<IActor> MakeAskActor( - TMaybe<ui32> expectedEventType, - TActorId recipient, - THolder<IEventBase> event, - TDuration timeout, - const NThreading::TPromise<THolder<IEventBase>>& promise); -} diff --git a/library/cpp/actors/core/ask_ut.cpp b/library/cpp/actors/core/ask_ut.cpp deleted file mode 100644 index e72ebdba9b..0000000000 --- a/library/cpp/actors/core/ask_ut.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include <library/cpp/testing/unittest/registar.h> - -#include "actorsystem.h" - -#include <library/cpp/actors/testlib/test_runtime.h> - -using namespace NActors; - -class TPingPong: public TActor<TPingPong> { -public: - TPingPong() - : TActor(&TPingPong::Main) - { - } - - STATEFN(Main) { - switch (ev->GetTypeRewrite()) { - hFunc(TEvents::TEvPing, OnPing); - hFunc(TEvents::TEvBlob, OnBlob); - } - } - - void OnPing(const TEvents::TEvPing::TPtr& ev) { - Send(ev->Sender, new TEvents::TEvPong); - } - - void OnBlob(const TEvents::TEvBlob::TPtr& ev) { - Send(ev->Sender, ev->Release().Release()); - } -}; - -class TPing: public TActor<TPing> { -public: - TPing() - : TActor(&TPing::Main) - { - } - - STATEFN(Main) { - Y_UNUSED(ev); - } -}; - -THolder<TTestActorRuntimeBase> CreateRuntime() { - auto runtime = MakeHolder<TTestActorRuntimeBase>(); - runtime->SetScheduledEventFilter([](auto&&, auto&&, auto&&, auto&&) { return false; }); - runtime->Initialize(); - return runtime; -} - -Y_UNIT_TEST_SUITE(AskActor) { - Y_UNIT_TEST(Ok) { - auto runtime = CreateRuntime(); - auto pingpong = runtime->Register(new TPingPong); - - { - auto fut = runtime->GetAnyNodeActorSystem()->Ask<TEvents::TEvPong>( - pingpong, - THolder(new TEvents::TEvPing)); - runtime->DispatchEvents(); - fut.ExtractValueSync(); - } - - { - auto fut = runtime->GetAnyNodeActorSystem()->Ask<TEvents::TEvBlob>( - pingpong, - THolder(new TEvents::TEvBlob("hello!"))); - runtime->DispatchEvents(); - auto ev = fut.ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(ev->Blob, "hello!"); - } - - { - auto fut = runtime->GetAnyNodeActorSystem()->Ask<IEventBase>( - pingpong, - THolder(new TEvents::TEvPing)); - runtime->DispatchEvents(); - auto ev = fut.ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL(ev->Type(), TEvents::TEvPong::EventType); - } - } - - Y_UNIT_TEST(Err) { - auto runtime = CreateRuntime(); - auto pingpong = runtime->Register(new TPingPong); - - { - auto fut = runtime->GetAnyNodeActorSystem()->Ask<TEvents::TEvBlob>( - pingpong, - THolder(new TEvents::TEvPing)); - runtime->DispatchEvents(); - UNIT_ASSERT_EXCEPTION_CONTAINS( - fut.ExtractValueSync(), - yexception, - "received unexpected response HelloWorld: Pong"); - } - } - - Y_UNIT_TEST(Timeout) { - auto runtime = CreateRuntime(); - auto ping = runtime->Register(new TPing); - - { - auto fut = runtime->GetAnyNodeActorSystem()->Ask<TEvents::TEvPong>( - ping, - THolder(new TEvents::TEvPing), - TDuration::Seconds(1)); - auto start = runtime->GetCurrentTime(); - runtime->DispatchEvents({}, TDuration::Seconds(5)); - UNIT_ASSERT_EXCEPTION_CONTAINS( - fut.ExtractValueSync(), - yexception, - "ask timeout"); - UNIT_ASSERT_VALUES_EQUAL(runtime->GetCurrentTime() - start, TDuration::Seconds(1)); - } - - { - auto fut = runtime->GetAnyNodeActorSystem()->Ask<IEventBase>( - ping, - THolder(new TEvents::TEvPing), - TDuration::Seconds(1)); - auto start = runtime->GetCurrentTime(); - runtime->DispatchEvents({}, TDuration::Seconds(5)); - UNIT_ASSERT_EXCEPTION_CONTAINS( - fut.ExtractValueSync(), - yexception, - "ask timeout"); - UNIT_ASSERT_VALUES_EQUAL(runtime->GetCurrentTime() - start, TDuration::Seconds(1)); - } - } -} diff --git a/library/cpp/actors/core/av_bootstrapped.cpp b/library/cpp/actors/core/av_bootstrapped.cpp deleted file mode 100644 index 771177242e..0000000000 --- a/library/cpp/actors/core/av_bootstrapped.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "av_bootstrapped.h" - -namespace NActors { - -class TEventForStart: public TEventLocalForActor<TEventForStart, TActorAutoStart> { -public: -}; - -TAutoPtr<NActors::IEventHandle> TActorAutoStart::AfterRegister(const TActorId& self, const TActorId& parentId) { - return new IEventHandle(self, parentId, new TEventForStart, 0); -} - -void TActorAutoStart::ProcessEvent(TEventContext<TEventForStart>& ev) { - DoOnStart(ev.GetHandle().Sender); -} - -} diff --git a/library/cpp/actors/core/av_bootstrapped.h b/library/cpp/actors/core/av_bootstrapped.h deleted file mode 100644 index 65bd224152..0000000000 --- a/library/cpp/actors/core/av_bootstrapped.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include "actor_virtual.h" - -namespace NActors { - -class TEventForStart; - -class TActorAutoStart: public IActor { -protected: - virtual void DoOnStart(const TActorId& senderActorId) = 0; - TAutoPtr<IEventHandle> AfterRegister(const TActorId& self, const TActorId& parentId) override; -public: - void ProcessEvent(TEventContext<TEventForStart>& ev); - - TActorAutoStart() - {} -}; -} diff --git a/library/cpp/actors/core/balancer.cpp b/library/cpp/actors/core/balancer.cpp deleted file mode 100644 index 5e8a280a8b..0000000000 --- a/library/cpp/actors/core/balancer.cpp +++ /dev/null @@ -1,311 +0,0 @@ -#include "balancer.h" - -#include "probes.h" - -#include <library/cpp/actors/util/cpu_load_log.h> -#include <library/cpp/actors/util/datetime.h> -#include <library/cpp/actors/util/intrinsics.h> - -#include <util/system/spinlock.h> - -#include <algorithm> - -namespace NActors { - LWTRACE_USING(ACTORLIB_PROVIDER); - - // Describes balancing-related state of pool, the most notable is `Importance` to add new cpu - struct TLevel { - // Balancer will try to give more cpu to overloaded pools - enum ELoadClass { - Underloaded = 0, - Moderate = 1, - Overloaded = 2, - }; - - double ScaleFactor; - ELoadClass LoadClass; - ui64 Importance; // pool with lower importance is allowed to pass cpu to pool with higher, but the opposite is forbidden - - TLevel() {} - - TLevel(const TBalancingConfig& cfg, TPoolId poolId, ui64 currentCpus, double cpuIdle, ui64 addLatencyUs, ui64 worstLatencyUs) { - ScaleFactor = double(currentCpus) / cfg.Cpus; - if ((worstLatencyUs + addLatencyUs) < 2000 && cpuIdle > 1.0) { // Uderload criterion, based on estimated latency w/o 1 cpu - LoadClass = Underloaded; - } else if (worstLatencyUs > 2000 || cpuIdle < 0.2) { // Overload criterion, based on latency - LoadClass = Overloaded; - } else { - LoadClass = Moderate; - } - Importance = MakeImportance(LoadClass, cfg.Priority, ScaleFactor, cpuIdle, poolId); - } - - private: - // Importance is simple ui64 value (from highest to lowest): - // 2 Bits: LoadClass - // 8 Bits: Priority - // 10 Bits: -ScaleFactor (for max-min fairness with weights equal to TBalancingConfig::Cpus) - // 10 Bits: -CpuIdle - // 6 Bits: PoolId - static ui64 MakeImportance(ELoadClass load, ui8 priority, double scaleFactor, double cpuIdle, TPoolId poolId) { - ui64 idle = std::clamp<i64>(1024 - cpuIdle * 512, 0, 1023); - ui64 scale = std::clamp<i64>(1024 - scaleFactor * 32, 0, 1023); - - Y_ABORT_UNLESS(ui64(load) < (1ull << 2ull)); - Y_ABORT_UNLESS(ui64(priority) < (1ull << 8ull)); - Y_ABORT_UNLESS(ui64(scale) < (1ull << 10ull)); - Y_ABORT_UNLESS(ui64(idle) < (1ull << 10ull)); - Y_ABORT_UNLESS(ui64(poolId) < (1ull << 6ull)); - - static_assert(ui64(MaxPools) <= (1ull << 6ull)); - - ui64 importance = - (ui64(load) << ui64(6 + 10 + 10 + 8)) | - (ui64(priority) << ui64(6 + 10 + 10)) | - (ui64(scale) << ui64(6 + 10)) | - (ui64(idle) << ui64(6)) | - ui64(poolId); - return importance; - } - }; - - // Main balancer implemenation - class TBalancer: public IBalancer { - private: - struct TCpu; - struct TPool; - - bool Disabled = true; - TSpinLock Lock; - ui64 NextBalanceTs; - TVector<TCpu> Cpus; // Indexed by CpuId, can have gaps - TVector<TPool> Pools; // Indexed by PoolId, can have gaps - TBalancerConfig Config; - - public: - - ui64 GetPeriodUs() override; - // Setup - TBalancer(const TBalancerConfig& config, const TVector<TUnitedExecutorPoolConfig>& unitedPools, ui64 ts); - bool AddCpu(const TCpuAllocation& cpuAlloc, TCpuState* cpu) override; - ~TBalancer(); - - // Balancing - bool TryLock(ui64 ts) override; - void SetPoolStats(TPoolId pool, const TBalancerStats& stats) override; - void Balance() override; - void Unlock() override; - - private: - void MoveCpu(TPool& from, TPool& to); - }; - - struct TBalancer::TPool { - TBalancingConfig Config; - TPoolId PoolId; - TString PoolName; - - // Input data for balancing - TBalancerStats Prev; - TBalancerStats Next; - - // Derived stats - double CpuLoad; - double CpuIdle; - - // Classification - // NOTE: We want to avoid passing cpu back and forth, so we must consider not only current level, - // NOTE: but expected levels after movements also - TLevel CurLevel; // Level with current amount of cpu - TLevel AddLevel; // Level after one cpu acception - TLevel SubLevel; // Level after one cpu donation - - // Balancing state - ui64 CurrentCpus = 0; // Total number of cpus assigned for this pool (zero means pools is not balanced) - ui64 PrevCpus = 0; // Cpus in last period - - explicit TPool(const TBalancingConfig& cfg = {}) - : Config(cfg) - {} - - void Configure(const TBalancingConfig& cfg, const TString& poolName) { - Config = cfg; - // Enforce constraints - if (Config.Cpus > 0) { - Config.MinCpus = std::clamp<ui32>(Config.MinCpus, 1, Config.Cpus); - Config.MaxCpus = Max<ui32>(Config.MaxCpus, Config.Cpus); - } else { - Y_ABORT_UNLESS(Config.Cpus == 0, - "Unexpected negative Config.Cpus# %" PRIi64, - (i64)Config.Cpus); - Config.MinCpus = 0; - Config.MaxCpus = 0; - } - PoolName = poolName; - } - }; - - struct TBalancer::TCpu { - TCpuState* State = nullptr; // Cpu state, nullptr means cpu is not used (gap) - TCpuAllocation Alloc; - TPoolId Current; - TPoolId Assigned; - }; - - TBalancer::TBalancer(const TBalancerConfig& config, const TVector<TUnitedExecutorPoolConfig>& unitedPools, ui64 ts) - : NextBalanceTs(ts) - , Config(config) - { - for (TPoolId pool = 0; pool < MaxPools; pool++) { - Pools.emplace_back(); - Pools.back().PoolId = pool; - } - for (const TUnitedExecutorPoolConfig& united : unitedPools) { - Pools[united.PoolId].Configure(united.Balancing, united.PoolName); - } - } - - TBalancer::~TBalancer() { - } - - bool TBalancer::AddCpu(const TCpuAllocation& cpuAlloc, TCpuState* state) { - // Setup - TCpuId cpuId = cpuAlloc.CpuId; - if (Cpus.size() <= cpuId) { - Cpus.resize(cpuId + 1); - } - TCpu& cpu = Cpus[cpuId]; - cpu.State = state; - cpu.Alloc = cpuAlloc; - - // Fill every pool with cpus up to TBalancingConfig::Cpus - TPoolId pool = 0; - for (TPool& p : Pools) { - if (p.CurrentCpus < p.Config.Cpus) { - p.CurrentCpus++; - break; - } - pool++; - } - if (pool != MaxPools) { // cpu under balancer control - state->SwitchPool(pool); - state->AssignPool(pool); - Disabled = false; - return true; - } - return false; // non-balanced cpu - } - - bool TBalancer::TryLock(ui64 ts) { - if (!Disabled && NextBalanceTs < ts && Lock.TryAcquire()) { - NextBalanceTs = ts + Us2Ts(Config.PeriodUs); - return true; - } - return false; - } - - void TBalancer::SetPoolStats(TPoolId pool, const TBalancerStats& stats) { - Y_ABORT_UNLESS(pool < MaxPools); - TPool& p = Pools[pool]; - p.Prev = p.Next; - p.Next = stats; - } - - void TBalancer::Balance() { - // Update every cpu state - for (TCpu& cpu : Cpus) { - if (cpu.State) { - cpu.State->Load(cpu.Assigned, cpu.Current); - if (cpu.Current < MaxPools && cpu.Current != cpu.Assigned) { - return; // previous movement has not been applied yet, wait - } - } - } - - // Process stats, classify and compute pool importance - TStackVec<TPool*, MaxPools> order; - for (TPool& pool : Pools) { - if (pool.Config.Cpus == 0) { - continue; // skip gaps (non-existent or non-united pools) - } - if (pool.Prev.Ts == 0 || pool.Prev.Ts >= pool.Next.Ts) { - return; // invalid stats - } - - // Compute derived stats - pool.CpuLoad = (pool.Next.CpuUs - pool.Prev.CpuUs) / Ts2Us(pool.Next.Ts - pool.Prev.Ts); - if (pool.Prev.IdleUs == ui64(-1) || pool.Next.IdleUs == ui64(-1)) { - pool.CpuIdle = pool.CurrentCpus - pool.CpuLoad; // for tests - } else { - pool.CpuIdle = (pool.Next.IdleUs - pool.Prev.IdleUs) / Ts2Us(pool.Next.Ts - pool.Prev.Ts); - } - - // Compute levels - pool.CurLevel = TLevel(pool.Config, pool.PoolId, pool.CurrentCpus, pool.CpuIdle, - pool.Next.ExpectedLatencyIncreaseUs, pool.Next.WorstActivationTimeUs); - pool.AddLevel = TLevel(pool.Config, pool.PoolId, pool.CurrentCpus + 1, pool.CpuIdle, - 0, pool.Next.WorstActivationTimeUs); // we expect taken cpu to became utilized - pool.SubLevel = TLevel(pool.Config, pool.PoolId, pool.CurrentCpus - 1, pool.CpuIdle - 1, - pool.Next.ExpectedLatencyIncreaseUs, pool.Next.WorstActivationTimeUs); - - // Prepare for balancing - pool.PrevCpus = pool.CurrentCpus; - order.push_back(&pool); - } - - // Sort pools by importance - std::sort(order.begin(), order.end(), [] (TPool* l, TPool* r) {return l->CurLevel.Importance < r->CurLevel.Importance; }); - for (TPool* pool : order) { - LWPROBE(PoolStats, pool->PoolId, pool->PoolName, pool->CurrentCpus, pool->CurLevel.LoadClass, pool->Config.Priority, pool->CurLevel.ScaleFactor, pool->CpuIdle, pool->CpuLoad, pool->CurLevel.Importance, pool->AddLevel.Importance, pool->SubLevel.Importance); - } - - // Move cpus from lower importance to higher importance pools - for (auto toIter = order.rbegin(); toIter != order.rend(); ++toIter) { - TPool& to = **toIter; - if (to.CurLevel.LoadClass == TLevel::Overloaded && // if pool is overloaded - to.CurrentCpus < to.Config.MaxCpus) // and constraints would not be violated - { - for (auto fromIter = order.begin(); (*fromIter)->CurLevel.Importance < to.CurLevel.Importance; ++fromIter) { - TPool& from = **fromIter; - if (from.CurrentCpus == from.PrevCpus && // if not balanced yet - from.CurrentCpus > from.Config.MinCpus && // and constraints would not be violated - from.SubLevel.Importance <= to.AddLevel.Importance) // and which of two pools is more important would not change after cpu movement - { - MoveCpu(from, to); - from.CurrentCpus--; - to.CurrentCpus++; - break; - } - } - } - } - } - - void TBalancer::MoveCpu(TBalancer::TPool& from, TBalancer::TPool& to) { - for (auto ci = Cpus.rbegin(), ce = Cpus.rend(); ci != ce; ci++) { - TCpu& cpu = *ci; - if (!cpu.State) { - continue; - } - if (cpu.Assigned == from.PoolId) { - cpu.State->AssignPool(to.PoolId); - cpu.Assigned = to.PoolId; - LWPROBE(MoveCpu, from.PoolId, to.PoolId, from.PoolName, to.PoolName, cpu.Alloc.CpuId); - return; - } - } - Y_ABORT(); - } - - void TBalancer::Unlock() { - Lock.Release(); - } - - ui64 TBalancer::GetPeriodUs() { - return Config.PeriodUs; - } - - IBalancer* MakeBalancer(const TBalancerConfig& config, const TVector<TUnitedExecutorPoolConfig>& unitedPools, ui64 ts) { - return new TBalancer(config, unitedPools, ts); - } -} diff --git a/library/cpp/actors/core/balancer.h b/library/cpp/actors/core/balancer.h deleted file mode 100644 index e1f6f33bf3..0000000000 --- a/library/cpp/actors/core/balancer.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "defs.h" -#include "config.h" -#include "cpu_state.h" - -namespace NActors { - // Per-pool statistics used by balancer - struct TBalancerStats { - ui64 Ts = 0; // Measurement timestamp - ui64 CpuUs = 0; // Total cpu microseconds consumed by pool on all cpus since start - ui64 IdleUs = ui64(-1); // Total cpu microseconds in spinning or waiting on futex - ui64 WorstActivationTimeUs = 0; - ui64 ExpectedLatencyIncreaseUs = 0; - }; - - // Pool cpu balancer - struct IBalancer { - virtual ~IBalancer() {} - virtual bool AddCpu(const TCpuAllocation& cpuAlloc, TCpuState* cpu) = 0; - virtual bool TryLock(ui64 ts) = 0; - virtual void SetPoolStats(TPoolId pool, const TBalancerStats& stats) = 0; - virtual void Balance() = 0; - virtual void Unlock() = 0; - virtual ui64 GetPeriodUs() = 0; - // TODO: add method for reconfiguration on fly - }; - - IBalancer* MakeBalancer(const TBalancerConfig& config, const TVector<TUnitedExecutorPoolConfig>& unitedPools, ui64 ts); -} diff --git a/library/cpp/actors/core/balancer_ut.cpp b/library/cpp/actors/core/balancer_ut.cpp deleted file mode 100644 index 7e5e95f4b9..0000000000 --- a/library/cpp/actors/core/balancer_ut.cpp +++ /dev/null @@ -1,225 +0,0 @@ -#include "balancer.h" - -#include <library/cpp/actors/util/datetime.h> -#include <library/cpp/lwtrace/all.h> -#include <library/cpp/testing/unittest/registar.h> - -#include <util/stream/str.h> - -using namespace NActors; - -//////////////////////////////////////////////////////////////////////////////// - -Y_UNIT_TEST_SUITE(PoolCpuBalancer) { - struct TTest { - TCpuManagerConfig Config; - TCpuMask Available; - THolder<IBalancer> Balancer; - TVector<TCpuState> CpuStates; - TVector<ui64> CpuUs; - ui64 Now = 0; - - void SetCpuCount(size_t count) { - Config.UnitedWorkers.CpuCount = count; - for (TCpuId cpuId = 0; cpuId < count; cpuId++) { - Available.Set(cpuId); - } - } - - void AddPool(ui32 minCpus, ui32 cpus, ui32 maxCpus, ui8 priority = 0) { - TUnitedExecutorPoolConfig u; - u.PoolId = TPoolId(Config.United.size()); - u.Balancing.Cpus = cpus; - u.Balancing.MinCpus = minCpus; - u.Balancing.MaxCpus = maxCpus; - u.Balancing.Priority = priority; - Config.United.push_back(u); - } - - void Start() { - TCpuAllocationConfig allocation(Available, Config); - Balancer.Reset(MakeBalancer(Config.UnitedWorkers.Balancer, Config.United, 0)); - CpuStates.resize(allocation.Items.size()); // do not resize it later to avoid dangling pointers - CpuUs.resize(CpuStates.size()); - for (const TCpuAllocation& cpuAlloc : allocation.Items) { - bool added = Balancer->AddCpu(cpuAlloc, &CpuStates[cpuAlloc.CpuId]); - UNIT_ASSERT(added); - } - } - - void Balance(ui64 deltaTs, const TVector<ui64>& cpuUs) { - Now += deltaTs; - ui64 ts = Now; - if (Balancer->TryLock(ts)) { - for (TPoolId pool = 0; pool < cpuUs.size(); pool++) { - CpuUs[pool] += cpuUs[pool]; - TBalancerStats stats; - stats.Ts = ts; - stats.CpuUs = CpuUs[pool]; - Balancer->SetPoolStats(pool, stats); - } - Balancer->Balance(); - Balancer->Unlock(); - } - } - - void ApplyMovements() { - for (TCpuState& state : CpuStates) { - TPoolId current; - TPoolId assigned; - state.Load(assigned, current); - state.SwitchPool(assigned); - } - } - - static TString ToStr(const TVector<ui64>& values) { - TStringStream ss; - ss << "{"; - for (auto v : values) { - ss << " " << v; - } - ss << " }"; - return ss.Str(); - } - - void AssertPoolsCurrentCpus(const TVector<ui64>& cpuRequired) { - TVector<ui64> cpuCurrent; - cpuCurrent.resize(cpuRequired.size()); - for (TCpuState& state : CpuStates) { - TPoolId current; - TPoolId assigned; - state.Load(assigned, current); - cpuCurrent[current]++; - } - for (TPoolId pool = 0; pool < cpuRequired.size(); pool++) { - UNIT_ASSERT_C(cpuCurrent[pool] == cpuRequired[pool], - "cpu distribution mismatch, required " << ToStr(cpuRequired) << " but got " << ToStr(cpuCurrent)); - } - } - }; - - Y_UNIT_TEST(StartLwtrace) { - NLWTrace::StartLwtraceFromEnv(); - } - - Y_UNIT_TEST(AllOverloaded) { - TTest t; - int cpus = 10; - t.SetCpuCount(cpus); - t.AddPool(1, 1, 10); // pool=0 - t.AddPool(1, 2, 10); // pool=1 - t.AddPool(1, 3, 10); // pool=2 - t.AddPool(1, 4, 10); // pool=2 - t.Start(); - ui64 dts = 1.01 * Us2Ts(t.Config.UnitedWorkers.Balancer.PeriodUs); - ui64 totalCpuUs = cpus * Ts2Us(dts); // pretend every pool has consumed as whole actorsystem, overload - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {totalCpuUs, totalCpuUs, totalCpuUs, totalCpuUs}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({1, 2, 3, 4}); - } - - Y_UNIT_TEST(OneOverloaded) { - TTest t; - int cpus = 10; - t.SetCpuCount(cpus); - t.AddPool(1, 1, 10); // pool=0 - t.AddPool(1, 2, 10); // pool=1 - t.AddPool(1, 3, 10); // pool=2 - t.AddPool(1, 4, 10); // pool=2 - t.Start(); - ui64 dts = 1.01 * Us2Ts(t.Config.UnitedWorkers.Balancer.PeriodUs); - ui64 totalCpuUs = cpus * Ts2Us(dts); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {totalCpuUs, 0, 0, 0}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({7, 1, 1, 1}); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {0, totalCpuUs, 0, 0}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({1, 7, 1, 1}); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {0, 0, totalCpuUs, 0}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({1, 1, 7, 1}); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {0, 0, 0, totalCpuUs}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({1, 1, 1, 7}); - } - - Y_UNIT_TEST(TwoOverloadedFairness) { - TTest t; - int cpus = 10; - t.SetCpuCount(cpus); - t.AddPool(1, 1, 10); // pool=0 - t.AddPool(1, 2, 10); // pool=1 - t.AddPool(1, 3, 10); // pool=2 - t.AddPool(1, 4, 10); // pool=2 - t.Start(); - ui64 dts = 1.01 * Us2Ts(t.Config.UnitedWorkers.Balancer.PeriodUs); - ui64 totalCpuUs = cpus * Ts2Us(dts); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {totalCpuUs, totalCpuUs, 0, 0}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({3, 5, 1, 1}); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {totalCpuUs, 0, totalCpuUs, 0}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({2, 1, 6, 1}); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {totalCpuUs, 0, 0, totalCpuUs}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({2, 1, 1, 6}); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {0, totalCpuUs, totalCpuUs, 0}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({1, 3, 5, 1}); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {0, totalCpuUs, 0, totalCpuUs}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({1, 3, 1, 5}); - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {0, 0, totalCpuUs, totalCpuUs}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({1, 1, 3, 5}); - } - - Y_UNIT_TEST(TwoOverloadedPriority) { - TTest t; - int cpus = 20; - t.SetCpuCount(cpus); - t.AddPool(1, 5, 20, 0); // pool=0 - t.AddPool(1, 5, 20, 1); // pool=1 - t.AddPool(1, 5, 20, 2); // pool=2 - t.AddPool(1, 5, 20, 3); // pool=3 - t.Start(); - ui64 dts = 1.01 * Us2Ts(t.Config.UnitedWorkers.Balancer.PeriodUs); - ui64 mErlang = Ts2Us(dts) / 1000; - for (int i = 0; i < cpus; i++) { - t.Balance(dts, {20000 * mErlang, 2500 * mErlang, 4500 * mErlang, 9500 * mErlang}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({2, 3, 5, 10}); - t.Balance(dts, {20000 * mErlang, 2500 * mErlang, 4500 * mErlang, 8500 * mErlang}); - t.ApplyMovements(); - t.AssertPoolsCurrentCpus({3, 3, 5, 9}); - // NOTE: this operation require one move, but we do not make global analysis, so multiple steps (1->2 & 0->1) are required (can be optimized later) - for (int i = 0; i < 3; i++) { - t.Balance(dts, {20000 * mErlang, 2500 * mErlang, 5500 * mErlang, 8500 * mErlang}); - t.ApplyMovements(); - } - t.AssertPoolsCurrentCpus({2, 3, 6, 9}); - } -} diff --git a/library/cpp/actors/core/benchmark_ut.cpp b/library/cpp/actors/core/benchmark_ut.cpp deleted file mode 100644 index 380e983b92..0000000000 --- a/library/cpp/actors/core/benchmark_ut.cpp +++ /dev/null @@ -1,1111 +0,0 @@ -#include "actorsystem.h" -#include "actor_bootstrapped.h" -#include "config.h" -#include "executor_pool_basic.h" -#include "hfunc.h" -#include "scheduler_basic.h" - -#include <library/cpp/testing/unittest/registar.h> - -#include <util/thread/pool.h> - -#include <algorithm> -#include <atomic> -#include <chrono> -#include <condition_variable> -#include <iostream> -#include <memory> -#include <mutex> -#include <optional> -#include <span> -#include <string> -#include <thread> -#include <utility> -#include <unordered_set> -#include <unordered_map> -#include <vector> - -#define BENCH_START(label) auto label##Start = std::chrono::steady_clock::now() -#define BENCH_END(label) std::chrono::steady_clock::now() - label##Start - -using namespace NActors; -using namespace std::chrono_literals; - -Y_UNIT_TEST_SUITE(ActorSystemBenchmark) { - - enum ESimpleEventType { - EvQuickSort, - EvSumVector, - EvSumVectorResult, - EvSumSendRequests, - EvKvSearch, - EvKvSendRequests, - }; - - using TContainer = std::vector<i32>; - using TActorIds = std::span<TActorId>; - - template <typename TId> - class TActiveEntityRegistry { - private: - std::unordered_set<TId> ActiveIds_; - std::mutex ActiveIdsMutex_; - std::condition_variable ActiveIdsCv_; - - public: - void SetActive(TId id) { - std::unique_lock lock(ActiveIdsMutex_); - ActiveIds_.insert(std::move(id)); - } - - void SetInactive(const TId& id) { - std::unique_lock lock(ActiveIdsMutex_); - ActiveIds_.erase(id); - if (ActiveIds_.empty()) { - ActiveIdsCv_.notify_all(); - } - } - - bool WaitForAllInactive(std::chrono::microseconds timeout = 1ms) { - std::unique_lock lock(ActiveIdsMutex_); - ActiveIdsCv_.wait_for(lock, timeout, [this] { - return ActiveIds_.empty(); - }); - return ActiveIds_.empty(); - } - }; - - class TQuickSortEngine { - public: - struct TParameters { - TContainer &Container; - i32 Left; - i32 Right; - void* CustomData = nullptr; - - TParameters() = delete; - TParameters(TContainer& container, i32 left, i32 right, void* customData) - : Container(container) - , Left(left) - , Right(right) - , CustomData(customData) - {} - }; - - public: - void Sort(TQuickSortEngine::TParameters& params) { - auto [newRight, newLeft] = Partition(params.Container, params.Left, params.Right); - if (!(params.Left < newRight || newLeft < params.Right)) { - return; - } - - auto [leftParams, rightParams] = SplitParameters(params, newRight, newLeft); - - bool ranAsync = false; - - if (newLeft < params.Right) { - ranAsync = TryRunAsync(rightParams); - if (ranAsync) { - Sort(rightParams); - } - } - if (params.Left < newRight) { - if (!ranAsync && !TryRunAsync(leftParams)) { - Sort(leftParams); - } - } - } - - // returns bounds of left and right sub-arrays for the next iteration - std::pair<i32, i32> Partition(TContainer& container, i32 left, i32 right) { - ui32 pivotIndex = (left + right) / 2; - auto pivot = container[pivotIndex]; - while (left <= right) { - while (container[left] < pivot) { - left++; - } - while (container[right] > pivot) { - right--; - } - - if (left <= right) { - std::swap(container[left++], container[right--]); - } - } - return {right, left}; - } - - protected: - virtual std::pair<TParameters, TParameters> SplitParameters(const TParameters& params, i32 newRight, i32 newLeft) = 0; - virtual bool TryRunAsync(const TParameters& params) = 0; - }; - - class TQuickSortTask : public TQuickSortEngine, public IObjectInQueue { - public: - using TParameters = TQuickSortEngine::TParameters; - struct TThreadPoolParameters { - const ui32 ThreadsLimit = 0; - std::atomic<ui32> ThreadsUsed = 0; - TThreadPool& ThreadPool; - - TThreadPoolParameters(ui32 threadsLimit, ui32 threadsUsed, TThreadPool &threadPool) - : ThreadsLimit(threadsLimit) - , ThreadsUsed(threadsUsed) - , ThreadPool(threadPool) - {} - }; - TParameters Params; - TActiveEntityRegistry<TQuickSortTask*>& ActiveThreadRegistry; - - public: - TQuickSortTask() = delete; - TQuickSortTask(TParameters params, TActiveEntityRegistry<TQuickSortTask*>& activeThreadRegistry) - : Params(params) - , ActiveThreadRegistry(activeThreadRegistry) - { - ActiveThreadRegistry.SetActive(this); - } - - void Process(void*) override { - Sort(Params); - ActiveThreadRegistry.SetInactive(this); - } - - protected: - std::pair<TParameters, TParameters> SplitParameters(const TParameters& params, i32 newRight, i32 newLeft) override { - return { - {params.Container, params.Left, newRight, params.CustomData}, - {params.Container, newLeft, params.Right, params.CustomData} - }; - } - - bool TryRunAsync(const TParameters& params) override { - auto threadPoolParams = static_cast<TThreadPoolParameters*>(params.CustomData); - if (threadPoolParams->ThreadsUsed++ >= threadPoolParams->ThreadsLimit) { - threadPoolParams->ThreadsUsed--; - return false; - } - return threadPoolParams->ThreadPool.AddAndOwn(THolder(new TQuickSortTask(params, ActiveThreadRegistry))); - } - }; - - class TEvQuickSort : public TEventLocal<TEvQuickSort, EvQuickSort> { - public: - using TParameters = TQuickSortEngine::TParameters; - struct TActorSystemParameters { - TActorIds ActorIds; - std::atomic<ui32> ActorIdsUsed = 0; - TActorSystemParameters() = delete; - TActorSystemParameters(const TActorIds& actorIds, ui32 actorIdsUsed = 0) - : ActorIds(actorIds) - , ActorIdsUsed(actorIdsUsed) - {} - }; - - TQuickSortEngine::TParameters Params; - - public: - TEvQuickSort() = delete; - TEvQuickSort(TParameters params, TActiveEntityRegistry<TEvQuickSort*>& activeEventRegistry) - : Params(params) - , ActiveEventRegistry_(activeEventRegistry) - { - Y_ABORT_UNLESS(!Params.Container.empty()); - Y_ABORT_UNLESS(Params.Right - Params.Left + 1 <= static_cast<i32>(Params.Container.size()), - "left: %d, right: %d, cont.size: %d", Params.Left, Params.Right, static_cast<i32>(Params.Container.size())); - ActiveEventRegistry_.SetActive(this); - } - - virtual ~TEvQuickSort() { - ActiveEventRegistry_.SetInactive(this); - } - - private: - TActiveEntityRegistry<TEvQuickSort*>& ActiveEventRegistry_; - }; - - class TQuickSortActor : public TQuickSortEngine, public TActorBootstrapped<TQuickSortActor> { - public: - using TParameters = TQuickSortEngine::TParameters; - - private: - TActiveEntityRegistry<TEvQuickSort*>& ActiveEventRegistry_; - - public: - TQuickSortActor() = delete; - TQuickSortActor(TActiveEntityRegistry<TEvQuickSort*>& activeEventRegistry) - : TActorBootstrapped<TQuickSortActor>() - , ActiveEventRegistry_(activeEventRegistry) - {} - - STFUNC(StateInit) { - switch (ev->GetTypeRewrite()) { - hFunc(TEvQuickSort, Handle); - default: - Y_ABORT_UNLESS(false); - } - } - - void Bootstrap() { - Become(&TThis::StateInit); - } - - protected: - std::pair<TParameters, TParameters> SplitParameters(const TParameters& params, i32 newRight, i32 newLeft) override { - return { - {params.Container, params.Left, newRight, params.CustomData}, - {params.Container, newLeft, params.Right, params.CustomData} - }; - } - - bool TryRunAsync(const TParameters& params) override { - auto actorSystemParams = static_cast<TEvQuickSort::TActorSystemParameters*>(params.CustomData); - const auto actorIdIndex = actorSystemParams->ActorIdsUsed++; - if (actorIdIndex >= actorSystemParams->ActorIds.size()) { - actorSystemParams->ActorIdsUsed--; - return false; - } - auto targetActorId = actorSystemParams->ActorIds[actorIdIndex]; - Send(targetActorId, new TEvQuickSort(params, ActiveEventRegistry_)); - return true; - } - - private: - void Handle(TEvQuickSort::TPtr& ev) { - auto evPtr = ev->Get(); - Sort(evPtr->Params); - } - }; - - std::vector<i32> PrepareVectorToSort(ui32 n) { - std::vector<i32> numbers(n); - for (ui32 i = 0; i < numbers.size(); i++) { - numbers[i] = numbers.size() - i; - } - return numbers; - } - - std::unique_ptr<TActorSystem> PrepareActorSystem(ui32 poolThreads, TAffinity* affinity = nullptr) { - auto setup = MakeHolder<TActorSystemSetup>(); - setup->NodeId = 1; - - setup->ExecutorsCount = 1; - setup->Executors.Reset(new TAutoPtr<IExecutorPool>[setup->ExecutorsCount]); - - ui32 poolId = 0; - ui64 poolSpinThreashold = 20; - setup->Executors[0].Reset(new TBasicExecutorPool( - poolId, poolThreads, poolSpinThreashold, "", nullptr, affinity)); - TSchedulerConfig schedulerConfig; - schedulerConfig.ResolutionMicroseconds = 512; - schedulerConfig.SpinThreshold = 100; - setup->Scheduler.Reset(new TBasicSchedulerThread(schedulerConfig)); - - return std::make_unique<TActorSystem>(setup); - } - - std::vector<TActorId> prepareQuickSortActors( - TActorSystem* actorSystem, ui32 actorsNum, TActiveEntityRegistry<TEvQuickSort*>& activeEventRegistry - ) { - std::vector<TActorId> actorIds; - actorIds.reserve(actorsNum); - - for (ui32 i = 0; i < actorsNum; i++) { - auto actor = new TQuickSortActor(activeEventRegistry); - auto actorId = actorSystem->Register(actor); - actorIds.push_back(actorId); - } - - return actorIds; - } - - std::pair<std::chrono::microseconds, std::vector<i32>> BenchmarkQuickSortActor( - ui32 threads, - ui32 iterations, - ui32 vectorSize - ) { - auto actorSystem = PrepareActorSystem(threads); - actorSystem->Start(); - - TActiveEntityRegistry<TEvQuickSort*> activeEventRegistry; - auto actorIds = prepareQuickSortActors(actorSystem.get(), threads, activeEventRegistry); - - std::vector<i32> actorSortResult; - auto actorQsDurationTotal = 0us; - for (ui32 i = 0; i < iterations; i++) { - auto numbers = PrepareVectorToSort(vectorSize); - - TEvQuickSort::TActorSystemParameters actorSystemParams(actorIds, 1); - TEvQuickSort::TParameters params(numbers, 0, numbers.size() - 1, &actorSystemParams); - auto ev3 = new TEvQuickSort(params, activeEventRegistry); - - BENCH_START(qs); - - actorSystem->Send(actorIds.front(), ev3); - UNIT_ASSERT_C(activeEventRegistry.WaitForAllInactive(60s), "timeout"); - - actorQsDurationTotal += std::chrono::duration_cast<std::chrono::microseconds>(BENCH_END(qs)); - - if (i + 1 == iterations) { - actorSortResult = numbers; - } - } - - return {actorQsDurationTotal / iterations, actorSortResult}; - } - - std::pair<std::chrono::microseconds, std::vector<i32>> BenchmarkQuickSortThreadPool( - ui32 threads, - ui32 iterations, - ui32 vectorSize - ) { - TThreadPool threadPool; - threadPool.Start(threads); - TActiveEntityRegistry<TQuickSortTask*> activeThreadRegistry; - - auto threaPoolSortDurationTotal = 0us; - std::vector<i32> threadPoolSortResult; - for (ui32 i = 0; i < iterations; i++) { - auto numbers = PrepareVectorToSort(vectorSize); - - TQuickSortTask::TThreadPoolParameters threadPoolParams(threads, 1, threadPool); - TQuickSortTask::TParameters params(numbers, 0, numbers.size() - 1, &threadPoolParams); - - BENCH_START(thread); - - Y_ABORT_UNLESS(threadPool.AddAndOwn(THolder(new TQuickSortTask(params, activeThreadRegistry)))); - UNIT_ASSERT_C(activeThreadRegistry.WaitForAllInactive(60s), "timeout"); - - threaPoolSortDurationTotal += std::chrono::duration_cast<std::chrono::microseconds>(BENCH_END(thread)); - - if (i + 1 == iterations) { - threadPoolSortResult = numbers; - } - } - - threadPool.Stop(); - - return {threaPoolSortDurationTotal / iterations, threadPoolSortResult}; - } - - Y_UNIT_TEST(QuickSortActor) { - const std::vector<ui32> threadss{1, 4}; - const std::vector<ui32> vectorSizes{100, 1'000, 1'000'000}; - const ui32 iterations = 3; - - std::cout << "sep=," << std::endl; - std::cout << "size,threads,actor_time(us),thread_pool_time(us)" << std::endl; - - for (auto vectorSize : vectorSizes) { - for (auto threads : threadss) { - std::cerr << "vector size: " << vectorSize << ", threads: " << threads << std::endl; - - auto [actorSortDuration, actorSortResult] = BenchmarkQuickSortActor(threads, iterations, vectorSize); - std::cerr << "actor sort duration: " << actorSortDuration.count() << "us" << std::endl; - - auto [threadPoolSortDuration, threadPoolSortResult] = BenchmarkQuickSortThreadPool(threads, iterations, vectorSize); - std::cerr << "thread pool sort duration: " << threadPoolSortDuration.count() << "us" << std::endl; - - auto referenceVector = PrepareVectorToSort(vectorSize); - std::sort(referenceVector.begin(), referenceVector.end()); - - UNIT_ASSERT_EQUAL_C(actorSortResult, referenceVector, - "vector size: " << vectorSize << "; threads: " << threads); - UNIT_ASSERT_EQUAL_C(threadPoolSortResult, referenceVector, - "vector size: " << vectorSize << "; threads: " << threads); - - std::cout << vectorSize << "," - << threads << "," - << actorSortDuration.count() << "," - << threadPoolSortDuration.count() << std::endl; - } - - std::cerr << "-----" << std::endl << std::endl; - } - } - - // KV-storage benchmark - - using TKvKey = std::string; - using TKvValue = i32; - using TDict = std::unordered_map<TKvKey, TKvValue>; - - struct TSearchStat { - ui32 Found = 0; - ui32 NotFound = 0; - - bool operator==(const TSearchStat& other) { - return Found == other.Found && NotFound == other.NotFound; - } - }; - - class TKvSearchTask : public IObjectInQueue { - private: - TKvKey Key_; - const TDict& Dict_; - TSearchStat SearchStat_ = {}; - - public: - TKvSearchTask() = delete; - TKvSearchTask(TKvKey key, const TDict& dict) - : Key_(key) - , Dict_(dict) - {} - - void Process(void*) override { - if (Dict_.contains(Key_)) { - SearchStat_.Found++; - } else { - SearchStat_.NotFound++; - } - } - }; - - class TEvKvSearch : public TEventLocal<TEvKvSearch, EvKvSearch> { - public: - TKvKey Key; - - public: - TEvKvSearch() = delete; - TEvKvSearch(TKvKey key) - : Key(std::move(key)) - {} - }; - - class TEvKvSendRequests : public TEventLocal<TEvKvSendRequests, EvKvSendRequests> { - public: - const std::vector<std::string>& KeysToSearch; - const std::vector<TActorId> SearchActorIds; - - public: - TEvKvSendRequests() = delete; - TEvKvSendRequests(const std::vector<std::string>& keysToSearch, std::vector<TActorId>&& searchActorIds) - : KeysToSearch(keysToSearch) - , SearchActorIds(std::move(searchActorIds)) - {} - }; - - class TKvSendRequestActor : public TActorBootstrapped<TKvSendRequestActor> { - public: - STFUNC(StateInit) { - switch (ev->GetTypeRewrite()) { - hFunc(TEvKvSendRequests, Handle); - default: - Y_ABORT_UNLESS(false); - } - } - - void Bootstrap() { - Become(&TThis::StateInit); - } - - private: - void Handle(TEvKvSendRequests::TPtr& ev) { - auto evPtr = ev->Get(); - ui32 actorIdx = 0; - for (auto& key : evPtr->KeysToSearch) { - auto actorId = evPtr->SearchActorIds[actorIdx]; - actorIdx = (actorIdx + 1) % evPtr->SearchActorIds.size(); - - Send(actorId, new TEvKvSearch(key)); - } - } - }; - - class TKvSearchActor : public TActorBootstrapped<TKvSearchActor> { - private: - const TDict& Dict_; - TSearchStat SearchStat_ = {}; - std::atomic<ui32> CompletedEvents_ = 0; - - public: - TKvSearchActor() = delete; - TKvSearchActor(const TDict& dict) - : TActorBootstrapped<TKvSearchActor>() - , Dict_(dict) - {} - - STFUNC(StateInit) { - switch (ev->GetTypeRewrite()) { - hFunc(TEvKvSearch, Handle); - default: - Y_ABORT_UNLESS(false); - } - } - - void Bootstrap() { - Become(&TThis::StateInit); - } - - const TSearchStat& SearchStat() { - return SearchStat_; - } - - ui32 CompletedEvents() { - return CompletedEvents_; - } - private: - void Handle(TEvKvSearch::TPtr& ev) { - auto evPtr = ev->Get(); - - if (Dict_.contains(evPtr->Key)) { - SearchStat_.Found++; - } else { - SearchStat_.NotFound++; - } - CompletedEvents_++; - } - }; - - TDict prepareKvSearchDict(const i32 dictSize) { - std::string permutableString = "abcdefghijklm"; - TDict dict; - for (i32 i = 0; i < dictSize; i++) { - dict.emplace(permutableString, i); - std::next_permutation(permutableString.begin(), permutableString.end()); - } - - return dict; - } - - std::vector<std::string> prepareKeysToSearch(const TDict &dict, ui32 requestsNumber) { - std::vector<std::string> keys; - auto keyAppearances = requestsNumber / dict.size() + 1; - keys.reserve(keyAppearances * dict.size()); - - for (auto& [key, _] : dict) { - for (ui32 i = 0; i < keyAppearances; i++) { - keys.push_back(key); - - // keep the original key value to search - if (i % 4 == 0) { - continue; - } - - // make non-exising key - keys.back() += "nonexistingkey"; - } - } - - Y_ABORT_UNLESS(keys.size() >= requestsNumber); - - std::random_shuffle(keys.begin(), keys.end()); - keys.resize(requestsNumber); - - return keys; - } - - std::pair<std::vector<TKvSearchActor*>, std::vector<TActorId>> prepareKvSearchActors( - TActorSystem* actorSystem, ui32 searchActorsNum, const std::vector<TDict>& dicts - ) { - std::vector<TKvSearchActor*> searchActors; - std::vector<TActorId> searchActorIds; - searchActors.reserve(searchActorsNum); - searchActorIds.reserve(searchActorsNum); - for (ui32 i = 0, dictIdx = 0; i < searchActorsNum; i++) { - const auto& dict = dicts[dictIdx]; - dictIdx = (dictIdx + 1) % dicts.size(); - - auto kvSearchActor = new TKvSearchActor(dict); - auto kvSearchActorId = actorSystem->Register(kvSearchActor); - searchActors.push_back(kvSearchActor); - searchActorIds.push_back(kvSearchActorId); - } - - return {searchActors, searchActorIds}; - } - - ui32 CalculateCompletedEvents(const std::vector<TKvSearchActor*>& actors) { - ui32 completedEvents = 0; - for (auto actor : actors) { - completedEvents += actor->CompletedEvents(); - } - return completedEvents; - } - - TSearchStat CollectKvSearchActorStat(const std::vector<TKvSearchActor*>& actors) { - TSearchStat stat; - for (auto actor : actors) { - stat.Found += actor->SearchStat().Found; - stat.NotFound += actor->SearchStat().NotFound; - } - return stat; - } - - std::pair<std::chrono::microseconds, TSearchStat> BenchmarkKvActor( - ui32 threads, ui32 actors, ui32 iterations, const std::vector<TDict>& dicts, const std::vector<std::string>& keysToSearch - ) { - TSearchStat stat = {}; - auto kvSearchActorDuration = 0us; - - for (ui32 i = 0; i < iterations; i++) { - auto actorSystem = PrepareActorSystem(threads); - actorSystem->Start(); - - auto [kvSearchActors, kvSearchActorIds] = prepareKvSearchActors(actorSystem.get(), actors, dicts); - - auto kvSendRequestActorId = actorSystem->Register(new TKvSendRequestActor()); - - BENCH_START(kvSearch); - actorSystem->Send(kvSendRequestActorId, new TEvKvSendRequests(keysToSearch, std::move(kvSearchActorIds))); - - // CondVar logic gives too much of overhead (2-10 times more than just sleep_for) - while (CalculateCompletedEvents(kvSearchActors) < keysToSearch.size()) { - std::this_thread::sleep_for(1us); - } - - kvSearchActorDuration += std::chrono::duration_cast<std::chrono::microseconds>(BENCH_END(kvSearch)); - - if (i + 1 == iterations) { - stat = CollectKvSearchActorStat(kvSearchActors); - } - } - - return {kvSearchActorDuration / iterations, stat}; - } - - std::pair<std::chrono::microseconds, TSearchStat> BenchmarkKvActorExternalSender( - ui32 threads, ui32 actors, ui32 iterations, const std::vector<TDict>& dicts, const std::vector<std::string>& keysToSearch - ) { - TSearchStat stat = {}; - auto kvSearchActorDuration = 0us; - for (ui32 i = 0; i < iterations; i++) { - auto actorSystem = PrepareActorSystem(threads); - actorSystem->Start(); - - auto [kvSearchActors, kvSearchActorIds] = prepareKvSearchActors(actorSystem.get(), actors, dicts); - - BENCH_START(kvSearch); - ui32 actorIdToUseIndex = 0; - for (auto& key : keysToSearch) { - actorSystem->Send(kvSearchActorIds[actorIdToUseIndex], new TEvKvSearch(key)); - actorIdToUseIndex = (actorIdToUseIndex + 1) % kvSearchActorIds.size(); - } - - // CondVar logic gives too much of overhead (2-10 times more than just sleep_for) - while (CalculateCompletedEvents(kvSearchActors) < keysToSearch.size()) { - std::this_thread::sleep_for(1us); - } - - kvSearchActorDuration += std::chrono::duration_cast<std::chrono::microseconds>(BENCH_END(kvSearch)); - - if (i + 1 == iterations) { - stat = CollectKvSearchActorStat(kvSearchActors); - } - } - - return {kvSearchActorDuration / iterations, stat}; - } - - std::chrono::microseconds BenchmarkKvThreadPool( - ui32 threads, ui32 iterations, const TDict& dict, const std::vector<std::string>& keysToSearch - ) { - TThreadPool threadPool; - - auto kvSearchActorDuration = 0us; - for (ui32 i = 0; i < iterations; i++) { - threadPool.Start(threads); - - BENCH_START(kvSearch); - - for (auto& key : keysToSearch) { - Y_ABORT_UNLESS(threadPool.AddAndOwn(THolder(new TKvSearchTask(key, dict)))); - } - - // CondVar logic gives too much of overhead (2-10 times more than just sleep_for) - while (threadPool.Size() > 0) { - std::this_thread::sleep_for(1us); - } - threadPool.Stop(); - - kvSearchActorDuration += std::chrono::duration_cast<std::chrono::microseconds>(BENCH_END(kvSearch)); - } - - return {kvSearchActorDuration / iterations}; - } - - std::pair<std::chrono::microseconds, TSearchStat> BenchmarkKvSingleThread( - ui32 iterations, const TDict& dict, const std::vector<std::string>& keysToSearch - ) { - TSearchStat stat = {}; - auto kvSearchDuration = 0us; - for (ui32 i = 0; i < iterations; i++) { - TSearchStat iterationStat = {}; - BENCH_START(kvSearch); - for (auto& key : keysToSearch) { - if (dict.contains(key)) { - iterationStat.Found++; - } else { - iterationStat.NotFound++; - } - } - kvSearchDuration += std::chrono::duration_cast<std::chrono::microseconds>(BENCH_END(kvSearch)); - - if (i + 1 == iterations) { - stat = iterationStat; - } - } - - return {kvSearchDuration / iterations, stat}; - } - - Y_UNIT_TEST(KvActor) { - const bool forCI = true; - - using TNumbers = std::vector<ui32>; - const TNumbers threadNumbers = forCI ? TNumbers{1} : TNumbers{1, 4, 8}; - const TNumbers actorNumbers = forCI ? TNumbers{1, 8} : TNumbers{1, 4, 8, 16, 32, 64}; - const TNumbers dictSizes = forCI ? TNumbers{1'000} : TNumbers{1'000, 1'000'000}; - const TNumbers dictsNumbers = forCI ? TNumbers{1} : TNumbers{1, 8}; - const ui32 iterations = 5; - - std::cout << "sep=," << std::endl; - std::cout << "requests_number,dicts_number,dict_size,threads,actors,actor_time(us),actor_ext_time(us),thread_pool_time(us),single_thread_time(us)" << std::endl; - - for (auto dictsNumber : dictsNumbers) { - for (auto dictSize : dictSizes) { - const auto dict = prepareKvSearchDict(dictSize); - const ui32 requestsNumber = forCI ? 10'000 : 1'000'000; - const auto keysToSearch = prepareKeysToSearch(dict, requestsNumber); - - for (auto threads : threadNumbers) { - std::cerr << "requestsNumber: " << requestsNumber - << ", dictSize: " << dictSize - << ", threads: " << threads << std::endl; - - auto tpKvDuration = BenchmarkKvThreadPool(threads, iterations, dict, keysToSearch); - std::cerr << "kv search threadpool duration: " << tpKvDuration.count() << "us" << std::endl; - - auto [singleThreadKvDuration, singleThreadKvStat] = BenchmarkKvSingleThread(iterations, dict, keysToSearch); - std::cerr << "kv search single thread duration: " << singleThreadKvDuration.count() << "us" << std::endl; - - std::vector<TDict> dicts(dictsNumber, dict); - - for (auto actors : actorNumbers) { - std::cerr << "----" << std::endl - << "requestsNumber: " << requestsNumber - << ", dictsNumber: " << dictsNumber - << ", dictSize: " << dictSize - << ", threads: " << threads - << ", actors: " << actors << std::endl; - - auto [actorKvDuration, actorKvStat] = BenchmarkKvActor(threads, actors, iterations, dicts, keysToSearch); - std::cerr << "kv search actor duration: " << actorKvDuration.count() << "us" << std::endl; - - auto [actorKvExtDuration, actorKvExtStat] = - BenchmarkKvActorExternalSender(threads, actors, iterations, dicts, keysToSearch); - std::cerr << "kv search actor with external message sender duration: " - << actorKvExtDuration.count() << "us" << std::endl; - Y_UNUSED(actorKvExtStat); - - - UNIT_ASSERT_EQUAL_C(actorKvStat, singleThreadKvStat, - "single thread found/not found: " << singleThreadKvStat.Found << "/" << singleThreadKvStat.NotFound << "; " - "actor stat found/not found: " << actorKvStat.Found << "/" << actorKvStat.NotFound); - - std::cout << requestsNumber << "," - << dictsNumber << "," - << dictSize << "," - << threads << "," - << actors << "," - << actorKvDuration.count() << "," - << actorKvExtDuration.count() << "," - << tpKvDuration.count() << "," - << singleThreadKvDuration.count() << std::endl; - } - std::cerr << "----" << std::endl; - } - } - } - } - - // vector sum benchmark - - i64 CalculateOddSum(const TContainer& numbers) { - i64 result = 0; - for (auto x : numbers) { - if (x % 2 == 1) { - result += x; - } - } - - return result; - } - - TContainer prepareVectorToSum(const ui32 vectorSize) { - TContainer numbers; - numbers.reserve(vectorSize); - for (ui32 i = 0; i < vectorSize; i++) { - numbers.push_back(i + 1); - } - - return numbers; - } - - class TEvSumVector : public TEventLocal<TEvSumVector, EvSumVector> { - public: - const TContainer Numbers; - - public: - TEvSumVector() = delete; - - TEvSumVector(TContainer&& numbers) - : Numbers(std::move(numbers)) - {} - }; - - class TEvSumVectorResult : public TEventLocal<TEvSumVectorResult, EvSumVectorResult> { - public: - const i64 Sum = 0; - - public: - TEvSumVectorResult(i64 sum) - : Sum(sum) - {} - }; - - class TEvSumSendRequests : public TEventLocal<TEvSumSendRequests, EvSumSendRequests> { - public: - const ui32 VectorSize; - const ui32 RequestsNumber; - const TActorIds ActorIds; - - public: - TEvSumSendRequests() = delete; - TEvSumSendRequests(ui32 vectorSize, ui32 requestsNumber, TActorIds actorIds) - : VectorSize(vectorSize) - , RequestsNumber(requestsNumber) - , ActorIds(actorIds) - {} - }; - - class TSumProxyActor : public TActorBootstrapped<TSumProxyActor> { - private: - i64 LastSum_ = 0; - ui32 NumberOfResults_ = 0; - ui32 ExpectedResults_ = 0; - ui32 VectorSize_ = 0; - TActorIds SumVectorActorIds_ = {}; - ui32 LastUsedActor_ = 0; - - std::mutex NumberOfResultsMutex_; - std::condition_variable NumberOfResultsCv_; - - public: - STFUNC(StateInit) { - switch (ev->GetTypeRewrite()) { - hFunc(TEvSumSendRequests, HandleRequest); - hFunc(TEvSumVectorResult, HandleResult); - default: - Y_ABORT_UNLESS(false); - } - } - - void Bootstrap() { - Become(&TThis::StateInit); - } - - i64 LastSum() { - return LastSum_; - } - - bool WaitForResults(std::chrono::microseconds timeout = 1ms, bool nonZero = true) { - std::unique_lock lock(NumberOfResultsMutex_); - NumberOfResultsCv_.wait_for(lock, timeout, [this, nonZero] { - return ((nonZero && NumberOfResults_ != 0) || !nonZero) - && NumberOfResults_ == ExpectedResults_; - }); - return NumberOfResults_ == ExpectedResults_; - } - - void ShiftLastUsedActor(ui32 shift) { - LastUsedActor_ += shift; - } - - private: - TActorId NextActorId() { - auto actorId = SumVectorActorIds_[LastUsedActor_ % SumVectorActorIds_.size()]; - LastUsedActor_ = (LastUsedActor_ + 1) % SumVectorActorIds_.size(); - - return actorId; - } - - bool SendVectorIfNeeded() { - if (NumberOfResults_ < ExpectedResults_) { - Send(NextActorId(), new TEvSumVector(prepareVectorToSum(VectorSize_))); - return true; - } - return false; - } - - void HandleRequest(TEvSumSendRequests::TPtr& ev) { - auto evPtr = ev->Get(); - ExpectedResults_ = evPtr->RequestsNumber; - VectorSize_ = evPtr->VectorSize; - SumVectorActorIds_ = evPtr->ActorIds; - - { - std::unique_lock lock(NumberOfResultsMutex_); - NumberOfResults_ = 0; - - SendVectorIfNeeded(); - } - } - - void HandleResult(TEvSumVectorResult::TPtr& ev) { - LastSum_ = ev->Get()->Sum; - { - std::unique_lock lock(NumberOfResultsMutex_); - NumberOfResults_++; - - if (!SendVectorIfNeeded()) { - NumberOfResultsCv_.notify_all(); - } - } - } - }; - - class TSumVectorActor : public TActorBootstrapped<TSumVectorActor> { - private: - TActorId ResultActorId_; - - public: - STFUNC(StateInit) { - switch (ev->GetTypeRewrite()) { - hFunc(TEvSumVector, Handle); - default: - Y_ABORT_UNLESS(false); - } - } - - void Bootstrap() { - Become(&TThis::StateInit); - } - - private: - void Handle(TEvSumVector::TPtr& ev) { - auto evPtr = ev->Get(); - auto oddSum = CalculateOddSum(evPtr->Numbers); - - Send(ev->Sender, new TEvSumVectorResult(oddSum)); - } - }; - - std::vector<TActorId> prepareSumActors(TActorSystem* actorSystem, ui32 actorsNumber) { - std::vector<TActorId> actorIds; - actorIds.reserve(actorsNumber); - for (ui32 i = 0; i < actorsNumber; i++) { - actorIds.push_back(actorSystem->Register(new TSumVectorActor())); - } - return actorIds; - } - - std::pair<std::vector<TSumProxyActor*>, std::vector<TActorId>> prepareProxyActors( - TActorSystem* actorSystem, ui32 actorsNumber - ) { - std::pair<std::vector<TSumProxyActor*>, std::vector<TActorId>> result; - auto& [actors, actorIds] = result; - actors.reserve(actorsNumber); - actorIds.reserve(actorsNumber); - for (ui32 i = 0; i < actorsNumber; i++) { - actors.push_back(new TSumProxyActor()); - actorIds.push_back(actorSystem->Register(actors.back())); - actors.back()->ShiftLastUsedActor(i); - } - - return result; - } - - std::chrono::microseconds calcTimeoutForSumVector( - ui32 vectorSize, ui32 iterations, ui32 proxyActorsNum, ui32 sumActorsNum, ui32 threadsNum - ) { - auto expectedMaxTimePerMillion = 100000us; - auto vectorSizeRatio = vectorSize / 1000000 + 1; - - return expectedMaxTimePerMillion * vectorSizeRatio * iterations * proxyActorsNum / std::min(threadsNum, sumActorsNum); - } - - bool WaitForSumActorResult(const std::vector<TSumProxyActor*>& actors, std::chrono::microseconds timeout = 1ms) { - for (auto& actor : actors) { - if (!actor->WaitForResults(timeout)) { - return false; - } - } - return true; - } - - std::pair<std::chrono::microseconds, i64> BenchmarkSumVectorActor( - ui32 threads, - ui32 proxyActorsNumber, - ui32 sumActorsNumber, - ui32 iterations, - ui32 vectorSize - ) { - auto actorSystem = PrepareActorSystem(threads); - actorSystem->Start(); - - auto sumActorIds = prepareSumActors(actorSystem.get(), sumActorsNumber); - auto [proxyActors, proxyActorIds] = prepareProxyActors(actorSystem.get(), proxyActorsNumber); - - auto timeout = calcTimeoutForSumVector(vectorSize, iterations, proxyActorsNumber, sumActorsNumber, threads); - - BENCH_START(sumVectorActor); - - for (auto proxyActorId : proxyActorIds) { - actorSystem->Send(proxyActorId, new TEvSumSendRequests(vectorSize, iterations, sumActorIds)); - } - - UNIT_ASSERT_C(WaitForSumActorResult(proxyActors, timeout), "timeout"); - - auto totalDuration = std::chrono::duration_cast<std::chrono::microseconds>(BENCH_END(sumVectorActor)); - auto checkSum = proxyActors.back()->LastSum(); - - return {totalDuration / iterations, checkSum}; - } - - Y_UNIT_TEST(SumVector) { - using TVui64 = std::vector<ui64>; - const bool forCI = true; - const TVui64 vectorSizes = forCI ? - TVui64{1'000, 1'000'000} : TVui64{1'000, 1'000'000, 10'000'000, 100'000'000}; - const TVui64 threadsNumbers = forCI ? TVui64{1} : TVui64{1, 4}; - const TVui64 proxyActorsNumbers = forCI ? TVui64{1} : TVui64{1, 4}; - const TVui64 sumActorsNumbers = forCI ? TVui64{1} : TVui64{1, 8, 32}; - const ui32 iterations = 30; - - std::cout << "sep=," << std::endl; - std::cout << "size,threads,proxy_actors,sum_actors,duration(us)" << std::endl; - - for (auto vectorSize : vectorSizes) { - for (auto threads : threadsNumbers) { - for (auto proxyActors : proxyActorsNumbers) { - for (auto sumActors : sumActorsNumbers) { - std::cerr << "vector size: " << vectorSize - << ", threads: " << threads - << ", proxy actors: " << proxyActors - << ", sum actors: " << sumActors << std::endl; - - auto [duration, resultSum] = BenchmarkSumVectorActor( - threads, proxyActors, sumActors, iterations, vectorSize); - std::cerr << "duration: " << duration.count() << "us" << std::endl; - - const i64 referenceSum = vectorSize * vectorSize / 4; - UNIT_ASSERT_EQUAL_C( - resultSum, referenceSum, - resultSum << "!=" << referenceSum << "; failed on vectorSize=" << vectorSize - << ", threads=" << threads - << ", proxyActors=" << proxyActors - << ", sumActors=" << sumActors); - - std::cout << vectorSize << "," - << threads << "," - << proxyActors << "," - << sumActors << "," - << duration.count() - << std::endl; - } - } - } - } - } -} diff --git a/library/cpp/actors/core/buffer.cpp b/library/cpp/actors/core/buffer.cpp deleted file mode 100644 index 91ff4dde68..0000000000 --- a/library/cpp/actors/core/buffer.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "buffer.h" - -#include <util/system/yassert.h> - -#include <algorithm> - -TBufferBase::TBufferBase(size_t size) noexcept - : Size(size) -{ -} - -size_t -TBufferBase::GetSize() const noexcept { - return Size; -} - -void TBufferBase::SetSize(size_t size) noexcept { - Size = size; -} - -///////////////////////////////////////////////////////////////////// - -template <typename PointerType> -TBufferBaseT<PointerType>::TBufferBaseT(PointerType data, size_t size) noexcept - : TBufferBase(size) - , Data(data) -{ -} - -template <typename PointerType> -PointerType -TBufferBaseT<PointerType>::GetPointer() const noexcept { - return Data; -} - -template <typename PointerType> -void TBufferBaseT<PointerType>::Assign(PointerType data, size_t size) noexcept { - Data = data; - Size = size; -} - -template <> -void TBufferBaseT<void*>::Cut(size_t offset) noexcept { - Y_DEBUG_ABORT_UNLESS(offset <= Size); - Data = static_cast<char*>(Data) + offset; - TBufferBase::Size -= offset; -} - -template <> -void TBufferBaseT<const void*>::Cut(size_t offset) noexcept { - Y_DEBUG_ABORT_UNLESS(offset <= Size); - Data = static_cast<const char*>(Data) + offset; - TBufferBase::Size -= offset; -} - -template class TBufferBaseT<void*>; -template class TBufferBaseT<const void*>; - -///////////////////////////////////////////////////////////////////// - -TConstBuffer::TConstBuffer(const void* data, size_t size) noexcept - : TBufferBaseT<const void*>(data, size) -{ -} - -TConstBuffer::TConstBuffer(const TMutableBuffer& buffer) noexcept - : TBufferBaseT<const void*>(buffer.GetPointer(), buffer.GetSize()) -{ -} - -TConstBuffer -TConstBuffer::Offset(ptrdiff_t offset, size_t size) const noexcept { - return TConstBuffer(static_cast<const char*>(Data) + offset, std::min(Size - offset, size)); -} - -//////////////////////////////////////////////////////////////////////////////// - -TMutableBuffer::TMutableBuffer(void* data, size_t size) noexcept - : TBufferBaseT<void*>(data, size) -{ -} - -TMutableBuffer -TMutableBuffer::Offset(ptrdiff_t offset, size_t size) const noexcept { - return TMutableBuffer(static_cast<char*>(Data) + offset, std::min(Size - offset, size)); -} - -size_t -TMutableBuffer::CopyFrom(const TConstBuffer& buffer) const noexcept { - const auto size = std::min(Size, buffer.Size); - std::memcpy(Data, buffer.Data, size); - return size; -} diff --git a/library/cpp/actors/core/buffer.h b/library/cpp/actors/core/buffer.h deleted file mode 100644 index 95425046d6..0000000000 --- a/library/cpp/actors/core/buffer.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include <limits> - -class TConstBuffer; -class TMutableBuffer; - -class TBufferBase { -public: - size_t GetSize() const noexcept; - - void SetSize(size_t newSize) noexcept; - -protected: - TBufferBase(size_t size = 0) noexcept; - - size_t Size; -}; - -template <typename PointerType> -class TBufferBaseT: public TBufferBase { -public: - PointerType GetPointer() const noexcept; - - void Cut(size_t offset) noexcept; - - void Assign(PointerType data = nullptr, size_t size = 0U) noexcept; - -protected: - TBufferBaseT(PointerType data, size_t size) noexcept; - - PointerType Data; -}; - -/// Represents constant memory buffer, but do not owns it. -class TConstBuffer: public TBufferBaseT<const void*> { - friend class TMutableBuffer; - -public: - TConstBuffer(const TMutableBuffer& buffer) noexcept; - - TConstBuffer(const void* data = nullptr, size_t size = 0U) noexcept; - - TConstBuffer Offset(ptrdiff_t offset, size_t size = std::numeric_limits<size_t>::max()) const noexcept; -}; - -/// Represents mutable memory buffer, but do not owns it. -class TMutableBuffer: public TBufferBaseT<void*> { - friend class TConstBuffer; - -public: - TMutableBuffer(void* data = nullptr, size_t size = 0U) noexcept; - - TMutableBuffer(const TMutableBuffer& value) noexcept - : TBufferBaseT<void*>(value) - { - } - - TMutableBuffer Offset(ptrdiff_t offset, size_t size = std::numeric_limits<size_t>::max()) const noexcept; - - size_t CopyFrom(const TConstBuffer& buffer) const noexcept; -}; diff --git a/library/cpp/actors/core/callstack.cpp b/library/cpp/actors/core/callstack.cpp deleted file mode 100644 index 559cc73550..0000000000 --- a/library/cpp/actors/core/callstack.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "callstack.h" -#include <util/thread/singleton.h> - -#ifdef USE_ACTOR_CALLSTACK - -namespace NActors { - namespace { - void (*PreviousFormatBackTrace)(IOutputStream*) = 0; - ui32 ActorBackTraceEnableCounter = 0; - } - - void ActorFormatBackTrace(IOutputStream* out) { - TStringStream str; - PreviousFormatBackTrace(&str); - str << Endl; - TCallstack::DumpCallstack(str); - *out << str.Str(); - } - - void EnableActorCallstack() { - if (ActorBackTraceEnableCounter == 0) { - Y_ABORT_UNLESS(PreviousFormatBackTrace == 0); - PreviousFormatBackTrace = SetFormatBackTraceFn(ActorFormatBackTrace); - } - - ++ActorBackTraceEnableCounter; - } - - void DisableActorCallstack() { - --ActorBackTraceEnableCounter; - - if (ActorBackTraceEnableCounter == 0) { - Y_ABORT_UNLESS(PreviousFormatBackTrace); - SetFormatBackTraceFn(PreviousFormatBackTrace); - PreviousFormatBackTrace = 0; - } - } - - TCallstack::TCallstack() - : BeginIdx(0) - , Size(0) - , LinesToSkip(0) - { - } - - void TCallstack::SetLinesToSkip() { - TTrace record; - LinesToSkip = BackTrace(record.Data, TTrace::CAPACITY); - } - - void TCallstack::Trace() { - size_t currentIdx = (BeginIdx + Size) % RECORDS; - if (Size == RECORDS) { - ++BeginIdx; - } else { - ++Size; - } - TTrace& record = Record[currentIdx]; - record.Size = BackTrace(record.Data, TTrace::CAPACITY); - record.LinesToSkip = LinesToSkip; - } - - void TCallstack::TraceIfEmpty() { - if (Size == 0) { - LinesToSkip = 0; - Trace(); - } - } - - TCallstack& TCallstack::GetTlsCallstack() { - return *FastTlsSingleton<TCallstack>(); - } - - void TCallstack::DumpCallstack(TStringStream& str) { - TCallstack& callstack = GetTlsCallstack(); - for (int i = callstack.Size - 1; i >= 0; --i) { - TTrace& record = callstack.Record[(callstack.BeginIdx + i) % RECORDS]; - str << Endl << "Trace entry " << i << Endl << Endl; - size_t size = record.Size; - if (size > record.LinesToSkip && size < TTrace::CAPACITY) { - size -= record.LinesToSkip; - } - if (size > RECORDS_TO_SKIP) { - FormatBackTrace(&str, &record.Data[RECORDS_TO_SKIP], size - RECORDS_TO_SKIP); - } else { - FormatBackTrace(&str, record.Data, size); - } - str << Endl; - } - } -} - -#endif diff --git a/library/cpp/actors/core/callstack.h b/library/cpp/actors/core/callstack.h deleted file mode 100644 index 034d0becf1..0000000000 --- a/library/cpp/actors/core/callstack.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#ifndef NDEBUG -//#define ENABLE_ACTOR_CALLSTACK -#endif - -#ifdef ENABLE_ACTOR_CALLSTACK -#include "defs.h" -#include <util/system/backtrace.h> -#include <util/stream/str.h> -#include <util/generic/deque.h> -#define USE_ACTOR_CALLSTACK - -namespace NActors { - struct TCallstack { - struct TTrace { - static const size_t CAPACITY = 50; - void* Data[CAPACITY]; - size_t Size; - size_t LinesToSkip; - - TTrace() - : Size(0) - , LinesToSkip(0) - { - } - }; - - static const size_t RECORDS = 8; - static const size_t RECORDS_TO_SKIP = 2; - TTrace Record[RECORDS]; - size_t BeginIdx; - size_t Size; - size_t LinesToSkip; - - TCallstack(); - void SetLinesToSkip(); - void Trace(); - void TraceIfEmpty(); - static TCallstack& GetTlsCallstack(); - static void DumpCallstack(TStringStream& str); - }; - - void EnableActorCallstack(); - void DisableActorCallstack(); - -} - -#else - -namespace NActors { - inline void EnableActorCallstack(){} - - inline void DisableActorCallstack(){} - -} - -#endif diff --git a/library/cpp/actors/core/config.h b/library/cpp/actors/core/config.h deleted file mode 100644 index 04bdd6aebe..0000000000 --- a/library/cpp/actors/core/config.h +++ /dev/null @@ -1,260 +0,0 @@ -#pragma once - -#include "defs.h" -#include <library/cpp/actors/util/cpumask.h> -#include <library/cpp/monlib/dynamic_counters/counters.h> -#include <util/datetime/base.h> -#include <util/generic/ptr.h> -#include <util/generic/string.h> -#include <util/generic/vector.h> - -namespace NActors { - - struct TBalancingConfig { - // Default cpu count (used during overload). Zero value disables this pool balancing - // 1) Sum of `Cpus` on all pools cannot be changed without restart - // (changing cpu mode between Shared and Assigned is not implemented yet) - // 2) This sum must be equal to TUnitedWorkersConfig::CpuCount, - // otherwise `CpuCount - SUM(Cpus)` cpus will be in Shared mode (i.e. actorsystem 2.0) - ui32 Cpus = 0; - - ui32 MinCpus = 0; // Lower balancing bound, should be at least 1, and not greater than `Cpus` - ui32 MaxCpus = 0; // Higher balancing bound, should be not lower than `Cpus` - ui8 Priority = 0; // Priority of pool to obtain cpu due to balancing (higher is better) - ui64 ToleratedLatencyUs = 0; // p100-latency threshold indicating that more cpus are required by pool - }; - - struct TBalancerConfig { - ui64 PeriodUs = 15000000; // Time between balancer steps - }; - - enum class EASProfile { - Default, - LowCpuConsumption, - LowLatency, - }; - - struct TBasicExecutorPoolConfig { - static constexpr TDuration DEFAULT_TIME_PER_MAILBOX = TDuration::MilliSeconds(10); - static constexpr ui32 DEFAULT_EVENTS_PER_MAILBOX = 100; - - ui32 PoolId = 0; - TString PoolName; - ui32 Threads = 1; - ui64 SpinThreshold = 100; - TCpuMask Affinity; // Executor thread affinity - TDuration TimePerMailbox = DEFAULT_TIME_PER_MAILBOX; - ui32 EventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX; - int RealtimePriority = 0; - i16 MinThreadCount = 0; - i16 MaxThreadCount = 0; - i16 DefaultThreadCount = 0; - i16 Priority = 0; - i16 SharedExecutorsCount = 0; - i16 SoftProcessingDurationTs = 0; - EASProfile ActorSystemProfile = EASProfile::Default; - }; - - struct TIOExecutorPoolConfig { - ui32 PoolId = 0; - TString PoolName; - ui32 Threads = 1; - TCpuMask Affinity; // Executor thread affinity - }; - - struct TUnitedExecutorPoolConfig { - static constexpr TDuration DEFAULT_TIME_PER_MAILBOX = TDuration::MilliSeconds(10); - static constexpr ui32 DEFAULT_EVENTS_PER_MAILBOX = 100; - - ui32 PoolId = 0; - TString PoolName; - - // Resource sharing - ui32 Concurrency = 0; // Limits simultaneously running mailboxes count if set to non-zero value (do not set if Balancing.Cpus != 0) - TPoolWeight Weight = 0; // Weight in fair cpu-local pool scheduler - TCpuMask Allowed; // Allowed CPUs for workers to run this pool on (ignored if balancer works, i.e. actorsystem 1.5) - - // Single mailbox execution limits - TDuration TimePerMailbox = DEFAULT_TIME_PER_MAILBOX; - ui32 EventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX; - - // Long-term balancing - TBalancingConfig Balancing; - }; - - struct TUnitedWorkersConfig { - ui32 CpuCount = 0; // Total CPUs running united workers (i.e. TBasicExecutorPoolConfig::Threads analog); set to zero to disable united workers - ui64 SpinThresholdUs = 100; // Limit for active spinning in case all pools became idle - ui64 PoolLimitUs = 500; // Soft limit on pool execution - ui64 EventLimitUs = 100; // Hard limit on last event execution exceeding pool limit - ui64 LimitPrecisionUs = 100; // Maximum delay of timer on limit excess (delay needed to avoid settimer syscall on every pool switch) - ui64 FastWorkerPriority = 10; // Real-time priority of workers not exceeding hard limits - ui64 IdleWorkerPriority = 20; // Real-time priority of standby workers waiting for hard preemption on timers (should be greater than FastWorkerPriority) - TCpuMask Allowed; // Allowed CPUs for workers to run on (every worker has affinity for exactly one cpu) - bool NoRealtime = false; // For environments w/o permissions for RT-threads - bool NoAffinity = false; // For environments w/o permissions for cpu affinity - TBalancerConfig Balancer; - }; - - struct TSelfPingInfo { - NMonitoring::TDynamicCounters::TCounterPtr AvgPingCounter; - NMonitoring::TDynamicCounters::TCounterPtr AvgPingCounterWithSmallWindow; - ui32 MaxAvgPingUs; - }; - - struct TCpuManagerConfig { - TUnitedWorkersConfig UnitedWorkers; - TVector<TBasicExecutorPoolConfig> Basic; - TVector<TIOExecutorPoolConfig> IO; - TVector<TUnitedExecutorPoolConfig> United; - TVector<TSelfPingInfo> PingInfoByPool; - - ui32 GetExecutorsCount() const { - return Basic.size() + IO.size() + United.size(); - } - - TString GetPoolName(ui32 poolId) const { - for (const auto& p : Basic) { - if (p.PoolId == poolId) { - return p.PoolName; - } - } - for (const auto& p : IO) { - if (p.PoolId == poolId) { - return p.PoolName; - } - } - for (const auto& p : United) { - if (p.PoolId == poolId) { - return p.PoolName; - } - } - Y_ABORT("undefined pool id: %" PRIu32, (ui32)poolId); - } - - std::optional<ui32> GetThreadsOptional(ui32 poolId) const { - for (const auto& p : Basic) { - if (p.PoolId == poolId) { - return p.DefaultThreadCount; - } - } - for (const auto& p : IO) { - if (p.PoolId == poolId) { - return p.Threads; - } - } - for (const auto& p : United) { - if (p.PoolId == poolId) { - return p.Concurrency ? p.Concurrency : UnitedWorkers.CpuCount; - } - } - return {}; - } - - ui32 GetThreads(ui32 poolId) const { - auto result = GetThreadsOptional(poolId); - Y_ABORT_UNLESS(result, "undefined pool id: %" PRIu32, (ui32)poolId); - return *result; - } - }; - - struct TSchedulerConfig { - TSchedulerConfig( - ui64 resolution = 1024, - ui64 spinThreshold = 100, - ui64 progress = 10000, - bool useSchedulerActor = false) - : ResolutionMicroseconds(resolution) - , SpinThreshold(spinThreshold) - , ProgressThreshold(progress) - , UseSchedulerActor(useSchedulerActor) - {} - - ui64 ResolutionMicroseconds = 1024; - ui64 SpinThreshold = 100; - ui64 ProgressThreshold = 10000; - bool UseSchedulerActor = false; // False is default because tests use scheduler thread - ui64 RelaxedSendPaceEventsPerSecond = 200000; - ui64 RelaxedSendPaceEventsPerCycle = RelaxedSendPaceEventsPerSecond * ResolutionMicroseconds / 1000000; - // For resolution >= 250000 microseconds threshold is SendPace - // For resolution <= 250 microseconds threshold is 20 * SendPace - ui64 RelaxedSendThresholdEventsPerSecond = RelaxedSendPaceEventsPerSecond * - (20 - ((20 - 1) * ClampVal(ResolutionMicroseconds, ui64(250), ui64(250000)) - 250) / (250000 - 250)); - ui64 RelaxedSendThresholdEventsPerCycle = RelaxedSendThresholdEventsPerSecond * ResolutionMicroseconds / 1000000; - - // Optional subsection for scheduler counters (usually subsystem=utils) - NMonitoring::TDynamicCounterPtr MonCounters = nullptr; - }; - - struct TCpuAllocation { - struct TPoolAllocation { - TPoolId PoolId; - TPoolWeight Weight; - - TPoolAllocation(TPoolId poolId = 0, TPoolWeight weight = 0) - : PoolId(poolId) - , Weight(weight) - {} - }; - - TCpuId CpuId; - TVector<TPoolAllocation> AllowedPools; - - TPoolsMask GetPoolsMask() const { - TPoolsMask mask = 0; - for (const auto& pa : AllowedPools) { - if (pa.PoolId < MaxPools) { - mask &= (1ull << pa.PoolId); - } - } - return mask; - } - - bool HasPool(TPoolId pool) const { - for (const auto& pa : AllowedPools) { - if (pa.PoolId == pool) { - return true; - } - } - return false; - } - }; - - struct TCpuAllocationConfig { - TVector<TCpuAllocation> Items; - - TCpuAllocationConfig(const TCpuMask& available, const TCpuManagerConfig& cfg) { - for (const TUnitedExecutorPoolConfig& pool : cfg.United) { - Y_ABORT_UNLESS(pool.PoolId < MaxPools, "wrong PoolId of united executor pool: %s(%d)", - pool.PoolName.c_str(), (pool.PoolId)); - } - ui32 allocated[MaxPools] = {0}; - for (TCpuId cpu = 0; cpu < available.Size() && Items.size() < cfg.UnitedWorkers.CpuCount; cpu++) { - if (available.IsSet(cpu)) { - TCpuAllocation item; - item.CpuId = cpu; - for (const TUnitedExecutorPoolConfig& pool : cfg.United) { - if (cfg.UnitedWorkers.Allowed.IsEmpty() || cfg.UnitedWorkers.Allowed.IsSet(cpu)) { - if (pool.Allowed.IsEmpty() || pool.Allowed.IsSet(cpu)) { - item.AllowedPools.emplace_back(pool.PoolId, pool.Weight); - allocated[pool.PoolId]++; - } - } - } - if (!item.AllowedPools.empty()) { - Items.push_back(item); - } - } - } - for (const TUnitedExecutorPoolConfig& pool : cfg.United) { - Y_ABORT_UNLESS(allocated[pool.PoolId] > 0, "unable to allocate cpu for united executor pool: %s(%d)", - pool.PoolName.c_str(), (pool.PoolId)); - } - } - - operator bool() const { - return !Items.empty(); - } - }; - -} diff --git a/library/cpp/actors/core/cpu_manager.cpp b/library/cpp/actors/core/cpu_manager.cpp deleted file mode 100644 index 24b3161e3c..0000000000 --- a/library/cpp/actors/core/cpu_manager.cpp +++ /dev/null @@ -1,148 +0,0 @@ -#include "cpu_manager.h" -#include "probes.h" - -#include "executor_pool_basic.h" -#include "executor_pool_io.h" -#include "executor_pool_united.h" - -namespace NActors { - LWTRACE_USING(ACTORLIB_PROVIDER); - - TCpuManager::TCpuManager(THolder<TActorSystemSetup>& setup) - : ExecutorPoolCount(setup->GetExecutorsCount()) - , Balancer(setup->Balancer) - , Config(setup->CpuManager) - { - if (setup->Executors) { // Explicit mode w/o united pools - Executors.Reset(setup->Executors.Release()); - for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { - IExecutorPool* pool = Executors[excIdx].Get(); - Y_ABORT_UNLESS(dynamic_cast<TUnitedExecutorPool*>(pool) == nullptr, - "united executor pool is prohibited in explicit mode of NActors::TCpuManager"); - } - } else { - Setup(); - } - } - - void TCpuManager::Setup() { - TAffinity available; - available.Current(); - TCpuAllocationConfig allocation(available, Config); - - if (allocation) { - if (!Balancer) { - Balancer.Reset(MakeBalancer(Config.UnitedWorkers.Balancer, Config.United, GetCycleCountFast())); - } - UnitedWorkers.Reset(new TUnitedWorkers(Config.UnitedWorkers, Config.United, allocation, Balancer.Get())); - } - - ui64 ts = GetCycleCountFast(); - Harmonizer.Reset(MakeHarmonizer(ts)); - - Executors.Reset(new TAutoPtr<IExecutorPool>[ExecutorPoolCount]); - - for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { - Executors[excIdx].Reset(CreateExecutorPool(excIdx)); - if (excIdx < Config.PingInfoByPool.size()) { - Harmonizer->AddPool(Executors[excIdx].Get(), &Config.PingInfoByPool[excIdx]); - } else { - Harmonizer->AddPool(Executors[excIdx].Get()); - } - } - } - - void TCpuManager::PrepareStart(TVector<NSchedulerQueue::TReader*>& scheduleReaders, TActorSystem* actorSystem) { - if (UnitedWorkers) { - UnitedWorkers->Prepare(actorSystem, scheduleReaders); - } - for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { - NSchedulerQueue::TReader* readers; - ui32 readersCount = 0; - Executors[excIdx]->Prepare(actorSystem, &readers, &readersCount); - for (ui32 i = 0; i != readersCount; ++i, ++readers) { - scheduleReaders.push_back(readers); - } - } - } - - void TCpuManager::Start() { - if (UnitedWorkers) { - UnitedWorkers->Start(); - } - for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { - Executors[excIdx]->Start(); - } - } - - void TCpuManager::PrepareStop() { - for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { - Executors[excIdx]->PrepareStop(); - } - if (UnitedWorkers) { - UnitedWorkers->PrepareStop(); - } - } - - void TCpuManager::Shutdown() { - for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { - Executors[excIdx]->Shutdown(); - } - if (UnitedWorkers) { - UnitedWorkers->Shutdown(); - } - for (ui32 round = 0, done = 0; done < ExecutorPoolCount && round < 3; ++round) { - done = 0; - for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { - if (Executors[excIdx]->Cleanup()) { - ++done; - } - } - } - } - - void TCpuManager::Cleanup() { - for (ui32 round = 0, done = 0; done < ExecutorPoolCount; ++round) { - Y_ABORT_UNLESS(round < 10, "actorsystem cleanup could not be completed in 10 rounds"); - done = 0; - for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) { - if (Executors[excIdx]->Cleanup()) { - ++done; - } - } - } - Executors.Destroy(); - UnitedWorkers.Destroy(); - } - - IExecutorPool* TCpuManager::CreateExecutorPool(ui32 poolId) { - for (TBasicExecutorPoolConfig& cfg : Config.Basic) { - if (cfg.PoolId == poolId) { - return new TBasicExecutorPool(cfg, Harmonizer.Get()); - } - } - for (TIOExecutorPoolConfig& cfg : Config.IO) { - if (cfg.PoolId == poolId) { - return new TIOExecutorPool(cfg); - } - } - for (TUnitedExecutorPoolConfig& cfg : Config.United) { - if (cfg.PoolId == poolId) { - IExecutorPool* result = new TUnitedExecutorPool(cfg, UnitedWorkers.Get()); - return result; - } - } - Y_ABORT("missing PoolId: %d", int(poolId)); - } - - TVector<IExecutorPool*> TCpuManager::GetBasicExecutorPools() const { - TVector<IExecutorPool*> pools; - for (ui32 idx = 0; idx < ExecutorPoolCount; ++idx) { - if (auto basicPool = dynamic_cast<TBasicExecutorPool*>(Executors[idx].Get()); basicPool != nullptr) { - pools.push_back(basicPool); - } - } - return pools; - } - -} diff --git a/library/cpp/actors/core/cpu_manager.h b/library/cpp/actors/core/cpu_manager.h deleted file mode 100644 index 26ba97aa39..0000000000 --- a/library/cpp/actors/core/cpu_manager.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include "harmonizer.h" -#include "executor_pool.h" -#include "executor_pool_united_workers.h" -#include "balancer.h" - -namespace NActors { - struct TActorSystemSetup; - - class TCpuManager : public TNonCopyable { - const ui32 ExecutorPoolCount; - TArrayHolder<TAutoPtr<IExecutorPool>> Executors; - THolder<TUnitedWorkers> UnitedWorkers; - THolder<IBalancer> Balancer; - THolder<IHarmonizer> Harmonizer; - TCpuManagerConfig Config; - - public: - explicit TCpuManager(THolder<TActorSystemSetup>& setup); - - void Setup(); - void PrepareStart(TVector<NSchedulerQueue::TReader*>& scheduleReaders, TActorSystem* actorSystem); - void Start(); - void PrepareStop(); - void Shutdown(); - void Cleanup(); - - TVector<IExecutorPool*> GetBasicExecutorPools() const; - - ui32 GetExecutorsCount() const { - return ExecutorPoolCount; - } - - IExecutorPool* GetExecutorPool(ui32 poolId) { - return Executors[poolId].Get(); - } - - void GetPoolStats(ui32 poolId, TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const { - if (poolId < ExecutorPoolCount) { - Executors[poolId]->GetCurrentStats(poolStats, statsCopy); - } - } - - THarmonizerStats GetHarmonizerStats() const { - if (Harmonizer) { - return Harmonizer->GetStats(); - } - return {}; - } - - private: - IExecutorPool* CreateExecutorPool(ui32 poolId); - }; -} diff --git a/library/cpp/actors/core/cpu_state.h b/library/cpp/actors/core/cpu_state.h deleted file mode 100644 index 3f779d5623..0000000000 --- a/library/cpp/actors/core/cpu_state.h +++ /dev/null @@ -1,215 +0,0 @@ -#pragma once - -#include "defs.h" - -#include <library/cpp/actors/util/futex.h> - -namespace NActors { - - class alignas(64) TCpuState { - // Atomic cachelign-aligned 64-bit state, see description below - TAtomic State = 0; - char Padding[64 - sizeof(TAtomic)]; - - // Bits 0-31: Currently executing pool - // - value less than MaxPools means cpu is executing corresponding pool (fast-worker is executing or waiting for slow-workers) - // - one of Cpu* values in case of idle cpu - // - used as futex by blocked fast-worker - static constexpr ui64 CurrentBits = 32; - static constexpr ui64 CurrentMask = ui64((1ull << CurrentBits) - 1); - - // Bits 32-63: Assigned pool - // - value is set by balancer - // - NOT used as futex - // - Not balanced - static constexpr ui64 AssignedOffs = 32; - static constexpr ui64 AssignedMask = ~CurrentMask; - - public: - TCpuState() { - Y_UNUSED(Padding); - } - - void Load(TPoolId& assigned, TPoolId& current) const { - TAtomicBase state = AtomicLoad(&State); - assigned = (state & AssignedMask) >> AssignedOffs; - current = state & CurrentMask; - } - - TPoolId CurrentPool() const { - return TPoolId(AtomicLoad(&State) & CurrentMask); - } - - void SwitchPool(TPoolId pool) { - while (true) { - TAtomicBase state = AtomicLoad(&State); - if (AtomicCas(&State, (state & ~CurrentMask) | pool, state)) { - return; - } - } - } - - TPoolId AssignedPool() const { - return TPoolId((AtomicLoad(&State) & AssignedMask) >> AssignedOffs); - } - - // Assigns new pool to cpu and wakes it up if cpu is idle - void AssignPool(TPoolId pool) { - while (true) { - TAtomicBase state = AtomicLoad(&State); - TPoolId current(state & CurrentMask); - if (Y_UNLIKELY(current == CpuStopped)) { - return; // it would be better to shutdown instead of balancing - } - // Idle cpu must be woken up after balancing to handle pending tokens (if any) in assigned/schedulable pool(s) - if (current == CpuSpinning) { - if (AtomicCas(&State, (ui64(pool) << AssignedOffs) | pool, state)) { - return; // successfully woken up - } - } else if (current == CpuBlocked) { - if (AtomicCas(&State, (ui64(pool) << AssignedOffs) | pool, state)) { - FutexWake(); - return; // successfully woken up - } - } else { - if (AtomicCas(&State, (ui64(pool) << AssignedOffs) | (state & ~AssignedMask), state)) { - return; // wakeup is not required - } - } - } - } - - void Stop() { - while (true) { - TAtomicBase state = AtomicLoad(&State); - if (AtomicCas(&State, (state & ~CurrentMask) | CpuStopped, state)) { - FutexWake(); - return; // successfully stopped - } - } - } - - // Start waiting, returns false in case of actorsystem shutdown - bool StartSpinning() { - while (true) { - TAtomicBase state = AtomicLoad(&State); - TPoolId current(state & CurrentMask); - if (Y_UNLIKELY(current == CpuStopped)) { - return false; - } - Y_DEBUG_ABORT_UNLESS(current < MaxPools, "unexpected already waiting state of cpu (%d)", (int)current); - if (AtomicCas(&State, (state & ~CurrentMask) | CpuSpinning, state)) { // successfully marked as spinning - return true; - } - } - } - - bool StartBlocking() { - while (true) { - TAtomicBase state = AtomicLoad(&State); - TPoolId current(state & CurrentMask); - if (current == CpuSpinning) { - if (AtomicCas(&State, (state & ~CurrentMask) | CpuBlocked, state)) { - return false; // successful switch - } - } else { - return true; // wakeup - } - } - } - - bool Block(ui64 timeoutNs, TPoolId& result) { -#ifdef _linux_ - timespec timeout; - timeout.tv_sec = timeoutNs / 1'000'000'000; - timeout.tv_nsec = timeoutNs % 1'000'000'000; - SysFutex(Futex(), FUTEX_WAIT_PRIVATE, CpuBlocked, &timeout, nullptr, 0); -#else - NanoSleep(timeoutNs); // non-linux wake is not supported, cpu will go idle on wake after blocked state -#endif - TAtomicBase state = AtomicLoad(&State); - TPoolId current(state & CurrentMask); - if (current == CpuBlocked) { - return false; // timeout - } else { - result = current; - return true; // wakeup - } - } - - enum EWakeResult { - Woken, // successfully woken up - NotIdle, // cpu is already not idle - Forbidden, // cpu is assigned to another pool - Stopped, // cpu is shutdown - }; - - EWakeResult WakeWithoutToken(TPoolId pool) { - while (true) { - TAtomicBase state = RelaxedLoad(&State); - TPoolId current(state & CurrentMask); - TPoolId assigned((state & AssignedMask) >> AssignedOffs); - if (assigned == CpuShared || assigned == pool) { - if (current == CpuSpinning) { - if (AtomicCas(&State, (state & ~CurrentMask) | pool, state)) { - return Woken; - } - } else if (current == CpuBlocked) { - if (AtomicCas(&State, (state & ~CurrentMask) | pool, state)) { - FutexWake(); - return Woken; - } - } else if (current == CpuStopped) { - return Stopped; - } else { - return NotIdle; - } - } else { - return Forbidden; - } - } - } - - EWakeResult WakeWithTokenAcquired(TPoolId token) { - while (true) { - TAtomicBase state = RelaxedLoad(&State); - TPoolId current(state & CurrentMask); - // NOTE: We ignore assigned value because we already have token, so - // NOTE: not assigned pool may be run here. This will be fixed - // NOTE: after we finish with current activation - if (current == CpuSpinning) { - if (AtomicCas(&State, (state & ~CurrentMask) | token, state)) { - return Woken; - } - } else if (current == CpuBlocked) { - if (AtomicCas(&State, (state & ~CurrentMask) | token, state)) { - FutexWake(); - return Woken; - } - } else if (current == CpuStopped) { - return Stopped; - } else { - return NotIdle; - } - } - } - - bool IsPoolReassigned(TPoolId current) const { - TAtomicBase state = AtomicLoad(&State); - TPoolId assigned((state & AssignedMask) >> AssignedOffs); - return assigned != current; - } - - private: - void* Futex() { - return (void*)&State; // little endian assumed - } - - void FutexWake() { -#ifdef _linux_ - SysFutex(Futex(), FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0); -#endif - } - }; - -} diff --git a/library/cpp/actors/core/defs.h b/library/cpp/actors/core/defs.h deleted file mode 100644 index 64b90e995d..0000000000 --- a/library/cpp/actors/core/defs.h +++ /dev/null @@ -1,77 +0,0 @@ -#pragma once - -// unique tag to fix pragma once gcc glueing: ./library/actorlib/core/defs.h - -#include <library/cpp/actors/util/defs.h> -#include <util/generic/hash.h> -#include <util/string/printf.h> - -// Enables collection of -// event send/receive counts -// activation time histograms -// event processing time histograms -#define ACTORSLIB_COLLECT_EXEC_STATS - -static constexpr bool ActorLibCollectUsageStats = false; - -namespace NActors { - using TPoolId = ui8; - using TPoolsMask = ui64; - static constexpr TPoolId PoolBits = 6; - static constexpr TPoolId MaxPools = (1 << PoolBits) - 1; // maximum amount of pools (poolid=63 is reserved) - static constexpr TPoolsMask WaitPoolsFlag = (1ull << MaxPools); // wait-for-slow-workers flag bitmask - - // Special TPoolId values used by TCpuState - static constexpr TPoolId CpuSpinning = MaxPools; // fast-worker is actively spinning, no slow-workers - static constexpr TPoolId CpuBlocked = MaxPools + 1; // fast-worker is blocked, no slow-workers - static constexpr TPoolId CpuStopped = TPoolId(-1); // special value indicating worker should stop - static constexpr TPoolId CpuShared = MaxPools; // special value for `assigned` meaning balancer disabled, pool scheduler is used instead - - using TPoolWeight = ui16; - static constexpr TPoolWeight MinPoolWeight = 1; - static constexpr TPoolWeight DefPoolWeight = 32; - static constexpr TPoolWeight MaxPoolWeight = 1024; - - using TWorkerId = i16; - static constexpr TWorkerId WorkerBits = 11; - static constexpr TWorkerId MaxWorkers = 1 << WorkerBits; - - using TThreadId = ui64; - static constexpr TThreadId UnknownThreadId = ui64(-1); - - struct TMailboxType { - enum EType { - Inherited = -1, // inherit mailbox from parent - Simple = 0, // simplest queue under producer lock. fastest in no-contention case - Revolving = 1, // somewhat outdated, tries to be wait-free. replaced by ReadAsFilled - HTSwap = 2, // other simple lf queue, suggested for low-contention case - ReadAsFilled = 3, // wait-free queue, suggested for high-contention or latency critical - TinyReadAsFilled = 4, // same as 3 but with lower overhead - //Inplace; - //Direct; - //Virtual - }; - }; - - struct TScopeId : std::pair<ui64, ui64> { - using TBase = std::pair<ui64, ui64>; - using TBase::TBase; - static const TScopeId LocallyGenerated; - }; - - static inline TString ScopeIdToString(const TScopeId& scopeId) { - return Sprintf("<%" PRIu64 ":%" PRIu64 ">", scopeId.first, scopeId.second); - } - - enum class ESendingType { - Common, - Lazy, - Tail, - }; - -} - -template<> -struct hash<NActors::TScopeId> : hash<std::pair<ui64, ui64>> {}; - -class TAffinity; diff --git a/library/cpp/actors/core/event.cpp b/library/cpp/actors/core/event.cpp deleted file mode 100644 index 6ffe42f65b..0000000000 --- a/library/cpp/actors/core/event.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "event.h" -#include "event_pb.h" - -namespace NActors { - - const TScopeId TScopeId::LocallyGenerated{ - Max<ui64>(), Max<ui64>() - }; - - TString IEventHandle::GetTypeName() const { - return HasEvent() ? TypeName(*(const_cast<IEventHandle*>(this)->GetBase())) : TypeName(*this); - } - - TString IEventHandle::ToString() const { - return HasEvent() ? const_cast<IEventHandle*>(this)->GetBase()->ToString().data() : "serialized?"; - } - - std::unique_ptr<IEventHandle> IEventHandle::Forward(std::unique_ptr<IEventHandle>&& ev, TActorId recipient) { - return std::unique_ptr<IEventHandle>(ev->Forward(recipient).Release()); - } - - TIntrusivePtr<TEventSerializedData> IEventHandle::ReleaseChainBuffer() { - if (Buffer) { - TIntrusivePtr<TEventSerializedData> result; - DoSwap(result, Buffer); - Event.Reset(); - return result; - } - if (Event) { - TAllocChunkSerializer serializer; - Event->SerializeToArcadiaStream(&serializer); - auto chainBuf = serializer.Release(Event->CreateSerializationInfo()); - Event.Reset(); - return chainBuf; - } - return new TEventSerializedData; - } - - TIntrusivePtr<TEventSerializedData> IEventHandle::GetChainBuffer() { - if (Buffer) { - return Buffer; - } - if (Event) { - TAllocChunkSerializer serializer; - Event->SerializeToArcadiaStream(&serializer); - Buffer = serializer.Release(Event->CreateSerializationInfo()); - return Buffer; - } - return new TEventSerializedData; - } -} diff --git a/library/cpp/actors/core/event.h b/library/cpp/actors/core/event.h deleted file mode 100644 index 3517dc7a68..0000000000 --- a/library/cpp/actors/core/event.h +++ /dev/null @@ -1,389 +0,0 @@ -#pragma once - -#include "defs.h" -#include "actorid.h" -#include "callstack.h" -#include "event_load.h" - -#include <library/cpp/actors/wilson/wilson_trace.h> - -#include <util/system/hp_timer.h> -#include <util/generic/maybe.h> - -namespace NActors { - class TChunkSerializer; - class IActor; - class ISerializerToStream { - public: - virtual bool SerializeToArcadiaStream(TChunkSerializer*) const = 0; - }; - - class IEventBase - : TNonCopyable, - public ISerializerToStream { - protected: - // for compatibility with virtual actors - virtual bool DoExecute(IActor* /*actor*/, std::unique_ptr<IEventHandle> /*eventPtr*/) { - Y_DEBUG_ABORT_UNLESS(false); - return false; - } - public: - // actual typing is performed by IEventHandle - - virtual ~IEventBase() { - } - - bool Execute(IActor* actor, std::unique_ptr<IEventHandle> eventPtr) { - return DoExecute(actor, std::move(eventPtr)); - } - - virtual TString ToStringHeader() const = 0; - virtual TString ToString() const { - return ToStringHeader(); - } - virtual ui32 CalculateSerializedSize() const { - return 0; - } - virtual ui32 Type() const = 0; - virtual bool SerializeToArcadiaStream(TChunkSerializer*) const = 0; - virtual bool IsSerializable() const = 0; - virtual ui32 CalculateSerializedSizeCached() const { - return CalculateSerializedSize(); - } - virtual TEventSerializationInfo CreateSerializationInfo() const { return {}; } - }; - - // fat handle - class IEventHandle : TNonCopyable { - struct TOnNondelivery { - TActorId Recipient; - - TOnNondelivery(const TActorId& recipient) - : Recipient(recipient) - { - } - }; - - public: - template <typename TEv> - inline TEv* CastAsLocal() const noexcept { - auto fits = GetTypeRewrite() == TEv::EventType; - - return fits ? static_cast<TEv*>(Event.Get()) : nullptr; - } - - template <typename TEventType> - TEventType* Get() { - if (Type != TEventType::EventType) - Y_ABORT("Event type %" PRIu32 " doesn't match the expected type %" PRIu32, Type, TEventType::EventType); - - if (!Event) { - static TEventSerializedData empty; - Event.Reset(TEventType::Load(Buffer ? Buffer.Get() : &empty)); - } - - if (Event) { - return static_cast<TEventType*>(Event.Get()); - } - - Y_ABORT("Failed to Load() event type %" PRIu32 " class %s", Type, TypeName<TEventType>().data()); - } - - template <typename T> - TAutoPtr<T> Release() { - TAutoPtr<T> x = Get<T>(); - Y_UNUSED(Event.Release()); - Buffer.Reset(); - return x; - } - - enum EFlags: ui32 { - FlagTrackDelivery = 1 << 0, - FlagForwardOnNondelivery = 1 << 1, - FlagSubscribeOnSession = 1 << 2, - FlagUseSubChannel = 1 << 3, - FlagGenerateUnsureUndelivered = 1 << 4, - FlagExtendedFormat = 1 << 5, - }; - using TEventFlags = ui32; - - const ui32 Type; - const TEventFlags Flags; - const TActorId Recipient; - TActorId Sender; - const ui64 Cookie; - const TScopeId OriginScopeId = TScopeId::LocallyGenerated; // filled in when the message is received from Interconnect - - // if set, used by ActorSystem/Interconnect to report tracepoints - NWilson::TTraceId TraceId; - - // filled if feeded by interconnect session - const TActorId InterconnectSession; - -#ifdef ACTORSLIB_COLLECT_EXEC_STATS - ::NHPTimer::STime SendTime; -#endif - - static const size_t ChannelBits = 12; - static const size_t ChannelShift = (sizeof(ui32) << 3) - ChannelBits; - -#ifdef USE_ACTOR_CALLSTACK - TCallstack Callstack; -#endif - ui16 GetChannel() const noexcept { - return Flags >> ChannelShift; - } - - ui64 GetSubChannel() const noexcept { - return Flags & FlagUseSubChannel ? Sender.LocalId() : 0ULL; - } - - static ui32 MakeFlags(ui32 channel, TEventFlags flags) { - Y_ABORT_UNLESS(channel < (1 << ChannelBits)); - Y_ABORT_UNLESS(flags < (1 << ChannelShift)); - return (flags | (channel << ChannelShift)); - } - - private: - THolder<IEventBase> Event; - TIntrusivePtr<TEventSerializedData> Buffer; - - TActorId RewriteRecipient; - ui32 RewriteType; - - THolder<TOnNondelivery> OnNondeliveryHolder; // only for local events - - public: - void Rewrite(ui32 typeRewrite, TActorId recipientRewrite) { - RewriteRecipient = recipientRewrite; - RewriteType = typeRewrite; - } - - void DropRewrite() { - RewriteRecipient = Recipient; - RewriteType = Type; - } - - const TActorId& GetRecipientRewrite() const { - return RewriteRecipient; - } - - ui32 GetTypeRewrite() const { - return RewriteType; - } - - TActorId GetForwardOnNondeliveryRecipient() const { - return OnNondeliveryHolder.Get() ? OnNondeliveryHolder->Recipient : TActorId(); - } - - IEventHandle(const TActorId& recipient, const TActorId& sender, IEventBase* ev, TEventFlags flags = 0, ui64 cookie = 0, - const TActorId* forwardOnNondelivery = nullptr, NWilson::TTraceId traceId = {}) - : Type(ev->Type()) - , Flags(flags) - , Recipient(recipient) - , Sender(sender) - , Cookie(cookie) - , TraceId(std::move(traceId)) -#ifdef ACTORSLIB_COLLECT_EXEC_STATS - , SendTime(0) -#endif - , Event(ev) - , RewriteRecipient(Recipient) - , RewriteType(Type) - { - if (forwardOnNondelivery) - OnNondeliveryHolder.Reset(new TOnNondelivery(*forwardOnNondelivery)); - } - - IEventHandle(ui32 type, - TEventFlags flags, - const TActorId& recipient, - const TActorId& sender, - TIntrusivePtr<TEventSerializedData> buffer, - ui64 cookie, - const TActorId* forwardOnNondelivery = nullptr, - NWilson::TTraceId traceId = {}) - : Type(type) - , Flags(flags) - , Recipient(recipient) - , Sender(sender) - , Cookie(cookie) - , TraceId(std::move(traceId)) -#ifdef ACTORSLIB_COLLECT_EXEC_STATS - , SendTime(0) -#endif - , Buffer(std::move(buffer)) - , RewriteRecipient(Recipient) - , RewriteType(Type) - { - if (forwardOnNondelivery) - OnNondeliveryHolder.Reset(new TOnNondelivery(*forwardOnNondelivery)); - } - - // Special ctor for events from interconnect. - IEventHandle(const TActorId& session, - ui32 type, - TEventFlags flags, - const TActorId& recipient, - const TActorId& sender, - TIntrusivePtr<TEventSerializedData> buffer, - ui64 cookie, - TScopeId originScopeId, - NWilson::TTraceId traceId) noexcept - : Type(type) - , Flags(flags) - , Recipient(recipient) - , Sender(sender) - , Cookie(cookie) - , OriginScopeId(originScopeId) - , TraceId(std::move(traceId)) - , InterconnectSession(session) -#ifdef ACTORSLIB_COLLECT_EXEC_STATS - , SendTime(0) -#endif - , Buffer(std::move(buffer)) - , RewriteRecipient(Recipient) - , RewriteType(Type) - { - } - - TIntrusivePtr<TEventSerializedData> GetChainBuffer(); - TIntrusivePtr<TEventSerializedData> ReleaseChainBuffer(); - - ui32 GetSize() const { - if (Buffer) { - return Buffer->GetSize(); - } else if (Event) { - return Event->CalculateSerializedSize(); - } else { - return 0; - } - } - - bool HasBuffer() const { - return bool(Buffer); - } - - bool HasEvent() const { - return bool(Event); - } - - IEventBase* GetBase() { - if (!Event) { - if (!Buffer) - return nullptr; - else - ythrow TWithBackTrace<yexception>() << "don't know how to load the event from buffer"; - } - - return Event.Get(); - } - - TAutoPtr<IEventBase> ReleaseBase() { - TAutoPtr<IEventBase> x = GetBase(); - Y_UNUSED(Event.Release()); - Buffer.Reset(); - return x; - } - - TAutoPtr<IEventHandle> Forward(const TActorId& dest) { - if (Event) - return new IEventHandle(dest, Sender, Event.Release(), Flags, Cookie, nullptr, std::move(TraceId)); - else - return new IEventHandle(Type, Flags, dest, Sender, Buffer, Cookie, nullptr, std::move(TraceId)); - } - - TString GetTypeName() const; - TString ToString() const; - - [[nodiscard]] static std::unique_ptr<IEventHandle> Forward(std::unique_ptr<IEventHandle>&& ev, TActorId recipient); - [[nodiscard]] static std::unique_ptr<IEventHandle> ForwardOnNondelivery(std::unique_ptr<IEventHandle>&& ev, ui32 reason, bool unsure = false); - - [[nodiscard]] static TAutoPtr<IEventHandle> Forward(TAutoPtr<IEventHandle>&& ev, TActorId recipient) { - return Forward(std::unique_ptr<IEventHandle>(ev.Release()), recipient).release(); - } - - [[nodiscard]] static THolder<IEventHandle> Forward(THolder<IEventHandle>&& ev, TActorId recipient) { - return THolder(Forward(std::unique_ptr<IEventHandle>(ev.Release()), recipient).release()); - } - - [[nodiscard]] static TAutoPtr<IEventHandle> ForwardOnNondelivery(TAutoPtr<IEventHandle>&& ev, ui32 reason, bool unsure = false) { - return ForwardOnNondelivery(std::unique_ptr<IEventHandle>(ev.Release()), reason, unsure).release(); - } - - [[nodiscard]] static THolder<IEventHandle> ForwardOnNondelivery(THolder<IEventHandle>&& ev, ui32 reason, bool unsure = false) { - return THolder(ForwardOnNondelivery(std::unique_ptr<IEventHandle>(ev.Release()), reason, unsure).release()); - } - - template<typename T> - static TAutoPtr<T> Release(TAutoPtr<IEventHandle>& ev) { - return ev->Release<T>(); - } - - template<typename T> - static TAutoPtr<T> Release(THolder<IEventHandle>& ev) { - return ev->Release<T>(); - } - - template <typename TEv> - inline TEv* StaticCastAsLocal() const noexcept { // blind cast - return static_cast<TEv*>(Event.Get()); - } - }; - - template <typename TEventType> - class TEventHandle: public IEventHandle { - TEventHandle(); // we never made instance of TEventHandle - public: - TEventType* Get() { - return IEventHandle::Get<TEventType>(); - } - - TAutoPtr<TEventType> Release() { - return IEventHandle::Release<TEventType>(); - } - }; - - static_assert(sizeof(TEventHandle<IEventBase>) == sizeof(IEventHandle), "expect sizeof(TEventHandle<IEventBase>) == sizeof(IEventHandle)"); - - template <typename TEventType, ui32 EventType0> - class TEventBase: public IEventBase { - public: - static constexpr ui32 EventType = EventType0; - ui32 Type() const override { - return EventType0; - } - // still abstract - - typedef TEventHandle<TEventType> THandle; - typedef TAutoPtr<THandle> TPtr; - }; - -#define DEFINE_SIMPLE_LOCAL_EVENT(eventType, header) \ - TString ToStringHeader() const override { \ - return TString(header); \ - } \ - bool SerializeToArcadiaStream(NActors::TChunkSerializer*) const override { \ - Y_ABORT("Local event " #eventType " is not serializable"); \ - } \ - static IEventBase* Load(NActors::TEventSerializedData*) { \ - Y_ABORT("Local event " #eventType " has no load method"); \ - } \ - bool IsSerializable() const override { \ - return false; \ - } - -#define DEFINE_SIMPLE_NONLOCAL_EVENT(eventType, header) \ - TString ToStringHeader() const override { \ - return TString(header); \ - } \ - bool SerializeToArcadiaStream(NActors::TChunkSerializer*) const override { \ - return true; \ - } \ - static IEventBase* Load(NActors::TEventSerializedData*) { \ - return new eventType(); \ - } \ - bool IsSerializable() const override { \ - return true; \ - } -} diff --git a/library/cpp/actors/core/event_load.cpp b/library/cpp/actors/core/event_load.cpp deleted file mode 100644 index 2171678bfb..0000000000 --- a/library/cpp/actors/core/event_load.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "event_load.h" - -namespace NActors { - -} diff --git a/library/cpp/actors/core/event_load.h b/library/cpp/actors/core/event_load.h deleted file mode 100644 index c776026cc4..0000000000 --- a/library/cpp/actors/core/event_load.h +++ /dev/null @@ -1,133 +0,0 @@ -#pragma once - -#include <util/stream/walk.h> -#include <util/system/types.h> -#include <util/generic/string.h> -#include <library/cpp/actors/util/rope.h> -#include <library/cpp/actors/wilson/wilson_trace.h> - -namespace NActors { - class IEventHandle; - - struct TConstIoVec { - const void* Data; - size_t Size; - }; - - struct TIoVec { - void* Data; - size_t Size; - }; - - struct TEventSectionInfo { - size_t Headroom = 0; // headroom to be created on the receiving side - size_t Size = 0; // full size of serialized event section (a chunk in rope) - size_t Tailroom = 0; // tailroom for the chunk - size_t Alignment = 0; // required alignment - bool IsInline = false; // if true, goes through ordinary channel - }; - - struct TEventSerializationInfo { - bool IsExtendedFormat = {}; - std::vector<TEventSectionInfo> Sections; - // total sum of Size for every section must match actual serialized size of the event - }; - - class TEventSerializedData - : public TThrRefBase - { - TRope Rope; - TEventSerializationInfo SerializationInfo; - - public: - TEventSerializedData() = default; - - TEventSerializedData(TRope&& rope, TEventSerializationInfo&& serializationInfo) - : Rope(std::move(rope)) - , SerializationInfo(std::move(serializationInfo)) - {} - - TEventSerializedData(const TEventSerializedData& original, TString extraBuffer) - : Rope(original.Rope) - , SerializationInfo(original.SerializationInfo) - { - if (!SerializationInfo.Sections.empty()) { - SerializationInfo.Sections.push_back(TEventSectionInfo{0, extraBuffer.size(), 0, 0, true}); - } - Append(std::move(extraBuffer)); - } - - TEventSerializedData(TString buffer, TEventSerializationInfo&& serializationInfo) - : SerializationInfo(std::move(serializationInfo)) - { - Append(std::move(buffer)); - } - - void SetSerializationInfo(TEventSerializationInfo&& serializationInfo) { - SerializationInfo = std::move(serializationInfo); - } - - const TEventSerializationInfo& GetSerializationInfo() const { - return SerializationInfo; - } - - TRope::TConstIterator GetBeginIter() const { - return Rope.Begin(); - } - - size_t GetSize() const { - return Rope.GetSize(); - } - - TString GetString() const { - TString result; - result.reserve(GetSize()); - for (auto it = Rope.Begin(); it.Valid(); it.AdvanceToNextContiguousBlock()) { - result.append(it.ContiguousData(), it.ContiguousSize()); - } - return result; - } - - TRope GetRope() const { - return TRope(Rope); - } - - TRope EraseBack(size_t count) { - Y_ABORT_UNLESS(count <= Rope.GetSize()); - TRope::TIterator iter = Rope.End(); - iter -= count; - return Rope.Extract(iter, Rope.End()); - } - - void Append(TRope&& from) { - Rope.Insert(Rope.End(), std::move(from)); - } - - void Append(TString buffer) { - if (buffer) { - Rope.Insert(Rope.End(), TRope(std::move(buffer))); - } - } - }; -} - -class TChainBufWalk : public IWalkInput { - TIntrusivePtr<NActors::TEventSerializedData> Buffer; - TRope::TConstIterator Iter; - -public: - TChainBufWalk(TIntrusivePtr<NActors::TEventSerializedData> buffer) - : Buffer(std::move(buffer)) - , Iter(Buffer->GetBeginIter()) - {} - -private: - size_t DoUnboundedNext(const void **ptr) override { - const size_t size = Iter.ContiguousSize(); - *ptr = Iter.ContiguousData(); - if (Iter.Valid()) { - Iter.AdvanceToNextContiguousBlock(); - } - return size; - } -}; diff --git a/library/cpp/actors/core/event_local.h b/library/cpp/actors/core/event_local.h deleted file mode 100644 index da0f740ba8..0000000000 --- a/library/cpp/actors/core/event_local.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include "event.h" -#include "scheduler_cookie.h" -#include "event_load.h" -#include <util/system/type_name.h> - -namespace NActors { - template <typename TEv, ui32 TEventType> - class TEventLocal: public TEventBase<TEv, TEventType> { - public: - TString ToStringHeader() const override { - return TypeName<TEv>(); - } - - bool SerializeToArcadiaStream(TChunkSerializer* /*serializer*/) const override { - Y_ABORT("Serialization of local event %s type %" PRIu32, TypeName<TEv>().data(), TEventType); - } - - bool IsSerializable() const override { - return false; - } - - static IEventBase* Load(TEventSerializedData*) { - Y_ABORT("Loading of local event %s type %" PRIu32, TypeName<TEv>().data(), TEventType); - } - }; - - template <typename TEv, ui32 TEventType> - class TEventScheduler: public TEventLocal<TEv, TEventType> { - public: - TSchedulerCookieHolder Cookie; - - TEventScheduler(ISchedulerCookie* cookie) - : Cookie(cookie) - { - } - }; - - template <ui32 TEventType> - class TEventSchedulerEv: public TEventScheduler<TEventSchedulerEv<TEventType>, TEventType> { - public: - TEventSchedulerEv(ISchedulerCookie* cookie) - : TEventScheduler<TEventSchedulerEv<TEventType>, TEventType>(cookie) - { - } - }; - - template <typename TEv, ui32 TEventType> - class TEventSimple: public TEventBase<TEv, TEventType> { - public: - TString ToStringHeader() const override { - static TString header(TypeName<TEv>()); - return header; - } - - bool SerializeToArcadiaStream(TChunkSerializer* /*serializer*/) const override { - static_assert(sizeof(TEv) == sizeof(TEventSimple<TEv, TEventType>), "Descendant should be an empty class"); - return true; - } - - bool IsSerializable() const override { - return true; - } - - static IEventBase* Load(NActors::TEventSerializedData*) { - return new TEv(); - } - - static IEventBase* Load(const TString&) { - return new TEv(); - } - }; -} diff --git a/library/cpp/actors/core/event_pb.cpp b/library/cpp/actors/core/event_pb.cpp deleted file mode 100644 index e6a863c44e..0000000000 --- a/library/cpp/actors/core/event_pb.cpp +++ /dev/null @@ -1,224 +0,0 @@ -#include "event_pb.h" - -namespace NActors { - bool TRopeStream::Next(const void** data, int* size) { - *data = Iter.ContiguousData(); - *size = Iter.ContiguousSize(); - if (size_t(*size + TotalByteCount) > Size) { - *size = Size - TotalByteCount; - Iter += *size; - } else if (Iter.Valid()) { - Iter.AdvanceToNextContiguousBlock(); - } - TotalByteCount += *size; - return *size != 0; - } - - void TRopeStream::BackUp(int count) { - Y_ABORT_UNLESS(count <= TotalByteCount); - Iter -= count; - TotalByteCount -= count; - } - - bool TRopeStream::Skip(int count) { - if (static_cast<size_t>(TotalByteCount + count) > Size) { - count = Size - TotalByteCount; - } - Iter += count; - TotalByteCount += count; - return static_cast<size_t>(TotalByteCount) != Size; - } - - TCoroutineChunkSerializer::TCoroutineChunkSerializer() - : TotalSerializedDataSize(0) - , Stack(64 * 1024) - , SelfClosure{this, TArrayRef(Stack.Begin(), Stack.End())} - , InnerContext(SelfClosure) - {} - - TCoroutineChunkSerializer::~TCoroutineChunkSerializer() { - CancelFlag = true; - Resume(); - Y_ABORT_UNLESS(Finished); - } - - bool TCoroutineChunkSerializer::AllowsAliasing() const { - return true; - } - - void TCoroutineChunkSerializer::Produce(const void *data, size_t size) { - Y_ABORT_UNLESS(size <= SizeRemain); - SizeRemain -= size; - TotalSerializedDataSize += size; - - if (!Chunks.empty()) { - auto& last = Chunks.back(); - if (last.first + last.second == data) { - last.second += size; // just extend the last buffer - return; - } - } - - Chunks.emplace_back(static_cast<const char*>(data), size); - } - - bool TCoroutineChunkSerializer::WriteAliasedRaw(const void* data, int size) { - Y_ABORT_UNLESS(!CancelFlag); - Y_ABORT_UNLESS(!AbortFlag); - Y_ABORT_UNLESS(size >= 0); - while (size) { - if (const size_t bytesToAppend = Min<size_t>(size, SizeRemain)) { - const void *produce = data; - if ((reinterpret_cast<uintptr_t>(data) & 63) + bytesToAppend <= 64 && - (Chunks.empty() || data != Chunks.back().first + Chunks.back().second)) { - memcpy(BufferPtr, data, bytesToAppend); - produce = BufferPtr; - BufferPtr += bytesToAppend; - } - Produce(produce, bytesToAppend); - data = static_cast<const char*>(data) + bytesToAppend; - size -= bytesToAppend; - } else { - InnerContext.SwitchTo(BufFeedContext); - if (CancelFlag || AbortFlag) { - return false; - } - } - } - return true; - } - - bool TCoroutineChunkSerializer::Next(void** data, int* size) { - Y_ABORT_UNLESS(!CancelFlag); - Y_ABORT_UNLESS(!AbortFlag); - if (!SizeRemain) { - InnerContext.SwitchTo(BufFeedContext); - if (CancelFlag || AbortFlag) { - return false; - } - } - Y_ABORT_UNLESS(SizeRemain); - *data = BufferPtr; - *size = SizeRemain; - BufferPtr += SizeRemain; - Produce(*data, *size); - return true; - } - - void TCoroutineChunkSerializer::BackUp(int count) { - if (!count) { - return; - } - Y_ABORT_UNLESS(count > 0); - Y_ABORT_UNLESS(!Chunks.empty()); - TChunk& buf = Chunks.back(); - Y_ABORT_UNLESS((size_t)count <= buf.second); - Y_ABORT_UNLESS(buf.first + buf.second == BufferPtr, "buf# %p:%zu BufferPtr# %p SizeRemain# %zu NumChunks# %zu", - buf.first, buf.second, BufferPtr, SizeRemain, Chunks.size()); - buf.second -= count; - if (!buf.second) { - Chunks.pop_back(); - } - BufferPtr -= count; - SizeRemain += count; - TotalSerializedDataSize -= count; - } - - void TCoroutineChunkSerializer::Resume() { - TContMachineContext feedContext; - BufFeedContext = &feedContext; - feedContext.SwitchTo(&InnerContext); - BufFeedContext = nullptr; - } - - bool TCoroutineChunkSerializer::WriteRope(const TRope *rope) { - for (auto iter = rope->Begin(); iter.Valid(); iter.AdvanceToNextContiguousBlock()) { - if (!WriteAliasedRaw(iter.ContiguousData(), iter.ContiguousSize())) { - return false; - } - } - return true; - } - - bool TCoroutineChunkSerializer::WriteString(const TString *s) { - return WriteAliasedRaw(s->data(), s->length()); - } - - std::span<TCoroutineChunkSerializer::TChunk> TCoroutineChunkSerializer::FeedBuf(void* data, size_t size) { - // fill in base params - BufferPtr = static_cast<char*>(data); - SizeRemain = size; - Y_DEBUG_ABORT_UNLESS(size); - - // transfer control to the coroutine - Y_ABORT_UNLESS(Event); - Chunks.clear(); - Resume(); - - return Chunks; - } - - void TCoroutineChunkSerializer::SetSerializingEvent(const IEventBase *event) { - Y_ABORT_UNLESS(Event == nullptr); - Event = event; - TotalSerializedDataSize = 0; - AbortFlag = false; - } - - void TCoroutineChunkSerializer::Abort() { - Y_ABORT_UNLESS(Event); - AbortFlag = true; - Resume(); - } - - void TCoroutineChunkSerializer::DoRun() { - while (!CancelFlag) { - Y_ABORT_UNLESS(Event); - SerializationSuccess = !AbortFlag && Event->SerializeToArcadiaStream(this); - Event = nullptr; - if (!CancelFlag) { // cancel flag may have been received during serialization - InnerContext.SwitchTo(BufFeedContext); - } - } - Finished = true; - InnerContext.SwitchTo(BufFeedContext); - } - - bool TAllocChunkSerializer::Next(void** pdata, int* psize) { - if (Backup) { - // we have some data in backup rope -- move the first chunk from the backup rope to the buffer and return - // pointer to the buffer; it is safe to remove 'const' here as we uniquely own this buffer - TRope::TIterator iter = Backup.Begin(); - *pdata = const_cast<char*>(iter.ContiguousData()); - *psize = iter.ContiguousSize(); - iter.AdvanceToNextContiguousBlock(); - Buffers->Append(Backup.Extract(Backup.Begin(), iter)); - } else { - // no backup buffer, so we have to create new one - auto item = TRopeAlignedBuffer::Allocate(4096); - *pdata = item->GetBuffer(); - *psize = item->GetCapacity(); - Buffers->Append(TRope(std::move(item))); - } - return true; - } - - void TAllocChunkSerializer::BackUp(int count) { - Backup.Insert(Backup.Begin(), Buffers->EraseBack(count)); - } - - bool TAllocChunkSerializer::WriteAliasedRaw(const void*, int) { - Y_ABORT_UNLESS(false); - return false; - } - - bool TAllocChunkSerializer::WriteRope(const TRope *rope) { - Buffers->Append(TRope(*rope)); - return true; - } - - bool TAllocChunkSerializer::WriteString(const TString *s) { - Buffers->Append(*s); - return true; - } -} diff --git a/library/cpp/actors/core/event_pb.h b/library/cpp/actors/core/event_pb.h deleted file mode 100644 index 5fce7c830f..0000000000 --- a/library/cpp/actors/core/event_pb.h +++ /dev/null @@ -1,654 +0,0 @@ -#pragma once - -#include "event.h" -#include "event_load.h" - -#include <google/protobuf/io/zero_copy_stream.h> -#include <google/protobuf/arena.h> -#include <library/cpp/actors/protos/actors.pb.h> -#include <library/cpp/containers/stack_vector/stack_vec.h> -#include <util/generic/deque.h> -#include <util/system/context.h> -#include <util/system/filemap.h> -#include <util/string/builder.h> -#include <util/thread/lfstack.h> -#include <array> -#include <span> - -// enable only when patch with this macro was successfully deployed -#define USE_EXTENDED_PAYLOAD_FORMAT 0 - -namespace NActors { - - class TRopeStream : public NProtoBuf::io::ZeroCopyInputStream { - TRope::TConstIterator Iter; - const size_t Size; - - public: - TRopeStream(TRope::TConstIterator iter, size_t size) - : Iter(iter) - , Size(size) - {} - - bool Next(const void** data, int* size) override; - void BackUp(int count) override; - bool Skip(int count) override; - int64_t ByteCount() const override { - return TotalByteCount; - } - - private: - int64_t TotalByteCount = 0; - }; - - class TChunkSerializer : public NProtoBuf::io::ZeroCopyOutputStream { - public: - TChunkSerializer() = default; - virtual ~TChunkSerializer() = default; - - virtual bool WriteRope(const TRope *rope) = 0; - virtual bool WriteString(const TString *s) = 0; - }; - - class TAllocChunkSerializer final : public TChunkSerializer { - public: - bool Next(void** data, int* size) override; - void BackUp(int count) override; - int64_t ByteCount() const override { - return Buffers->GetSize(); - } - bool WriteAliasedRaw(const void* data, int size) override; - - // WARNING: these methods require owner to retain ownership and immutability of passed objects - bool WriteRope(const TRope *rope) override; - bool WriteString(const TString *s) override; - - inline TIntrusivePtr<TEventSerializedData> Release(TEventSerializationInfo&& serializationInfo) { - Buffers->SetSerializationInfo(std::move(serializationInfo)); - return std::move(Buffers); - } - - protected: - TIntrusivePtr<TEventSerializedData> Buffers = new TEventSerializedData; - TRope Backup; - }; - - class TCoroutineChunkSerializer final : public TChunkSerializer, protected ITrampoLine { - public: - using TChunk = std::pair<const char*, size_t>; - - TCoroutineChunkSerializer(); - ~TCoroutineChunkSerializer(); - - void SetSerializingEvent(const IEventBase *event); - void Abort(); - std::span<TChunk> FeedBuf(void* data, size_t size); - bool IsComplete() const { - return !Event; - } - bool IsSuccessfull() const { - return SerializationSuccess; - } - const IEventBase *GetCurrentEvent() const { - return Event; - } - - bool Next(void** data, int* size) override; - void BackUp(int count) override; - int64_t ByteCount() const override { - return TotalSerializedDataSize; - } - bool WriteAliasedRaw(const void* data, int size) override; - bool AllowsAliasing() const override; - - bool WriteRope(const TRope *rope) override; - bool WriteString(const TString *s) override; - - protected: - void DoRun() override; - void Resume(); - void Produce(const void *data, size_t size); - - i64 TotalSerializedDataSize; - TMappedAllocation Stack; - TContClosure SelfClosure; - TContMachineContext InnerContext; - TContMachineContext *BufFeedContext = nullptr; - char *BufferPtr; - size_t SizeRemain; - std::vector<TChunk> Chunks; - const IEventBase *Event = nullptr; - bool CancelFlag = false; - bool AbortFlag; - bool SerializationSuccess; - bool Finished = false; - }; - - struct TProtoArenaHolder : public TAtomicRefCount<TProtoArenaHolder> { - google::protobuf::Arena Arena; - TProtoArenaHolder() = default; - - explicit TProtoArenaHolder(const google::protobuf::ArenaOptions& arenaOptions) - : Arena(arenaOptions) - {}; - - google::protobuf::Arena* Get() { - return &Arena; - } - - template<typename TRecord> - TRecord* Allocate() { - return google::protobuf::Arena::CreateMessage<TRecord>(&Arena); - } - }; - - static const size_t EventMaxByteSize = 140 << 20; // (140MB) - - template <typename TEv, typename TRecord /*protobuf record*/, ui32 TEventType, typename TRecHolder> - class TEventPBBase: public TEventBase<TEv, TEventType> , public TRecHolder { - // a vector of data buffers referenced by record; if filled, then extended serialization mechanism applies - TVector<TRope> Payload; - size_t TotalPayloadSize = 0; - - public: - using TRecHolder::Record; - - public: - using ProtoRecordType = TRecord; - - TEventPBBase() = default; - - explicit TEventPBBase(const TRecord& rec) - : TRecHolder(rec) - {} - - explicit TEventPBBase(TRecord&& rec) - : TRecHolder(rec) - {} - - explicit TEventPBBase(TIntrusivePtr<TProtoArenaHolder> arena) - : TRecHolder(std::move(arena)) - {} - - TString ToStringHeader() const override { - return Record.GetTypeName(); - } - - TString ToString() const override { - TStringStream ss; - ss << ToStringHeader() << " " << Record.ShortDebugString(); - return ss.Str(); - } - - bool IsSerializable() const override { - return true; - } - - bool SerializeToArcadiaStream(TChunkSerializer* chunker) const override { - return SerializeToArcadiaStreamImpl(chunker, TString()); - } - - ui32 CalculateSerializedSize() const override { - ssize_t result = Record.ByteSize(); - if (result >= 0 && Payload) { - ++result; // marker - char buf[MaxNumberBytes]; - result += SerializeNumber(Payload.size(), buf); - for (const TRope& rope : Payload) { - result += SerializeNumber(rope.GetSize(), buf); - } - result += TotalPayloadSize; - } - return result; - } - - static IEventBase* Load(TEventSerializedData *input) { - THolder<TEventPBBase> ev(new TEv()); - if (!input->GetSize()) { - Y_PROTOBUF_SUPPRESS_NODISCARD ev->Record.ParseFromString(TString()); - } else { - TRope::TConstIterator iter = input->GetBeginIter(); - ui64 size = input->GetSize(); - - if (const auto& info = input->GetSerializationInfo(); info.IsExtendedFormat) { - // check marker - if (!iter.Valid() || (*iter.ContiguousData() != PayloadMarker && *iter.ContiguousData() != ExtendedPayloadMarker)) { - Y_ABORT("invalid event"); - } - - const bool dataIsSeparate = *iter.ContiguousData() == ExtendedPayloadMarker; // ropes go after sizes - - auto fetchRope = [&](size_t len) { - TRope::TConstIterator begin = iter; - iter += len; - size -= len; - ev->Payload.emplace_back(begin, iter); - ev->TotalPayloadSize += len; - }; - - // skip marker - iter += 1; - --size; - // parse number of payload ropes - size_t numRopes = DeserializeNumber(iter, size); - if (numRopes == Max<size_t>()) { - Y_ABORT("invalid event"); - } - TStackVec<size_t, 16> ropeLens; - if (dataIsSeparate) { - ropeLens.reserve(numRopes); - } - while (numRopes--) { - // parse length of the rope - const size_t len = DeserializeNumber(iter, size); - if (len == Max<size_t>() || size < len) { - Y_ABORT("invalid event len# %zu size# %" PRIu64, len, size); - } - // extract the rope - if (dataIsSeparate) { - ropeLens.push_back(len); - } else { - fetchRope(len); - } - } - for (size_t len : ropeLens) { - fetchRope(len); - } - } - - // parse the protobuf - TRopeStream stream(iter, size); - if (!ev->Record.ParseFromZeroCopyStream(&stream)) { - Y_ABORT("Failed to parse protobuf event type %" PRIu32 " class %s", TEventType, TypeName(ev->Record).data()); - } - } - ev->CachedByteSize = input->GetSize(); - return ev.Release(); - } - - size_t GetCachedByteSize() const { - if (CachedByteSize == 0) { - CachedByteSize = CalculateSerializedSize(); - } - return CachedByteSize; - } - - ui32 CalculateSerializedSizeCached() const override { - return GetCachedByteSize(); - } - - void InvalidateCachedByteSize() { - CachedByteSize = 0; - } - - TEventSerializationInfo CreateSerializationInfo() const override { - return CreateSerializationInfoImpl(0); - } - - bool AllowExternalDataChannel() const { - return TotalPayloadSize >= 4096; - } - - public: - void ReservePayload(size_t size) { - Payload.reserve(size); - } - - ui32 AddPayload(TRope&& rope) { - const ui32 id = Payload.size(); - TotalPayloadSize += rope.size(); - Payload.push_back(std::move(rope)); - InvalidateCachedByteSize(); - return id; - } - - const TRope& GetPayload(ui32 id) const { - Y_ABORT_UNLESS(id < Payload.size()); - return Payload[id]; - } - - ui32 GetPayloadCount() const { - return Payload.size(); - } - - void StripPayload() { - Payload.clear(); - TotalPayloadSize = 0; - } - - protected: - TEventSerializationInfo CreateSerializationInfoImpl(size_t preserializedSize) const { - TEventSerializationInfo info; - info.IsExtendedFormat = static_cast<bool>(Payload); - - if (static_cast<const TEv&>(*this).AllowExternalDataChannel()) { - if (Payload) { - char temp[MaxNumberBytes]; -#if USE_EXTENDED_PAYLOAD_FORMAT - size_t headerLen = 1 + SerializeNumber(Payload.size(), temp); - for (const TRope& rope : Payload) { - headerLen += SerializeNumber(rope.size(), temp); - } - info.Sections.push_back(TEventSectionInfo{0, headerLen, 0, 0, true}); - for (const TRope& rope : Payload) { - info.Sections.push_back(TEventSectionInfo{0, rope.size(), 0, 0, false}); - } -#else - info.Sections.push_back(TEventSectionInfo{0, 1 + SerializeNumber(Payload.size(), temp), 0, 0, true}); // payload marker and rope count - for (const TRope& rope : Payload) { - const size_t ropeSize = rope.GetSize(); - info.Sections.back().Size += SerializeNumber(ropeSize, temp); - info.Sections.push_back(TEventSectionInfo{0, ropeSize, 0, 0, false}); // data as a separate section - } -#endif - } - - const size_t byteSize = Max<ssize_t>(0, Record.ByteSize()) + preserializedSize; - info.Sections.push_back(TEventSectionInfo{0, byteSize, 0, 0, true}); // protobuf itself - -#ifndef NDEBUG - size_t total = 0; - for (const auto& section : info.Sections) { - total += section.Size; - } - size_t serialized = CalculateSerializedSize(); - Y_ABORT_UNLESS(total == serialized, "total# %zu serialized# %zu byteSize# %zd Payload.size# %zu", total, - serialized, byteSize, Payload.size()); -#endif - } - - return info; - } - - bool SerializeToArcadiaStreamImpl(TChunkSerializer* chunker, const TString& preserialized) const { - // serialize payload first - if (Payload) { - void *data; - int size = 0; - auto append = [&](const char *p, size_t len) { - while (len) { - if (size) { - const size_t numBytesToCopy = std::min<size_t>(size, len); - memcpy(data, p, numBytesToCopy); - data = static_cast<char*>(data) + numBytesToCopy; - size -= numBytesToCopy; - p += numBytesToCopy; - len -= numBytesToCopy; - } else if (!chunker->Next(&data, &size)) { - return false; - } - } - return true; - }; - auto appendNumber = [&](size_t number) { - char buf[MaxNumberBytes]; - return append(buf, SerializeNumber(number, buf)); - }; - -#if USE_EXTENDED_PAYLOAD_FORMAT - char marker = ExtendedPayloadMarker; - append(&marker, 1); - if (!appendNumber(Payload.size())) { - return false; - } - for (const TRope& rope : Payload) { - if (!appendNumber(rope.GetSize())) { - return false; - } - } - if (size) { - chunker->BackUp(std::exchange(size, 0)); - } - for (const TRope& rope : Payload) { - if (!chunker->WriteRope(&rope)) { - return false; - } - } -#else - char marker = PayloadMarker; - append(&marker, 1); - if (!appendNumber(Payload.size())) { - return false; - } - for (const TRope& rope : Payload) { - if (!appendNumber(rope.GetSize())) { - return false; - } - if (rope) { - if (size) { - chunker->BackUp(std::exchange(size, 0)); - } - if (!chunker->WriteRope(&rope)) { - return false; - } - } - } - if (size) { - chunker->BackUp(size); - } -#endif - } - - if (preserialized && !chunker->WriteString(&preserialized)) { - return false; - } - - return Record.SerializeToZeroCopyStream(chunker); - } - - protected: - mutable size_t CachedByteSize = 0; - - static constexpr char ExtendedPayloadMarker = 0x06; - static constexpr char PayloadMarker = 0x07; - static constexpr size_t MaxNumberBytes = (sizeof(size_t) * CHAR_BIT + 6) / 7; - - static size_t SerializeNumber(size_t num, char *buffer) { - char *begin = buffer; - do { - *buffer++ = (num & 0x7F) | (num >= 128 ? 0x80 : 0x00); - num >>= 7; - } while (num); - return buffer - begin; - } - - static size_t DeserializeNumber(const char **ptr, const char *end) { - const char *p = *ptr; - size_t res = 0; - size_t offset = 0; - for (;;) { - if (p == end) { - return Max<size_t>(); - } - const char byte = *p++; - res |= (static_cast<size_t>(byte) & 0x7F) << offset; - offset += 7; - if (!(byte & 0x80)) { - break; - } - } - *ptr = p; - return res; - } - - static size_t DeserializeNumber(TRope::TConstIterator& iter, ui64& size) { - size_t res = 0; - size_t offset = 0; - for (;;) { - if (!iter.Valid()) { - return Max<size_t>(); - } - const char byte = *iter.ContiguousData(); - iter += 1; - --size; - res |= (static_cast<size_t>(byte) & 0x7F) << offset; - offset += 7; - if (!(byte & 0x80)) { - break; - } - } - return res; - } - }; - - // Protobuf record not using arena - template <typename TRecord> - struct TRecordHolder { - TRecord Record; - - TRecordHolder() = default; - TRecordHolder(const TRecord& rec) - : Record(rec) - {} - - TRecordHolder(TRecord&& rec) - : Record(std::move(rec)) - {} - }; - - // Protobuf arena and a record allocated on it - template <typename TRecord, size_t InitialBlockSize, size_t MaxBlockSize> - struct TArenaRecordHolder { - TIntrusivePtr<TProtoArenaHolder> Arena; - TRecord& Record; - - // Arena depends on block size to be a multiple of 8 for correctness - // FIXME: uncomment these asserts when code is synchronized between repositories - // static_assert((InitialBlockSize & 7) == 0, "Misaligned InitialBlockSize"); - // static_assert((MaxBlockSize & 7) == 0, "Misaligned MaxBlockSize"); - - static const google::protobuf::ArenaOptions GetArenaOptions() { - google::protobuf::ArenaOptions opts; - opts.initial_block_size = InitialBlockSize; - opts.max_block_size = MaxBlockSize; - return opts; - } - - TArenaRecordHolder() - : Arena(MakeIntrusive<TProtoArenaHolder>(GetArenaOptions())) - , Record(*Arena->Allocate<TRecord>()) - {}; - - TArenaRecordHolder(const TRecord& rec) - : TArenaRecordHolder() - { - Record.CopyFrom(rec); - } - - // not allowed to move from another protobuf, it's a potenial copying - TArenaRecordHolder(TRecord&& rec) = delete; - - TArenaRecordHolder(TIntrusivePtr<TProtoArenaHolder> arena) - : Arena(std::move(arena)) - , Record(*Arena->Allocate<TRecord>()) - {}; - }; - - template <typename TEv, typename TRecord, ui32 TEventType> - class TEventPB : public TEventPBBase<TEv, TRecord, TEventType, TRecordHolder<TRecord> > { - typedef TEventPBBase<TEv, TRecord, TEventType, TRecordHolder<TRecord> > TPbBase; - // NOTE: No extra fields allowed: TEventPB must be a "template typedef" - public: - using TPbBase::TPbBase; - }; - - template <typename TEv, typename TRecord, ui32 TEventType, size_t InitialBlockSize = 512, size_t MaxBlockSize = 16*1024> - using TEventPBWithArena = TEventPBBase<TEv, TRecord, TEventType, TArenaRecordHolder<TRecord, InitialBlockSize, MaxBlockSize> >; - - template <typename TEv, typename TRecord, ui32 TEventType> - class TEventShortDebugPB: public TEventPB<TEv, TRecord, TEventType> { - public: - using TBase = TEventPB<TEv, TRecord, TEventType>; - TEventShortDebugPB() = default; - explicit TEventShortDebugPB(const TRecord& rec) - : TBase(rec) - { - } - explicit TEventShortDebugPB(TRecord&& rec) - : TBase(std::move(rec)) - { - } - TString ToString() const override { - return TypeName<TEv>() + " { " + TBase::Record.ShortDebugString() + " }"; - } - }; - - template <typename TEv, typename TRecord, ui32 TEventType> - class TEventPreSerializedPB: public TEventPB<TEv, TRecord, TEventType> { - protected: - using TBase = TEventPB<TEv, TRecord, TEventType>; - using TSelf = TEventPreSerializedPB<TEv, TRecord, TEventType>; - using TBase::Record; - - public: - TString PreSerializedData; // already serialized PB data (using message::SerializeToString) - - TEventPreSerializedPB() = default; - - explicit TEventPreSerializedPB(const TRecord& rec) - : TBase(rec) - { - } - - explicit TEventPreSerializedPB(TRecord&& rec) - : TBase(std::move(rec)) - { - } - - // when remote event received locally this method will merge preserialized data - const TRecord& GetRecord() { - TRecord& base(TBase::Record); - if (!PreSerializedData.empty()) { - TRecord copy; - Y_PROTOBUF_SUPPRESS_NODISCARD copy.ParseFromString(PreSerializedData); - copy.MergeFrom(base); - base.Swap(©); - PreSerializedData.clear(); - } - return TBase::Record; - } - - const TRecord& GetRecord() const { - return const_cast<TSelf*>(this)->GetRecord(); - } - - TRecord* MutableRecord() { - GetRecord(); // Make sure PreSerializedData is parsed - return &(TBase::Record); - } - - TString ToString() const override { - return GetRecord().ShortDebugString(); - } - - bool SerializeToArcadiaStream(TChunkSerializer* chunker) const override { - return TBase::SerializeToArcadiaStreamImpl(chunker, PreSerializedData); - } - - ui32 CalculateSerializedSize() const override { - return PreSerializedData.size() + TBase::CalculateSerializedSize(); - } - - size_t GetCachedByteSize() const { - return PreSerializedData.size() + TBase::GetCachedByteSize(); - } - - ui32 CalculateSerializedSizeCached() const override { - return GetCachedByteSize(); - } - - TEventSerializationInfo CreateSerializationInfo() const override { - return TBase::CreateSerializationInfoImpl(PreSerializedData.size()); - } - }; - - inline TActorId ActorIdFromProto(const NActorsProto::TActorId& actorId) { - return TActorId(actorId.GetRawX1(), actorId.GetRawX2()); - } - - inline void ActorIdToProto(const TActorId& src, NActorsProto::TActorId* dest) { - Y_DEBUG_ABORT_UNLESS(dest); - dest->SetRawX1(src.RawX1()); - dest->SetRawX2(src.RawX2()); - } -} diff --git a/library/cpp/actors/core/event_pb_payload_ut.cpp b/library/cpp/actors/core/event_pb_payload_ut.cpp deleted file mode 100644 index c75169db44..0000000000 --- a/library/cpp/actors/core/event_pb_payload_ut.cpp +++ /dev/null @@ -1,154 +0,0 @@ -#include "event_pb.h" -#include "events.h" - -#include <library/cpp/testing/unittest/registar.h> -#include <library/cpp/actors/protos/unittests.pb.h> - -using namespace NActors; - -enum { - EvMessageWithPayload = EventSpaceBegin(TEvents::ES_PRIVATE), - EvArenaMessage, - EvArenaMessageBig, - EvMessageWithPayloadPreSerialized -}; - -struct TEvMessageWithPayload : TEventPB<TEvMessageWithPayload, TMessageWithPayload, EvMessageWithPayload> { - TEvMessageWithPayload() = default; - explicit TEvMessageWithPayload(const TMessageWithPayload& p) - : TEventPB<TEvMessageWithPayload, TMessageWithPayload, EvMessageWithPayload>(p) - {} -}; - -struct TEvMessageWithPayloadPreSerialized : TEventPreSerializedPB<TEvMessageWithPayloadPreSerialized, TMessageWithPayload, EvMessageWithPayloadPreSerialized> { -}; - - -TRope MakeStringRope(const TString& message) { - return message ? TRope(message) : TRope(); -} - -TString MakeString(size_t len) { - TString res; - for (size_t i = 0; i < len; ++i) { - res += RandomNumber<char>(); - } - return res; -} - -Y_UNIT_TEST_SUITE(TEventProtoWithPayload) { - - template <class TEventFrom, class TEventTo> - void TestSerializeDeserialize(size_t size1, size_t size2) { - static_assert(TEventFrom::EventType == TEventTo::EventType, "Must be same event type"); - - TEventFrom msg; - msg.Record.SetMeta("hello, world!"); - msg.Record.AddPayloadId(msg.AddPayload(MakeStringRope(MakeString(size1)))); - msg.Record.AddPayloadId(msg.AddPayload(MakeStringRope(MakeString(size2)))); - msg.Record.AddSomeData(MakeString((size1 + size2) % 50 + 11)); - - auto serializer = MakeHolder<TAllocChunkSerializer>(); - msg.SerializeToArcadiaStream(serializer.Get()); - auto buffers = serializer->Release(msg.CreateSerializationInfo()); - UNIT_ASSERT_VALUES_EQUAL(buffers->GetSize(), msg.CalculateSerializedSize()); - TString ser = buffers->GetString(); - - TString chunkerRes; - TCoroutineChunkSerializer chunker; - chunker.SetSerializingEvent(&msg); - while (!chunker.IsComplete()) { - char buffer[4096]; - auto range = chunker.FeedBuf(buffer, sizeof(buffer)); - for (auto [data, size] : range) { - chunkerRes += TString(data, size); - } - } - UNIT_ASSERT_VALUES_EQUAL(chunkerRes, ser); - - THolder<IEventBase> ev2 = THolder(TEventTo::Load(buffers.Get())); - TEventTo& msg2 = static_cast<TEventTo&>(*ev2); - UNIT_ASSERT_VALUES_EQUAL(msg2.Record.GetMeta(), msg.Record.GetMeta()); - UNIT_ASSERT_EQUAL(msg2.GetPayload(msg2.Record.GetPayloadId(0)), msg.GetPayload(msg.Record.GetPayloadId(0))); - UNIT_ASSERT_EQUAL(msg2.GetPayload(msg2.Record.GetPayloadId(1)), msg.GetPayload(msg.Record.GetPayloadId(1))); - } - - template <class TEvent> - void TestAllSizes(size_t step1 = 100, size_t step2 = 111) { - for (size_t size1 = 0; size1 < 10000; size1 += step1) { - for (size_t size2 = 0; size2 < 10000; size2 += step2) { - TestSerializeDeserialize<TEvent, TEvent>(size1, size2); - } - } - } - -#if (!defined(_tsan_enabled_)) - Y_UNIT_TEST(SerializeDeserialize) { - TestAllSizes<TEvMessageWithPayload>(); - } -#endif - - - struct TEvArenaMessage : TEventPBWithArena<TEvArenaMessage, TMessageWithPayload, EvArenaMessage> { - }; - - Y_UNIT_TEST(SerializeDeserializeArena) { - TestAllSizes<TEvArenaMessage>(500, 111); - } - - - struct TEvArenaMessageBig : TEventPBWithArena<TEvArenaMessageBig, TMessageWithPayload, EvArenaMessageBig, 4000, 32000> { - }; - - Y_UNIT_TEST(SerializeDeserializeArenaBig) { - TestAllSizes<TEvArenaMessageBig>(111, 500); - } - - - // Compatible with TEvArenaMessage but doesn't use arenas - struct TEvArenaMessageWithoutArena : TEventPB<TEvArenaMessageWithoutArena, TMessageWithPayload, EvArenaMessage> { - }; - - Y_UNIT_TEST(Compatibility) { - TestSerializeDeserialize<TEvArenaMessage, TEvArenaMessageWithoutArena>(200, 14010); - TestSerializeDeserialize<TEvArenaMessageWithoutArena, TEvArenaMessage>(2000, 4010); - } - - Y_UNIT_TEST(PreSerializedCompatibility) { - // ensure TEventPreSerializedPB and TEventPB are interchangable with no compatibility issues - TMessageWithPayload msg; - msg.SetMeta("hello, world!"); - msg.AddPayloadId(123); - msg.AddPayloadId(999); - msg.AddSomeData("abc"); - msg.AddSomeData("xyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"); - - TEvMessageWithPayloadPreSerialized e1; - Y_PROTOBUF_SUPPRESS_NODISCARD msg.SerializeToString(&e1.PreSerializedData); - - auto serializer1 = MakeHolder<TAllocChunkSerializer>(); - e1.SerializeToArcadiaStream(serializer1.Get()); - auto buffers1 = serializer1->Release(e1.CreateSerializationInfo()); - UNIT_ASSERT_VALUES_EQUAL(buffers1->GetSize(), e1.CalculateSerializedSize()); - TString ser1 = buffers1->GetString(); - - TEvMessageWithPayload e2(msg); - auto serializer2 = MakeHolder<TAllocChunkSerializer>(); - e2.SerializeToArcadiaStream(serializer2.Get()); - auto buffers2 = serializer2->Release(e2.CreateSerializationInfo()); - UNIT_ASSERT_VALUES_EQUAL(buffers2->GetSize(), e2.CalculateSerializedSize()); - TString ser2 = buffers2->GetString(); - UNIT_ASSERT_VALUES_EQUAL(ser1, ser2); - - // deserialize - auto data = MakeIntrusive<TEventSerializedData>(ser1, TEventSerializationInfo{}); - THolder<TEvMessageWithPayloadPreSerialized> parsedEvent(static_cast<TEvMessageWithPayloadPreSerialized*>(TEvMessageWithPayloadPreSerialized::Load(data.Get()))); - UNIT_ASSERT_VALUES_EQUAL(parsedEvent->PreSerializedData, ""); // this field is empty after deserialization - auto& record = parsedEvent->GetRecord(); - UNIT_ASSERT_VALUES_EQUAL(record.GetMeta(), msg.GetMeta()); - UNIT_ASSERT_VALUES_EQUAL(record.PayloadIdSize(), msg.PayloadIdSize()); - UNIT_ASSERT_VALUES_EQUAL(record.PayloadIdSize(), 2); - UNIT_ASSERT_VALUES_EQUAL(record.GetPayloadId(0), msg.GetPayloadId(0)); - UNIT_ASSERT_VALUES_EQUAL(record.GetPayloadId(1), msg.GetPayloadId(1)); - } -} diff --git a/library/cpp/actors/core/event_pb_ut.cpp b/library/cpp/actors/core/event_pb_ut.cpp deleted file mode 100644 index 0dfd173651..0000000000 --- a/library/cpp/actors/core/event_pb_ut.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "event_pb.h" - -#include <library/cpp/testing/unittest/registar.h> -#include <library/cpp/actors/protos/unittests.pb.h> - -Y_UNIT_TEST_SUITE(TEventSerialization) { - struct TMockEvent: public NActors::IEventBase { - TBigMessage* msg; - bool - SerializeToArcadiaStream(NActors::TChunkSerializer* chunker) const override { - return msg->SerializeToZeroCopyStream(chunker); - } - bool IsSerializable() const override { - return true; - } - TString ToStringHeader() const override { - return TString(); - } - virtual TString Serialize() const { - return TString(); - } - ui32 Type() const override { - return 0; - }; - }; - - Y_UNIT_TEST(Coroutine) { - TString strA(507, 'a'); - TString strB(814, 'b'); - TString strC(198, 'c'); - - TBigMessage bm; - - TSimple* simple0 = bm.AddSimples(); - simple0->SetStr1(strA); - simple0->SetStr2(strB); - simple0->SetNumber1(213431324); - - TSimple* simple1 = bm.AddSimples(); - simple1->SetStr1(strC); - simple1->SetStr2(strA); - simple1->SetNumber1(21039313); - - bm.AddManyStr(strA); - bm.AddManyStr(strC); - bm.AddManyStr(strB); - - bm.SetOneMoreStr(strB); - bm.SetYANumber(394143); - - TString bmSerialized; - Y_PROTOBUF_SUPPRESS_NODISCARD bm.SerializeToString(&bmSerialized); - UNIT_ASSERT_UNEQUAL(bmSerialized.size(), 0); - - NActors::TCoroutineChunkSerializer chunker; - for (int i = 0; i < 4; ++i) { - TMockEvent event; - event.msg = &bm; - chunker.SetSerializingEvent(&event); - char buf1[87]; - TString bmChunkedSerialized; - while (!chunker.IsComplete()) { - auto range = chunker.FeedBuf(&buf1[0], sizeof(buf1)); - for (auto [data, size] : range) { - bmChunkedSerialized.append(data, size); - } - } - UNIT_ASSERT_EQUAL(bmSerialized, bmChunkedSerialized); - } - } -} diff --git a/library/cpp/actors/core/events.h b/library/cpp/actors/core/events.h deleted file mode 100644 index 911a76d35e..0000000000 --- a/library/cpp/actors/core/events.h +++ /dev/null @@ -1,224 +0,0 @@ -#pragma once - -#include "event.h" -#include "event_pb.h" - -#include <library/cpp/actors/protos/actors.pb.h> -#include <util/system/unaligned_mem.h> - -namespace NActors { - struct TEvents { - enum EEventSpace { - ES_HELLOWORLD = 0, - ES_SYSTEM = 1, - ES_INTERCONNECT = 2, - ES_INTERCONNECT_MSGBUS = 3, - ES_DNS = 4, - ES_SOCKET_POLLER = 5, - ES_LOGGER = 6, - ES_MON = 7, - ES_INTERCONNECT_TCP = 8, - ES_PROFILER = 9, - ES_YF = 10, - ES_HTTP = 11, - ES_PGWIRE = 12, - - ES_USERSPACE = 4096, - - ES_PRIVATE = (1 << 15) - 16, - ES_MAX = (1 << 15), - }; - -#define EventSpaceBegin(eventSpace) (eventSpace << 16u) -#define EventSpaceEnd(eventSpace) ((eventSpace << 16u) + (1u << 16u)) - - struct THelloWorld { - enum { - Start = EventSpaceBegin(ES_HELLOWORLD), - Ping, - Pong, - Blob, - End - }; - - static_assert(End < EventSpaceEnd(ES_HELLOWORLD), "expect End < EventSpaceEnd(ES_HELLOWORLD)"); - }; - - struct TEvPing: public TEventBase<TEvPing, THelloWorld::Ping> { - DEFINE_SIMPLE_NONLOCAL_EVENT(TEvPing, "HelloWorld: Ping"); - }; - - struct TEvPong: public TEventBase<TEvPong, THelloWorld::Pong> { - DEFINE_SIMPLE_NONLOCAL_EVENT(TEvPong, "HelloWorld: Pong"); - }; - - struct TEvBlob: public TEventBase<TEvBlob, THelloWorld::Blob> { - const TString Blob; - - TEvBlob(const TString& blob) noexcept - : Blob(blob) - { - } - - TString ToStringHeader() const noexcept override { - return "THelloWorld::Blob"; - } - - bool SerializeToArcadiaStream(TChunkSerializer *serializer) const override { - return serializer->WriteString(&Blob); - } - - static IEventBase* Load(TEventSerializedData* bufs) noexcept { - return new TEvBlob(bufs->GetString()); - } - - bool IsSerializable() const override { - return true; - } - }; - - struct TSystem { - enum { - Start = EventSpaceBegin(ES_SYSTEM), - Bootstrap, // generic bootstrap event - Wakeup, // generic timeout - Subscribe, // generic subscribe to something - Unsubscribe, // generic unsubscribe from something - Delivered, // event delivered - Undelivered, // event undelivered - Poison, // request actor to shutdown - Completed, // generic async job result event - PoisonTaken, // generic Poison taken (reply to PoisonPill event, i.e. died completely) - FlushLog, - CallbackCompletion, - CallbackException, - Gone, // Generic notification of actor death - TrackActor, - UntrackActor, - InvokeResult, - CoroTimeout, - InvokeQuery, - Wilson, - End, - - // Compatibility section - PoisonPill = Poison, - ActorDied = Gone, - }; - - static_assert(End < EventSpaceEnd(ES_SYSTEM), "expect End < EventSpaceEnd(ES_SYSTEM)"); - }; - - struct TEvBootstrap: public TEventBase<TEvBootstrap, TSystem::Bootstrap> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvBootstrap, "System: TEvBootstrap") - }; - - struct TEvPoison : public TEventBase<TEvPoison, TSystem::Poison> { - DEFINE_SIMPLE_NONLOCAL_EVENT(TEvPoison, "System: TEvPoison") - }; - - struct TEvWakeup: public TEventBase<TEvWakeup, TSystem::Wakeup> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvWakeup, "System: TEvWakeup") - - TEvWakeup(ui64 tag = 0) : Tag(tag) { } - - const ui64 Tag = 0; - }; - - struct TEvSubscribe: public TEventBase<TEvSubscribe, TSystem::Subscribe> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvSubscribe, "System: TEvSubscribe") - }; - - struct TEvUnsubscribe: public TEventBase<TEvUnsubscribe, TSystem::Unsubscribe> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvUnsubscribe, "System: TEvUnsubscribe") - }; - - struct TEvUndelivered: public TEventBase<TEvUndelivered, TSystem::Undelivered> { - enum EReason { - ReasonUnknown, - ReasonActorUnknown, - Disconnected - }; - const ui32 SourceType; - const EReason Reason; - const bool Unsure; - const TString Data; - - TEvUndelivered(ui32 sourceType, ui32 reason, bool unsure = false) - : SourceType(sourceType) - , Reason(static_cast<EReason>(reason)) - , Unsure(unsure) - , Data(MakeData(sourceType, reason)) - {} - - TString ToStringHeader() const override; - bool SerializeToArcadiaStream(TChunkSerializer *serializer) const override; - static IEventBase* Load(TEventSerializedData* bufs); - bool IsSerializable() const override; - - ui32 CalculateSerializedSize() const override { return 2 * sizeof(ui32); } - - static void Out(IOutputStream& o, EReason x); - - private: - static TString MakeData(ui32 sourceType, ui32 reason) { - TString s = TString::Uninitialized(sizeof(ui32) + sizeof(ui32)); - char *p = s.Detach(); - WriteUnaligned<ui32>(p + 0, sourceType); - WriteUnaligned<ui32>(p + 4, reason); - return s; - } - }; - - struct TEvCompleted: public TEventBase<TEvCompleted, TSystem::Completed> { - const ui32 Id; - const ui32 Status; - TEvCompleted(ui32 id = 0, ui32 status = 0) - : Id(id) - , Status(status) - { - } - - DEFINE_SIMPLE_LOCAL_EVENT(TEvCompleted, "System: TEvCompleted") - }; - - struct TEvPoisonTaken: public TEventBase<TEvPoisonTaken, TSystem::PoisonTaken> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvPoisonTaken, "System: TEvPoisonTaken") - }; - - struct TEvFlushLog: public TEventBase<TEvFlushLog, TSystem::FlushLog> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvFlushLog, "System: TEvFlushLog") - }; - - struct TEvCallbackException: public TEventPB<TEvCallbackException, - NActorsProto::TCallbackException, - TSystem::CallbackException> { - TEvCallbackException(const TActorId& id, const TString& msg) { - ActorIdToProto(id, Record.MutableActorId()); - Record.SetExceptionMessage(msg); - } - }; - - struct TEvCallbackCompletion: public TEventPB<TEvCallbackCompletion, - NActorsProto::TActorId, - TSystem::CallbackCompletion> { - TEvCallbackCompletion(const TActorId& id) { - ActorIdToProto(id, &Record); - } - }; - - struct TEvGone: public TEventBase<TEvGone, TSystem::Gone> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvGone, "System: TEvGone") - }; - - struct TEvInvokeResult; - - using TEvPoisonPill = TEvPoison; // Legacy name, deprecated - using TEvActorDied = TEvGone; - }; -} - -template <> -inline void Out<NActors::TEvents::TEvUndelivered::EReason>(IOutputStream& o, NActors::TEvents::TEvUndelivered::EReason x) { - NActors::TEvents::TEvUndelivered::Out(o, x); -} diff --git a/library/cpp/actors/core/events_undelivered.cpp b/library/cpp/actors/core/events_undelivered.cpp deleted file mode 100644 index 7804d5c09d..0000000000 --- a/library/cpp/actors/core/events_undelivered.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "events.h" -#include "actorsystem.h" - -namespace NActors { - TString TEvents::TEvUndelivered::ToStringHeader() const { - return "TSystem::Undelivered"; - } - - bool TEvents::TEvUndelivered::SerializeToArcadiaStream(TChunkSerializer *serializer) const { - Y_ABORT_UNLESS(!Unsure); // these are local-only events generated by Interconnect - return serializer->WriteString(&Data); - } - - void TEvents::TEvUndelivered::Out(IOutputStream& o, EReason x) { - switch (x) { - case ReasonActorUnknown: - o << "ActorUnknown"; - break; - case Disconnected: - o << "Disconnected"; - break; - default: - o << "Undefined"; - break; - } - } - - bool TEvents::TEvUndelivered::IsSerializable() const { - return true; - } - - IEventBase* TEvents::TEvUndelivered::Load(TEventSerializedData* bufs) { - TString str = bufs->GetString(); - Y_ABORT_UNLESS(str.size() == (sizeof(ui32) + sizeof(ui32))); - const char* p = str.data(); - const ui64 sourceType = ReadUnaligned<ui32>(p + 0); - const ui64 reason = ReadUnaligned<ui32>(p + 4); - return new TEvUndelivered(sourceType, reason); - } - - std::unique_ptr<IEventHandle> IEventHandle::ForwardOnNondelivery(std::unique_ptr<IEventHandle>&& ev, ui32 reason, bool unsure) { - if (ev->Flags & FlagForwardOnNondelivery) { - const ui32 updatedFlags = ev->Flags & ~(FlagForwardOnNondelivery | FlagSubscribeOnSession); - const TActorId recp = ev->OnNondeliveryHolder ? ev->OnNondeliveryHolder->Recipient : TActorId(); - - if (ev->Event) - return std::unique_ptr<IEventHandle>(new IEventHandle(recp, ev->Sender, ev->Event.Release(), updatedFlags, ev->Cookie, &ev->Recipient, std::move(ev->TraceId))); - else - return std::unique_ptr<IEventHandle>(new IEventHandle(ev->Type, updatedFlags, recp, ev->Sender, ev->Buffer, ev->Cookie, &ev->Recipient, std::move(ev->TraceId))); - } - - if (ev->Flags & FlagTrackDelivery) { - const ui32 updatedFlags = ev->Flags & ~(FlagTrackDelivery | FlagSubscribeOnSession | FlagGenerateUnsureUndelivered); - return std::unique_ptr<IEventHandle>(new IEventHandle(ev->Sender, ev->Recipient, new TEvents::TEvUndelivered(ev->Type, reason, unsure), updatedFlags, - ev->Cookie, nullptr, std::move(ev->TraceId))); - } - return {}; - } -} diff --git a/library/cpp/actors/core/executelater.h b/library/cpp/actors/core/executelater.h deleted file mode 100644 index 1d5b5fa5a9..0000000000 --- a/library/cpp/actors/core/executelater.h +++ /dev/null @@ -1,86 +0,0 @@ -#pragma once - -#include "actor_bootstrapped.h" - -#include <utility> - -namespace NActors { - template <typename TCallback> - class TExecuteLater: public TActorBootstrapped<TExecuteLater<TCallback>> { - public: - - static constexpr char ActorName[] = "AS_EXECUTE_LATER"; - - TExecuteLater( - TCallback&& callback, - IActor::EActivityType activityType, - ui32 channel = 0, - ui64 cookie = 0, - const TActorId& reportCompletionTo = TActorId(), - const TActorId& reportExceptionTo = TActorId()) noexcept - : Callback(std::move(callback)) - , Channel(channel) - , Cookie(cookie) - , ReportCompletionTo(reportCompletionTo) - , ReportExceptionTo(reportExceptionTo) - { - this->SetActivityType(activityType); - } - - void Bootstrap(const TActorContext& ctx) noexcept { - try { - { - /* RAII, Callback should be destroyed right before sending - TEvCallbackCompletion */ - - auto local = std::move(Callback); - using T = decltype(local); - - if constexpr (std::is_invocable_v<T, const TActorContext&>) { - local(ctx); - } else { - local(); - } - } - - if (ReportCompletionTo) { - ctx.Send(ReportCompletionTo, - new TEvents::TEvCallbackCompletion(ctx.SelfID), - Channel, Cookie); - } - } catch (...) { - if (ReportExceptionTo) { - const TString msg = CurrentExceptionMessage(); - ctx.Send(ReportExceptionTo, - new TEvents::TEvCallbackException(ctx.SelfID, msg), - Channel, Cookie); - } - } - - this->Die(ctx); - } - - private: - TCallback Callback; - const ui32 Channel; - const ui64 Cookie; - const TActorId ReportCompletionTo; - const TActorId ReportExceptionTo; - }; - - template <typename T> - IActor* CreateExecuteLaterActor( - T&& func, - IActor::EActivityType activityType, - ui32 channel = 0, - ui64 cookie = 0, - const TActorId& reportCompletionTo = TActorId(), - const TActorId& reportExceptionTo = TActorId()) noexcept { - return new TExecuteLater<T>(std::forward<T>(func), - activityType, - channel, - cookie, - reportCompletionTo, - reportExceptionTo); - } -} diff --git a/library/cpp/actors/core/executor_pool.h b/library/cpp/actors/core/executor_pool.h deleted file mode 100644 index 5498a6403e..0000000000 --- a/library/cpp/actors/core/executor_pool.h +++ /dev/null @@ -1,154 +0,0 @@ -#pragma once - -#include "event.h" -#include "scheduler_queue.h" - -namespace NActors { - class TActorSystem; - struct TMailboxHeader; - struct TWorkerContext; - struct TExecutorPoolStats; - struct TExecutorThreadStats; - class ISchedulerCookie; - - struct TCpuConsumption { - double ConsumedUs = 0; - double BookedUs = 0; - ui64 NotEnoughCpuExecutions = 0; - - void Add(const TCpuConsumption& other) { - ConsumedUs += other.ConsumedUs; - BookedUs += other.BookedUs; - NotEnoughCpuExecutions += other.NotEnoughCpuExecutions; - } - }; - - class IExecutorPool : TNonCopyable { - public: - const ui32 PoolId; - - TAtomic ActorRegistrations; - TAtomic DestroyedActors; - - IExecutorPool(ui32 poolId) - : PoolId(poolId) - , ActorRegistrations(0) - , DestroyedActors(0) - { - } - - virtual ~IExecutorPool() { - } - - // for workers - virtual void Initialize(TWorkerContext& wctx) { - Y_UNUSED(wctx); - } - virtual ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) = 0; - virtual void ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingCounter) = 0; - virtual TMailboxHeader *ResolveMailbox(ui32 hint) = 0; - - /** - * Schedule one-shot event that will be send at given time point in the future. - * - * @param deadline the wallclock time point in future when event must be send - * @param ev the event to send - * @param cookie cookie that will be piggybacked with event - * @param workerId index of thread which will perform event dispatching - */ - virtual void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) = 0; - - /** - * Schedule one-shot event that will be send at given time point in the future. - * - * @param deadline the monotonic time point in future when event must be send - * @param ev the event to send - * @param cookie cookie that will be piggybacked with event - * @param workerId index of thread which will perform event dispatching - */ - virtual void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) = 0; - - /** - * Schedule one-shot event that will be send after given delay. - * - * @param delta the time from now to delay event sending - * @param ev the event to send - * @param cookie cookie that will be piggybacked with event - * @param workerId index of thread which will perform event dispatching - */ - virtual void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) = 0; - - // for actorsystem - virtual bool Send(TAutoPtr<IEventHandle>& ev) = 0; - virtual bool SpecificSend(TAutoPtr<IEventHandle>& ev) = 0; - virtual void ScheduleActivation(ui32 activation) = 0; - virtual void SpecificScheduleActivation(ui32 activation) = 0; - virtual void ScheduleActivationEx(ui32 activation, ui64 revolvingCounter) = 0; - virtual TActorId Register(IActor* actor, TMailboxType::EType mailboxType, ui64 revolvingCounter, const TActorId& parentId) = 0; - virtual TActorId Register(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId) = 0; - - // lifecycle stuff - virtual void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) = 0; - virtual void Start() = 0; - virtual void PrepareStop() = 0; - virtual void Shutdown() = 0; - virtual bool Cleanup() = 0; - - virtual void GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const { - // TODO: make pure virtual and override everywhere - Y_UNUSED(poolStats); - Y_UNUSED(statsCopy); - } - - virtual TString GetName() const { - return TString(); - } - - virtual ui32 GetThreads() const { - return 1; - } - - virtual i16 GetPriority() const { - return 0; - } - - // generic - virtual TAffinity* Affinity() const = 0; - - virtual void SetRealTimeMode() const {} - - virtual i16 GetThreadCount() const { - return 1; - } - - virtual void SetThreadCount(i16 threads) { - Y_UNUSED(threads); - } - - virtual void SetSpinThresholdCycles(ui32 cycles) { - Y_UNUSED(cycles); - } - - virtual i16 GetBlockingThreadCount() const { - return 0; - } - - virtual i16 GetDefaultThreadCount() const { - return 1; - } - - virtual i16 GetMinThreadCount() const { - return 1; - } - - virtual i16 GetMaxThreadCount() const { - return 1; - } - - virtual TCpuConsumption GetThreadCpuConsumption(i16 threadIdx) { - Y_UNUSED(threadIdx); - return TCpuConsumption{0.0, 0.0}; - } - }; - -} diff --git a/library/cpp/actors/core/executor_pool_base.cpp b/library/cpp/actors/core/executor_pool_base.cpp deleted file mode 100644 index 1c9a536b9b..0000000000 --- a/library/cpp/actors/core/executor_pool_base.cpp +++ /dev/null @@ -1,271 +0,0 @@ -#include "actorsystem.h" -#include "actor.h" -#include "executor_pool_base.h" -#include "executor_pool_basic_feature_flags.h" -#include "executor_thread.h" -#include "mailbox.h" -#include "probes.h" -#include <library/cpp/actors/util/datetime.h> - -namespace NActors { - LWTRACE_USING(ACTORLIB_PROVIDER); - - void DoActorInit(TActorSystem* sys, IActor* actor, const TActorId& self, const TActorId& owner) { - actor->SelfActorId = self; - actor->DoActorInit(); - actor->Registered(sys, owner); - } - - TExecutorPoolBaseMailboxed::TExecutorPoolBaseMailboxed(ui32 poolId) - : IExecutorPool(poolId) - , ActorSystem(nullptr) - , MailboxTable(new TMailboxTable) - {} - - TExecutorPoolBaseMailboxed::~TExecutorPoolBaseMailboxed() { - MailboxTable.Destroy(); - } - -#if defined(ACTORSLIB_COLLECT_EXEC_STATS) - void TExecutorPoolBaseMailboxed::RecalculateStuckActors(TExecutorThreadStats& stats) const { - if (!ActorSystem || !ActorSystem->MonitorStuckActors()) { - return; - } - - const TMonotonic now = ActorSystem->Monotonic(); - - for (auto& u : stats.UsageByActivity) { - u.fill(0); - } - - auto accountUsage = [&](ui32 activityType, double usage) { - Y_ABORT_UNLESS(0 <= usage); - Y_ABORT_UNLESS(usage <= 1); - int bin = Min<int>(9, usage * 10); - ++stats.UsageByActivity[activityType][bin]; - }; - - std::fill(stats.StuckActorsByActivity.begin(), stats.StuckActorsByActivity.end(), 0); - - with_lock (StuckObserverMutex) { - for (size_t i = 0; i < Actors.size(); ++i) { - IActor *actor = Actors[i]; - Y_ABORT_UNLESS(actor->StuckIndex == i); - const TDuration delta = now - actor->LastReceiveTimestamp; - if (delta > TDuration::Seconds(30)) { - ++stats.StuckActorsByActivity[actor->GetActivityType()]; - } - accountUsage(actor->GetActivityType(), actor->GetUsage(GetCycleCountFast())); - } - for (const auto& [activityType, usage] : DeadActorsUsage) { - accountUsage(activityType, usage); - } - DeadActorsUsage.clear(); - } - } -#endif - - TExecutorPoolBase::TExecutorPoolBase(ui32 poolId, ui32 threads, TAffinity* affinity) - : TExecutorPoolBaseMailboxed(poolId) - , PoolThreads(threads) - , ThreadsAffinity(affinity) - {} - - TExecutorPoolBase::~TExecutorPoolBase() { - while (Activations.Pop(0)) - ; - } - - void TExecutorPoolBaseMailboxed::ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingWriteCounter) { - Y_UNUSED(workerId); - MailboxTable->ReclaimMailbox(mailboxType, hint, revolvingWriteCounter); - } - - TMailboxHeader *TExecutorPoolBaseMailboxed::ResolveMailbox(ui32 hint) { - return MailboxTable->Get(hint); - } - - ui64 TExecutorPoolBaseMailboxed::AllocateID() { - return ActorSystem->AllocateIDSpace(1); - } - - bool TExecutorPoolBaseMailboxed::Send(TAutoPtr<IEventHandle>& ev) { - Y_DEBUG_ABORT_UNLESS(ev->GetRecipientRewrite().PoolID() == PoolId); -#ifdef ACTORSLIB_COLLECT_EXEC_STATS - RelaxedStore(&ev->SendTime, (::NHPTimer::STime)GetCycleCountFast()); -#endif - if (TlsThreadContext) { - TlsThreadContext->IsCurrentRecipientAService = ev->Recipient.IsService(); - } - return MailboxTable->SendTo(ev, this); - } - - bool TExecutorPoolBaseMailboxed::SpecificSend(TAutoPtr<IEventHandle>& ev) { - Y_DEBUG_ABORT_UNLESS(ev->GetRecipientRewrite().PoolID() == PoolId); -#ifdef ACTORSLIB_COLLECT_EXEC_STATS - RelaxedStore(&ev->SendTime, (::NHPTimer::STime)GetCycleCountFast()); -#endif - if (TlsThreadContext) { - TlsThreadContext->IsCurrentRecipientAService = ev->Recipient.IsService(); - } - return MailboxTable->SpecificSendTo(ev, this); - } - - void TExecutorPoolBase::ScheduleActivation(ui32 activation) { - ScheduleActivationEx(activation, AtomicIncrement(ActivationsRevolvingCounter)); - } - - Y_FORCE_INLINE bool IsAllowedToCapture(IExecutorPool *self) { - if (TlsThreadContext->Pool != self || TlsThreadContext->CapturedType == ESendingType::Tail) { - return false; - } - return TlsThreadContext->SendingType != ESendingType::Common; - } - - Y_FORCE_INLINE bool IsTailSend(IExecutorPool *self) { - return TlsThreadContext->Pool == self && TlsThreadContext->SendingType == ESendingType::Tail && TlsThreadContext->CapturedType != ESendingType::Tail; - } - - void TExecutorPoolBase::SpecificScheduleActivation(ui32 activation) { - if (NFeatures::IsCommon() && IsAllowedToCapture(this) || IsTailSend(this)) { - std::swap(TlsThreadContext->CapturedActivation, activation); - TlsThreadContext->CapturedType = TlsThreadContext->SendingType; - } - if (activation) { - ScheduleActivationEx(activation, AtomicIncrement(ActivationsRevolvingCounter)); - } - } - - TActorId TExecutorPoolBaseMailboxed::Register(IActor* actor, TMailboxType::EType mailboxType, ui64 revolvingWriteCounter, const TActorId& parentId) { - NHPTimer::STime hpstart = GetCycleCountFast(); -#ifdef ACTORSLIB_COLLECT_EXEC_STATS - ui32 at = actor->GetActivityType(); - Y_DEBUG_ABORT_UNLESS(at < Stats.ActorsAliveByActivity.size()); - if (at >= Stats.MaxActivityType()) { - at = TActorTypeOperator::GetActorActivityIncorrectIndex(); - Y_ABORT_UNLESS(at < Stats.ActorsAliveByActivity.size()); - } - AtomicIncrement(Stats.ActorsAliveByActivity[at]); -#endif - AtomicIncrement(ActorRegistrations); - - // first step - find good enough mailbox - ui32 hint = 0; - TMailboxHeader* mailbox = nullptr; - - if (revolvingWriteCounter == 0) - revolvingWriteCounter = AtomicIncrement(RegisterRevolvingCounter); - - { - ui32 hintBackoff = 0; - - while (hint == 0) { - hint = MailboxTable->AllocateMailbox(mailboxType, ++revolvingWriteCounter); - mailbox = MailboxTable->Get(hint); - - if (!mailbox->LockFromFree()) { - MailboxTable->ReclaimMailbox(mailboxType, hintBackoff, ++revolvingWriteCounter); - hintBackoff = hint; - hint = 0; - } - } - - MailboxTable->ReclaimMailbox(mailboxType, hintBackoff, ++revolvingWriteCounter); - } - - const ui64 localActorId = AllocateID(); - - // ok, got mailbox - mailbox->AttachActor(localActorId, actor); - - // do init - const TActorId actorId(ActorSystem->NodeId, PoolId, localActorId, hint); - DoActorInit(ActorSystem, actor, actorId, parentId); - -#ifdef ACTORSLIB_COLLECT_EXEC_STATS - if (ActorSystem->MonitorStuckActors()) { - with_lock (StuckObserverMutex) { - Y_ABORT_UNLESS(actor->StuckIndex == Max<size_t>()); - actor->StuckIndex = Actors.size(); - Actors.push_back(actor); - } - } -#endif - - // Once we unlock the mailbox the actor starts running and we cannot use the pointer any more - actor = nullptr; - - switch (mailboxType) { - case TMailboxType::Simple: - UnlockFromExecution((TMailboxTable::TSimpleMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); - break; - case TMailboxType::Revolving: - UnlockFromExecution((TMailboxTable::TRevolvingMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); - break; - case TMailboxType::HTSwap: - UnlockFromExecution((TMailboxTable::THTSwapMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); - break; - case TMailboxType::ReadAsFilled: - UnlockFromExecution((TMailboxTable::TReadAsFilledMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); - break; - case TMailboxType::TinyReadAsFilled: - UnlockFromExecution((TMailboxTable::TTinyReadAsFilledMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter); - break; - default: - Y_ABORT(); - } - - NHPTimer::STime elapsed = GetCycleCountFast() - hpstart; - if (elapsed > 1000000) { - LWPROBE(SlowRegisterNew, PoolId, NHPTimer::GetSeconds(elapsed) * 1000.0); - } - - return actorId; - } - - TActorId TExecutorPoolBaseMailboxed::Register(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId) { - NHPTimer::STime hpstart = GetCycleCountFast(); -#ifdef ACTORSLIB_COLLECT_EXEC_STATS - ui32 at = actor->GetActivityType(); - if (at >= Stats.MaxActivityType()) - at = 0; - AtomicIncrement(Stats.ActorsAliveByActivity[at]); -#endif - AtomicIncrement(ActorRegistrations); - - const ui64 localActorId = AllocateID(); - mailbox->AttachActor(localActorId, actor); - - const TActorId actorId(ActorSystem->NodeId, PoolId, localActorId, hint); - DoActorInit(ActorSystem, actor, actorId, parentId); - -#ifdef ACTORSLIB_COLLECT_EXEC_STATS - if (ActorSystem->MonitorStuckActors()) { - with_lock (StuckObserverMutex) { - Y_ABORT_UNLESS(actor->StuckIndex == Max<size_t>()); - actor->StuckIndex = Actors.size(); - Actors.push_back(actor); - } - } -#endif - - NHPTimer::STime elapsed = GetCycleCountFast() - hpstart; - if (elapsed > 1000000) { - LWPROBE(SlowRegisterAdd, PoolId, NHPTimer::GetSeconds(elapsed) * 1000.0); - } - - return actorId; - } - - TAffinity* TExecutorPoolBase::Affinity() const { - return ThreadsAffinity.Get(); - } - - bool TExecutorPoolBaseMailboxed::Cleanup() { - return MailboxTable->Cleanup(); - } - - ui32 TExecutorPoolBase::GetThreads() const { - return PoolThreads; - } -} diff --git a/library/cpp/actors/core/executor_pool_base.h b/library/cpp/actors/core/executor_pool_base.h deleted file mode 100644 index 6bfabb527f..0000000000 --- a/library/cpp/actors/core/executor_pool_base.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include "executor_pool.h" -#include "executor_thread.h" -#include "mon_stats.h" -#include "scheduler_queue.h" -#include <library/cpp/actors/util/affinity.h> -#include <library/cpp/actors/util/unordered_cache.h> -#include <library/cpp/actors/util/threadparkpad.h> - -namespace NActors { - class TActorSystem; - - class TExecutorPoolBaseMailboxed: public IExecutorPool { - protected: - TActorSystem* ActorSystem; - THolder<TMailboxTable> MailboxTable; -#ifdef ACTORSLIB_COLLECT_EXEC_STATS - // Need to have per pool object to collect stats like actor registrations (because - // registrations might be done in threads from other pools) - TExecutorThreadStats Stats; - - // Stuck actor monitoring - TMutex StuckObserverMutex; - std::vector<IActor*> Actors; - mutable std::vector<std::tuple<ui32, double>> DeadActorsUsage; - friend class TExecutorThread; - void RecalculateStuckActors(TExecutorThreadStats& stats) const; -#endif - TAtomic RegisterRevolvingCounter = 0; - ui64 AllocateID(); - public: - explicit TExecutorPoolBaseMailboxed(ui32 poolId); - ~TExecutorPoolBaseMailboxed(); - void ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingWriteCounter) override; - TMailboxHeader *ResolveMailbox(ui32 hint) override; - bool Send(TAutoPtr<IEventHandle>& ev) override; - bool SpecificSend(TAutoPtr<IEventHandle>& ev) override; - TActorId Register(IActor* actor, TMailboxType::EType mailboxType, ui64 revolvingWriteCounter, const TActorId& parentId) override; - TActorId Register(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId) override; - bool Cleanup() override; - }; - - class TExecutorPoolBase: public TExecutorPoolBaseMailboxed { - protected: - const i16 PoolThreads; - TIntrusivePtr<TAffinity> ThreadsAffinity; - TAtomic Semaphore = 0; - TUnorderedCache<ui32, 512, 4> Activations; - TAtomic ActivationsRevolvingCounter = 0; - volatile bool StopFlag = false; - public: - TExecutorPoolBase(ui32 poolId, ui32 threads, TAffinity* affinity); - ~TExecutorPoolBase(); - void ScheduleActivation(ui32 activation) override; - void SpecificScheduleActivation(ui32 activation) override; - TAffinity* Affinity() const override; - ui32 GetThreads() const override; - }; - - void DoActorInit(TActorSystem*, IActor*, const TActorId&, const TActorId&); -} diff --git a/library/cpp/actors/core/executor_pool_basic.cpp b/library/cpp/actors/core/executor_pool_basic.cpp deleted file mode 100644 index 4a9019e26d..0000000000 --- a/library/cpp/actors/core/executor_pool_basic.cpp +++ /dev/null @@ -1,749 +0,0 @@ -#include "executor_pool_basic.h" -#include "executor_pool_basic_feature_flags.h" -#include "actor.h" -#include "probes.h" -#include "mailbox.h" -#include <library/cpp/actors/util/affinity.h> -#include <library/cpp/actors/util/datetime.h> - -#ifdef _linux_ -#include <pthread.h> -#endif - -namespace NActors { - LWTRACE_USING(ACTORLIB_PROVIDER); - - - const double TWaitingStatsConstants::HistogramResolutionUs = MaxSpinThersholdUs / BucketCount; - const ui64 TWaitingStatsConstants::HistogramResolution = NHPTimer::GetCyclesPerSecond() * 0.000001 * HistogramResolutionUs; - - constexpr TDuration TBasicExecutorPool::DEFAULT_TIME_PER_MAILBOX; - - TBasicExecutorPool::TBasicExecutorPool( - ui32 poolId, - ui32 threads, - ui64 spinThreshold, - const TString& poolName, - IHarmonizer *harmonizer, - TAffinity* affinity, - TDuration timePerMailbox, - ui32 eventsPerMailbox, - int realtimePriority, - ui32 maxActivityType, - i16 minThreadCount, - i16 maxThreadCount, - i16 defaultThreadCount, - i16 priority) - : TExecutorPoolBase(poolId, threads, affinity) - , DefaultSpinThresholdCycles(spinThreshold * NHPTimer::GetCyclesPerSecond() * 0.000001) // convert microseconds to cycles - , SpinThresholdCycles(DefaultSpinThresholdCycles) - , SpinThresholdCyclesPerThread(new NThreading::TPadded<std::atomic<ui64>>[threads]) - , Threads(new NThreading::TPadded<TThreadCtx>[threads]) - , WaitingStats(new TWaitingStats<ui64>[threads]) - , PoolName(poolName) - , TimePerMailbox(timePerMailbox) - , EventsPerMailbox(eventsPerMailbox) - , RealtimePriority(realtimePriority) - , ThreadUtilization(0) - , MaxUtilizationCounter(0) - , MaxUtilizationAccumulator(0) - , WrongWakenedThreadCount(0) - , ThreadCount(threads) - , MinThreadCount(minThreadCount) - , MaxThreadCount(maxThreadCount) - , DefaultThreadCount(defaultThreadCount) - , Harmonizer(harmonizer) - , Priority(priority) - { - if constexpr (NFeatures::IsLocalQueues()) { - LocalQueues.Reset(new NThreading::TPadded<std::queue<ui32>>[threads]); - if constexpr (NFeatures::TLocalQueuesFeatureFlags::FIXED_LOCAL_QUEUE_SIZE) { - LocalQueueSize = *NFeatures::TLocalQueuesFeatureFlags::FIXED_LOCAL_QUEUE_SIZE; - } else { - LocalQueueSize = NFeatures::TLocalQueuesFeatureFlags::MIN_LOCAL_QUEUE_SIZE; - } - } - if constexpr (NFeatures::TSpinFeatureFlags::CalcPerThread) { - for (ui32 idx = 0; idx < threads; ++idx) { - SpinThresholdCyclesPerThread[idx].store(0); - } - } - if constexpr (NFeatures::TSpinFeatureFlags::UsePseudoMovingWindow) { - MovingWaitingStats.Reset(new TWaitingStats<double>[threads]); - } - - Y_UNUSED(maxActivityType); - i16 limit = Min(threads, (ui32)Max<i16>()); - if (DefaultThreadCount) { - DefaultThreadCount = Min(DefaultThreadCount, limit); - } else { - DefaultThreadCount = limit; - } - - MaxThreadCount = Min(Max(MaxThreadCount, DefaultThreadCount), limit); - - if (MinThreadCount) { - MinThreadCount = Max((i16)1, Min(MinThreadCount, DefaultThreadCount)); - } else { - MinThreadCount = DefaultThreadCount; - } - ThreadCount = MaxThreadCount; - auto semaphore = TSemaphore(); - semaphore.CurrentThreadCount = ThreadCount; - Semaphore = semaphore.ConverToI64(); - } - - TBasicExecutorPool::TBasicExecutorPool(const TBasicExecutorPoolConfig& cfg, IHarmonizer *harmonizer) - : TBasicExecutorPool( - cfg.PoolId, - cfg.Threads, - cfg.SpinThreshold, - cfg.PoolName, - harmonizer, - new TAffinity(cfg.Affinity), - cfg.TimePerMailbox, - cfg.EventsPerMailbox, - cfg.RealtimePriority, - 0, - cfg.MinThreadCount, - cfg.MaxThreadCount, - cfg.DefaultThreadCount, - cfg.Priority - ) - { - SetSharedExecutorsCount(cfg.SharedExecutorsCount); - SoftProcessingDurationTs = cfg.SoftProcessingDurationTs; - ActorSystemProfile = cfg.ActorSystemProfile; - } - - TBasicExecutorPool::~TBasicExecutorPool() { - Threads.Destroy(); - } - - bool TBasicExecutorPool::GoToSleep(TThreadCtx& threadCtx, TTimers &timers) { - do { - timers.HPNow = GetCycleCountFast(); - timers.Elapsed += timers.HPNow - timers.HPStart; - if (threadCtx.WaitingPad.Park()) // interrupted - return true; - timers.HPStart = GetCycleCountFast(); - timers.Parked += timers.HPStart - timers.HPNow; - } while (AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_BLOCKED && !RelaxedLoad(&StopFlag)); - return false; - } - - ui32 TBasicExecutorPool::GoToSpin(TThreadCtx& threadCtx, i64 start, i64 &end) { - ui32 spinPauseCount = 0; - i64 spinThresholdCycles = 0; - if constexpr (NFeatures::TSpinFeatureFlags::CalcPerThread) { - spinThresholdCycles = SpinThresholdCyclesPerThread[TlsThreadContext->WorkerId].load(); - } else { - spinThresholdCycles = SpinThresholdCycles.load(); - } - do { - end = GetCycleCountFast(); - if (end >= (start + spinThresholdCycles) || AtomicLoad(&threadCtx.WaitingFlag) != TThreadCtx::WS_ACTIVE) { - return spinPauseCount; - } - - SpinLockPause(); - spinPauseCount++; - } while (!RelaxedLoad(&StopFlag)); - - return spinPauseCount; - } - - bool TBasicExecutorPool::GoToWaiting(TThreadCtx& threadCtx, TTimers &timers, bool needToBlock) { -#if defined ACTORSLIB_COLLECT_EXEC_STATS - if (AtomicGetAndIncrement(ThreadUtilization) == 0) { - // Initially counter contains -t0, the pool start timestamp - // When the first thread goes to sleep we add t1, so the counter - // becomes t1-t0 >= 0, or the duration of max utilization so far. - // If the counter was negative and becomes positive, that means - // counter just turned into a duration and we should store that - // duration. Otherwise another thread raced with us and - // subtracted some other timestamp t2. - const i64 t = GetCycleCountFast(); - const i64 x = AtomicGetAndAdd(MaxUtilizationCounter, t); - if (x < 0 && x + t > 0) - AtomicStore(&MaxUtilizationAccumulator, x + t); - } -#endif - - i64 startWaiting = GetCycleCountFast(); - i64 endSpinning = 0; - TAtomic state = AtomicLoad(&threadCtx.WaitingFlag); - bool wasSleeping = false; - Y_ABORT_UNLESS(state == TThreadCtx::WS_NONE, "WaitingFlag# %d", int(state)); - - if (SpinThresholdCycles > 0 && !needToBlock) { - // spin configured period - AtomicSet(threadCtx.WaitingFlag, TThreadCtx::WS_ACTIVE); - ui32 spinPauseCount = GoToSpin(threadCtx, startWaiting, endSpinning); - SpinningTimeUs += endSpinning - startWaiting; - // then - sleep - if (AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_ACTIVE) { - if (AtomicCas(&threadCtx.WaitingFlag, TThreadCtx::WS_BLOCKED, TThreadCtx::WS_ACTIVE)) { - if (NFeatures::TCommonFeatureFlags::ProbeSpinCycles) { - LWPROBE(SpinCycles, PoolId, PoolName, spinPauseCount, true); - } - - wasSleeping = true; - if (GoToSleep(threadCtx, timers)) { // interrupted - return true; - } - AllThreadsSleep.store(false); - } - } - if (NFeatures::TCommonFeatureFlags::ProbeSpinCycles && !wasSleeping) { - LWPROBE(SpinCycles, PoolId, PoolName, spinPauseCount, false); - } - } else { - AtomicSet(threadCtx.WaitingFlag, TThreadCtx::WS_BLOCKED); - wasSleeping = true; - if (GoToSleep(threadCtx, timers)) { // interrupted - return true; - } - AllThreadsSleep.store(false); - } - - i64 needTimeTs = threadCtx.StartWakingTs.exchange(0); - if (wasSleeping && needTimeTs) { - ui64 waitingDuration = std::max<i64>(0, needTimeTs - startWaiting); - ui64 awakingDuration = std::max<i64>(0, GetCycleCountFast() - needTimeTs); - WaitingStats[TlsThreadContext->WorkerId].AddAwakening(waitingDuration, awakingDuration); - } else { - ui64 waitingDuration = std::max<i64>(0, endSpinning - startWaiting); - if (wasSleeping) { - WaitingStats[TlsThreadContext->WorkerId].AddFastAwakening(waitingDuration); - } else { - WaitingStats[TlsThreadContext->WorkerId].Add(waitingDuration); - } - } - - Y_DEBUG_ABORT_UNLESS(AtomicLoad(&StopFlag) || AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_NONE); - -#if defined ACTORSLIB_COLLECT_EXEC_STATS - if (AtomicDecrement(ThreadUtilization) == 0) { - // When we started sleeping counter contained t1-t0, or the - // last duration of max utilization. Now we subtract t2 >= t1, - // which turns counter negative again, and the next sleep cycle - // at timestamp t3 would be adding some new duration t3-t2. - // If the counter was positive and becomes negative that means - // there are no current races with other threads and we should - // store the last positive duration we observed. Multiple - // threads may be adding and subtracting values in potentially - // arbitrary order, which would cause counter to oscillate - // around zero. When it crosses zero is a good indication of a - // correct value. - const i64 t = GetCycleCountFast(); - const i64 x = AtomicGetAndAdd(MaxUtilizationCounter, -t); - if (x > 0 && x - t < 0) - AtomicStore(&MaxUtilizationAccumulator, x); - } -#endif - return false; - } - - void TBasicExecutorPool::AskToGoToSleep(bool *needToWait, bool *needToBlock) { - TAtomic x = AtomicGet(Semaphore); - do { - i64 oldX = x; - TSemaphore semaphore = TSemaphore::GetSemaphore(x);; - if (semaphore.CurrentSleepThreadCount < 0) { - semaphore.CurrentSleepThreadCount++; - x = AtomicGetAndCas(&Semaphore, semaphore.ConverToI64(), x); - if (x == oldX) { - *needToWait = true; - *needToBlock = true; - return; - } - continue; - } - - if (semaphore.OldSemaphore == 0) { - semaphore.CurrentSleepThreadCount++; - if (semaphore.CurrentSleepThreadCount == AtomicLoad(&ThreadCount)) { - AllThreadsSleep.store(true); - } - x = AtomicGetAndCas(&Semaphore, semaphore.ConverToI64(), x); - if (x == oldX) { - *needToWait = true; - *needToBlock = false; - return; - } - continue; - } - - *needToWait = false; - *needToBlock = false; - return; - } while (true); - } - - ui32 TBasicExecutorPool::GetReadyActivationCommon(TWorkerContext& wctx, ui64 revolvingCounter) { - TWorkerId workerId = wctx.WorkerId; - Y_DEBUG_ABORT_UNLESS(workerId < PoolThreads); - - TTimers timers; - - if (Harmonizer) { - LWPROBE(TryToHarmonize, PoolId, PoolName); - Harmonizer->Harmonize(timers.HPStart); - } - - if (workerId >= 0) { - AtomicSet(Threads[workerId].WaitingFlag, TThreadCtx::WS_NONE); - } - - TAtomic x = AtomicGet(Semaphore); - TSemaphore semaphore = TSemaphore::GetSemaphore(x); - while (!RelaxedLoad(&StopFlag)) { - if (!semaphore.OldSemaphore || semaphore.CurrentSleepThreadCount < 0) { - if (workerId < 0 || !wctx.IsNeededToWaitNextActivation) { - timers.HPNow = GetCycleCountFast(); - wctx.AddElapsedCycles(ActorSystemIndex, timers.HPNow - timers.HPStart); - return 0; - } - - bool needToWait = false; - bool needToBlock = false; - AskToGoToSleep(&needToWait, &needToBlock); - if (needToWait) { - if (GoToWaiting(Threads[workerId], timers, needToBlock)) { // interrupted - return 0; - } - } - } else { - if (const ui32 activation = Activations.Pop(++revolvingCounter)) { - if (workerId >= 0) { - AtomicSet(Threads[workerId].WaitingFlag, TThreadCtx::WS_RUNNING); - } - AtomicDecrement(Semaphore); - timers.HPNow = GetCycleCountFast(); - timers.Elapsed += timers.HPNow - timers.HPStart; - wctx.AddElapsedCycles(ActorSystemIndex, timers.Elapsed); - if (timers.Parked > 0) { - wctx.AddParkedCycles(timers.Parked); - } - - return activation; - } - semaphore.CurrentSleepThreadCount++; - } - - SpinLockPause(); - x = AtomicGet(Semaphore); - semaphore = TSemaphore::GetSemaphore(x); - } - - return 0; - } - - ui32 TBasicExecutorPool::GetReadyActivationLocalQueue(TWorkerContext& wctx, ui64 revolvingCounter) { - TWorkerId workerId = wctx.WorkerId; - Y_DEBUG_ABORT_UNLESS(workerId < static_cast<i32>(PoolThreads)); - - if (workerId >= 0 && LocalQueues[workerId].size()) { - ui32 activation = LocalQueues[workerId].front(); - LocalQueues[workerId].pop(); - return activation; - } else { - TlsThreadContext->WriteTurn = 0; - TlsThreadContext->LocalQueueSize = LocalQueueSize.load(std::memory_order_relaxed); - } - return GetReadyActivationCommon(wctx, revolvingCounter); - } - - ui32 TBasicExecutorPool::GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) { - if constexpr (NFeatures::IsLocalQueues()) { - if (SharedExecutorsCount) { - return GetReadyActivationCommon(wctx, revolvingCounter); - } - return GetReadyActivationLocalQueue(wctx, revolvingCounter); - } else { - return GetReadyActivationCommon(wctx, revolvingCounter); - } - return 0; - } - - inline void TBasicExecutorPool::WakeUpLoop(i16 currentThreadCount) { - if (AllThreadsSleep) { - TThreadCtx& hotThreadCtx = Threads[0]; - if (AtomicCas(&hotThreadCtx.WaitingFlag, TThreadCtx::WS_NONE, TThreadCtx::WS_ACTIVE)) { - return; - } - - TThreadCtx& coldThreadCtx = Threads[AtomicLoad(&ThreadCount) - 1]; - if (AtomicCas(&coldThreadCtx.WaitingFlag, TThreadCtx::WS_NONE, TThreadCtx::WS_BLOCKED)) { - if (TlsThreadContext && TlsThreadContext->WaitingStats) { - ui64 beforeUnpark = GetCycleCountFast(); - coldThreadCtx.StartWakingTs = beforeUnpark; - coldThreadCtx.WaitingPad.Unpark(); - TlsThreadContext->WaitingStats->AddWakingUp(GetCycleCountFast() - beforeUnpark); - } else { - coldThreadCtx.WaitingPad.Unpark(); - } - return; - } - } - for (i16 i = 0;;) { - TThreadCtx& threadCtx = Threads[i]; - TThreadCtx::EWaitState state = static_cast<TThreadCtx::EWaitState>(AtomicLoad(&threadCtx.WaitingFlag)); - switch (state) { - case TThreadCtx::WS_NONE: - case TThreadCtx::WS_RUNNING: - if (++i >= MaxThreadCount - SharedExecutorsCount) { - i = 0; - } - break; - case TThreadCtx::WS_ACTIVE: - case TThreadCtx::WS_BLOCKED: - if (AtomicCas(&threadCtx.WaitingFlag, TThreadCtx::WS_NONE, state)) { - if (state == TThreadCtx::WS_BLOCKED) { - ui64 beforeUnpark = GetCycleCountFast(); - threadCtx.StartWakingTs = beforeUnpark; - if (TlsThreadContext && TlsThreadContext->WaitingStats) { - threadCtx.WaitingPad.Unpark(); - TlsThreadContext->WaitingStats->AddWakingUp(GetCycleCountFast() - beforeUnpark); - } else { - threadCtx.WaitingPad.Unpark(); - } - } - if (i >= currentThreadCount) { - AtomicIncrement(WrongWakenedThreadCount); - } - return; - } - break; - default: - Y_ABORT(); - } - } - } - - void TBasicExecutorPool::ScheduleActivationExCommon(ui32 activation, ui64 revolvingCounter, TAtomic x) { - TSemaphore semaphore = TSemaphore::GetSemaphore(x); - - Activations.Push(activation, revolvingCounter); - bool needToWakeUp = false; - - do { - needToWakeUp = semaphore.CurrentSleepThreadCount > SharedExecutorsCount; - i64 oldX = semaphore.ConverToI64(); - semaphore.OldSemaphore++; - if (needToWakeUp) { - semaphore.CurrentSleepThreadCount--; - } - x = AtomicGetAndCas(&Semaphore, semaphore.ConverToI64(), oldX); - if (x == oldX) { - break; - } - semaphore = TSemaphore::GetSemaphore(x); - } while (true); - - if (needToWakeUp) { // we must find someone to wake-up - WakeUpLoop(semaphore.CurrentThreadCount); - } - } - - void TBasicExecutorPool::ScheduleActivationExLocalQueue(ui32 activation, ui64 revolvingWriteCounter) { - if (TlsThreadContext && TlsThreadContext->Pool == this && TlsThreadContext->WorkerId >= 0) { - if (++TlsThreadContext->WriteTurn < TlsThreadContext->LocalQueueSize) { - LocalQueues[TlsThreadContext->WorkerId].push(activation); - return; - } - if (ActorSystemProfile != EASProfile::Default) { - TAtomic x = AtomicGet(Semaphore); - TSemaphore semaphore = TSemaphore::GetSemaphore(x); - if constexpr (NFeatures::TLocalQueuesFeatureFlags::UseIfAllOtherThreadsAreSleeping) { - if (semaphore.CurrentSleepThreadCount == semaphore.CurrentThreadCount - 1 && semaphore.OldSemaphore == 0) { - if (LocalQueues[TlsThreadContext->WorkerId].empty()) { - LocalQueues[TlsThreadContext->WorkerId].push(activation); - return; - } - } - } - - if constexpr (NFeatures::TLocalQueuesFeatureFlags::UseOnMicroburst) { - if (semaphore.OldSemaphore >= semaphore.CurrentThreadCount) { - if (LocalQueues[TlsThreadContext->WorkerId].empty() && TlsThreadContext->WriteTurn < 1) { - TlsThreadContext->WriteTurn++; - LocalQueues[TlsThreadContext->WorkerId].push(activation); - return; - } - } - } - ScheduleActivationExCommon(activation, revolvingWriteCounter, x); - return; - } - } - ScheduleActivationExCommon(activation, revolvingWriteCounter, AtomicGet(Semaphore)); - } - - void TBasicExecutorPool::ScheduleActivationEx(ui32 activation, ui64 revolvingCounter) { - if constexpr (NFeatures::IsLocalQueues()) { - ScheduleActivationExLocalQueue(activation, revolvingCounter); - } else { - ScheduleActivationExCommon(activation, revolvingCounter, AtomicGet(Semaphore)); - } - } - - void TBasicExecutorPool::GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const { - poolStats.MaxUtilizationTime = RelaxedLoad(&MaxUtilizationAccumulator) / (i64)(NHPTimer::GetCyclesPerSecond() / 1000); - poolStats.WrongWakenedThreadCount = RelaxedLoad(&WrongWakenedThreadCount); - poolStats.CurrentThreadCount = RelaxedLoad(&ThreadCount); - poolStats.DefaultThreadCount = DefaultThreadCount; - poolStats.MaxThreadCount = MaxThreadCount; - poolStats.SpinningTimeUs = Ts2Us(SpinningTimeUs); - poolStats.SpinThresholdUs = Ts2Us(SpinThresholdCycles); - if (Harmonizer) { - TPoolHarmonizerStats stats = Harmonizer->GetPoolStats(PoolId); - poolStats.IsNeedy = stats.IsNeedy; - poolStats.IsStarved = stats.IsStarved; - poolStats.IsHoggish = stats.IsHoggish; - poolStats.IncreasingThreadsByNeedyState = stats.IncreasingThreadsByNeedyState; - poolStats.IncreasingThreadsByExchange = stats.IncreasingThreadsByExchange; - poolStats.DecreasingThreadsByStarvedState = stats.DecreasingThreadsByStarvedState; - poolStats.DecreasingThreadsByHoggishState = stats.DecreasingThreadsByHoggishState; - poolStats.DecreasingThreadsByExchange = stats.DecreasingThreadsByExchange; - poolStats.PotentialMaxThreadCount = stats.PotentialMaxThreadCount; - poolStats.MaxConsumedCpuUs = stats.MaxConsumedCpu; - poolStats.MinConsumedCpuUs = stats.MinConsumedCpu; - poolStats.MaxBookedCpuUs = stats.MaxBookedCpu; - poolStats.MinBookedCpuUs = stats.MinBookedCpu; - } - - statsCopy.resize(PoolThreads + 1); - // Save counters from the pool object - statsCopy[0] = TExecutorThreadStats(); - statsCopy[0].Aggregate(Stats); -#if defined(ACTORSLIB_COLLECT_EXEC_STATS) - RecalculateStuckActors(statsCopy[0]); -#endif - // Per-thread stats - for (i16 i = 0; i < PoolThreads; ++i) { - Threads[i].Thread->GetCurrentStats(statsCopy[i + 1]); - } - } - - void TBasicExecutorPool::Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) { - TAffinityGuard affinityGuard(Affinity()); - - ActorSystem = actorSystem; - - ScheduleReaders.Reset(new NSchedulerQueue::TReader[PoolThreads]); - ScheduleWriters.Reset(new NSchedulerQueue::TWriter[PoolThreads]); - - for (i16 i = 0; i != PoolThreads; ++i) { - if (i < MaxThreadCount - SharedExecutorsCount) { - Threads[i].Thread.Reset( - new TExecutorThread( - i, - 0, // CpuId is not used in BASIC pool - actorSystem, - this, - MailboxTable.Get(), - PoolName, - TimePerMailbox, - EventsPerMailbox)); - } else { - Threads[i].Thread.Reset( - new TExecutorThread( - i, - actorSystem, - actorSystem->GetBasicExecutorPools(), - PoolName, - SoftProcessingDurationTs, - TimePerMailbox, - EventsPerMailbox)); - } - ScheduleWriters[i].Init(ScheduleReaders[i]); - } - - *scheduleReaders = ScheduleReaders.Get(); - *scheduleSz = PoolThreads; - } - - void TBasicExecutorPool::Start() { - TAffinityGuard affinityGuard(Affinity()); - - ThreadUtilization = 0; - AtomicAdd(MaxUtilizationCounter, -(i64)GetCycleCountFast()); - - for (i16 i = 0; i != PoolThreads; ++i) { - Threads[i].Thread->Start(); - } - } - - void TBasicExecutorPool::PrepareStop() { - AtomicStore(&StopFlag, true); - for (i16 i = 0; i != PoolThreads; ++i) { - Threads[i].Thread->StopFlag = true; - Threads[i].WaitingPad.Interrupt(); - } - } - - void TBasicExecutorPool::Shutdown() { - for (i16 i = 0; i != PoolThreads; ++i) - Threads[i].Thread->Join(); - } - - void TBasicExecutorPool::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { - Y_DEBUG_ABORT_UNLESS(workerId < PoolThreads); - - Schedule(deadline - ActorSystem->Timestamp(), ev, cookie, workerId); - } - - void TBasicExecutorPool::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { - Y_DEBUG_ABORT_UNLESS(workerId < PoolThreads); - - const auto current = ActorSystem->Monotonic(); - if (deadline < current) - deadline = current; - - ScheduleWriters[workerId].Push(deadline.MicroSeconds(), ev.Release(), cookie); - } - - void TBasicExecutorPool::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { - Y_DEBUG_ABORT_UNLESS(workerId < PoolThreads); - - const auto deadline = ActorSystem->Monotonic() + delta; - ScheduleWriters[workerId].Push(deadline.MicroSeconds(), ev.Release(), cookie); - } - - void TBasicExecutorPool::SetRealTimeMode() const { -// TODO: musl-libc version of `sched_param` struct is for some reason different from pthread -// version in Ubuntu 12.04 -#if defined(_linux_) && !defined(_musl_) - if (RealtimePriority != 0) { - pthread_t threadSelf = pthread_self(); - sched_param param = {RealtimePriority}; - if (pthread_setschedparam(threadSelf, SCHED_FIFO, ¶m)) { - Y_ABORT("Cannot set realtime priority"); - } - } -#else - Y_UNUSED(RealtimePriority); -#endif - } - - i16 TBasicExecutorPool::GetThreadCount() const { - return AtomicGet(ThreadCount); - } - - void TBasicExecutorPool::SetThreadCount(i16 threads) { - threads = Max(i16(1), Min(PoolThreads, threads)); - with_lock (ChangeThreadsLock) { - i16 prevCount = GetThreadCount(); - AtomicSet(ThreadCount, threads); - TSemaphore semaphore = TSemaphore::GetSemaphore(AtomicGet(Semaphore)); - i64 oldX = semaphore.ConverToI64(); - semaphore.CurrentThreadCount = threads; - if (threads > prevCount) { - semaphore.CurrentSleepThreadCount += (i64)threads - prevCount; - } else { - semaphore.CurrentSleepThreadCount -= (i64)prevCount - threads; - } - AtomicAdd(Semaphore, semaphore.ConverToI64() - oldX); - LWPROBE(ThreadCount, PoolId, PoolName, threads, MinThreadCount, MaxThreadCount, DefaultThreadCount); - } - } - - i16 TBasicExecutorPool::GetDefaultThreadCount() const { - return DefaultThreadCount; - } - - i16 TBasicExecutorPool::GetMinThreadCount() const { - return MinThreadCount; - } - - i16 TBasicExecutorPool::GetMaxThreadCount() const { - return MaxThreadCount; - } - - TCpuConsumption TBasicExecutorPool::GetThreadCpuConsumption(i16 threadIdx) { - if (threadIdx >= PoolThreads) { - return {0.0, 0.0}; - } - TThreadCtx& threadCtx = Threads[threadIdx]; - TExecutorThreadStats stats; - threadCtx.Thread->GetCurrentStats(stats); - return {Ts2Us(stats.SafeElapsedTicks), static_cast<double>(stats.CpuUs), stats.NotEnoughCpuExecutions}; - } - - i16 TBasicExecutorPool::GetBlockingThreadCount() const { - TAtomic x = AtomicGet(Semaphore); - TSemaphore semaphore = TSemaphore::GetSemaphore(x); - return -Min<i16>(semaphore.CurrentSleepThreadCount, 0); - } - - i16 TBasicExecutorPool::GetPriority() const { - return Priority; - } - - void TBasicExecutorPool::SetSharedExecutorsCount(i16 count) { - SharedExecutorsCount = count; - } - - void TBasicExecutorPool::SetLocalQueueSize(ui16 size) { - if constexpr (!NFeatures::TLocalQueuesFeatureFlags::FIXED_LOCAL_QUEUE_SIZE) { - LocalQueueSize.store(std::max(size, NFeatures::TLocalQueuesFeatureFlags::MAX_LOCAL_QUEUE_SIZE), std::memory_order_relaxed); - } - } - - void TBasicExecutorPool::Initialize(TWorkerContext& wctx) { - if (wctx.WorkerId >= 0) { - TlsThreadContext->WaitingStats = &WaitingStats[wctx.WorkerId]; - } - } - - void TBasicExecutorPool::SetSpinThresholdCycles(ui32 cycles) { - if (ActorSystemProfile == EASProfile::LowLatency) { - if (DefaultSpinThresholdCycles > cycles) { - cycles = DefaultSpinThresholdCycles; - } - } - SpinThresholdCycles = cycles; - double resolutionUs = TWaitingStatsConstants::HistogramResolutionUs; - ui32 bucketIdx = cycles / TWaitingStatsConstants::HistogramResolution; - LWPROBE(ChangeSpinThreshold, PoolId, PoolName, cycles, resolutionUs * bucketIdx, bucketIdx); - } - - void TBasicExecutorPool::GetWaitingStats(TWaitingStats<ui64> &acc) const { - acc.Clear(); - double resolutionUs = TWaitingStatsConstants::HistogramResolutionUs; - for (ui32 idx = 0; idx < ThreadCount; ++idx) { - for (ui32 bucketIdx = 0; bucketIdx < TWaitingStatsConstants::BucketCount; ++bucketIdx) { - LWPROBE(WaitingHistogramPerThread, PoolId, PoolName, idx, resolutionUs * bucketIdx, resolutionUs * (bucketIdx + 1), WaitingStats[idx].WaitingUntilNeedsTimeHist[bucketIdx].load()); - } - acc.Add(WaitingStats[idx]); - } - for (ui32 bucketIdx = 0; bucketIdx < TWaitingStatsConstants::BucketCount; ++bucketIdx) { - LWPROBE(WaitingHistogram, PoolId, PoolName, resolutionUs * bucketIdx, resolutionUs * (bucketIdx + 1), acc.WaitingUntilNeedsTimeHist[bucketIdx].load()); - } - } - - void TBasicExecutorPool::ClearWaitingStats() const { - for (ui32 idx = 0; idx < ThreadCount; ++idx) { - WaitingStats[idx].Clear(); - } - } - - void TBasicExecutorPool::CalcSpinPerThread(ui64 wakingUpConsumption) { - for (i16 threadIdx = 0; threadIdx < PoolThreads; ++threadIdx) { - ui64 newSpinThreshold = 0; - if constexpr (NFeatures::TSpinFeatureFlags::UsePseudoMovingWindow) { - MovingWaitingStats[threadIdx].Add(WaitingStats[threadIdx], 0.8, 0.2); - newSpinThreshold = MovingWaitingStats[threadIdx].CalculateGoodSpinThresholdCycles(wakingUpConsumption); - } else { - newSpinThreshold = WaitingStats[threadIdx].CalculateGoodSpinThresholdCycles(wakingUpConsumption); - } - SpinThresholdCyclesPerThread[threadIdx].store(newSpinThreshold); - - double resolutionUs = TWaitingStatsConstants::HistogramResolutionUs; - ui32 bucketIdx = newSpinThreshold / TWaitingStatsConstants::HistogramResolution; - LWPROBE(ChangeSpinThresholdPerThread, PoolId, PoolName, threadIdx, newSpinThreshold, resolutionUs * bucketIdx, bucketIdx); - } - } -} diff --git a/library/cpp/actors/core/executor_pool_basic.h b/library/cpp/actors/core/executor_pool_basic.h deleted file mode 100644 index d1a4c9fd27..0000000000 --- a/library/cpp/actors/core/executor_pool_basic.h +++ /dev/null @@ -1,291 +0,0 @@ -#pragma once - -#include "actorsystem.h" -#include "executor_thread.h" -#include "executor_pool_basic_feature_flags.h" -#include "scheduler_queue.h" -#include "executor_pool_base.h" -#include "harmonizer.h" -#include <library/cpp/actors/actor_type/indexes.h> -#include <library/cpp/actors/util/unordered_cache.h> -#include <library/cpp/actors/util/threadparkpad.h> -#include <library/cpp/monlib/dynamic_counters/counters.h> - -#include <library/cpp/threading/chunk_queue/queue.h> - -#include <util/system/mutex.h> - -#include <queue> - -namespace NActors { - - struct TWaitingStatsConstants { - static constexpr ui64 BucketCount = 128; - static constexpr double MaxSpinThersholdUs = 12.8; - - static constexpr ui64 KnownAvgWakingUpTime = 4250; - static constexpr ui64 KnownAvgAwakeningTime = 7000; - - static const double HistogramResolutionUs; - static const ui64 HistogramResolution; - }; - - template <typename T> - struct TWaitingStats : TWaitingStatsConstants { - std::array<std::atomic<T>, BucketCount> WaitingUntilNeedsTimeHist; - - std::atomic<T> WakingUpTotalTime; - std::atomic<T> WakingUpCount; - std::atomic<T> AwakingTotalTime; - std::atomic<T> AwakingCount; - - TWaitingStats() - { - Clear(); - } - - void Clear() { - std::fill(WaitingUntilNeedsTimeHist.begin(), WaitingUntilNeedsTimeHist.end(), 0); - WakingUpTotalTime = 0; - WakingUpCount = 0; - AwakingTotalTime = 0; - AwakingCount = 0; - } - - void Add(ui64 waitingUntilNeedsTime) { - ui64 waitIdx = std::min(waitingUntilNeedsTime / HistogramResolution, BucketCount - 1); - WaitingUntilNeedsTimeHist[waitIdx]++; - } - - void AddAwakening(ui64 waitingUntilNeedsTime, ui64 awakingTime) { - Add(waitingUntilNeedsTime); - AwakingTotalTime += awakingTime; - AwakingCount++; - } - - void AddFastAwakening(ui64 waitingUntilNeedsTime) { - Add(waitingUntilNeedsTime - HistogramResolution); - } - - void AddWakingUp(ui64 wakingUpTime) { - WakingUpTotalTime += wakingUpTime; - WakingUpCount++; - } - - void Add(const TWaitingStats<T> &stats) { - for (ui32 idx = 0; idx < BucketCount; ++idx) { - WaitingUntilNeedsTimeHist[idx] += stats.WaitingUntilNeedsTimeHist[idx]; - } - WakingUpTotalTime += stats.WakingUpTotalTime; - WakingUpCount += stats.WakingUpCount; - AwakingTotalTime += stats.AwakingTotalTime; - AwakingCount += stats.AwakingCount; - } - - template <typename T2> - void Add(const TWaitingStats<T2> &stats, double oldK, double newK) { - for (ui32 idx = 0; idx < BucketCount; ++idx) { - WaitingUntilNeedsTimeHist[idx] = oldK * WaitingUntilNeedsTimeHist[idx] + newK * stats.WaitingUntilNeedsTimeHist[idx]; - } - WakingUpTotalTime = oldK * WakingUpTotalTime + newK * stats.WakingUpTotalTime; - WakingUpCount = oldK * WakingUpCount + newK * stats.WakingUpCount; - AwakingTotalTime = oldK * AwakingTotalTime + newK * stats.AwakingTotalTime; - AwakingCount = oldK * AwakingCount + newK * stats.AwakingCount; - } - - ui32 CalculateGoodSpinThresholdCycles(ui64 avgWakingUpConsumption) { - auto &bucketCount = TWaitingStatsConstants::BucketCount; - auto &resolution = TWaitingStatsConstants::HistogramResolution; - - T waitingsCount = std::accumulate(WaitingUntilNeedsTimeHist.begin(), WaitingUntilNeedsTimeHist.end(), 0); - - ui32 bestBucketIdx = 0; - T bestCpuConsumption = Max<T>(); - - T spinTime = 0; - T spinCount = 0; - - for (ui32 bucketIdx = 0; bucketIdx < bucketCount; ++bucketIdx) { - auto &bucket = WaitingUntilNeedsTimeHist[bucketIdx]; - ui64 imaginarySpingThreshold = resolution * bucketIdx; - T cpuConsumption = spinTime + (waitingsCount - spinCount) * (avgWakingUpConsumption + imaginarySpingThreshold); - if (bestCpuConsumption > cpuConsumption) { - bestCpuConsumption = cpuConsumption; - bestBucketIdx = bucketIdx; - } - spinTime += (2 * imaginarySpingThreshold + resolution) * bucket / 2; - spinCount += bucket; - // LWPROBE(WaitingHistogram, Pool->PoolId, Pool->GetName(), resolutionUs * bucketIdx, resolutionUs * (bucketIdx + 1), bucket); - } - ui64 result = resolution * bestBucketIdx; - return result; - } - }; - - class TBasicExecutorPool: public TExecutorPoolBase { - struct TThreadCtx { - TAutoPtr<TExecutorThread> Thread; - TThreadParkPad WaitingPad; - TAtomic WaitingFlag; - std::atomic<i64> StartWakingTs; - std::atomic<i64> EndWakingTs; - - enum EWaitState { - WS_NONE, - WS_ACTIVE, - WS_BLOCKED, - WS_RUNNING - }; - - TThreadCtx() - : WaitingFlag(WS_NONE) - { - } - }; - - struct TTimers { - NHPTimer::STime Elapsed = 0; - NHPTimer::STime Parked = 0; - NHPTimer::STime HPStart = GetCycleCountFast(); - NHPTimer::STime HPNow; - }; - - NThreading::TPadded<std::atomic_bool> AllThreadsSleep = true; - const ui64 DefaultSpinThresholdCycles; - std::atomic<ui64> SpinThresholdCycles; - std::unique_ptr<NThreading::TPadded< std::atomic<ui64>>[]> SpinThresholdCyclesPerThread; - - TArrayHolder<NThreading::TPadded<TThreadCtx>> Threads; - static_assert(sizeof(std::decay_t<decltype(Threads[0])>) == PLATFORM_CACHE_LINE); - TArrayHolder<NThreading::TPadded<std::queue<ui32>>> LocalQueues; - TArrayHolder<TWaitingStats<ui64>> WaitingStats; - TArrayHolder<TWaitingStats<double>> MovingWaitingStats; - std::atomic<ui16> LocalQueueSize; - - - TArrayHolder<NSchedulerQueue::TReader> ScheduleReaders; - TArrayHolder<NSchedulerQueue::TWriter> ScheduleWriters; - - const TString PoolName; - const TDuration TimePerMailbox; - const ui32 EventsPerMailbox; - EASProfile ActorSystemProfile; - - const int RealtimePriority; - - TAtomic ThreadUtilization; - TAtomic MaxUtilizationCounter; - TAtomic MaxUtilizationAccumulator; - TAtomic WrongWakenedThreadCount; - std::atomic<ui64> SpinningTimeUs; - - TAtomic ThreadCount; - TMutex ChangeThreadsLock; - - i16 MinThreadCount; - i16 MaxThreadCount; - i16 DefaultThreadCount; - IHarmonizer *Harmonizer; - i16 SharedExecutorsCount = 0; - ui64 SoftProcessingDurationTs = 0; - - const i16 Priority = 0; - const ui32 ActorSystemIndex = NActors::TActorTypeOperator::GetActorSystemIndex(); - public: - struct TSemaphore { - i64 OldSemaphore = 0; // 34 bits - // Sign bit - i16 CurrentSleepThreadCount = 0; // 14 bits - // Sign bit - i16 CurrentThreadCount = 0; // 14 bits - - inline i64 ConverToI64() { - i64 value = (1ll << 34) + OldSemaphore; - return value - | (((i64)CurrentSleepThreadCount + (1 << 14)) << 35) - | ((i64)CurrentThreadCount << 50); - } - - static inline TSemaphore GetSemaphore(i64 value) { - TSemaphore semaphore; - semaphore.OldSemaphore = (value & 0x7ffffffffll) - (1ll << 34); - semaphore.CurrentSleepThreadCount = ((value >> 35) & 0x7fff) - (1 << 14); - semaphore.CurrentThreadCount = (value >> 50) & 0x3fff; - return semaphore; - } - }; - - static constexpr TDuration DEFAULT_TIME_PER_MAILBOX = TBasicExecutorPoolConfig::DEFAULT_TIME_PER_MAILBOX; - static constexpr ui32 DEFAULT_EVENTS_PER_MAILBOX = TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX; - - TBasicExecutorPool(ui32 poolId, - ui32 threads, - ui64 spinThreshold, - const TString& poolName = "", - IHarmonizer *harmonizer = nullptr, - TAffinity* affinity = nullptr, - TDuration timePerMailbox = DEFAULT_TIME_PER_MAILBOX, - ui32 eventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX, - int realtimePriority = 0, - ui32 maxActivityType = 0 /* deprecated */, - i16 minThreadCount = 0, - i16 maxThreadCount = 0, - i16 defaultThreadCount = 0, - i16 priority = 0); - explicit TBasicExecutorPool(const TBasicExecutorPoolConfig& cfg, IHarmonizer *harmonizer); - ~TBasicExecutorPool(); - - void SetSharedExecutorsCount(i16 count); - - void Initialize(TWorkerContext& wctx) override; - ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingReadCounter) override; - ui32 GetReadyActivationCommon(TWorkerContext& wctx, ui64 revolvingReadCounter); - ui32 GetReadyActivationLocalQueue(TWorkerContext& wctx, ui64 revolvingReadCounter); - - void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; - void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; - void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; - - void ScheduleActivationEx(ui32 activation, ui64 revolvingWriteCounter) override; - void ScheduleActivationExCommon(ui32 activation, ui64 revolvingWriteCounter, TAtomic semaphoreValue); - void ScheduleActivationExLocalQueue(ui32 activation, ui64 revolvingWriteCounter); - - void SetLocalQueueSize(ui16 size); - - void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) override; - void Start() override; - void PrepareStop() override; - void Shutdown() override; - - void GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const override; - TString GetName() const override { - return PoolName; - } - - void SetRealTimeMode() const override; - - i16 GetThreadCount() const override; - void SetThreadCount(i16 threads) override; - i16 GetDefaultThreadCount() const override; - i16 GetMinThreadCount() const override; - i16 GetMaxThreadCount() const override; - TCpuConsumption GetThreadCpuConsumption(i16 threadIdx) override; - i16 GetBlockingThreadCount() const override; - i16 GetPriority() const override; - - void SetSpinThresholdCycles(ui32 cycles) override; - - void GetWaitingStats(TWaitingStats<ui64> &acc) const; - void CalcSpinPerThread(ui64 wakingUpConsumption); - void ClearWaitingStats() const; - - private: - void AskToGoToSleep(bool *needToWait, bool *needToBlock); - - void WakeUpLoop(i16 currentThreadCount); - bool GoToWaiting(TThreadCtx& threadCtx, TTimers &timers, bool needToBlock); - ui32 GoToSpin(TThreadCtx& threadCtx, i64 start, i64 &end); - bool GoToSleep(TThreadCtx& threadCtx, TTimers &timers); - bool GoToBeBlocked(TThreadCtx& threadCtx, TTimers &timers); - }; -} diff --git a/library/cpp/actors/core/executor_pool_basic_feature_flags.h b/library/cpp/actors/core/executor_pool_basic_feature_flags.h deleted file mode 100644 index 17f2a81df4..0000000000 --- a/library/cpp/actors/core/executor_pool_basic_feature_flags.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include "defs.h" - -#include <optional> - - -namespace NActors::NFeatures { - - enum class EActorSystemOptimizationType { - Common, - LocalQueues, - }; - - struct TCommonFeatureFlags { - static constexpr EActorSystemOptimizationType OptimizationType = EActorSystemOptimizationType::Common; - - static constexpr bool ProbeSpinCycles = false; - }; - - struct TLocalQueuesFeatureFlags { - static constexpr EActorSystemOptimizationType OptimizationType = EActorSystemOptimizationType::LocalQueues; - - static constexpr ui16 MIN_LOCAL_QUEUE_SIZE = 0; - static constexpr ui16 MAX_LOCAL_QUEUE_SIZE = 16; - static constexpr std::optional<ui16> FIXED_LOCAL_QUEUE_SIZE = std::nullopt; - - static constexpr bool UseIfAllOtherThreadsAreSleeping = false; - static constexpr bool UseOnMicroburst = false; - }; - - struct TSpinFeatureFlags { - static constexpr bool DoNotSpinLower = false; - static constexpr bool UsePseudoMovingWindow = true; - - static constexpr bool HotColdThreads = false; - static constexpr bool CalcPerThread = false; - }; - - using TFeatureFlags = TCommonFeatureFlags; - - consteval bool IsCommon() { - return TFeatureFlags::OptimizationType == EActorSystemOptimizationType::Common; - } - - consteval bool IsLocalQueues() { - return TFeatureFlags::OptimizationType == EActorSystemOptimizationType::LocalQueues; - } - -} diff --git a/library/cpp/actors/core/executor_pool_basic_ut.cpp b/library/cpp/actors/core/executor_pool_basic_ut.cpp deleted file mode 100644 index df8df52635..0000000000 --- a/library/cpp/actors/core/executor_pool_basic_ut.cpp +++ /dev/null @@ -1,666 +0,0 @@ -#include "actorsystem.h" -#include "executor_pool_basic.h" -#include "hfunc.h" -#include "scheduler_basic.h" - -#include <library/cpp/actors/util/should_continue.h> - -#include <library/cpp/testing/unittest/registar.h> - -using namespace NActors; - -#define VALUES_EQUAL(a, b, ...) \ - UNIT_ASSERT_VALUES_EQUAL_C((a), (b), (i64)semaphore.OldSemaphore \ - << ' ' << (i64)semaphore.CurrentSleepThreadCount \ - << ' ' << (i64)semaphore.CurrentThreadCount __VA_ARGS__); - -//////////////////////////////////////////////////////////////////////////////// - -struct TEvMsg : public NActors::TEventBase<TEvMsg, 10347> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvMsg, "ExecutorPoolTest: Msg"); -}; - -//////////////////////////////////////////////////////////////////////////////// - -class TTestSenderActor : public IActorCallback { -private: - using EActivityType = IActor::EActivityType ; - using EActorActivity = IActor::EActorActivity; - -private: - TAtomic Counter; - TActorId Receiver; - - std::function<void(void)> Action; - -public: - TTestSenderActor(std::function<void(void)> action = [](){}, - EActivityType activityType = EActorActivity::OTHER) - : IActorCallback(static_cast<TReceiveFunc>(&TTestSenderActor::Execute), activityType) - , Action(action) - {} - - void Start(TActorId receiver, size_t count) - { - AtomicSet(Counter, count); - Receiver = receiver; - } - - void Stop() { - while (true) { - if (GetCounter() == 0) { - break; - } - - Sleep(TDuration::MilliSeconds(1)); - } - } - - size_t GetCounter() const { - return AtomicGet(Counter); - } - -private: - STFUNC(Execute) - { - switch (ev->GetTypeRewrite()) { - hFunc(TEvMsg, Handle); - } - } - - void Handle(TEvMsg::TPtr &ev) - { - Y_UNUSED(ev); - Action(); - TAtomicBase count = AtomicDecrement(Counter); - Y_ABORT_UNLESS(count != Max<TAtomicBase>()); - if (count) { - Send(Receiver, new TEvMsg()); - } - } -}; - -THolder<TActorSystemSetup> GetActorSystemSetup(TBasicExecutorPool* pool) -{ - auto setup = MakeHolder<NActors::TActorSystemSetup>(); - setup->NodeId = 1; - setup->ExecutorsCount = 1; - setup->Executors.Reset(new TAutoPtr<NActors::IExecutorPool>[1]); - setup->Executors[0] = pool; - setup->Scheduler = new TBasicSchedulerThread(NActors::TSchedulerConfig(512, 0)); - return setup; -} - -Y_UNIT_TEST_SUITE(WaitingBenchs) { - - Y_UNIT_TEST(SpinPause) { - const ui32 count = 1'000'000; - ui64 startTs = GetCycleCountFast(); - for (ui32 idx = 0; idx < count; ++idx) { - SpinLockPause(); - } - ui64 stopTs = GetCycleCountFast(); - Cerr << Ts2Us(stopTs - startTs) / count << Endl; - Cerr << double(stopTs - startTs) / count << Endl; - } - - struct TThread : public ISimpleThread { - static const ui64 CyclesInMicroSecond; - std::array<ui64, 128> Hist; - ui64 WakingTime = 0; - ui64 AwakeningTime = 0; - ui64 SleepTime = 0; - ui64 IterationCount = 0; - - std::atomic<ui64> Awakens = 0; - std::atomic<ui64> *OtherAwaken; - - TThreadParkPad OwnPad; - TThreadParkPad *OtherPad; - - bool IsWaiting = false; - - void GoToWait() { - ui64 start = GetCycleCountFast(); - OwnPad.Park(); - ui64 elapsed = GetCycleCountFast() - start; - AwakeningTime += elapsed; - ui64 idx = std::min(Hist.size() - 1, (elapsed - 20 * CyclesInMicroSecond) / CyclesInMicroSecond); - Hist[idx]++; - Awakens++; - } - - void GoToWakeUp() { - ui64 start = GetCycleCountFast(); - OtherPad->Unpark(); - ui64 elapsed = GetCycleCountFast() - start; - WakingTime += elapsed; - ui64 idx = std::min(Hist.size() - 1, elapsed / CyclesInMicroSecond); - Hist[idx]++; - } - - void GoToSleep() { - ui64 start = GetCycleCountFast(); - ui64 stop = start; - while (stop - start < 20 * CyclesInMicroSecond) { - SpinLockPause(); - stop = GetCycleCountFast(); - } - SleepTime += stop - start; - } - - void* ThreadProc() { - for (ui32 idx = 0; idx < IterationCount; ++idx) { - if (IsWaiting) { - GoToWait(); - } else { - GoToSleep(); - GoToWakeUp(); - while(OtherAwaken->load() == idx) { - SpinLockPause(); - } - } - } - return nullptr; - } - }; - - const ui64 TThread::CyclesInMicroSecond = NHPTimer::GetCyclesPerSecond() * 0.000001; - - Y_UNIT_TEST(WakingUpTest) { - TThread a, b; - constexpr ui64 iterations = 100'000; - std::fill(a.Hist.begin(), a.Hist.end(), 0); - std::fill(b.Hist.begin(), b.Hist.end(), 0); - a.IterationCount = iterations; - b.IterationCount = iterations; - a.IsWaiting = true; - b.IsWaiting = false; - b.OtherAwaken = &a.Awakens; - a.OtherPad = &b.OwnPad; - b.OtherPad = &a.OwnPad; - a.Start(); - b.Start(); - a.Join(); - b.Join(); - - ui64 awakeningTime = a.AwakeningTime + b.AwakeningTime - a.SleepTime - b.SleepTime; - ui64 wakingUpTime = a.WakingTime + b.WakingTime; - - Cerr << "AvgAwakeningCycles: " << double(awakeningTime) / iterations << Endl; - Cerr << "AvgAwakeningUs: " << Ts2Us(awakeningTime) / iterations << Endl; - Cerr << "AvgSleep20usCycles:" << double(b.SleepTime) / iterations << Endl; - Cerr << "AvgSleep20usUs:" << Ts2Us(b.SleepTime) / iterations << Endl; - Cerr << "AvgWakingUpCycles: " << double(wakingUpTime) / iterations << Endl; - Cerr << "AvgWakingUpUs: " << Ts2Us(wakingUpTime) / iterations << Endl; - - Cerr << "AwakeningHist:\n"; - for (ui32 idx = 0; idx < a.Hist.size(); ++idx) { - if (a.Hist[idx]) { - if (idx + 1 != a.Hist.size()) { - Cerr << " [" << idx << "us - " << idx + 1 << "us] " << a.Hist[idx] << Endl; - } else { - Cerr << " [" << idx << "us - ...] " << a.Hist[idx] << Endl; - } - } - } - - Cerr << "WakingUpHist:\n"; - for (ui32 idx = 0; idx < b.Hist.size(); ++idx) { - if (b.Hist[idx]) { - if (idx + 1 != b.Hist.size()) { - Cerr << " [" << idx << "us - " << idx + 1 << "us] " << b.Hist[idx] << Endl; - } else { - Cerr << " [" << idx << "us - ...] " << b.Hist[idx] << Endl; - } - } - } - } - -} - -Y_UNIT_TEST_SUITE(BasicExecutorPool) { - - Y_UNIT_TEST(Semaphore) { - TBasicExecutorPool::TSemaphore semaphore; - semaphore = TBasicExecutorPool::TSemaphore::GetSemaphore(0); - - VALUES_EQUAL(0, semaphore.ConverToI64()); - semaphore = TBasicExecutorPool::TSemaphore::GetSemaphore(-1); - VALUES_EQUAL(-1, semaphore.ConverToI64()); - semaphore = TBasicExecutorPool::TSemaphore::GetSemaphore(1); - VALUES_EQUAL(1, semaphore.ConverToI64()); - - for (i64 value = -1'000'000; value <= 1'000'000; ++value) { - VALUES_EQUAL(TBasicExecutorPool::TSemaphore::GetSemaphore(value).ConverToI64(), value); - } - - for (i8 sleepThreads = -10; sleepThreads <= 10; ++sleepThreads) { - - semaphore = TBasicExecutorPool::TSemaphore(); - semaphore.CurrentSleepThreadCount = sleepThreads; - i64 initialValue = semaphore.ConverToI64(); - - semaphore = TBasicExecutorPool::TSemaphore::GetSemaphore(initialValue - 1); - VALUES_EQUAL(-1, semaphore.OldSemaphore); - - i64 value = initialValue; - value -= 100; - for (i32 expected = -100; expected <= 100; ++expected) { - semaphore = TBasicExecutorPool::TSemaphore::GetSemaphore(value); - UNIT_ASSERT_VALUES_EQUAL_C(expected, semaphore.OldSemaphore, (i64)semaphore.OldSemaphore - << ' ' << (i64)semaphore.CurrentSleepThreadCount - << ' ' << (i64)semaphore.CurrentThreadCount); - UNIT_ASSERT_VALUES_EQUAL_C(sleepThreads, semaphore.CurrentSleepThreadCount, (i64)semaphore.OldSemaphore - << ' ' << (i64)semaphore.CurrentSleepThreadCount - << ' ' << (i64)semaphore.CurrentThreadCount); - semaphore = TBasicExecutorPool::TSemaphore(); - semaphore.OldSemaphore = expected; - semaphore.CurrentSleepThreadCount = sleepThreads; - UNIT_ASSERT_VALUES_EQUAL(semaphore.ConverToI64(), value); - value++; - } - - for (i32 expected = 101; expected >= -101; --expected) { - semaphore = TBasicExecutorPool::TSemaphore::GetSemaphore(value); - UNIT_ASSERT_VALUES_EQUAL_C(expected, semaphore.OldSemaphore, (i64)semaphore.OldSemaphore - << ' ' << (i64)semaphore.CurrentSleepThreadCount - << ' ' << (i64)semaphore.CurrentThreadCount); - UNIT_ASSERT_VALUES_EQUAL_C(sleepThreads, semaphore.CurrentSleepThreadCount, (i64)semaphore.OldSemaphore - << ' ' << (i64)semaphore.CurrentSleepThreadCount - << ' ' << (i64)semaphore.CurrentThreadCount); - value--; - } - } - - //UNIT_ASSERT_VALUES_EQUAL_C(-1, TBasicExecutorPool::TSemaphore::GetSemaphore(value-1).OldSemaphore); - } - - Y_UNIT_TEST(CheckCompleteOne) { - const size_t size = 4; - const size_t msgCount = 1e4; - TBasicExecutorPool* executorPool = new TBasicExecutorPool(0, size, 50); - - auto setup = GetActorSystemSetup(executorPool); - TActorSystem actorSystem(setup); - actorSystem.Start(); - - auto begin = TInstant::Now(); - - auto actor = new TTestSenderActor(); - auto actorId = actorSystem.Register(actor); - actor->Start(actor->SelfId(), msgCount); - actorSystem.Send(actorId, new TEvMsg()); - - while (actor->GetCounter()) { - auto now = TInstant::Now(); - UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Counter is " << actor->GetCounter()); - - Sleep(TDuration::MilliSeconds(1)); - } - } - - Y_UNIT_TEST(CheckCompleteAll) { - const size_t size = 4; - const size_t msgCount = 1e4; - TBasicExecutorPool* executorPool = new TBasicExecutorPool(0, size, 50); - - auto setup = GetActorSystemSetup(executorPool); - TActorSystem actorSystem(setup); - actorSystem.Start(); - - auto begin = TInstant::Now(); - - TTestSenderActor* actors[size]; - TActorId actorIds[size]; - - for (size_t i = 0; i < size; ++i) { - actors[i] = new TTestSenderActor(); - actorIds[i] = actorSystem.Register(actors[i]); - } - for (size_t i = 0; i < size; ++i) { - actors[i]->Start(actors[i]->SelfId(), msgCount); - } - for (size_t i = 0; i < size; ++i) { - actorSystem.Send(actorIds[i], new TEvMsg()); - } - - - while (true) { - size_t maxCounter = 0; - for (size_t i = 0; i < size; ++i) { - maxCounter = Max(maxCounter, actors[i]->GetCounter()); - } - - if (maxCounter == 0) { - break; - } - - auto now = TInstant::Now(); - UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Max counter is " << maxCounter); - - Sleep(TDuration::MilliSeconds(1)); - } - } - - Y_UNIT_TEST(CheckCompleteOver) { - const size_t size = 4; - const size_t actorsCount = size * 2; - const size_t msgCount = 1e4; - TBasicExecutorPool* executorPool = new TBasicExecutorPool(0, size, 50); - - auto setup = GetActorSystemSetup(executorPool); - TActorSystem actorSystem(setup); - actorSystem.Start(); - - auto begin = TInstant::Now(); - - TTestSenderActor* actors[actorsCount]; - TActorId actorIds[actorsCount]; - - for (size_t i = 0; i < actorsCount; ++i) { - actors[i] = new TTestSenderActor(); - actorIds[i] = actorSystem.Register(actors[i]); - } - for (size_t i = 0; i < actorsCount; ++i) { - actors[i]->Start(actors[i]->SelfId(), msgCount); - } - for (size_t i = 0; i < actorsCount; ++i) { - actorSystem.Send(actorIds[i], new TEvMsg()); - } - - - while (true) { - size_t maxCounter = 0; - for (size_t i = 0; i < actorsCount; ++i) { - maxCounter = Max(maxCounter, actors[i]->GetCounter()); - } - - if (maxCounter == 0) { - break; - } - - auto now = TInstant::Now(); - UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Max counter is " << maxCounter); - - Sleep(TDuration::MilliSeconds(1)); - } - } - - Y_UNIT_TEST(CheckCompleteRoundRobinOver) { - const size_t size = 4; - const size_t actorsCount = size * 2; - const size_t msgCount = 1e2; - TBasicExecutorPool* executorPool = new TBasicExecutorPool(0, size, 50); - - auto setup = GetActorSystemSetup(executorPool); - TActorSystem actorSystem(setup); - actorSystem.Start(); - - auto begin = TInstant::Now(); - - TTestSenderActor* actors[actorsCount]; - TActorId actorIds[actorsCount]; - - for (size_t i = 0; i < actorsCount; ++i) { - actors[i] = new TTestSenderActor(); - actorIds[i] = actorSystem.Register(actors[i]); - } - for (size_t i = 0; i < actorsCount; ++i) { - actors[i]->Start(actorIds[(i + 1) % actorsCount], msgCount); - } - for (size_t i = 0; i < actorsCount; ++i) { - actorSystem.Send(actorIds[i], new TEvMsg()); - } - - while (true) { - size_t maxCounter = 0; - for (size_t i = 0; i < actorsCount; ++i) { - maxCounter = Max(maxCounter, actors[i]->GetCounter()); - } - - if (maxCounter == 0) { - break; - } - - auto now = TInstant::Now(); - UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Max counter is " << maxCounter); - - Sleep(TDuration::MilliSeconds(1)); - } - } - - Y_UNIT_TEST(CheckStats) { - const size_t size = 4; - const size_t msgCount = 1e4; - TBasicExecutorPool* executorPool = new TBasicExecutorPool(0, size, 50); - - auto setup = GetActorSystemSetup(executorPool); - TActorSystem actorSystem(setup); - actorSystem.Start(); - - auto begin = TInstant::Now(); - - auto actor = new TTestSenderActor(); - auto actorId = actorSystem.Register(actor); - actor->Start(actor->SelfId(), msgCount); - actorSystem.Send(actorId, new TEvMsg()); - - while (actor->GetCounter()) { - auto now = TInstant::Now(); - UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Counter is " << actor->GetCounter()); - - Sleep(TDuration::MilliSeconds(1)); - } - - TVector<TExecutorThreadStats> stats; - TExecutorPoolStats poolStats; - actorSystem.GetPoolStats(0, poolStats, stats); - // Sum all per-thread counters into the 0th element - for (ui32 idx = 1; idx < stats.size(); ++idx) { - stats[0].Aggregate(stats[idx]); - } - - UNIT_ASSERT_VALUES_EQUAL(stats[0].SentEvents, msgCount - 1); - UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PreemptedEvents, 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].NonDeliveredEvents, 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].EmptyMailboxActivation, 0); - //UNIT_ASSERT_VALUES_EQUAL(stats[0].CpuUs, 0); // depends on total duration of test, so undefined - UNIT_ASSERT(stats[0].ElapsedTicks > 0); - UNIT_ASSERT(stats[0].ParkedTicks > 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].BlockedTicks, 0); - UNIT_ASSERT(stats[0].ActivationTimeHistogram.TotalSamples >= msgCount / TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX); - UNIT_ASSERT_VALUES_EQUAL(stats[0].EventDeliveryTimeHistogram.TotalSamples, msgCount); - UNIT_ASSERT_VALUES_EQUAL(stats[0].EventProcessingCountHistogram.TotalSamples, msgCount); - UNIT_ASSERT(stats[0].EventProcessingTimeHistogram.TotalSamples > 0); - UNIT_ASSERT(stats[0].ElapsedTicksByActivity[NActors::TActorTypeOperator::GetOtherActivityIndex()] > 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEventsByActivity[NActors::TActorTypeOperator::GetOtherActivityIndex()], msgCount); - UNIT_ASSERT_VALUES_EQUAL(stats[0].ActorsAliveByActivity[NActors::TActorTypeOperator::GetOtherActivityIndex()], 1); - UNIT_ASSERT_VALUES_EQUAL(stats[0].ScheduledEventsByActivity[NActors::TActorTypeOperator::GetOtherActivityIndex()], 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolDestroyedActors, 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolAllocatedMailboxes, 4095); // one line - UNIT_ASSERT(stats[0].MailboxPushedOutByTime + stats[0].MailboxPushedOutByEventCount >= msgCount / TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX); - UNIT_ASSERT_VALUES_EQUAL(stats[0].MailboxPushedOutBySoftPreemption, 0); - } -} - -Y_UNIT_TEST_SUITE(ChangingThreadsCountInBasicExecutorPool) { - - struct TMockState { - void ActorDo() {} - }; - - struct TTestActors { - const size_t Count; - TArrayHolder<TTestSenderActor*> Actors; - TArrayHolder<TActorId> ActorIds; - - TTestActors(size_t count) - : Count(count) - , Actors(new TTestSenderActor*[count]) - , ActorIds(new TActorId[count]) - { } - - void Start(TActorSystem &actorSystem, size_t msgCount) { - for (size_t i = 0; i < Count; ++i) { - Actors[i]->Start(Actors[i]->SelfId(), msgCount); - } - for (size_t i = 0; i < Count; ++i) { - actorSystem.Send(ActorIds[i], new TEvMsg()); - } - } - - void Stop() { - for (size_t i = 0; i < Count; ++i) { - Actors[i]->Stop(); - } - } - }; - - template <typename TState = TMockState> - struct TTestCtx { - const size_t MaxThreadCount; - const size_t SendingMessageCount; - std::unique_ptr<TBasicExecutorPool> ExecutorPool; - THolder<TActorSystemSetup> Setup; - TActorSystem ActorSystem; - - TState State; - - TTestCtx(size_t maxThreadCount, size_t sendingMessageCount) - : MaxThreadCount(maxThreadCount) - , SendingMessageCount(sendingMessageCount) - , ExecutorPool(new TBasicExecutorPool(0, MaxThreadCount, 50)) - , Setup(GetActorSystemSetup(ExecutorPool.get())) - , ActorSystem(Setup) - { - } - - TTestCtx(size_t maxThreadCount, size_t sendingMessageCount, const TState &state) - : MaxThreadCount(maxThreadCount) - , SendingMessageCount(sendingMessageCount) - , ExecutorPool(new TBasicExecutorPool(0, MaxThreadCount, 50)) - , Setup(GetActorSystemSetup(ExecutorPool.get())) - , ActorSystem(Setup) - , State(state) - { - } - - ~TTestCtx() { - ExecutorPool.release(); - } - - TTestActors RegisterCheckActors(size_t actorCount) { - TTestActors res(actorCount); - for (size_t i = 0; i < actorCount; ++i) { - res.Actors[i] = new TTestSenderActor([&] { - State.ActorDo(); - }); - res.ActorIds[i] = ActorSystem.Register(res.Actors[i]); - } - return res; - } - }; - - struct TCheckingInFlightState { - TAtomic ExpectedMaximum = 0; - TAtomic CurrentInFlight = 0; - - void ActorStartProcessing() { - ui32 inFlight = AtomicIncrement(CurrentInFlight); - ui32 maximum = AtomicGet(ExpectedMaximum); - if (maximum) { - UNIT_ASSERT_C(inFlight <= maximum, "inFlight# " << inFlight << " maximum# " << maximum); - } - } - - void ActorStopProcessing() { - AtomicDecrement(CurrentInFlight); - } - - void ActorDo() { - ActorStartProcessing(); - NanoSleep(1'000'000); - ActorStopProcessing(); - } - }; - - Y_UNIT_TEST(DecreaseIncreaseThreadCount) { - const size_t msgCount = 1e2; - const size_t size = 4; - const size_t testCount = 2; - TTestCtx<TCheckingInFlightState> ctx(size, msgCount); - ctx.ActorSystem.Start(); - - TVector<TExecutorThreadStats> statsCopy[testCount]; - - TTestActors testActors = ctx.RegisterCheckActors(size); - - const size_t N = 6; - const size_t threadsCounts[N] = { 1, 3, 2, 3, 1, 4 }; - for (ui32 idx = 0; idx < 4 * N; ++idx) { - size_t currentThreadCount = threadsCounts[idx % N]; - ctx.ExecutorPool->SetThreadCount(currentThreadCount); - AtomicSet(ctx.State.ExpectedMaximum, currentThreadCount); - - for (size_t testIdx = 0; testIdx < testCount; ++testIdx) { - testActors.Start(ctx.ActorSystem, msgCount); - Sleep(TDuration::MilliSeconds(100)); - testActors.Stop(); - } - Sleep(TDuration::MilliSeconds(10)); - } - ctx.ActorSystem.Stop(); - } - - Y_UNIT_TEST(ContiniousChangingThreadCount) { - const size_t msgCount = 1e2; - const size_t size = 4; - - auto begin = TInstant::Now(); - TTestCtx<TCheckingInFlightState> ctx(size, msgCount, TCheckingInFlightState{msgCount}); - ctx.ActorSystem.Start(); - TTestActors testActors = ctx.RegisterCheckActors(size); - - testActors.Start(ctx.ActorSystem, msgCount); - - const size_t N = 6; - const size_t threadsCouns[N] = { 1, 3, 2, 3, 1, 4 }; - - ui64 counter = 0; - - TTestSenderActor* changerActor = new TTestSenderActor([&]{ - ctx.State.ActorStartProcessing(); - AtomicSet(ctx.State.ExpectedMaximum, 0); - ctx.ExecutorPool->SetThreadCount(threadsCouns[counter]); - NanoSleep(10'000'000); - AtomicSet(ctx.State.ExpectedMaximum, threadsCouns[counter]); - counter++; - if (counter == N) { - counter = 0; - } - ctx.State.ActorStopProcessing(); - }); - TActorId changerActorId = ctx.ActorSystem.Register(changerActor); - changerActor->Start(changerActorId, msgCount); - ctx.ActorSystem.Send(changerActorId, new TEvMsg()); - - while (true) { - size_t maxCounter = 0; - for (size_t i = 0; i < size; ++i) { - maxCounter = Max(maxCounter, testActors.Actors[i]->GetCounter()); - } - if (maxCounter == 0) { - break; - } - auto now = TInstant::Now(); - UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Max counter is " << maxCounter); - Sleep(TDuration::MilliSeconds(1)); - } - - changerActor->Stop(); - ctx.ActorSystem.Stop(); - } -} diff --git a/library/cpp/actors/core/executor_pool_io.cpp b/library/cpp/actors/core/executor_pool_io.cpp deleted file mode 100644 index 78e1d8e1ea..0000000000 --- a/library/cpp/actors/core/executor_pool_io.cpp +++ /dev/null @@ -1,157 +0,0 @@ -#include "executor_pool_io.h" -#include "actor.h" -#include "mailbox.h" -#include <library/cpp/actors/util/affinity.h> -#include <library/cpp/actors/util/datetime.h> - -namespace NActors { - TIOExecutorPool::TIOExecutorPool(ui32 poolId, ui32 threads, const TString& poolName, TAffinity* affinity) - : TExecutorPoolBase(poolId, threads, affinity) - , Threads(new TThreadCtx[threads]) - , PoolName(poolName) - {} - - TIOExecutorPool::TIOExecutorPool(const TIOExecutorPoolConfig& cfg) - : TIOExecutorPool( - cfg.PoolId, - cfg.Threads, - cfg.PoolName, - new TAffinity(cfg.Affinity) - ) - {} - - TIOExecutorPool::~TIOExecutorPool() { - Threads.Destroy(); - while (ThreadQueue.Pop(0)) - ; - } - - ui32 TIOExecutorPool::GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) { - i16 workerId = wctx.WorkerId; - Y_DEBUG_ABORT_UNLESS(workerId < PoolThreads); - - NHPTimer::STime elapsed = 0; - NHPTimer::STime parked = 0; - NHPTimer::STime hpstart = GetCycleCountFast(); - NHPTimer::STime hpnow; - - const TAtomic x = AtomicDecrement(Semaphore); - if (x < 0) { - TThreadCtx& threadCtx = Threads[workerId]; - ThreadQueue.Push(workerId + 1, revolvingCounter); - hpnow = GetCycleCountFast(); - elapsed += hpnow - hpstart; - if (threadCtx.Pad.Park()) - return 0; - hpstart = GetCycleCountFast(); - parked += hpstart - hpnow; - } - - while (!RelaxedLoad(&StopFlag)) { - if (const ui32 activation = Activations.Pop(++revolvingCounter)) { - hpnow = GetCycleCountFast(); - elapsed += hpnow - hpstart; - wctx.AddElapsedCycles(ActorSystemIndex, elapsed); - if (parked > 0) { - wctx.AddParkedCycles(parked); - } - return activation; - } - SpinLockPause(); - } - - return 0; - } - - void TIOExecutorPool::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { - Schedule(deadline - ActorSystem->Timestamp(), ev, cookie, workerId); - } - - void TIOExecutorPool::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { - Y_UNUSED(workerId); - - const auto current = ActorSystem->Monotonic(); - if (deadline < current) - deadline = current; - - TTicketLock::TGuard guard(&ScheduleLock); - ScheduleQueue->Writer.Push(deadline.MicroSeconds(), ev.Release(), cookie); - } - - void TIOExecutorPool::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { - Y_UNUSED(workerId); - const auto deadline = ActorSystem->Monotonic() + delta; - - TTicketLock::TGuard guard(&ScheduleLock); - ScheduleQueue->Writer.Push(deadline.MicroSeconds(), ev.Release(), cookie); - } - - void TIOExecutorPool::ScheduleActivationEx(ui32 activation, ui64 revolvingWriteCounter) { - Activations.Push(activation, revolvingWriteCounter); - const TAtomic x = AtomicIncrement(Semaphore); - if (x <= 0) { - for (;; ++revolvingWriteCounter) { - if (const ui32 x = ThreadQueue.Pop(revolvingWriteCounter)) { - const ui32 threadIdx = x - 1; - Threads[threadIdx].Pad.Unpark(); - return; - } - SpinLockPause(); - } - } - } - - void TIOExecutorPool::Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) { - TAffinityGuard affinityGuard(Affinity()); - - ActorSystem = actorSystem; - - ScheduleQueue.Reset(new NSchedulerQueue::TQueueType()); - - for (i16 i = 0; i != PoolThreads; ++i) { - Threads[i].Thread.Reset(new TExecutorThread(i, 0, actorSystem, this, MailboxTable.Get(), PoolName)); - } - - *scheduleReaders = &ScheduleQueue->Reader; - *scheduleSz = 1; - } - - void TIOExecutorPool::Start() { - TAffinityGuard affinityGuard(Affinity()); - - for (i16 i = 0; i != PoolThreads; ++i) - Threads[i].Thread->Start(); - } - - void TIOExecutorPool::PrepareStop() { - AtomicStore(&StopFlag, true); - for (i16 i = 0; i != PoolThreads; ++i) { - Threads[i].Thread->StopFlag = true; - Threads[i].Pad.Interrupt(); - } - } - - void TIOExecutorPool::Shutdown() { - for (i16 i = 0; i != PoolThreads; ++i) - Threads[i].Thread->Join(); - } - - void TIOExecutorPool::GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const { - poolStats.CurrentThreadCount = PoolThreads; - poolStats.DefaultThreadCount = PoolThreads; - poolStats.MaxThreadCount = PoolThreads; - poolStats.PotentialMaxThreadCount = PoolThreads; - statsCopy.resize(PoolThreads + 1); - // Save counters from the pool object - statsCopy[0] = TExecutorThreadStats(); - statsCopy[0].Aggregate(Stats); - // Per-thread stats - for (i16 i = 0; i < PoolThreads; ++i) { - Threads[i].Thread->GetCurrentStats(statsCopy[i + 1]); - } - } - - TString TIOExecutorPool::GetName() const { - return PoolName; - } -} diff --git a/library/cpp/actors/core/executor_pool_io.h b/library/cpp/actors/core/executor_pool_io.h deleted file mode 100644 index f3f1a11819..0000000000 --- a/library/cpp/actors/core/executor_pool_io.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include "actorsystem.h" -#include "executor_thread.h" -#include "scheduler_queue.h" -#include "executor_pool_base.h" -#include <library/cpp/actors/actor_type/indexes.h> -#include <library/cpp/actors/util/ticket_lock.h> -#include <library/cpp/actors/util/unordered_cache.h> -#include <library/cpp/actors/util/threadparkpad.h> -#include <util/system/condvar.h> - -namespace NActors { - class TIOExecutorPool: public TExecutorPoolBase { - struct TThreadCtx { - TAutoPtr<TExecutorThread> Thread; - TThreadParkPad Pad; - }; - - TArrayHolder<TThreadCtx> Threads; - TUnorderedCache<ui32, 512, 4> ThreadQueue; - - THolder<NSchedulerQueue::TQueueType> ScheduleQueue; - TTicketLock ScheduleLock; - - const TString PoolName; - const ui32 ActorSystemIndex = NActors::TActorTypeOperator::GetActorSystemIndex(); - public: - TIOExecutorPool(ui32 poolId, ui32 threads, const TString& poolName = "", TAffinity* affinity = nullptr); - explicit TIOExecutorPool(const TIOExecutorPoolConfig& cfg); - ~TIOExecutorPool(); - - ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) override; - - void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; - void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; - void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; - - void ScheduleActivationEx(ui32 activation, ui64 revolvingWriteCounter) override; - - void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) override; - void Start() override; - void PrepareStop() override; - void Shutdown() override; - - void GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const override; - TString GetName() const override; - }; -} diff --git a/library/cpp/actors/core/executor_pool_united.cpp b/library/cpp/actors/core/executor_pool_united.cpp deleted file mode 100644 index 960545ffb5..0000000000 --- a/library/cpp/actors/core/executor_pool_united.cpp +++ /dev/null @@ -1,1455 +0,0 @@ -#include "executor_pool_united.h" -#include "executor_pool_united_workers.h" - -#include "actor.h" -#include "balancer.h" -#include "cpu_state.h" -#include "executor_thread.h" -#include "probes.h" -#include "mailbox.h" -#include "scheduler_queue.h" -#include <library/cpp/actors/util/affinity.h> -#include <library/cpp/actors/util/cpu_load_log.h> -#include <library/cpp/actors/util/datetime.h> -#include <library/cpp/actors/util/futex.h> -#include <library/cpp/actors/util/intrinsics.h> -#include <library/cpp/actors/util/timerfd.h> - -#include <util/system/datetime.h> -#include <util/system/hp_timer.h> - -#include <algorithm> - -namespace NActors { - LWTRACE_USING(ACTORLIB_PROVIDER); - - struct TUnitedWorkers::TWorker: public TNonCopyable { - TAutoPtr<TExecutorThread> Thread; - volatile TThreadId ThreadId = UnknownThreadId; - NSchedulerQueue::TQueueType SchedulerQueue; - }; - - struct TUnitedWorkers::TPool: public TNonCopyable { - TAtomic Waiters = 0; // Number of idle cpus, waiting for activations in this pool - char Padding[64 - sizeof(TAtomic)]; - - TUnorderedCache<ui32, 512, 4> Activations; // MPMC-queue for mailbox activations - TAtomic Active = 0; // Number of mailboxes ready for execution or currently executing - TAtomic Tokens = 0; // Pending tokens (token is required for worker to start execution, guarantees concurrency limit and activation availability) - volatile bool StopFlag = false; - - // Configuration - TPoolId PoolId; - TAtomicBase Concurrency; // Max concurrent workers running this pool - IExecutorPool* ExecutorPool; - TMailboxTable* MailboxTable; - ui64 TimePerMailboxTs; - ui32 EventsPerMailbox; - - // Cpus this pool is allowed to run on - // Cpus are specified in wake order - TStackVec<TCpu*, 15> WakeOrderCpus; - - ~TPool() { - while (Activations.Pop(0)) {} - } - - void Stop() { - AtomicStore(&StopFlag, true); - } - - bool IsUnited() const { - return WakeOrderCpus.size(); - } - - // Add activation of newly scheduled mailbox. Returns generated token (unless concurrency is exceeded) - bool PushActivation(ui32 activation, ui64 revolvingCounter) { - Activations.Push(activation, revolvingCounter); - TAtomicBase active = AtomicIncrement(Active); - if (active <= Concurrency) { // token generated - AtomicIncrement(Tokens); - return true; - } - return false; - } - - template <bool Relaxed> - static bool TryAcquireTokenImpl(TAtomic* tokens) { - while (true) { - TAtomicBase value; - if constexpr (Relaxed) { - value = RelaxedLoad(tokens); - } else { - value = AtomicLoad(tokens); - } - if (value > 0) { - if (AtomicCas(tokens, value - 1, value)) { - return true; // token acquired - } - } else { - return false; // no more tokens - } - } - } - - // Try acquire pending token. Must be done before execution - bool TryAcquireToken() { - return TryAcquireTokenImpl<false>(&Tokens); - } - - // Try acquire pending token. Must be done before execution - bool TryAcquireTokenRelaxed() { - return TryAcquireTokenImpl<true>(&Tokens); - } - - // Get activation. Requires acquired token. - void BeginExecution(ui32& activation, ui64 revolvingCounter) { - while (!RelaxedLoad(&StopFlag)) { - if (activation = Activations.Pop(++revolvingCounter)) { - return; - } - SpinLockPause(); - } - activation = 0; // should stop - } - - // End currently active execution and start new one if token is available. - // Reuses token if it's not destroyed. - // Returned `true` means successful switch, `activation` is filled. - // Returned `false` means execution has ended, no need to call StopExecution() - bool NextExecution(ui32& activation, ui64 revolvingCounter) { - if (AtomicDecrement(Active) >= Concurrency) { // reuse just released token - BeginExecution(activation, revolvingCounter); - return true; - } else if (TryAcquireToken()) { // another token acquired - BeginExecution(activation, revolvingCounter); - return true; - } - return false; // no more tokens available - } - - // Stop active execution. Returns released token (unless it is destroyed) - bool StopExecution() { - TAtomicBase active = AtomicDecrement(Active); - if (active >= Concurrency) { // token released - AtomicIncrement(Tokens); - return true; - } - return false; // token destroyed - } - - // Switch worker context into this pool - void Switch(TWorkerContext& wctx, ui64 softDeadlineTs, TExecutorThreadStats& stats) { - wctx.Switch(ExecutorPool, MailboxTable, TimePerMailboxTs, EventsPerMailbox, softDeadlineTs, &stats); - } - }; - - class TPoolScheduler { - class TSchedulable { - // Lower PoolBits store PoolId - // All other higher bits store virtual runtime in cycles - using TValue = ui64; - TValue Value; - - static constexpr ui64 PoolIdMask = ui64((1ull << PoolBits) - 1); - static constexpr ui64 VRunTsMask = ~PoolIdMask; - - public: - explicit TSchedulable(TPoolId poolId = MaxPools, ui64 vrunts = 0) - : Value((poolId & PoolIdMask) | (vrunts & VRunTsMask)) - {} - - TPoolId GetPoolId() const { - return Value & PoolIdMask; - } - - ui64 GetVRunTs() const { - // Do not truncate pool id - // NOTE: it decrease accuracy, but improves performance - return Value; - } - - ui64 GetPreciseVRunTs() const { - return Value & VRunTsMask; - } - - void SetVRunTs(ui64 vrunts) { - Value = (Value & PoolIdMask) | (vrunts & VRunTsMask); - } - - void Account(ui64 base, ui64 ts) { - // Add at least minimum amount to change Value - SetVRunTs(base + Max(ts, PoolIdMask + 1)); - } - }; - - // For min-heap of Items - struct TCmp { - bool operator()(TSchedulable lhs, TSchedulable rhs) const { - return lhs.GetVRunTs() > rhs.GetVRunTs(); - } - }; - - TPoolId Size = 0; // total number of pools on this cpu - TPoolId Current = 0; // index of current pool in `Items` - - // At the beginning `Current` items are orginized as binary min-heap -- ready to be scheduled - // The rest `Size - Current` items are unordered (required to keep track of last vrunts) - TSchedulable Items[MaxPools]; // virtual runtime in cycles for each pool - ui64 MinVRunTs = 0; // virtual runtime used by waking pools (system's vrunts) - ui64 Ts = 0; // real timestamp of current execution start (for accounting) - - // Maps PoolId into it's inverse weight - ui64 InvWeights[MaxPools]; - static constexpr ui64 VRunTsOverflow = ui64(1ull << 62ull) / MaxPoolWeight; - - public: - void AddPool(TPoolId pool, TPoolWeight weight) { - Items[Size] = TSchedulable(pool, MinVRunTs); - Size++; - InvWeights[pool] = MaxPoolWeight / std::clamp(weight ? weight : DefPoolWeight, MinPoolWeight, MaxPoolWeight); - } - - // Iterate over pools in scheduling order - // should be used in construction: - // for (TPoolId pool = Begin(); pool != End(); pool = Next()) - TPoolId Begin() { - // Wrap vruntime around to avoid overflow, if required - if (Y_UNLIKELY(MinVRunTs >= VRunTsOverflow)) { - for (TPoolId i = 0; i < Size; i++) { - ui64 ts = Items[i].GetPreciseVRunTs(); - Items[i].SetVRunTs(ts >= VRunTsOverflow ? ts - VRunTsOverflow : 0); - } - MinVRunTs -= VRunTsOverflow; - } - Current = Size; - std::make_heap(Items, Items + Current, TCmp()); - return Next(); - } - - constexpr TPoolId End() const { - return MaxPools; - } - - TPoolId Next() { - if (Current > 0) { - std::pop_heap(Items, Items + Current, TCmp()); - Current--; - return CurrentPool(); - } else { - return End(); - } - } - - // Scheduling was successful, we are going to run CurrentPool() - void Scheduled() { - MinVRunTs = Max(MinVRunTs, Items[Current].GetPreciseVRunTs()); - // NOTE: Ts is propagated on Account() to avoid gaps - } - - // Schedule specific pool that woke up cpu after idle - void ScheduledAfterIdle(TPoolId pool, ui64 ts) { - if (Y_UNLIKELY(ts < Ts)) { // anomaly: time goes backwards (e.g. rdtsc is reset to zero on cpu reset) - Ts = ts; // just skip anomalous time slice - return; - } - MinVRunTs += (ts - Ts) * (MaxPoolWeight / DefPoolWeight); // propagate system's vrunts to blur difference between pools - Ts = ts; // propagate time w/o accounting to any pool - - // Set specified pool as current, it requires scan - for (Current = 0; Current < Size && pool != Items[Current].GetPoolId(); Current++) {} - Y_ABORT_UNLESS(Current < Size); - } - - // Account currently running pool till now (ts) - void Account(ui64 ts) { - // Skip time slice for the first run and when time goes backwards (e.g. rdtsc is reset to zero on cpu reset) - if (Y_LIKELY(Ts > 0 && Ts <= ts)) { - TPoolId pool = CurrentPool(); - Y_ABORT_UNLESS(pool < MaxPools); - Items[Current].Account(MinVRunTs, (ts - Ts) * InvWeights[pool]); - } - Ts = ts; // propagate time - } - - TPoolId CurrentPool() const { - return Items[Current].GetPoolId(); - } - }; - - // Cyclic array of timers for idle workers to wait for hard preemption on - struct TIdleQueue: public TNonCopyable { - TArrayHolder<TTimerFd> Timers; - size_t Size; - TAtomic EnqueueCounter = 0; - TAtomic DequeueCounter = 0; - - explicit TIdleQueue(size_t size) - : Timers(new TTimerFd[size]) - , Size(size) - {} - - void Stop() { - for (size_t i = 0; i < Size; i++) { - Timers[i].Wake(); - } - } - - // Returns timer which new idle-worker should wait for - TTimerFd* Enqueue() { - return &Timers[AtomicGetAndIncrement(EnqueueCounter) % Size]; - } - - // Returns timer that hard preemption should trigger to wake idle-worker - TTimerFd* Dequeue() { - return &Timers[AtomicGetAndIncrement(DequeueCounter) % Size]; - } - }; - - // Base class for cpu-local managers that help workers on single cpu to cooperate - struct TCpuLocalManager: public TThrRefBase { - TUnitedWorkers* United; - - explicit TCpuLocalManager(TUnitedWorkers* united) - : United(united) - {} - - virtual TWorkerId WorkerCount() const = 0; - virtual void AddWorker(TWorkerId workerId) = 0; - virtual void Stop() = 0; - }; - - // Represents cpu with single associated worker that is able to execute any pool. - // It always executes pool assigned by balancer and switch pool only if assigned pool has changed - struct TAssignedCpu: public TCpuLocalManager { - bool Started = false; - - TAssignedCpu(TUnitedWorkers* united) - : TCpuLocalManager(united) - {} - - TWorkerId WorkerCount() const override { - return 1; - } - - void AddWorker(TWorkerId workerId) override { - Y_UNUSED(workerId); - } - - ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) { - ui32 activation; - if (Y_UNLIKELY(!Started)) { - Started = true; - } else if (Y_UNLIKELY(United->IsPoolReassigned(wctx))) { - United->StopExecution(wctx.PoolId); // stop current execution and switch pool if reassigned - } else if (United->NextExecution(wctx.PoolId, activation, revolvingCounter)) { - return activation; // another activation from currently executing pool (or 0 if stopped) - } - - // Switch to another pool, it blocks until token is acquired - if (Y_UNLIKELY(!SwitchPool(wctx))) { - return 0; // stopped - } - United->SwitchPool(wctx, 0); - United->BeginExecution(wctx.PoolId, activation, revolvingCounter); - return activation; - } - - void Stop() override { - } - - private: - // Sets next pool to run, and acquires token, blocks if there are no tokens - bool SwitchPool(TWorkerContext& wctx) { - if (Y_UNLIKELY(United->IsStopped())) { - return false; - } - - // Run balancer (if it's time to) - United->Balance(); - - // Select pool to execute - wctx.PoolId = United->AssignedPool(wctx); - Y_ABORT_UNLESS(wctx.PoolId != CpuShared); - if (United->TryAcquireToken(wctx.PoolId)) { - return true; - } - - // No more work -- wait for activations (spinning, then blocked) - wctx.PoolId = United->Idle(wctx.PoolId, wctx); - - // Wakeup or stop occured - if (Y_UNLIKELY(wctx.PoolId == CpuStopped)) { - return false; - } - return true; // United->Idle() has already acquired token - } - }; - - // Lock-free data structure that help workers on single cpu to discover their state and do hard preemptions - struct TSharedCpu: public TCpuLocalManager { - // Current lease - volatile TLease::TValue CurrentLease; - char Padding1[64 - sizeof(TLease)]; - - // Slow pools - // the highest bit: 1=wait-for-slow-workers mode 0=else - // any lower bit (poolId is bit position): 1=pool-is-slow 0=pool-is-fast - volatile TPoolsMask SlowPoolsMask = 0; - char Padding2[64 - sizeof(TPoolsMask)]; - - // Must be accessed under never expiring lease to avoid races - TPoolScheduler PoolSched; - TWorkerId FastWorker = MaxWorkers; - TTimerFd* PreemptionTimer = nullptr; - ui64 HardPreemptionTs = 0; - bool Started = false; - - TIdleQueue IdleQueue; - - struct TConfig { - const TCpuId CpuId; - const TWorkerId Workers; - ui64 SoftLimitTs; - ui64 HardLimitTs; - ui64 EventLimitTs; - ui64 LimitPrecisionTs; - const int IdleWorkerPriority; - const int FastWorkerPriority; - const bool NoRealtime; - const bool NoAffinity; - const TCpuAllocation CpuAlloc; - - TConfig(const TCpuAllocation& allocation, const TUnitedWorkersConfig& united) - : CpuId(allocation.CpuId) - , Workers(allocation.AllowedPools.size() + 1) - , SoftLimitTs(Us2Ts(united.PoolLimitUs)) - , HardLimitTs(Us2Ts(united.PoolLimitUs + united.EventLimitUs)) - , EventLimitTs(Us2Ts(united.EventLimitUs)) - , LimitPrecisionTs(Us2Ts(united.LimitPrecisionUs)) - , IdleWorkerPriority(std::clamp<ui64>(united.IdleWorkerPriority ? united.IdleWorkerPriority : 20, 1, 99)) - , FastWorkerPriority(std::clamp<ui64>(united.FastWorkerPriority ? united.FastWorkerPriority : 10, 1, IdleWorkerPriority - 1)) - , NoRealtime(united.NoRealtime) - , NoAffinity(united.NoAffinity) - , CpuAlloc(allocation) - {} - }; - - TConfig Config; - TVector<TWorkerId> Workers; - - TSharedCpu(const TConfig& cfg, TUnitedWorkers* united) - : TCpuLocalManager(united) - , IdleQueue(cfg.Workers) - , Config(cfg) - { - for (const auto& pa : Config.CpuAlloc.AllowedPools) { - PoolSched.AddPool(pa.PoolId, pa.Weight); - } - } - - TWorkerId WorkerCount() const override { - return Config.Workers; - } - - void AddWorker(TWorkerId workerId) override { - if (Workers.empty()) { - // Grant lease to the first worker - AtomicStore(&CurrentLease, TLease(workerId, NeverExpire).Value); - } - Workers.push_back(workerId); - } - - ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) { - ui32 activation; - if (!wctx.Lease.IsNeverExpiring()) { - if (wctx.SoftDeadlineTs < GetCycleCountFast()) { // stop if lease has expired or is near to be expired - United->StopExecution(wctx.PoolId); - } else if (United->NextExecution(wctx.PoolId, activation, revolvingCounter)) { - return activation; // another activation from currently executing pool (or 0 if stopped) - } - } - - // Switch to another pool, it blocks until token is acquired - if (Y_UNLIKELY(!SwitchPool(wctx))) { - return 0; // stopped - } - United->BeginExecution(wctx.PoolId, activation, revolvingCounter); - return activation; - } - - void Stop() override { - IdleQueue.Stop(); - } - - private: - enum EPriority { - IdlePriority, // highest (real-time, Config.IdleWorkerPriority) - FastPriority, // normal (real-time, Config.FastWorkerPriority) - SlowPriority, // lowest (not real-time) - }; - - enum EWorkerAction { - // Fast-worker - ExecuteFast, - WaitForSlow, - - // Slow-worker - BecameIdle, - WakeFast, - - // Idle-worker - BecameFast, - Standby, - - // Common - Stopped, - }; - - // Thread-safe; should be called from worker - // Blocks for idle-workers; sets lease and next pool to run - bool SwitchPool(TWorkerContext& wctx) { - TTimerFd* idleTimer = nullptr; - while (true) { - if (DisablePreemptionAndTryExtend(wctx.Lease)) { // if fast-worker - if (Y_UNLIKELY(!Started)) { - SetPriority(0, FastPriority); - Started = true; - } - while (true) { - switch (FastWorkerAction(wctx)) { - case ExecuteFast: - United->SwitchPool(wctx, wctx.Lease.GetPreciseExpireTs() - Config.EventLimitTs); - EnablePreemptionAndGrant(wctx.Lease); - return true; - case WaitForSlow: - FastWorkerSleep(GetCycleCountFast() + Config.SoftLimitTs); - break; - case Stopped: return false; - default: Y_ABORT(); - } - } - } else if (wctx.Lease.IsNeverExpiring()) { // if idle-worker - switch (IdleWorkerAction(idleTimer, wctx.Lease.GetWorkerId())) { - case BecameFast: - SetPriority(0, FastPriority); - break; // try acquire new lease - case Standby: - if (!idleTimer) { - idleTimer = IdleQueue.Enqueue(); - } - SetPriority(0, IdlePriority); - idleTimer->Wait(); - break; - case Stopped: return false; - default: Y_ABORT(); - } - } else { // lease has expired and hard preemption occured, so we are executing in a slow-worker - wctx.IncrementPreemptedEvents(); - switch (SlowWorkerAction(wctx.PoolId)) { - case WakeFast: - WakeFastWorker(); - [[fallthrough]]; // no break; pass through - case BecameIdle: - wctx.Lease = wctx.Lease.NeverExpire(); - wctx.PoolId = MaxPools; - idleTimer = nullptr; - break; - case Stopped: return false; - default: Y_ABORT(); - } - } - } - } - - enum ETryRunPool { - RunFastPool, - RunSlowPool, - NoTokens, - }; - - ETryRunPool TryRun(TPoolId pool) { - while (true) { - // updates WaitPoolsFlag in SlowPoolsMask according to scheduled pool slowness - TPoolsMask slow = AtomicLoad(&SlowPoolsMask); - if ((1ull << pool) & slow) { // we are about to execute slow pool (fast-worker will just wait, token is NOT required) - if (slow & WaitPoolsFlag) { - return RunSlowPool; // wait flag is already set - } else { - if (AtomicCas(&SlowPoolsMask, slow | WaitPoolsFlag, slow)) { // try set wait flag - return RunSlowPool; // wait flag has been successfully set - } - } - } else { // we are about to execute fast pool, token required - if (slow & WaitPoolsFlag) { // reset wait flag if required - if (AtomicCas(&SlowPoolsMask, slow & ~WaitPoolsFlag, slow)) { // try reset wait flag - return United->TryAcquireToken(pool) ? RunFastPool : NoTokens; // wait flag has been successfully reset - } - } else { - return United->TryAcquireToken(pool) ? RunFastPool : NoTokens; // wait flag is already reset - } - } - } - } - - EWorkerAction FastWorkerAction(TWorkerContext& wctx) { - if (Y_UNLIKELY(United->IsStopped())) { - return Stopped; - } - - // Account current pool - ui64 ts = GetCycleCountFast(); - PoolSched.Account(ts); - - // Select next pool to execute - for (wctx.PoolId = PoolSched.Begin(); wctx.PoolId != PoolSched.End(); wctx.PoolId = PoolSched.Next()) { - switch (TryRun(wctx.PoolId)) { - case RunFastPool: - PoolSched.Scheduled(); - wctx.Lease = PostponePreemption(wctx.Lease.GetWorkerId(), ts); - return ExecuteFast; - case RunSlowPool: - PoolSched.Scheduled(); - ResetPreemption(wctx.Lease.GetWorkerId(), ts); // there is no point in preemption during wait - return WaitForSlow; - case NoTokens: // concurrency limit reached, or no more work in pool - break; // just try next pool (if any) - } - } - - // No more work, no slow-workers -- wait for activations (active, then blocked) - wctx.PoolId = United->Idle(CpuShared, wctx); - - // Wakeup or stop occured - if (Y_UNLIKELY(wctx.PoolId == CpuStopped)) { - return Stopped; - } - ts = GetCycleCountFast(); - PoolSched.ScheduledAfterIdle(wctx.PoolId, ts); - wctx.Lease = PostponePreemption(wctx.Lease.GetWorkerId(), ts); - return ExecuteFast; // United->Idle() has already acquired token - } - - EWorkerAction IdleWorkerAction(TTimerFd* idleTimer, TWorkerId workerId) { - if (Y_UNLIKELY(United->IsStopped())) { - return Stopped; - } - if (!idleTimer) { // either worker start or became idle -- hard preemption is not required - return Standby; - } - - TLease lease = TLease(AtomicLoad(&CurrentLease)); - ui64 ts = GetCycleCountFast(); - if (lease.GetExpireTs() < ts) { // current lease has expired - if (TryBeginHardPreemption(lease)) { - SetPoolIsSlowFlag(PoolSched.CurrentPool()); - TWorkerId preempted = lease.GetWorkerId(); - SetPriority(United->GetWorkerThreadId(preempted), SlowPriority); - LWPROBE(HardPreemption, Config.CpuId, PoolSched.CurrentPool(), preempted, workerId); - EndHardPreemption(workerId); - return BecameFast; - } else { - // Lease has been changed just now, no way we need preemption right now, so no retry needed - return Standby; - } - } else { - // Lease has not expired yet (maybe never expiring lease) - return Standby; - } - } - - EWorkerAction SlowWorkerAction(TPoolId pool) { - if (Y_UNLIKELY(United->IsStopped())) { - return Stopped; - } - while (true) { - TPoolsMask slow = AtomicLoad(&SlowPoolsMask); - if (slow & (1ull << pool)) { - if (slow == (1ull << pool) & WaitPoolsFlag) { // the last slow pool is going to became fast - if (AtomicCas(&SlowPoolsMask, 0, slow)) { // reset both pool-is-slow flag and WaitPoolsFlag - return WakeFast; - } - } else { // there are (a) several slow-worker or (b) one slow-worker w/o waiting fast-worker - if (AtomicCas(&SlowPoolsMask, slow & ~(1ull << pool), slow)) { // reset pool-is-slow flag - return BecameIdle; - } - } - } else { - // SlowWorkerAction has been called between TryBeginHardPreemption and SetPoolIsSlowFlag - // flag for this pool is not set yet, but we can be sure pool is slow: - // - because SlowWorkerAction has been called; - // - this mean lease has expired and hard preemption occured. - // So just wait other worker to call SetPoolIsSlowFlag - LWPROBE(SlowWorkerActionRace, Config.CpuId, pool, slow); - } - } - } - - void SetPoolIsSlowFlag(TPoolId pool) { - while (true) { - TPoolsMask slow = AtomicLoad(&SlowPoolsMask); - if ((slow & (1ull << pool)) == 0) { // if pool is fast - if (AtomicCas(&SlowPoolsMask, slow | (1ull << pool), slow)) { // set pool-is-slow flag - return; - } - } else { - Y_ABORT("two slow-workers executing the same pool on the same core"); - return; // pool is already slow - } - } - } - - bool TryBeginHardPreemption(TLease lease) { - return AtomicCas(&CurrentLease, HardPreemptionLease, lease); - } - - void EndHardPreemption(TWorkerId to) { - ATOMIC_COMPILER_BARRIER(); - if (!AtomicCas(&CurrentLease, TLease(to, NeverExpire), HardPreemptionLease)) { - Y_ABORT("hard preemption failed"); - } - } - - bool DisablePreemptionAndTryExtend(TLease lease) { - return AtomicCas(&CurrentLease, lease.NeverExpire(), lease); - } - - void EnablePreemptionAndGrant(TLease lease) { - ATOMIC_COMPILER_BARRIER(); - if (!AtomicCas(&CurrentLease, lease, lease.NeverExpire())) { - Y_ABORT("lease grant failed"); - } - } - - void FastWorkerSleep(ui64 deadlineTs) { - while (true) { - TPoolsMask slow = AtomicLoad(&SlowPoolsMask); - if ((slow & WaitPoolsFlag) == 0) { - return; // woken by WakeFast action - } - ui64 ts = GetCycleCountFast(); - if (deadlineTs <= ts) { - if (AtomicCas(&SlowPoolsMask, slow & ~WaitPoolsFlag, slow)) { // try reset wait flag - return; // wait flag has been successfully reset after timeout - } - } else { // should wait - ui64 timeoutNs = Ts2Ns(deadlineTs - ts); -#ifdef _linux_ - timespec timeout; - timeout.tv_sec = timeoutNs / 1'000'000'000; - timeout.tv_nsec = timeoutNs % 1'000'000'000; - SysFutex(FastWorkerFutex(), FUTEX_WAIT_PRIVATE, FastWorkerFutexValue(slow), &timeout, nullptr, 0); -#else - NanoSleep(timeoutNs); // non-linux wake is not supported, cpu will go idle on slow -> fast switch -#endif - } - } - } - - void WakeFastWorker() { -#ifdef _linux_ - SysFutex(FastWorkerFutex(), FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0); -#endif - } - -#ifdef _linux_ - ui32* FastWorkerFutex() { - // Actually we wait on one highest bit, but futex value size is 4 bytes on all platforms - static_assert(sizeof(TPoolsMask) >= 4, "cannot be used as futex value on linux"); - return (ui32*)&SlowPoolsMask + 1; // higher 32 bits (little endian assumed) - } - - ui32 FastWorkerFutexValue(TPoolsMask slow) { - return ui32(slow >> 32); // higher 32 bits - } -#endif - - void SetPriority(TThreadId tid, EPriority priority) { - if (Config.NoRealtime) { - return; - } -#ifdef _linux_ - int policy; - struct sched_param param; - switch (priority) { - case IdlePriority: - policy = SCHED_FIFO; - param.sched_priority = Config.IdleWorkerPriority; - break; - case FastPriority: - policy = SCHED_FIFO; - param.sched_priority = Config.FastWorkerPriority; - break; - case SlowPriority: - policy = SCHED_OTHER; - param.sched_priority = 0; - break; - } - int ret = sched_setscheduler(tid, policy, ¶m); - switch (ret) { - case 0: return; - case EINVAL: - Y_ABORT("sched_setscheduler(%" PRIu64 ", %d, %d) -> EINVAL", tid, policy, param.sched_priority); - case EPERM: - // Requirements: - // * CAP_SYS_NICE capability to run real-time processes and set cpu affinity. - // Either run under root or set application capabilities: - // sudo setcap cap_sys_nice=eip BINARY - // * Non-zero rt-runtime (in case cgroups are used). - // Either (a) disable global limit on RT processes bandwidth: - // sudo sysctl -w kernel.sched_rt_runtime_us=-1 - // Or (b) set non-zero rt-runtime for your cgroup: - // echo -1 > /sys/fs/cgroup/cpu/[cgroup]/cpu.rt_runtime_us - // (also set the same value for every parent cgroup) - // https://www.kernel.org/doc/Documentation/scheduler/sched-rt-group.txt - Y_ABORT("sched_setscheduler(%" PRIu64 ", %d, %d) -> EPERM", tid, policy, param.sched_priority); - case ESRCH: - Y_ABORT("sched_setscheduler(%" PRIu64 ", %d, %d) -> ESRCH", tid, policy, param.sched_priority); - default: - Y_ABORT("sched_setscheduler(%" PRIu64 ", %d, %d) -> %d", tid, policy, param.sched_priority, ret); - } -#else - Y_UNUSED(tid); - Y_UNUSED(priority); -#endif - } - - void ResetPreemption(TWorkerId fastWorkerId, ui64 ts) { - if (Y_UNLIKELY(!PreemptionTimer)) { - return; - } - if (FastWorker == fastWorkerId && HardPreemptionTs > 0) { - PreemptionTimer->Reset(); - LWPROBE(ResetPreemptionTimer, Config.CpuId, FastWorker, PreemptionTimer->Fd, Ts2Ms(ts), Ts2Ms(HardPreemptionTs)); - HardPreemptionTs = 0; - } - } - - TLease PostponePreemption(TWorkerId fastWorkerId, ui64 ts) { - // Select new timer after hard preemption - if (FastWorker != fastWorkerId) { - FastWorker = fastWorkerId; - PreemptionTimer = IdleQueue.Dequeue(); - HardPreemptionTs = 0; - } - - ui64 hardPreemptionTs = ts + Config.HardLimitTs; - if (hardPreemptionTs > HardPreemptionTs) { - // Reset timer (at most once in TickIntervalTs, sacrifice precision) - HardPreemptionTs = hardPreemptionTs + Config.LimitPrecisionTs; - PreemptionTimer->Set(HardPreemptionTs); - LWPROBE(SetPreemptionTimer, Config.CpuId, FastWorker, PreemptionTimer->Fd, Ts2Ms(ts), Ts2Ms(HardPreemptionTs)); - } - - return TLease(fastWorkerId, hardPreemptionTs); - } - }; - - // Proxy for start and switching TUnitedExecutorPool-s on single cpu via GetReadyActivation() - // (does not implement any other method in IExecutorPool) - class TCpuExecutorPool: public IExecutorPool { - const TString Name; - - public: - explicit TCpuExecutorPool(const TString& name) - : IExecutorPool(MaxPools) - , Name(name) - {} - - TString GetName() const override { - return Name; - } - - void SetRealTimeMode() const override { - // derived classes controls rt-priority - do nothing - } - - // Should never be called - void ReclaimMailbox(TMailboxType::EType, ui32, TWorkerId, ui64) override { Y_ABORT(); } - TMailboxHeader *ResolveMailbox(ui32) override { Y_ABORT(); } - void Schedule(TInstant, TAutoPtr<IEventHandle>, ISchedulerCookie*, TWorkerId) override { Y_ABORT(); } - void Schedule(TMonotonic, TAutoPtr<IEventHandle>, ISchedulerCookie*, TWorkerId) override { Y_ABORT(); } - void Schedule(TDuration, TAutoPtr<IEventHandle>, ISchedulerCookie*, TWorkerId) override { Y_ABORT(); } - bool Send(TAutoPtr<IEventHandle>&) override { Y_ABORT(); } - bool SpecificSend(TAutoPtr<IEventHandle>&) override { Y_ABORT(); } - void ScheduleActivation(ui32) override { Y_ABORT(); } - void SpecificScheduleActivation(ui32) override { Y_ABORT(); } - void ScheduleActivationEx(ui32, ui64) override { Y_ABORT(); } - TActorId Register(IActor*, TMailboxType::EType, ui64, const TActorId&) override { Y_ABORT(); } - TActorId Register(IActor*, TMailboxHeader*, ui32, const TActorId&) override { Y_ABORT(); } - void Prepare(TActorSystem*, NSchedulerQueue::TReader**, ui32*) override { Y_ABORT(); } - void Start() override { Y_ABORT(); } - void PrepareStop() override { Y_ABORT(); } - void Shutdown() override { Y_ABORT(); } - bool Cleanup() override { Y_ABORT(); } - }; - - // Proxy executor pool working with cpu-local scheduler (aka actorsystem 2.0) - class TSharedCpuExecutorPool: public TCpuExecutorPool { - TSharedCpu* Local; - TIntrusivePtr<TAffinity> SingleCpuAffinity; // no migration support yet - public: - explicit TSharedCpuExecutorPool(TSharedCpu* local, const TUnitedWorkersConfig& config) - : TCpuExecutorPool("u-" + ToString(local->Config.CpuId)) - , Local(local) - , SingleCpuAffinity(config.NoAffinity ? nullptr : new TAffinity(TCpuMask(local->Config.CpuId))) - {} - - TAffinity* Affinity() const override { - return SingleCpuAffinity.Get(); - } - - ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) override { - return Local->GetReadyActivation(wctx, revolvingCounter); - } - }; - - // Proxy executor pool working with balancer and assigned pools (aka actorsystem 1.5) - class TAssignedCpuExecutorPool: public TCpuExecutorPool { - TAssignedCpu* Local; - TIntrusivePtr<TAffinity> CpuAffinity; - public: - explicit TAssignedCpuExecutorPool(TAssignedCpu* local, const TUnitedWorkersConfig& config) - : TCpuExecutorPool("United") - , Local(local) - , CpuAffinity(config.NoAffinity ? nullptr : new TAffinity(config.Allowed)) - {} - - TAffinity* Affinity() const override { - return CpuAffinity.Get(); - } - - ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) override { - return Local->GetReadyActivation(wctx, revolvingCounter); - } - }; - - // Representation of a single cpu and it's state visible to other cpus and pools - struct TUnitedWorkers::TCpu: public TNonCopyable { - struct TScopedWaiters { - TCpu& Cpu; - TPool* AssignedPool; // nullptr if CpuShared - - // Subscribe on wakeups from allowed pools - TScopedWaiters(TCpu& cpu, TPool* assignedPool) : Cpu(cpu), AssignedPool(assignedPool) { - if (!AssignedPool) { - for (TPool* pool : Cpu.AllowedPools) { - AtomicIncrement(pool->Waiters); - } - } else { - AtomicIncrement(AssignedPool->Waiters); - } - } - - // Unsubscribe from pools we've subscribed on - ~TScopedWaiters() { - if (!AssignedPool) { - for (TPool* pool : Cpu.AllowedPools) { - AtomicDecrement(pool->Waiters); - } - } else { - AtomicDecrement(AssignedPool->Waiters); - } - } - }; - - // Current cpu state important for other cpus and balancer - TCpuState State; - - // Thread-safe per pool stats - // NOTE: It's guaranteed that cpu never executes two instance of the same pool - TVector<TExecutorThreadStats> PoolStats; - TCpuLoadLog<1024> LoadLog; - - - // Configuration - TCpuId CpuId; - THolder<TCpuLocalManager> LocalManager; - THolder<TCpuExecutorPool> ExecutorPool; - - // Pools allowed to run on this cpu - TStackVec<TPool*, 15> AllowedPools; - - void Stop() { - if (LocalManager) { - State.Stop(); - LocalManager->Stop(); - } - } - - bool StartSpinning(TUnitedWorkers* united, TPool* assignedPool, TPoolId& result) { - // Mark cpu as idle - if (Y_UNLIKELY(!State.StartSpinning())) { - result = CpuStopped; - return true; - } - - // Avoid using multiple atomic seq_cst loads in cycle, use barrier once and relaxed ops - AtomicBarrier(); - - // Check there is no pending tokens (can be released before Waiters increment) - if (!assignedPool) { - for (TPool* pool : AllowedPools) { - if (pool->TryAcquireTokenRelaxed()) { - result = WakeWithTokenAcquired(united, pool->PoolId); - return true; // token acquired or stop - } - } - } else { - if (assignedPool->TryAcquireTokenRelaxed()) { - result = WakeWithTokenAcquired(united, assignedPool->PoolId); - return true; // token acquired or stop - } - } - - // At this point we can be sure wakeup won't be lost - // So we can actively spin or block w/o checking for pending tokens - return false; - } - - bool ActiveWait(ui64 spinThresholdTs, TPoolId& result) { - ui64 ts = GetCycleCountFast(); - LoadLog.RegisterBusyPeriod(ts); - ui64 deadline = ts + spinThresholdTs; - while (GetCycleCountFast() < deadline) { - for (ui32 i = 0; i < 12; ++i) { - TPoolId current = State.CurrentPool(); - if (current == CpuSpinning) { - SpinLockPause(); - } else { - result = current; - LoadLog.RegisterIdlePeriod(GetCycleCountFast()); - return true; // wakeup - } - } - } - return false; // spin threshold exceeded, no wakeups - } - - bool StartBlocking(TPoolId& result) { - // Switch into blocked state - if (State.StartBlocking()) { - result = State.CurrentPool(); - return true; - } else { - return false; - } - } - - bool BlockedWait(TPoolId& result, ui64 timeoutNs) { - return State.Block(timeoutNs, result); - } - - void SwitchPool(TPoolId pool) { - return State.SwitchPool(pool); - } - - private: - TPoolId WakeWithTokenAcquired(TUnitedWorkers* united, TPoolId token) { - switch (State.WakeWithTokenAcquired(token)) { - case TCpuState::Woken: // we've got token and successfully woken up this cpu - // NOTE: sending thread may also wakeup another worker, which wont be able to acquire token and will go idle (it's ok) - return token; - case TCpuState::NotIdle: { // wakeup event has also occured - TPoolId wakeup = State.CurrentPool(); - if (wakeup != token) { // token and wakeup for different pools - united->TryWake(wakeup); // rewake another cpu to avoid losing wakeup - } - return token; - } - case TCpuState::Forbidden: - Y_ABORT(); - case TCpuState::Stopped: - return CpuStopped; - } - } - }; - - TUnitedWorkers::TUnitedWorkers( - const TUnitedWorkersConfig& config, - const TVector<TUnitedExecutorPoolConfig>& unitedPools, - const TCpuAllocationConfig& allocation, - IBalancer* balancer) - : Balancer(balancer) - , Config(config) - , Allocation(allocation) - { - // Find max pool id and initialize pools - PoolCount = 0; - for (const TCpuAllocation& cpuAlloc : allocation.Items) { - for (const auto& pa : cpuAlloc.AllowedPools) { - PoolCount = Max<size_t>(PoolCount, pa.PoolId + 1); - } - } - Pools.Reset(new TPool[PoolCount]); - - // Find max cpu id and initialize cpus - CpuCount = 0; - for (const TCpuAllocation& cpuAlloc : allocation.Items) { - CpuCount = Max<size_t>(CpuCount, cpuAlloc.CpuId + 1); - } - Cpus.Reset(new TCpu[CpuCount]); - - // Setup allocated cpus - // NOTE: leave gaps for not allocated cpus (default-initialized) - WorkerCount = 0; - for (const TCpuAllocation& cpuAlloc : allocation.Items) { - TCpu& cpu = Cpus[cpuAlloc.CpuId]; - cpu.CpuId = cpuAlloc.CpuId; - cpu.PoolStats.resize(PoolCount); // NOTE: also may have gaps - for (const auto& pa : cpuAlloc.AllowedPools) { - cpu.AllowedPools.emplace_back(&Pools[pa.PoolId]); - } - - // Setup balancing and cpu-local manager - if (!Balancer->AddCpu(cpuAlloc, &cpu.State)) { - cpu.State.SwitchPool(0); // set initial state to non-idle to avoid losing wakeups on start - cpu.State.AssignPool(CpuShared); - TSharedCpu* local = new TSharedCpu(TSharedCpu::TConfig(cpuAlloc, Config), this); - cpu.LocalManager.Reset(local); - cpu.ExecutorPool.Reset(new TSharedCpuExecutorPool(local, Config)); - } else { - TAssignedCpu* local = new TAssignedCpu(this); - cpu.LocalManager.Reset(local); - cpu.ExecutorPool.Reset(new TAssignedCpuExecutorPool(local, Config)); - } - WorkerCount += cpu.LocalManager->WorkerCount(); - } - - // Initialize workers - Workers.Reset(new TWorker[WorkerCount]); - - // Setup pools - // NOTE: leave gaps for not united pools (default-initialized) - for (const TUnitedExecutorPoolConfig& cfg : unitedPools) { - TPool& pool = Pools[cfg.PoolId]; - Y_ABORT_UNLESS(cfg.PoolId < MaxPools); - pool.PoolId = cfg.PoolId; - pool.Concurrency = cfg.Concurrency ? cfg.Concurrency : Config.CpuCount; - pool.ExecutorPool = nullptr; // should be set later using SetupPool() - pool.MailboxTable = nullptr; // should be set later using SetupPool() - pool.TimePerMailboxTs = DurationToCycles(cfg.TimePerMailbox); - pool.EventsPerMailbox = cfg.EventsPerMailbox; - - // Reinitialize per cpu pool stats with right MaxActivityType - for (const TCpuAllocation& cpuAlloc : allocation.Items) { - TCpu& cpu = Cpus[cpuAlloc.CpuId]; - cpu.PoolStats[cfg.PoolId] = TExecutorThreadStats(); - } - - // Setup WakeOrderCpus: left to right exclusive cpus, then left to right shared cpus. - // Waking exclusive cpus first reduce load on shared cpu and improve latency isolation, which is - // the point of using exclusive cpu. But note that number of actively spinning idle cpus may increase, - // so cpu consumption on light load is higher. - for (const TCpuAllocation& cpuAlloc : allocation.Items) { - TCpu& cpu = Cpus[cpuAlloc.CpuId]; - if (cpu.AllowedPools.size() == 1 && cpu.AllowedPools[0] == &pool) { - pool.WakeOrderCpus.emplace_back(&cpu); - } - } - for (const TCpuAllocation& cpuAlloc : allocation.Items) { - TCpu& cpu = Cpus[cpuAlloc.CpuId]; - if (cpu.AllowedPools.size() > 1 && cpuAlloc.HasPool(pool.PoolId)) { - pool.WakeOrderCpus.emplace_back(&cpu); - } - } - } - } - - TUnitedWorkers::~TUnitedWorkers() { - } - - void TUnitedWorkers::Prepare(TActorSystem* actorSystem, TVector<NSchedulerQueue::TReader*>& scheduleReaders) { - // Setup allocated cpus - // NOTE: leave gaps for not allocated cpus (default-initialized) - TWorkerId workers = 0; - for (TCpuId cpuId = 0; cpuId < CpuCount; cpuId++) { - TCpu& cpu = Cpus[cpuId]; - - // Setup cpu-local workers - if (cpu.LocalManager) { - for (i16 i = 0; i < cpu.LocalManager->WorkerCount(); i++) { - TWorkerId workerId = workers++; - cpu.LocalManager->AddWorker(workerId); - - // Setup worker - Y_ABORT_UNLESS(workerId < WorkerCount); - Workers[workerId].Thread.Reset(new TExecutorThread( - workerId, - cpu.CpuId, - actorSystem, - cpu.ExecutorPool.Get(), // use cpu-local manager as proxy executor for all workers on cpu - nullptr, // MailboxTable is pool-specific, will be set on pool switch - cpu.ExecutorPool->GetName())); - // NOTE: TWorker::ThreadId will be initialized after in Start() - - scheduleReaders.push_back(&Workers[workerId].SchedulerQueue.Reader); - } - } - } - } - - void TUnitedWorkers::Start() { - for (TWorkerId workerId = 0; workerId < WorkerCount; workerId++) { - Workers[workerId].Thread->Start(); - } - for (TWorkerId workerId = 0; workerId < WorkerCount; workerId++) { - AtomicStore(&Workers[workerId].ThreadId, Workers[workerId].Thread->GetThreadId()); - } - } - - inline TThreadId TUnitedWorkers::GetWorkerThreadId(TWorkerId workerId) const { - volatile TThreadId* threadId = &Workers[workerId].ThreadId; -#ifdef _linux_ - while (AtomicLoad(threadId) == UnknownThreadId) { - NanoSleep(1000); - } -#endif - return AtomicLoad(threadId); - } - - inline NSchedulerQueue::TWriter* TUnitedWorkers::GetScheduleWriter(TWorkerId workerId) const { - return &Workers[workerId].SchedulerQueue.Writer; - } - - void TUnitedWorkers::SetupPool(TPoolId pool, IExecutorPool* executorPool, TMailboxTable* mailboxTable) { - Pools[pool].ExecutorPool = executorPool; - Pools[pool].MailboxTable = mailboxTable; - } - - void TUnitedWorkers::PrepareStop() { - AtomicStore(&StopFlag, true); - for (TPoolId pool = 0; pool < PoolCount; pool++) { - Pools[pool].Stop(); - } - for (TCpuId cpuId = 0; cpuId < CpuCount; cpuId++) { - Cpus[cpuId].Stop(); - } - } - - void TUnitedWorkers::Shutdown() { - for (TWorkerId workerId = 0; workerId < WorkerCount; workerId++) { - Workers[workerId].Thread->Join(); - } - } - - inline void TUnitedWorkers::PushActivation(TPoolId pool, ui32 activation, ui64 revolvingCounter) { - if (Pools[pool].PushActivation(activation, revolvingCounter)) { // token generated - TryWake(pool); - } - } - - inline bool TUnitedWorkers::TryAcquireToken(TPoolId pool) { - return Pools[pool].TryAcquireToken(); - } - - inline void TUnitedWorkers::TryWake(TPoolId pool) { - // Avoid using multiple atomic seq_cst loads in cycle, use barrier once - AtomicBarrier(); - - // Scan every allowed cpu in pool's wakeup order and try to wake the first idle cpu - if (RelaxedLoad(&Pools[pool].Waiters) > 0) { - for (TCpu* cpu : Pools[pool].WakeOrderCpus) { - if (cpu->State.WakeWithoutToken(pool) == TCpuState::Woken) { - return; // successful wake up - } - } - } - - // Cpu has not been woken up - } - - inline void TUnitedWorkers::BeginExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter) { - Pools[pool].BeginExecution(activation, revolvingCounter); - } - - inline bool TUnitedWorkers::NextExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter) { - return Pools[pool].NextExecution(activation, revolvingCounter); - } - - inline void TUnitedWorkers::StopExecution(TPoolId pool) { - if (Pools[pool].StopExecution()) { // pending token - TryWake(pool); - } - } - - inline void TUnitedWorkers::Balance() { - ui64 ts = GetCycleCountFast(); - if (Balancer->TryLock(ts)) { - for (TPoolId pool = 0; pool < PoolCount; pool++) { - if (Pools[pool].IsUnited()) { - ui64 ElapsedTs = 0; - ui64 ParkedTs = 0; - TStackVec<TCpuLoadLog<1024>*, 128> logs; - ui64 worstActivationTimeUs = 0; - for (TCpu* cpu : Pools[pool].WakeOrderCpus) { - TExecutorThreadStats& cpuStats = cpu->PoolStats[pool]; - ElapsedTs += cpuStats.ElapsedTicks; - ParkedTs += cpuStats.ParkedTicks; - worstActivationTimeUs = Max(worstActivationTimeUs, cpuStats.WorstActivationTimeUs); - AtomicStore<decltype(cpuStats.WorstActivationTimeUs)>(&cpuStats.WorstActivationTimeUs, 0ul); - logs.push_back(&cpu->LoadLog); - } - ui64 minPeriodTs = Min(ui64(Us2Ts(Balancer->GetPeriodUs())), ui64((1024ull-2ull)*64ull*128ull*1024ull)); - ui64 estimatedTs = MinusOneCpuEstimator.MaxLatencyIncreaseWithOneLessCpu( - &logs[0], logs.size(), ts, minPeriodTs); - TBalancerStats stats; - stats.Ts = ts; - stats.CpuUs = Ts2Us(ElapsedTs); - stats.IdleUs = Ts2Us(ParkedTs); - stats.ExpectedLatencyIncreaseUs = Ts2Us(estimatedTs); - stats.WorstActivationTimeUs = worstActivationTimeUs; - Balancer->SetPoolStats(pool, stats); - } - } - Balancer->Balance(); - Balancer->Unlock(); - } - } - - inline TPoolId TUnitedWorkers::AssignedPool(TWorkerContext& wctx) { - return Cpus[wctx.CpuId].State.AssignedPool(); - } - - inline bool TUnitedWorkers::IsPoolReassigned(TWorkerContext& wctx) { - return Cpus[wctx.CpuId].State.IsPoolReassigned(wctx.PoolId); - } - - inline void TUnitedWorkers::SwitchPool(TWorkerContext& wctx, ui64 softDeadlineTs) { - Pools[wctx.PoolId].Switch(wctx, softDeadlineTs, Cpus[wctx.CpuId].PoolStats[wctx.PoolId]); - Cpus[wctx.CpuId].SwitchPool(wctx.PoolId); - } - - TPoolId TUnitedWorkers::Idle(TPoolId assigned, TWorkerContext& wctx) { - wctx.SwitchToIdle(); - - TPoolId result; - TTimeTracker timeTracker; - TCpu& cpu = Cpus[wctx.CpuId]; - TPool* assignedPool = assigned == CpuShared ? nullptr : &Pools[assigned]; - TCpu::TScopedWaiters scopedWaiters(cpu, assignedPool); - while (true) { - if (cpu.StartSpinning(this, assignedPool, result)) { - break; // token already acquired (or stop) - } - result = WaitSequence(cpu, wctx, timeTracker); - if (Y_UNLIKELY(result == CpuStopped) || TryAcquireToken(result)) { - break; // token acquired (or stop) - } - } - - wctx.AddElapsedCycles(ActorSystemIndex, timeTracker.Elapsed()); - return result; - } - - TPoolId TUnitedWorkers::WaitSequence(TCpu& cpu, TWorkerContext& wctx, TTimeTracker& timeTracker) { - TPoolId result; - if (cpu.ActiveWait(Us2Ts(Config.SpinThresholdUs), result)) { - wctx.AddElapsedCycles(ActorSystemIndex, timeTracker.Elapsed()); - return result; - } - if (cpu.StartBlocking(result)) { - wctx.AddElapsedCycles(ActorSystemIndex, timeTracker.Elapsed()); - return result; - } - wctx.AddElapsedCycles(ActorSystemIndex, timeTracker.Elapsed()); - cpu.LoadLog.RegisterBusyPeriod(GetCycleCountFast()); - bool wakeup; - do { - wakeup = cpu.BlockedWait(result, Config.Balancer.PeriodUs * 1000); - wctx.AddParkedCycles(timeTracker.Elapsed()); - } while (!wakeup); - cpu.LoadLog.RegisterIdlePeriod(GetCycleCountFast()); - return result; - } - - void TUnitedWorkers::GetCurrentStats(TPoolId pool, TVector<TExecutorThreadStats>& statsCopy) const { - size_t idx = 1; - statsCopy.resize(idx + Pools[pool].WakeOrderCpus.size()); - for (TCpu* cpu : Pools[pool].WakeOrderCpus) { - TExecutorThreadStats& s = statsCopy[idx++]; - s = TExecutorThreadStats(); - s.Aggregate(cpu->PoolStats[pool]); - } - } - - TUnitedExecutorPool::TUnitedExecutorPool(const TUnitedExecutorPoolConfig& cfg, TUnitedWorkers* united) - : TExecutorPoolBaseMailboxed(cfg.PoolId) - , United(united) - , PoolName(cfg.PoolName) - { - United->SetupPool(TPoolId(cfg.PoolId), this, MailboxTable.Get()); - } - - void TUnitedExecutorPool::Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) { - ActorSystem = actorSystem; - - // Schedule readers are initialized through TUnitedWorkers::Prepare - *scheduleReaders = nullptr; - *scheduleSz = 0; - } - - void TUnitedExecutorPool::Start() { - // workers are actually started in TUnitedWorkers::Start() - } - - void TUnitedExecutorPool::PrepareStop() { - } - - void TUnitedExecutorPool::Shutdown() { - // workers are actually joined in TUnitedWorkers::Shutdown() - } - - TAffinity* TUnitedExecutorPool::Affinity() const { - Y_ABORT(); // should never be called, TCpuExecutorPool is used instead - } - - ui32 TUnitedExecutorPool::GetThreads() const { - return 0; - } - - ui32 TUnitedExecutorPool::GetReadyActivation(TWorkerContext&, ui64) { - Y_ABORT(); // should never be called, TCpu*ExecutorPool is used instead - } - - inline void TUnitedExecutorPool::ScheduleActivation(ui32 activation) { - TUnitedExecutorPool::ScheduleActivationEx(activation, AtomicIncrement(ActivationsRevolvingCounter)); - } - - inline void TUnitedExecutorPool::SpecificScheduleActivation(ui32 activation) { - TUnitedExecutorPool::ScheduleActivation(activation); - } - - inline void TUnitedExecutorPool::ScheduleActivationEx(ui32 activation, ui64 revolvingCounter) { - United->PushActivation(PoolId, activation, revolvingCounter); - } - - void TUnitedExecutorPool::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { - TUnitedExecutorPool::Schedule(deadline - ActorSystem->Timestamp(), ev, cookie, workerId); - } - - void TUnitedExecutorPool::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { - Y_DEBUG_ABORT_UNLESS(workerId < United->GetWorkerCount()); - const auto current = ActorSystem->Monotonic(); - if (deadline < current) { - deadline = current; - } - United->GetScheduleWriter(workerId)->Push(deadline.MicroSeconds(), ev.Release(), cookie); - } - - void TUnitedExecutorPool::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) { - Y_DEBUG_ABORT_UNLESS(workerId < United->GetWorkerCount()); - const auto deadline = ActorSystem->Monotonic() + delta; - United->GetScheduleWriter(workerId)->Push(deadline.MicroSeconds(), ev.Release(), cookie); - } - - void TUnitedExecutorPool::GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const { - Y_UNUSED(poolStats); - if (statsCopy.empty()) { - statsCopy.resize(1); - } - statsCopy[0] = TExecutorThreadStats(); - statsCopy[0].Aggregate(Stats); - United->GetCurrentStats(PoolId, statsCopy); - } -} diff --git a/library/cpp/actors/core/executor_pool_united.h b/library/cpp/actors/core/executor_pool_united.h deleted file mode 100644 index c0563a9053..0000000000 --- a/library/cpp/actors/core/executor_pool_united.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include "actorsystem.h" -#include "balancer.h" -#include "scheduler_queue.h" -#include "executor_pool_base.h" - -#include <library/cpp/actors/util/unordered_cache.h> - -#include <library/cpp/monlib/dynamic_counters/counters.h> -#include <library/cpp/actors/util/cpu_load_log.h> -#include <library/cpp/actors/util/unordered_cache.h> -#include <library/cpp/containers/stack_vector/stack_vec.h> - -#include <util/generic/noncopyable.h> - -namespace NActors { - class TMailboxTable; - - class TUnitedExecutorPool: public TExecutorPoolBaseMailboxed { - TUnitedWorkers* United; - const TString PoolName; - TAtomic ActivationsRevolvingCounter = 0; - public: - TUnitedExecutorPool(const TUnitedExecutorPoolConfig& cfg, TUnitedWorkers* united); - - void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) override; - void Start() override; - void PrepareStop() override; - void Shutdown() override; - - TAffinity* Affinity() const override; - ui32 GetThreads() const override; - ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingReadCounter) override; - void ScheduleActivation(ui32 activation) override; - void SpecificScheduleActivation(ui32 activation) override; - void ScheduleActivationEx(ui32 activation, ui64 revolvingWriteCounter) override; - void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; - void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; - void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override; - - void GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const override; - - TString GetName() const override { - return PoolName; - } - }; -} diff --git a/library/cpp/actors/core/executor_pool_united_ut.cpp b/library/cpp/actors/core/executor_pool_united_ut.cpp deleted file mode 100644 index df3e2d29d8..0000000000 --- a/library/cpp/actors/core/executor_pool_united_ut.cpp +++ /dev/null @@ -1,341 +0,0 @@ -#include "actorsystem.h" -#include "executor_pool_basic.h" -#include "hfunc.h" -#include "scheduler_basic.h" - -#include <library/cpp/actors/util/should_continue.h> - -#include <library/cpp/testing/unittest/registar.h> -#include <library/cpp/actors/protos/unittests.pb.h> - -using namespace NActors; - -//////////////////////////////////////////////////////////////////////////////// - -struct TEvMsg : public NActors::TEventBase<TEvMsg, 10347> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvMsg, "ExecutorPoolTest: Msg"); -}; - -//////////////////////////////////////////////////////////////////////////////// - -inline ui64 DoTimedWork(ui64 workUs) { - ui64 startUs = ThreadCPUTime(); - ui64 endUs = startUs + workUs; - ui64 nowUs = startUs; - do { - ui64 endTs = GetCycleCountFast() + Us2Ts(endUs - nowUs); - while (GetCycleCountFast() <= endTs) {} - nowUs = ThreadCPUTime(); - } while (nowUs <= endUs); - return nowUs - startUs; -} - -class TTestSenderActor : public IActorCallback { -private: - using EActivityType = IActor::EActivityType ; - using EActorActivity = IActor::EActorActivity; - -private: - TAtomic Counter; - TActorId Receiver; - - std::function<void(void)> Action; - -public: - TTestSenderActor(std::function<void(void)> action = [](){}, - EActivityType activityType = EActorActivity::OTHER) - : IActorCallback(static_cast<TReceiveFunc>(&TTestSenderActor::Execute), activityType) - , Action(action) - {} - - void Start(TActorId receiver, size_t count) { - AtomicSet(Counter, count); - Receiver = receiver; - } - - void Stop() { - while (true) { - if (GetCounter() == 0) { - break; - } - - Sleep(TDuration::MilliSeconds(1)); - } - } - - size_t GetCounter() const { - return AtomicGet(Counter); - } - -private: - STFUNC(Execute) { - switch (ev->GetTypeRewrite()) { - hFunc(TEvMsg, Handle); - } - } - - void Handle(TEvMsg::TPtr &ev) { - Y_UNUSED(ev); - Action(); - TAtomicBase count = AtomicDecrement(Counter); - Y_ABORT_UNLESS(count != Max<TAtomicBase>()); - if (count) { - Send(Receiver, new TEvMsg()); - } - } -}; - -// Single cpu balancer that switches pool on every activation; not thread-safe -struct TRoundRobinBalancer: public IBalancer { - TCpuState* State; - TMap<TPoolId, TPoolId> NextPool; - - bool AddCpu(const TCpuAllocation& cpuAlloc, TCpuState* cpu) override { - State = cpu; - TPoolId prev = cpuAlloc.AllowedPools.rbegin()->PoolId; - for (auto& p : cpuAlloc.AllowedPools) { - NextPool[prev] = p.PoolId; - prev = p.PoolId; - } - return true; - } - - bool TryLock(ui64) override { return true; } - void SetPoolStats(TPoolId, const TBalancerStats&) override {} - void Unlock() override {} - - void Balance() override { - TPoolId assigned; - TPoolId current; - State->Load(assigned, current); - State->AssignPool(NextPool[assigned]); - } - - ui64 GetPeriodUs() override { - return 1000; - } -}; - -void AddUnitedPool(THolder<TActorSystemSetup>& setup, ui32 concurrency = 0) { - TUnitedExecutorPoolConfig united; - united.PoolId = setup->GetExecutorsCount(); - united.Concurrency = concurrency; - setup->CpuManager.United.emplace_back(std::move(united)); -} - -THolder<TActorSystemSetup> GetActorSystemSetup(ui32 cpuCount) { - auto setup = MakeHolder<NActors::TActorSystemSetup>(); - setup->NodeId = 1; - setup->CpuManager.UnitedWorkers.CpuCount = cpuCount; - setup->CpuManager.UnitedWorkers.NoRealtime = true; // unavailable in test environment - setup->Scheduler = new TBasicSchedulerThread(NActors::TSchedulerConfig(512, 0)); - return setup; -} - -Y_UNIT_TEST_SUITE(UnitedExecutorPool) { - -#ifdef _linux_ - - Y_UNIT_TEST(OnePoolManyCpus) { - const size_t msgCount = 1e4; - auto setup = GetActorSystemSetup(4); - AddUnitedPool(setup); - TActorSystem actorSystem(setup); - actorSystem.Start(); - - auto begin = TInstant::Now(); - - auto actor = new TTestSenderActor(); - auto actorId = actorSystem.Register(actor); - actor->Start(actor->SelfId(), msgCount); - actorSystem.Send(actorId, new TEvMsg()); - - while (actor->GetCounter()) { - auto now = TInstant::Now(); - UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Counter is " << actor->GetCounter()); - - Sleep(TDuration::MilliSeconds(1)); - } - - TVector<TExecutorThreadStats> stats; - TExecutorPoolStats poolStats; - actorSystem.GetPoolStats(0, poolStats, stats); - // Sum all per-thread counters into the 0th element - for (ui32 idx = 1; idx < stats.size(); ++idx) { - stats[0].Aggregate(stats[idx]); - } - - UNIT_ASSERT_VALUES_EQUAL(stats[0].SentEvents, msgCount - 1); - UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount); - //UNIT_ASSERT_VALUES_EQUAL(stats[0].PreemptedEvents, 0); // depends on execution time and system load, so may be non-zero - UNIT_ASSERT_VALUES_EQUAL(stats[0].NonDeliveredEvents, 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].EmptyMailboxActivation, 0); - //UNIT_ASSERT_VALUES_EQUAL(stats[0].CpuUs, 0); // depends on total duration of test, so undefined - UNIT_ASSERT(stats[0].ElapsedTicks > 0); - //UNIT_ASSERT(stats[0].ParkedTicks == 0); // per-pool parked time does not make sense for united pools - UNIT_ASSERT_VALUES_EQUAL(stats[0].BlockedTicks, 0); - UNIT_ASSERT(stats[0].ActivationTimeHistogram.TotalSamples >= msgCount / TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX); - UNIT_ASSERT_VALUES_EQUAL(stats[0].EventDeliveryTimeHistogram.TotalSamples, msgCount); - UNIT_ASSERT_VALUES_EQUAL(stats[0].EventProcessingCountHistogram.TotalSamples, msgCount); - UNIT_ASSERT(stats[0].EventProcessingTimeHistogram.TotalSamples > 0); - UNIT_ASSERT(stats[0].ElapsedTicksByActivity[NActors::TActorTypeOperator::GetOtherActivityIndex()] > 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEventsByActivity[NActors::TActorTypeOperator::GetOtherActivityIndex()], msgCount); - UNIT_ASSERT_VALUES_EQUAL(stats[0].ActorsAliveByActivity[NActors::TActorTypeOperator::GetOtherActivityIndex()], 1); - UNIT_ASSERT_VALUES_EQUAL(stats[0].ScheduledEventsByActivity[NActors::TActorTypeOperator::GetOtherActivityIndex()], 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolDestroyedActors, 0); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolAllocatedMailboxes, 4095); // one line - UNIT_ASSERT(stats[0].MailboxPushedOutByTime + stats[0].MailboxPushedOutByEventCount + stats[0].MailboxPushedOutBySoftPreemption >= msgCount / TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX); - } - - Y_UNIT_TEST(ManyPoolsOneSharedCpu) { - const size_t msgCount = 1e4; - const size_t pools = 4; - auto setup = GetActorSystemSetup(1); - for (size_t pool = 0; pool < pools; pool++) { - AddUnitedPool(setup); - } - TActorSystem actorSystem(setup); - actorSystem.Start(); - - auto begin = TInstant::Now(); - - TVector<TTestSenderActor*> actors; - for (size_t pool = 0; pool < pools; pool++) { - auto actor = new TTestSenderActor(); - auto actorId = actorSystem.Register(actor, TMailboxType::HTSwap, pool); - actor->Start(actor->SelfId(), msgCount); - actorSystem.Send(actorId, new TEvMsg()); - actors.push_back(actor); - } - - while (true) { - size_t left = 0; - for (auto actor : actors) { - left += actor->GetCounter(); - } - if (left == 0) { - break; - } - auto now = TInstant::Now(); - UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "left " << left); - Sleep(TDuration::MilliSeconds(1)); - } - - for (size_t pool = 0; pool < pools; pool++) { - TVector<TExecutorThreadStats> stats; - TExecutorPoolStats poolStats; - actorSystem.GetPoolStats(pool, poolStats, stats); - // Sum all per-thread counters into the 0th element - for (ui32 idx = 1; idx < stats.size(); ++idx) { - stats[0].Aggregate(stats[idx]); - } - - UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1); - } - } - - Y_UNIT_TEST(ManyPoolsOneAssignedCpu) { - const size_t msgCount = 1e4; - const size_t pools = 4; - auto setup = GetActorSystemSetup(1); - setup->Balancer.Reset(new TRoundRobinBalancer()); - for (size_t pool = 0; pool < pools; pool++) { - AddUnitedPool(setup); - } - TActorSystem actorSystem(setup); - actorSystem.Start(); - - auto begin = TInstant::Now(); - - TVector<TTestSenderActor*> actors; - for (size_t pool = 0; pool < pools; pool++) { - auto actor = new TTestSenderActor(); - auto actorId = actorSystem.Register(actor, TMailboxType::HTSwap, pool); - actor->Start(actor->SelfId(), msgCount); - actorSystem.Send(actorId, new TEvMsg()); - actors.push_back(actor); - } - - while (true) { - size_t left = 0; - for (auto actor : actors) { - left += actor->GetCounter(); - } - if (left == 0) { - break; - } - auto now = TInstant::Now(); - UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "left " << left); - Sleep(TDuration::MilliSeconds(1)); - } - - for (size_t pool = 0; pool < pools; pool++) { - TVector<TExecutorThreadStats> stats; - TExecutorPoolStats poolStats; - actorSystem.GetPoolStats(pool, poolStats, stats); - // Sum all per-thread counters into the 0th element - for (ui32 idx = 1; idx < stats.size(); ++idx) { - stats[0].Aggregate(stats[idx]); - } - - UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1); - } - } - - Y_UNIT_TEST(ManyPoolsOneCpuSlowEvents) { - const size_t msgCount = 3; - const size_t pools = 4; - auto setup = GetActorSystemSetup(1); - for (size_t pool = 0; pool < pools; pool++) { - AddUnitedPool(setup); - } - TActorSystem actorSystem(setup); - actorSystem.Start(); - - auto begin = TInstant::Now(); - - TVector<TTestSenderActor*> actors; - for (size_t pool = 0; pool < pools; pool++) { - auto actor = new TTestSenderActor([]() { - DoTimedWork(100'000); - }); - auto actorId = actorSystem.Register(actor, TMailboxType::HTSwap, pool); - actor->Start(actor->SelfId(), msgCount); - actorSystem.Send(actorId, new TEvMsg()); - actors.push_back(actor); - } - - while (true) { - size_t left = 0; - for (auto actor : actors) { - left += actor->GetCounter(); - } - if (left == 0) { - break; - } - auto now = TInstant::Now(); - UNIT_ASSERT_C(now - begin < TDuration::Seconds(15), "left " << left); - Sleep(TDuration::MilliSeconds(1)); - } - - for (size_t pool = 0; pool < pools; pool++) { - TVector<TExecutorThreadStats> stats; - TExecutorPoolStats poolStats; - actorSystem.GetPoolStats(pool, poolStats, stats); - // Sum all per-thread counters into the 0th element - for (ui32 idx = 1; idx < stats.size(); ++idx) { - stats[0].Aggregate(stats[idx]); - } - - UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount); - UNIT_ASSERT_VALUES_EQUAL(stats[0].PreemptedEvents, msgCount); // every 100ms event should be preempted - UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1); - } - } - -#endif - -} diff --git a/library/cpp/actors/core/executor_pool_united_workers.h b/library/cpp/actors/core/executor_pool_united_workers.h deleted file mode 100644 index c683ae7d9f..0000000000 --- a/library/cpp/actors/core/executor_pool_united_workers.h +++ /dev/null @@ -1,105 +0,0 @@ -#pragma once - -#include "defs.h" -#include "balancer.h" -#include "scheduler_queue.h" - -#include <library/cpp/actors/actor_type/indexes.h> -#include <library/cpp/actors/util/cpu_load_log.h> -#include <library/cpp/actors/util/datetime.h> -#include <util/generic/noncopyable.h> - -namespace NActors { - class TActorSystem; - class TMailboxTable; - - class TUnitedWorkers: public TNonCopyable { - struct TWorker; - struct TPool; - struct TCpu; - - i16 WorkerCount; - TArrayHolder<TWorker> Workers; // indexed by WorkerId - size_t PoolCount; - TArrayHolder<TPool> Pools; // indexed by PoolId, so may include not used (not united) pools - size_t CpuCount; - TArrayHolder<TCpu> Cpus; // indexed by CpuId, so may include not allocated CPUs - - IBalancer* Balancer; // external pool cpu balancer - - TUnitedWorkersConfig Config; - TCpuAllocationConfig Allocation; - - volatile bool StopFlag = false; - TMinusOneCpuEstimator<1024> MinusOneCpuEstimator; - const ui32 ActorSystemIndex = NActors::TActorTypeOperator::GetActorSystemIndex(); - public: - TUnitedWorkers( - const TUnitedWorkersConfig& config, - const TVector<TUnitedExecutorPoolConfig>& unitedPools, - const TCpuAllocationConfig& allocation, - IBalancer* balancer); - ~TUnitedWorkers(); - void Prepare(TActorSystem* actorSystem, TVector<NSchedulerQueue::TReader*>& scheduleReaders); - void Start(); - void PrepareStop(); - void Shutdown(); - - bool IsStopped() const { - return RelaxedLoad(&StopFlag); - } - - TWorkerId GetWorkerCount() const { - return WorkerCount; - } - - // Returns thread id of a worker - TThreadId GetWorkerThreadId(TWorkerId workerId) const; - - // Returns per worker schedule writers - NSchedulerQueue::TWriter* GetScheduleWriter(TWorkerId workerId) const; - - // Sets executor for specified pool - void SetupPool(TPoolId pool, IExecutorPool* executorPool, TMailboxTable* mailboxTable); - - // Add activation of newly scheduled mailbox and wake cpu to execute it if required - void PushActivation(TPoolId pool, ui32 activation, ui64 revolvingCounter); - - // Try acquire pending token. Must be done before execution - bool TryAcquireToken(TPoolId pool); - - // Try to wake idle cpu waiting for tokens on specified pool - void TryWake(TPoolId pool); - - // Get activation from pool; requires pool's token - void BeginExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter); - - // Stop currently active execution and start new one if token is available - // NOTE: Reuses token if it's not destroyed - bool NextExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter); - - // Stop active execution - void StopExecution(TPoolId pool); - - // Runs balancer to assign pools to cpus - void Balance(); - - // Returns pool to be executed by worker or `CpuShared` - TPoolId AssignedPool(TWorkerContext& wctx); - - // Checks if balancer has assigned another pool for worker's cpu - bool IsPoolReassigned(TWorkerContext& wctx); - - // Switch worker context into specified pool - void SwitchPool(TWorkerContext& wctx, ui64 softDeadlineTs); - - // Wait for tokens from any pool allowed on specified cpu - TPoolId Idle(TPoolId assigned, TWorkerContext& wctx); - - // Fill stats for specified pool - void GetCurrentStats(TPoolId pool, TVector<TExecutorThreadStats>& statsCopy) const; - - private: - TPoolId WaitSequence(TCpu& cpu, TWorkerContext& wctx, TTimeTracker& timeTracker); - }; -} diff --git a/library/cpp/actors/core/executor_thread.cpp b/library/cpp/actors/core/executor_thread.cpp deleted file mode 100644 index 4aab7b3e31..0000000000 --- a/library/cpp/actors/core/executor_thread.cpp +++ /dev/null @@ -1,714 +0,0 @@ -#include "executor_thread.h" -#include "actorsystem.h" -#include "actor.h" -#include "callstack.h" -#include "mailbox.h" -#include "event.h" -#include "events.h" -#include "executor_pool_base.h" -#include "probes.h" - -#include <library/cpp/actors/prof/tag.h> -#include <library/cpp/actors/util/affinity.h> -#include <library/cpp/actors/util/datetime.h> -#include <library/cpp/actors/util/thread.h> - -#ifdef BALLOC -#include <library/cpp/balloc/optional/operators.h> -#endif - -#ifdef _linux_ -#include <sys/syscall.h> -#include <unistd.h> -#endif - -#include <util/system/type_name.h> -#include <util/system/datetime.h> - -LWTRACE_USING(ACTORLIB_PROVIDER) - -namespace NActors { - constexpr TDuration TExecutorThread::DEFAULT_TIME_PER_MAILBOX; - - TExecutorThread::TExecutorThread( - TWorkerId workerId, - TWorkerId cpuId, - TActorSystem* actorSystem, - IExecutorPool* executorPool, - TMailboxTable* mailboxTable, - const TString& threadName, - TDuration timePerMailbox, - ui32 eventsPerMailbox) - : ActorSystem(actorSystem) - , ExecutorPool(executorPool) - , Ctx(workerId, cpuId) - , ThreadName(threadName) - , IsUnitedWorker(true) - , TimePerMailbox(timePerMailbox) - , EventsPerMailbox(eventsPerMailbox) - { - Ctx.Switch( - ExecutorPool, - mailboxTable, - NHPTimer::GetClockRate() * timePerMailbox.SecondsFloat(), - eventsPerMailbox, - ui64(-1), // infinite soft deadline - &Ctx.WorkerStats); - } - - TExecutorThread::TExecutorThread(TWorkerId workerId, - TActorSystem* actorSystem, - TVector<IExecutorPool*> executorPools, - const TString& threadName, - ui64 softProcessingDurationTs, - TDuration timePerMailbox, - ui32 eventsPerMailbox) - : ActorSystem(actorSystem) - , AvailableExecutorPools(executorPools) - , Ctx(workerId, 0) - , ThreadName(threadName) - , IsUnitedWorker(false) - , TimePerMailbox(timePerMailbox) - , EventsPerMailbox(eventsPerMailbox) - , SoftProcessingDurationTs(softProcessingDurationTs) - {} - - - - TExecutorThread::~TExecutorThread() - { } - - void TExecutorThread::UnregisterActor(TMailboxHeader* mailbox, TActorId actorId) { - Y_DEBUG_ABORT_UNLESS(IsUnitedWorker || actorId.PoolID() == ExecutorPool->PoolId && ExecutorPool->ResolveMailbox(actorId.Hint()) == mailbox); - IActor* actor = mailbox->DetachActor(actorId.LocalId()); - Ctx.DecrementActorsAliveByActivity(actor->GetActivityType()); - DyingActors.push_back(THolder(actor)); - } - - void TExecutorThread::DropUnregistered() { -#if defined(ACTORSLIB_COLLECT_EXEC_STATS) - if (ActorSystem->MonitorStuckActors()) { - if (auto *pool = dynamic_cast<TExecutorPoolBaseMailboxed*>(ExecutorPool)) { - with_lock (pool->StuckObserverMutex) { - for (const auto& actor : DyingActors) { - const size_t i = actor->StuckIndex; - auto& actorPtr = pool->Actors[i]; - actorPtr = pool->Actors.back(); - actorPtr->StuckIndex = i; - pool->Actors.pop_back(); - pool->DeadActorsUsage.emplace_back(actor->GetActivityType(), actor->GetUsage(GetCycleCountFast())); - } - } - } - } -#endif - DyingActors.clear(); // here is actual destruction of actors - } - - void TExecutorThread::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) { - ++CurrentActorScheduledEventsCounter; - Ctx.Executor->Schedule(deadline, ev, cookie, Ctx.WorkerId); - } - - void TExecutorThread::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) { - ++CurrentActorScheduledEventsCounter; - Ctx.Executor->Schedule(deadline, ev, cookie, Ctx.WorkerId); - } - - void TExecutorThread::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) { - ++CurrentActorScheduledEventsCounter; - Ctx.Executor->Schedule(delta, ev, cookie, Ctx.WorkerId); - } - - template <class T> - inline TString SafeTypeName(const T* t) { - if (t == nullptr) { - return "nullptr"; - } - try { - return TypeName(*t); - } catch (...) { - return "unknown-type"; - } - } - - inline void LwTraceSlowDelivery(IEventHandle* ev, const std::type_info* actorType, ui32 poolId, const TActorId& currentRecipient, - double delivMs, double sinceActivationMs, ui32 eventsExecutedBefore) { - LWPROBE(EventSlowDelivery, - poolId, - delivMs, - sinceActivationMs, - eventsExecutedBefore, - ev && ev->HasEvent() ? ev->GetTypeName() : (ev ? ToString(ev->Type) : TString("nullptr")), - currentRecipient.ToString(), - SafeTypeName(actorType)); - } - - inline void LwTraceSlowEvent(IEventHandle* ev, ui32 evTypeForTracing, const std::type_info* actorType, ui32 poolId, - const TActorId& currentRecipient, double eventMs) { - // Event could have been destroyed by actor->Receive(); - LWPROBE(SlowEvent, - poolId, - eventMs, - ev && ev->HasEvent() ? ev->GetTypeName() : ToString(evTypeForTracing), - currentRecipient.ToString(), - SafeTypeName(actorType)); - } - - template <typename TMailbox> - bool TExecutorThread::Execute(TMailbox* mailbox, ui32 hint, bool isTailExecution) { - Y_DEBUG_ABORT_UNLESS(DyingActors.empty()); - - bool reclaimAsFree = false; - - if (!isTailExecution) { - Ctx.HPStart = GetCycleCountFast(); - Ctx.ExecutedEvents = 0; - } - NHPTimer::STime hpprev = Ctx.HPStart; - - IActor* actor = nullptr; - const std::type_info* actorType = nullptr; - ui32 prevActivityType = std::numeric_limits<ui32>::max(); - TActorId recipient; - bool firstEvent = true; - bool preempted = false; - for (; Ctx.ExecutedEvents < Ctx.EventsPerMailbox; ++Ctx.ExecutedEvents) { - if (TAutoPtr<IEventHandle> evExt = mailbox->Pop()) { - mailbox->ProcessEvents(mailbox); - NHPTimer::STime hpnow; - recipient = evExt->GetRecipientRewrite(); - TActorContext ctx(*mailbox, *this, hpprev, recipient); - TlsActivationContext = &ctx; // ensure dtor (if any) is called within actor system - // move for destruct before ctx; - auto ev = std::move(evExt); - if (actor = mailbox->FindActor(recipient.LocalId())) { - // Since actor is not null there should be no exceptions - actorType = &typeid(*actor); - -#ifdef USE_ACTOR_CALLSTACK - TCallstack::GetTlsCallstack() = ev->Callstack; - TCallstack::GetTlsCallstack().SetLinesToSkip(); -#endif - CurrentRecipient = recipient; - CurrentActorScheduledEventsCounter = 0; - - if (firstEvent) { - double usec = Ctx.AddActivationStats(AtomicLoad(&mailbox->ScheduleMoment), hpprev); - if (usec > 500) { - GLOBAL_LWPROBE(ACTORLIB_PROVIDER, SlowActivation, Ctx.PoolId, usec / 1000.0); - } - firstEvent = false; - } - - i64 usecDeliv = Ctx.AddEventDeliveryStats(ev->SendTime, hpprev); - if (usecDeliv > 5000) { - double sinceActivationMs = NHPTimer::GetSeconds(hpprev - Ctx.HPStart) * 1000.0; - LwTraceSlowDelivery(ev.Get(), actorType, Ctx.PoolId, CurrentRecipient, NHPTimer::GetSeconds(hpprev - ev->SendTime) * 1000.0, sinceActivationMs, Ctx.ExecutedEvents); - } - - ui32 evTypeForTracing = ev->Type; - - ui32 activityType = actor->GetActivityType(); - if (activityType != prevActivityType) { - prevActivityType = activityType; - NProfiling::TMemoryTagScope::Reset(activityType); - } - - actor->Receive(ev); - mailbox->ProcessEvents(mailbox); - actor->OnDequeueEvent(); - - size_t dyingActorsCnt = DyingActors.size(); - Ctx.UpdateActorsStats(dyingActorsCnt); - if (dyingActorsCnt) { - DropUnregistered(); - mailbox->ProcessEvents(mailbox); - actor = nullptr; - } - - if (mailbox->IsEmpty()) // was not-free and become free, we must reclaim mailbox - reclaimAsFree = true; - - hpnow = GetCycleCountFast(); - NHPTimer::STime elapsed = Ctx.AddEventProcessingStats(hpprev, hpnow, activityType, CurrentActorScheduledEventsCounter); - if (elapsed > 1000000) { - LwTraceSlowEvent(ev.Get(), evTypeForTracing, actorType, Ctx.PoolId, CurrentRecipient, NHPTimer::GetSeconds(elapsed) * 1000.0); - } - - // The actor might have been destroyed - if (actor) - actor->AddElapsedTicks(elapsed); - - CurrentRecipient = TActorId(); - } else { - actorType = nullptr; - - TAutoPtr<IEventHandle> nonDelivered = IEventHandle::ForwardOnNondelivery(std::move(ev), TEvents::TEvUndelivered::ReasonActorUnknown); - if (nonDelivered.Get()) { - ActorSystem->Send(nonDelivered); - } else { - Ctx.IncrementNonDeliveredEvents(); - } - hpnow = GetCycleCountFast(); - } - - hpprev = hpnow; - - if (TlsThreadContext->CapturedType == ESendingType::Tail) { - AtomicStore(&mailbox->ScheduleMoment, hpnow); - Ctx.IncrementMailboxPushedOutByTailSending(); - LWTRACK(MailboxPushedOutByTailSending, - Ctx.Orbit, - Ctx.PoolId, - Ctx.Executor->GetName(), - Ctx.ExecutedEvents + 1, - CyclesToDuration(hpnow - Ctx.HPStart), - Ctx.WorkerId, - recipient.ToString(), - SafeTypeName(actorType)); - break; - } - - // Soft preemption in united pool - if (Ctx.SoftDeadlineTs < (ui64)hpnow) { - AtomicStore(&mailbox->ScheduleMoment, hpnow); - Ctx.IncrementMailboxPushedOutBySoftPreemption(); - LWTRACK(MailboxPushedOutBySoftPreemption, - Ctx.Orbit, - Ctx.PoolId, - Ctx.Executor->GetName(), - Ctx.ExecutedEvents + 1, - CyclesToDuration(hpnow - Ctx.HPStart), - Ctx.WorkerId, - recipient.ToString(), - SafeTypeName(actorType)); - preempted = true; - break; - } - - // time limit inside one mailbox passed, let others do some work - if (hpnow - Ctx.HPStart > (i64)Ctx.TimePerMailboxTs) { - AtomicStore(&mailbox->ScheduleMoment, hpnow); - Ctx.IncrementMailboxPushedOutByTime(); - LWTRACK(MailboxPushedOutByTime, - Ctx.Orbit, - Ctx.PoolId, - Ctx.Executor->GetName(), - Ctx.ExecutedEvents + 1, - CyclesToDuration(hpnow - Ctx.HPStart), - Ctx.WorkerId, - recipient.ToString(), - SafeTypeName(actorType)); - preempted = true; - break; - } - - if (Ctx.ExecutedEvents + 1 == Ctx.EventsPerMailbox) { - AtomicStore(&mailbox->ScheduleMoment, hpnow); - Ctx.IncrementMailboxPushedOutByEventCount(); - LWTRACK(MailboxPushedOutByEventCount, - Ctx.Orbit, - Ctx.PoolId, - Ctx.Executor->GetName(), - Ctx.ExecutedEvents + 1, - CyclesToDuration(hpnow - Ctx.HPStart), - Ctx.WorkerId, - recipient.ToString(), - SafeTypeName(actorType)); - preempted = true; - break; - } - } else { - if (Ctx.ExecutedEvents == 0) - Ctx.IncrementEmptyMailboxActivation(); - LWTRACK(MailboxEmpty, - Ctx.Orbit, - Ctx.PoolId, - Ctx.Executor->GetName(), - Ctx.ExecutedEvents, - CyclesToDuration(GetCycleCountFast() - Ctx.HPStart), - Ctx.WorkerId, - recipient.ToString(), - SafeTypeName(actor)); - break; // empty queue, leave - } - } - - NProfiling::TMemoryTagScope::Reset(0); - TlsActivationContext = nullptr; - UnlockFromExecution(mailbox, Ctx.Executor, reclaimAsFree, hint, Ctx.WorkerId, RevolvingWriteCounter); - return preempted; - } - - TThreadId TExecutorThread::GetThreadId() const { -#ifdef _linux_ - while (AtomicLoad(&ThreadId) == UnknownThreadId) { - NanoSleep(1000); - } -#endif - return ThreadId; - } - - TWorkerId TExecutorThread::GetWorkerId() const { - return Ctx.WorkerId; - } - - void TExecutorThread::ProcessExecutorPool(IExecutorPool *pool, bool isSharedThread) { - ExecutorPool = pool; - TThreadContext threadCtx; - TlsThreadContext = &threadCtx; - TlsThreadContext->Pool = static_cast<IExecutorPool*>(ExecutorPool); - TlsThreadContext->WorkerId = Ctx.WorkerId; - pool->Initialize(Ctx); - - ExecutorPool->SetRealTimeMode(); - TAffinityGuard affinity(ExecutorPool->Affinity()); - - NHPTimer::STime hpnow = GetCycleCountFast(); - NHPTimer::STime hpprev = hpnow; - ui64 execCount = 0; - ui64 readyActivationCount = 0; - i64 execCycles = 0; - i64 nonExecCycles = 0; - - bool needToStop = false; - - auto executeActivation = [&](ui32 activation, bool isTailExecution) { - LWTRACK(ActivationBegin, Ctx.Orbit, Ctx.CpuId, Ctx.PoolId, Ctx.WorkerId, NHPTimer::GetSeconds(Ctx.Lease.GetPreciseExpireTs()) * 1e3); - readyActivationCount++; - if (TMailboxHeader* header = Ctx.MailboxTable->Get(activation)) { - if (header->LockForExecution()) { - hpnow = GetCycleCountFast(); - nonExecCycles += hpnow - hpprev; - hpprev = hpnow; -#define EXECUTE_MAILBOX(type) \ - case TMailboxType:: type: \ - { \ - using TMailBox = TMailboxTable:: T ## type ## Mailbox ; \ - if (Execute<TMailBox>(static_cast<TMailBox*>(header), activation, isTailExecution)) { \ - TlsThreadContext->CapturedType = ESendingType::Lazy; \ - } \ - } \ - break \ -// EXECUTE_MAILBOX - switch (header->Type) { - EXECUTE_MAILBOX(Simple); - EXECUTE_MAILBOX(Revolving); - EXECUTE_MAILBOX(HTSwap); - EXECUTE_MAILBOX(ReadAsFilled); - EXECUTE_MAILBOX(TinyReadAsFilled); - } -#undef EXECUTE_MAILBOX - hpnow = GetCycleCountFast(); - i64 currentExecCycles = hpnow - hpprev; - execCycles += currentExecCycles; - hpprev = hpnow; - execCount++; - if (execCycles + nonExecCycles > 39000000) { // every 15 ms at 2.6GHz, so 1000 items is 15 sec (solomon interval) - LWPROBE(ExecutorThreadStats, ExecutorPool->PoolId, ExecutorPool->GetName(), Ctx.WorkerId, - execCount, readyActivationCount, - NHPTimer::GetSeconds(execCycles) * 1000.0, NHPTimer::GetSeconds(nonExecCycles) * 1000.0); - execCount = 0; - readyActivationCount = 0; - execCycles = 0; - nonExecCycles = 0; - Ctx.UpdateThreadTime(); - } - - if (isSharedThread && (ui64)hpnow > Ctx.SoftDeadlineTs) { - needToStop = true; - } - - if (!TlsThreadContext->IsEnoughCpu) { - Ctx.IncreaseNotEnoughCpuExecutions(); - TlsThreadContext->IsEnoughCpu = true; - } - } - } - LWTRACK(ActivationEnd, Ctx.Orbit, Ctx.CpuId, Ctx.PoolId, Ctx.WorkerId); - Ctx.Orbit.Reset(); - }; - - while (!needToStop && !StopFlag.load(std::memory_order_relaxed)) { - if (TlsThreadContext->CapturedType == ESendingType::Tail) { - TlsThreadContext->CapturedType = ESendingType::Lazy; - ui32 activation = std::exchange(TlsThreadContext->CapturedActivation, 0); - executeActivation(activation, true); - continue; - } - Ctx.IsNeededToWaitNextActivation = !TlsThreadContext->CapturedActivation && !isSharedThread; - ui32 activation = ExecutorPool->GetReadyActivation(Ctx, ++RevolvingReadCounter); - if (!activation) { - activation = std::exchange(TlsThreadContext->CapturedActivation, 0); - } else if (TlsThreadContext->CapturedActivation) { - ui32 capturedActivation = std::exchange(TlsThreadContext->CapturedActivation, 0); - ExecutorPool->ScheduleActivation(capturedActivation); - } - if (!activation) { - break; - } - executeActivation(activation, false); - } - } - - void* TExecutorThread::ThreadProc() { -#ifdef _linux_ - pid_t tid = syscall(SYS_gettid); - AtomicSet(ThreadId, (ui64)tid); -#endif - -#ifdef BALLOC - ThreadDisableBalloc(); -#endif - - if (ThreadName) { - ::SetCurrentThreadName(ThreadName); - } - - - std::vector<TExecutorPoolBaseMailboxed*> pools; - pools.reserve(AvailableExecutorPools.size()); - for (auto pool : AvailableExecutorPools) { - TExecutorPoolBaseMailboxed* mailboxedPool = dynamic_cast<TExecutorPoolBaseMailboxed*>(pool); - if (mailboxedPool) { - pools.push_back(mailboxedPool); - } - } - - if (pools.size() == 1) { - ExecutorPool = pools[0]; - Ctx.Switch( - pools[0], - pools[0]->MailboxTable.Get(), - NHPTimer::GetClockRate() * TimePerMailbox.SecondsFloat(), - EventsPerMailbox, - GetCycleCountFast() + SoftProcessingDurationTs, - &Ctx.WorkerStats); - } - - if (pools.size() <= 1) { - ProcessExecutorPool(ExecutorPool, false); - } else { - while (!StopFlag.load(std::memory_order_relaxed)) { - for (auto pool : pools) { - Ctx.Switch( - pool, - pool->MailboxTable.Get(), - NHPTimer::GetClockRate() * TimePerMailbox.SecondsFloat(), - EventsPerMailbox, - GetCycleCountFast() + SoftProcessingDurationTs, - &Ctx.WorkerStats); - Ctx.WorkerId = -1; - ProcessExecutorPool(pool, true); - } - } - } - - return nullptr; - } - - // there must be barrier and check-read with following cas - // or just cas w/o read. - // or queue unlocks must be performed with exchange and not generic write - // TODO: check performance of those options under contention - - // placed here in hope for better compiler optimization - - bool TMailboxHeader::MarkForSchedule() { - AtomicBarrier(); - for (;;) { - const ui32 state = AtomicLoad(&ExecutionState); - switch (state) { - case TExecutionState::Inactive: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::Scheduled, TExecutionState::Inactive)) - return true; - break; - case TExecutionState::Scheduled: - return false; - case TExecutionState::Leaving: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::LeavingMarked, TExecutionState::Leaving)) - return true; - break; - case TExecutionState::Executing: - case TExecutionState::LeavingMarked: - return false; - case TExecutionState::Free: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::Free)) - return true; - break; - case TExecutionState::FreeScheduled: - return false; - case TExecutionState::FreeLeaving: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeLeavingMarked, TExecutionState::FreeLeaving)) - return true; - break; - case TExecutionState::FreeExecuting: - case TExecutionState::FreeLeavingMarked: - return false; - default: - Y_ABORT(); - } - } - } - - bool TMailboxHeader::LockForExecution() { - AtomicBarrier(); // strictly speaking here should be AtomicBarrier, but as we got mailboxes from queue - this barrier is already set implicitly and could be removed - for (;;) { - const ui32 state = AtomicLoad(&ExecutionState); - switch (state) { - case TExecutionState::Inactive: - return false; - case TExecutionState::Scheduled: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::Executing, TExecutionState::Scheduled)) - return true; - break; - case TExecutionState::Leaving: - case TExecutionState::Executing: - case TExecutionState::LeavingMarked: - return false; - case TExecutionState::Free: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeExecuting, TExecutionState::Free)) - return true; - break; - case TExecutionState::FreeScheduled: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeExecuting, TExecutionState::FreeScheduled)) - return true; - break; - case TExecutionState::FreeLeaving: - case TExecutionState::FreeExecuting: - case TExecutionState::FreeLeavingMarked: - return false; - default: - Y_ABORT(); - } - } - } - - bool TMailboxHeader::LockFromFree() { - AtomicBarrier(); - for (;;) { - const ui32 state = AtomicLoad(&ExecutionState); - switch (state) { - case TExecutionState::Inactive: - case TExecutionState::Scheduled: - case TExecutionState::Leaving: - case TExecutionState::Executing: - case TExecutionState::LeavingMarked: - Y_ABORT(); - case TExecutionState::Free: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::Executing, TExecutionState::Free)) - return true; - break; - case TExecutionState::FreeScheduled: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::Executing, TExecutionState::FreeScheduled)) - return true; - break; - case TExecutionState::FreeLeaving: - case TExecutionState::FreeExecuting: - case TExecutionState::FreeLeavingMarked: - return false; - default: - Y_ABORT(); - } - } - } - - void TMailboxHeader::UnlockFromExecution1() { - const ui32 state = AtomicLoad(&ExecutionState); - if (state == TExecutionState::Executing) - AtomicStore(&ExecutionState, (ui32)TExecutionState::Leaving); - else if (state == TExecutionState::FreeExecuting) - AtomicStore(&ExecutionState, (ui32)TExecutionState::FreeLeaving); - else - Y_ABORT(); - AtomicBarrier(); - } - - bool TMailboxHeader::UnlockFromExecution2(bool wouldReschedule) { - AtomicBarrier(); - for (;;) { - const ui32 state = AtomicLoad(&ExecutionState); - switch (state) { - case TExecutionState::Inactive: - case TExecutionState::Scheduled: - Y_ABORT(); - case TExecutionState::Leaving: - if (!wouldReschedule) { - if (AtomicUi32Cas(&ExecutionState, TExecutionState::Inactive, TExecutionState::Leaving)) - return false; - } else { - if (AtomicUi32Cas(&ExecutionState, TExecutionState::Scheduled, TExecutionState::Leaving)) - return true; - } - break; - case TExecutionState::Executing: - Y_ABORT(); - case TExecutionState::LeavingMarked: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::Scheduled, TExecutionState::LeavingMarked)) - return true; - break; - case TExecutionState::Free: - case TExecutionState::FreeScheduled: - Y_ABORT(); - case TExecutionState::FreeLeaving: - if (!wouldReschedule) { - if (AtomicUi32Cas(&ExecutionState, TExecutionState::Free, TExecutionState::FreeLeaving)) - return false; - } else { - if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::FreeLeaving)) - return true; - } - break; - case TExecutionState::FreeExecuting: - Y_ABORT(); - case TExecutionState::FreeLeavingMarked: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::FreeLeavingMarked)) - return true; - break; - default: - Y_ABORT(); - } - } - } - - bool TMailboxHeader::UnlockAsFree(bool wouldReschedule) { - AtomicBarrier(); - for (;;) { - const ui32 state = AtomicLoad(&ExecutionState); - switch (state) { - case TExecutionState::Inactive: - case TExecutionState::Scheduled: - Y_ABORT(); - case TExecutionState::Leaving: - if (!wouldReschedule) { - if (AtomicUi32Cas(&ExecutionState, TExecutionState::Free, TExecutionState::Leaving)) - return false; - } else { - if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::Leaving)) - return true; - } - break; - case TExecutionState::Executing: - Y_ABORT(); - case TExecutionState::LeavingMarked: - if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::LeavingMarked)) - return true; - break; - case TExecutionState::Free: - case TExecutionState::FreeScheduled: - case TExecutionState::FreeLeaving: - case TExecutionState::FreeExecuting: - case TExecutionState::FreeLeavingMarked: - Y_ABORT(); - default: - Y_ABORT(); - } - } - } - - void TExecutorThread::GetCurrentStats(TExecutorThreadStats& statsCopy) const { - Ctx.GetCurrentStats(statsCopy); - } - -} diff --git a/library/cpp/actors/core/executor_thread.h b/library/cpp/actors/core/executor_thread.h deleted file mode 100644 index b466ad2423..0000000000 --- a/library/cpp/actors/core/executor_thread.h +++ /dev/null @@ -1,126 +0,0 @@ -#pragma once - -#include "defs.h" -#include "event.h" -#include "callstack.h" -#include "probes.h" -#include "worker_context.h" -#include "log_settings.h" - -#include <library/cpp/actors/util/datetime.h> - -#include <util/system/thread.h> - -namespace NActors { - class IActor; - class TActorSystem; - - class TExecutorThread: public ISimpleThread { - public: - static constexpr TDuration DEFAULT_TIME_PER_MAILBOX = - TDuration::MilliSeconds(10); - static constexpr ui32 DEFAULT_EVENTS_PER_MAILBOX = 100; - - TExecutorThread(TWorkerId workerId, - TWorkerId cpuId, - TActorSystem* actorSystem, - IExecutorPool* executorPool, - TMailboxTable* mailboxTable, - const TString& threadName, - TDuration timePerMailbox = DEFAULT_TIME_PER_MAILBOX, - ui32 eventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX); - - TExecutorThread(TWorkerId workerId, - TActorSystem* actorSystem, - IExecutorPool* executorPool, - TMailboxTable* mailboxTable, - const TString& threadName, - TDuration timePerMailbox = DEFAULT_TIME_PER_MAILBOX, - ui32 eventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX) - : TExecutorThread(workerId, 0, actorSystem, executorPool, mailboxTable, threadName, timePerMailbox, eventsPerMailbox) - {} - - TExecutorThread(TWorkerId workerId, - TActorSystem* actorSystem, - TVector<IExecutorPool*> executorPools, - const TString& threadName, - ui64 softProcessingDurationTs, - TDuration timePerMailbox, - ui32 eventsPerMailbox); - - virtual ~TExecutorThread(); - - template <ESendingType SendingType = ESendingType::Common> - TActorId RegisterActor(IActor* actor, TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 poolId = Max<ui32>(), - TActorId parentId = TActorId()); - template <ESendingType SendingType = ESendingType::Common> - TActorId RegisterActor(IActor* actor, TMailboxHeader* mailbox, ui32 hint, TActorId parentId = TActorId()); - void UnregisterActor(TMailboxHeader* mailbox, TActorId actorId); - void DropUnregistered(); - const std::vector<THolder<IActor>>& GetUnregistered() const { return DyingActors; } - - void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr); - void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr); - void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr); - - template <ESendingType SendingType = ESendingType::Common> - bool Send(TAutoPtr<IEventHandle> ev); - - void GetCurrentStats(TExecutorThreadStats& statsCopy) const; - - TThreadId GetThreadId() const; // blocks, must be called after Start() - TWorkerId GetWorkerId() const; - - private: - void* ThreadProc(); - - void ProcessExecutorPool(IExecutorPool *pool, bool isSharedThread); - - template <typename TMailbox> - bool Execute(TMailbox* mailbox, ui32 hint, bool isTailExecution); - - public: - TActorSystem* const ActorSystem; - std::atomic<bool> StopFlag = false; - - private: - // Pool-specific - IExecutorPool* ExecutorPool; - TVector<IExecutorPool*> AvailableExecutorPools; - - // Event-specific (currently executing) - TVector<THolder<IActor>> DyingActors; - TActorId CurrentRecipient; - ui64 CurrentActorScheduledEventsCounter = 0; - - // Thread-specific - TWorkerContext Ctx; - ui64 RevolvingReadCounter = 0; - ui64 RevolvingWriteCounter = 0; - const TString ThreadName; - volatile TThreadId ThreadId = UnknownThreadId; - bool IsUnitedWorker = false; - - TDuration TimePerMailbox; - ui32 EventsPerMailbox; - ui64 SoftProcessingDurationTs; - }; - - template <typename TMailbox> - void UnlockFromExecution(TMailbox* mailbox, IExecutorPool* executorPool, bool asFree, ui32 hint, TWorkerId workerId, ui64& revolvingWriteCounter) { - mailbox->UnlockFromExecution1(); - const bool needReschedule1 = (nullptr != mailbox->Head()); - if (!asFree) { - if (mailbox->UnlockFromExecution2(needReschedule1)) { - RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); - executorPool->ScheduleActivationEx(hint, ++revolvingWriteCounter); - } - } else { - if (mailbox->UnlockAsFree(needReschedule1)) { - RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); - executorPool->ScheduleActivationEx(hint, ++revolvingWriteCounter); - } - executorPool->ReclaimMailbox(TMailbox::MailboxType, hint, workerId, ++revolvingWriteCounter); - } - } -} diff --git a/library/cpp/actors/core/harmonizer.cpp b/library/cpp/actors/core/harmonizer.cpp deleted file mode 100644 index 4464603dc8..0000000000 --- a/library/cpp/actors/core/harmonizer.cpp +++ /dev/null @@ -1,700 +0,0 @@ -#include "harmonizer.h" - -#include "probes.h" -#include "actorsystem.h" -#include "executor_pool_basic.h" -#include "executor_pool_basic_feature_flags.h" - -#include <library/cpp/actors/util/cpu_load_log.h> -#include <library/cpp/actors/util/datetime.h> -#include <library/cpp/actors/util/intrinsics.h> - -#include <util/system/spinlock.h> - -#include <algorithm> - -namespace NActors { - -LWTRACE_USING(ACTORLIB_PROVIDER); - -constexpr bool CheckBinaryPower(ui64 value) { - return !(value & (value - 1)); -} - -template <ui8 HistoryBufferSize = 8> -struct TValueHistory { - static_assert(CheckBinaryPower(HistoryBufferSize)); - - double History[HistoryBufferSize] = {0.0}; - ui64 HistoryIdx = 0; - ui64 LastTs = Max<ui64>(); - double LastUs = 0.0; - double AccumulatedUs = 0.0; - ui64 AccumulatedTs = 0; - - template <bool WithTail=false> - double Accumulate(auto op, auto comb, ui8 seconds) { - double acc = AccumulatedUs; - size_t idx = HistoryIdx; - ui8 leftSeconds = seconds; - if constexpr (!WithTail) { - idx--; - leftSeconds--; - if (idx >= HistoryBufferSize) { - idx = HistoryBufferSize - 1; - } - acc = History[idx]; - } - do { - idx--; - leftSeconds--; - if (idx >= HistoryBufferSize) { - idx = HistoryBufferSize - 1; - } - if constexpr (WithTail) { - acc = op(acc, History[idx]); - } else if (leftSeconds) { - acc = op(acc, History[idx]); - } else { - ui64 tsInSecond = Us2Ts(1'000'000.0); - acc = op(acc, History[idx] * (tsInSecond - AccumulatedTs) / tsInSecond); - } - } while (leftSeconds); - double duration = 1'000'000.0 * seconds; - if constexpr (WithTail) { - duration += Ts2Us(AccumulatedTs); - } - return comb(acc, duration); - } - - template <bool WithTail=false> - double GetAvgPartForLastSeconds(ui8 seconds) { - auto sum = [](double acc, double value) { - return acc + value; - }; - auto avg = [](double sum, double duration) { - return sum / duration; - }; - return Accumulate<WithTail>(sum, avg, seconds); - } - - double GetAvgPart() { - return GetAvgPartForLastSeconds<true>(HistoryBufferSize); - } - - double GetMaxForLastSeconds(ui8 seconds) { - auto max = [](const double& acc, const double& value) { - return Max(acc, value); - }; - auto fst = [](const double& value, const double&) { return value; }; - return Accumulate<false>(max, fst, seconds); - } - - double GetMax() { - return GetMaxForLastSeconds(HistoryBufferSize); - } - - i64 GetMaxInt() { - return static_cast<i64>(GetMax()); - } - - double GetMinForLastSeconds(ui8 seconds) { - auto min = [](const double& acc, const double& value) { - return Min(acc, value); - }; - auto fst = [](const double& value, const double&) { return value; }; - return Accumulate<false>(min, fst, seconds); - } - - double GetMin() { - return GetMinForLastSeconds(HistoryBufferSize); - } - - i64 GetMinInt() { - return static_cast<i64>(GetMin()); - } - - void Register(ui64 ts, double valueUs) { - if (ts < LastTs) { - LastTs = ts; - LastUs = valueUs; - AccumulatedUs = 0.0; - AccumulatedTs = 0; - return; - } - ui64 lastTs = std::exchange(LastTs, ts); - ui64 dTs = ts - lastTs; - double lastUs = std::exchange(LastUs, valueUs); - double dUs = valueUs - lastUs; - LWPROBE(RegisterValue, ts, lastTs, dTs, Us2Ts(8'000'000.0), valueUs, lastUs, dUs); - - if (dTs > Us2Ts(8'000'000.0)) { - dUs = dUs * 1'000'000.0 / Ts2Us(dTs); - for (size_t idx = 0; idx < HistoryBufferSize; ++idx) { - History[idx] = dUs; - } - AccumulatedUs = 0.0; - AccumulatedTs = 0; - return; - } - - while (dTs > 0) { - if (AccumulatedTs + dTs < Us2Ts(1'000'000.0)) { - AccumulatedTs += dTs; - AccumulatedUs += dUs; - break; - } else { - ui64 addTs = Us2Ts(1'000'000.0) - AccumulatedTs; - double addUs = dUs * addTs / dTs; - dTs -= addTs; - dUs -= addUs; - History[HistoryIdx] = AccumulatedUs + addUs; - HistoryIdx = (HistoryIdx + 1) % HistoryBufferSize; - AccumulatedUs = 0.0; - AccumulatedTs = 0; - } - } - } -}; - -struct TThreadInfo { - TValueHistory<8> Consumed; - TValueHistory<8> Booked; -}; - -struct TPoolInfo { - std::vector<TThreadInfo> ThreadInfo; - IExecutorPool* Pool = nullptr; - TBasicExecutorPool* BasicPool = nullptr; - i16 DefaultThreadCount = 0; - i16 MinThreadCount = 0; - i16 MaxThreadCount = 0; - i16 Priority = 0; - NMonitoring::TDynamicCounters::TCounterPtr AvgPingCounter; - NMonitoring::TDynamicCounters::TCounterPtr AvgPingCounterWithSmallWindow; - ui32 MaxAvgPingUs = 0; - ui64 LastUpdateTs = 0; - ui64 NotEnoughCpuExecutions = 0; - ui64 NewNotEnoughCpuExecutions = 0; - ui16 LocalQueueSize = NFeatures::TLocalQueuesFeatureFlags::MIN_LOCAL_QUEUE_SIZE; - - TAtomic LastFlags = 0; // 0 - isNeedy; 1 - isStarved; 2 - isHoggish - TAtomic IncreasingThreadsByNeedyState = 0; - TAtomic IncreasingThreadsByExchange = 0; - TAtomic DecreasingThreadsByStarvedState = 0; - TAtomic DecreasingThreadsByHoggishState = 0; - TAtomic DecreasingThreadsByExchange = 0; - TAtomic PotentialMaxThreadCount = 0; - - TValueHistory<16> Consumed; - TValueHistory<16> Booked; - - TAtomic MaxConsumedCpu = 0; - TAtomic MinConsumedCpu = 0; - TAtomic MaxBookedCpu = 0; - TAtomic MinBookedCpu = 0; - - std::unique_ptr<TWaitingStats<ui64>> WaitingStats; - std::unique_ptr<TWaitingStats<double>> MovingWaitingStats; - - double GetBooked(i16 threadIdx); - double GetlastSecondPoolBooked(i16 threadIdx); - double GetConsumed(i16 threadIdx); - double GetlastSecondPoolConsumed(i16 threadIdx); - TCpuConsumption PullStats(ui64 ts); - i16 GetThreadCount(); - void SetThreadCount(i16 threadCount); - bool IsAvgPingGood(); -}; - -double TPoolInfo::GetBooked(i16 threadIdx) { - if ((size_t)threadIdx < ThreadInfo.size()) { - return ThreadInfo[threadIdx].Booked.GetAvgPart(); - } - return 0.0; -} - -double TPoolInfo::GetlastSecondPoolBooked(i16 threadIdx) { - if ((size_t)threadIdx < ThreadInfo.size()) { - return ThreadInfo[threadIdx].Booked.GetAvgPartForLastSeconds(1); - } - return 0.0; -} - -double TPoolInfo::GetConsumed(i16 threadIdx) { - if ((size_t)threadIdx < ThreadInfo.size()) { - return ThreadInfo[threadIdx].Consumed.GetAvgPart(); - } - return 0.0; -} - -double TPoolInfo::GetlastSecondPoolConsumed(i16 threadIdx) { - if ((size_t)threadIdx < ThreadInfo.size()) { - return ThreadInfo[threadIdx].Consumed.GetAvgPartForLastSeconds(1); - } - return 0.0; -} - -#define UNROLL_HISTORY(history) (history)[0], (history)[1], (history)[2], (history)[3], (history)[4], (history)[5], (history)[6], (history)[7] -TCpuConsumption TPoolInfo::PullStats(ui64 ts) { - TCpuConsumption acc; - for (i16 threadIdx = 0; threadIdx < MaxThreadCount; ++threadIdx) { - TThreadInfo &threadInfo = ThreadInfo[threadIdx]; - TCpuConsumption cpuConsumption = Pool->GetThreadCpuConsumption(threadIdx); - acc.Add(cpuConsumption); - threadInfo.Consumed.Register(ts, cpuConsumption.ConsumedUs); - LWPROBE(SavedValues, Pool->PoolId, Pool->GetName(), "consumed", UNROLL_HISTORY(threadInfo.Consumed.History)); - threadInfo.Booked.Register(ts, cpuConsumption.BookedUs); - LWPROBE(SavedValues, Pool->PoolId, Pool->GetName(), "booked", UNROLL_HISTORY(threadInfo.Booked.History)); - } - Consumed.Register(ts, acc.ConsumedUs); - RelaxedStore(&MaxConsumedCpu, Consumed.GetMaxInt()); - RelaxedStore(&MinConsumedCpu, Consumed.GetMinInt()); - Booked.Register(ts, acc.BookedUs); - RelaxedStore(&MaxBookedCpu, Booked.GetMaxInt()); - RelaxedStore(&MinBookedCpu, Booked.GetMinInt()); - NewNotEnoughCpuExecutions = acc.NotEnoughCpuExecutions - NotEnoughCpuExecutions; - NotEnoughCpuExecutions = acc.NotEnoughCpuExecutions; - if (WaitingStats && BasicPool) { - WaitingStats->Clear(); - BasicPool->GetWaitingStats(*WaitingStats); - if constexpr (!NFeatures::TSpinFeatureFlags::CalcPerThread) { - MovingWaitingStats->Add(*WaitingStats, 0.8, 0.2); - } - } - return acc; -} -#undef UNROLL_HISTORY - -i16 TPoolInfo::GetThreadCount() { - return Pool->GetThreadCount(); -} - -void TPoolInfo::SetThreadCount(i16 threadCount) { - Pool->SetThreadCount(threadCount); -} - -bool TPoolInfo::IsAvgPingGood() { - bool res = true; - if (AvgPingCounter) { - res &= *AvgPingCounter > MaxAvgPingUs; - } - if (AvgPingCounterWithSmallWindow) { - res &= *AvgPingCounterWithSmallWindow > MaxAvgPingUs; - } - return res; -} - -class THarmonizer: public IHarmonizer { -private: - std::atomic<bool> IsDisabled = false; - TSpinLock Lock; - std::atomic<ui64> NextHarmonizeTs = 0; - std::vector<TPoolInfo> Pools; - std::vector<ui16> PriorityOrder; - - TValueHistory<16> Consumed; - TValueHistory<16> Booked; - - TAtomic MaxConsumedCpu = 0; - TAtomic MinConsumedCpu = 0; - TAtomic MaxBookedCpu = 0; - TAtomic MinBookedCpu = 0; - - std::atomic<double> AvgAwakeningTimeUs = 0; - std::atomic<double> AvgWakingUpTimeUs = 0; - - void PullStats(ui64 ts); - void HarmonizeImpl(ui64 ts); - void CalculatePriorityOrder(); -public: - THarmonizer(ui64 ts); - virtual ~THarmonizer(); - double Rescale(double value) const; - void Harmonize(ui64 ts) override; - void DeclareEmergency(ui64 ts) override; - void AddPool(IExecutorPool* pool, TSelfPingInfo *pingInfo) override; - void Enable(bool enable) override; - TPoolHarmonizerStats GetPoolStats(i16 poolId) const override; - THarmonizerStats GetStats() const override; -}; - -THarmonizer::THarmonizer(ui64 ts) { - NextHarmonizeTs = ts; -} - -THarmonizer::~THarmonizer() { -} - -double THarmonizer::Rescale(double value) const { - return Max(0.0, Min(1.0, value * (1.0/0.9))); -} - -void THarmonizer::PullStats(ui64 ts) { - TCpuConsumption acc; - for (TPoolInfo &pool : Pools) { - TCpuConsumption consumption = pool.PullStats(ts); - acc.Add(consumption); - } - Consumed.Register(ts, acc.ConsumedUs); - RelaxedStore(&MaxConsumedCpu, Consumed.GetMaxInt()); - RelaxedStore(&MinConsumedCpu, Consumed.GetMinInt()); - Booked.Register(ts, acc.BookedUs); - RelaxedStore(&MaxBookedCpu, Booked.GetMaxInt()); - RelaxedStore(&MinBookedCpu, Booked.GetMinInt()); -} - -Y_FORCE_INLINE bool IsStarved(double consumed, double booked) { - return Max(consumed, booked) > 0.1 && consumed < booked * 0.7; -} - -Y_FORCE_INLINE bool IsHoggish(double booked, ui16 currentThreadCount) { - return booked < currentThreadCount - 1; -} - -void THarmonizer::HarmonizeImpl(ui64 ts) { - bool isStarvedPresent = false; - double booked = 0.0; - double consumed = 0.0; - double lastSecondBooked = 0.0; - i64 beingStopped = 0; - i64 total = 0; - TStackVec<size_t, 8> needyPools; - TStackVec<size_t, 8> hoggishPools; - TStackVec<bool, 8> isNeedyByPool; - - size_t sumOfAdditionalThreads = 0; - - - ui64 TotalWakingUpTime = 0; - ui64 TotalWakingUps = 0; - ui64 TotalAwakeningTime = 0; - ui64 TotalAwakenings = 0; - for (size_t poolIdx = 0; poolIdx < Pools.size(); ++poolIdx) { - TPoolInfo& pool = Pools[poolIdx]; - if (pool.WaitingStats) { - TotalWakingUpTime += pool.WaitingStats->WakingUpTotalTime; - TotalWakingUps += pool.WaitingStats->WakingUpCount; - TotalAwakeningTime += pool.WaitingStats->AwakingTotalTime; - TotalAwakenings += pool.WaitingStats->AwakingCount; - } - } - - constexpr ui64 knownAvgWakingUpTime = TWaitingStatsConstants::KnownAvgWakingUpTime; - constexpr ui64 knownAvgAwakeningUpTime = TWaitingStatsConstants::KnownAvgAwakeningTime; - - ui64 realAvgWakingUpTime = (TotalWakingUps ? TotalWakingUpTime / TotalWakingUps : knownAvgWakingUpTime); - ui64 avgWakingUpTime = realAvgWakingUpTime; - if (avgWakingUpTime > 2 * knownAvgWakingUpTime || !realAvgWakingUpTime) { - avgWakingUpTime = knownAvgWakingUpTime; - } - AvgWakingUpTimeUs = Ts2Us(avgWakingUpTime); - - ui64 realAvgAwakeningTime = (TotalAwakenings ? TotalAwakeningTime / TotalAwakenings : knownAvgAwakeningUpTime); - ui64 avgAwakeningTime = realAvgAwakeningTime; - if (avgAwakeningTime > 2 * knownAvgAwakeningUpTime || !realAvgAwakeningTime) { - avgAwakeningTime = knownAvgAwakeningUpTime; - } - AvgAwakeningTimeUs = Ts2Us(avgAwakeningTime); - - ui64 avgWakingUpConsumption = avgWakingUpTime + avgAwakeningTime; - LWPROBE(WakingUpConsumption, Ts2Us(avgWakingUpTime), Ts2Us(avgWakingUpTime), Ts2Us(avgAwakeningTime), Ts2Us(realAvgAwakeningTime), Ts2Us(avgWakingUpConsumption)); - - for (size_t poolIdx = 0; poolIdx < Pools.size(); ++poolIdx) { - TPoolInfo& pool = Pools[poolIdx]; - if (!pool.BasicPool) { - continue; - } - if constexpr (NFeatures::TSpinFeatureFlags::CalcPerThread) { - pool.BasicPool->CalcSpinPerThread(avgWakingUpConsumption); - } else if constexpr (NFeatures::TSpinFeatureFlags::UsePseudoMovingWindow) { - ui64 newSpinThreshold = pool.MovingWaitingStats->CalculateGoodSpinThresholdCycles(avgWakingUpConsumption); - pool.BasicPool->SetSpinThresholdCycles(newSpinThreshold); - } else { - ui64 newSpinThreshold = pool.WaitingStats->CalculateGoodSpinThresholdCycles(avgWakingUpConsumption); - pool.BasicPool->SetSpinThresholdCycles(newSpinThreshold); - } - pool.BasicPool->ClearWaitingStats(); - } - - for (size_t poolIdx = 0; poolIdx < Pools.size(); ++poolIdx) { - TPoolInfo& pool = Pools[poolIdx]; - total += pool.DefaultThreadCount; - - ui32 currentThreadCount = pool.GetThreadCount(); - sumOfAdditionalThreads += currentThreadCount - pool.DefaultThreadCount; - - double poolBooked = 0.0; - double poolConsumed = 0.0; - double lastSecondPoolBooked = 0.0; - double lastSecondPoolConsumed = 0.0; - beingStopped += pool.Pool->GetBlockingThreadCount(); - for (i16 threadIdx = 0; threadIdx < pool.MaxThreadCount; ++threadIdx) { - poolBooked += Rescale(pool.GetBooked(threadIdx)); - lastSecondPoolBooked += Rescale(pool.GetlastSecondPoolBooked(threadIdx)); - poolConsumed += Rescale(pool.GetConsumed(threadIdx)); - lastSecondPoolConsumed += Rescale(pool.GetlastSecondPoolConsumed(threadIdx)); - } - bool isStarved = IsStarved(poolConsumed, poolBooked) || IsStarved(lastSecondPoolConsumed, lastSecondPoolBooked); - if (isStarved) { - isStarvedPresent = true; - } - - bool isNeedy = (pool.IsAvgPingGood() || pool.NewNotEnoughCpuExecutions) && poolBooked >= currentThreadCount; - if (pool.AvgPingCounter) { - if (pool.LastUpdateTs + Us2Ts(3'000'000ull) > ts) { - isNeedy = false; - } else { - pool.LastUpdateTs = ts; - } - } - isNeedyByPool.push_back(isNeedy); - if (isNeedy) { - needyPools.push_back(poolIdx); - } - bool isHoggish = IsHoggish(poolBooked, currentThreadCount) - || IsHoggish(lastSecondPoolBooked, currentThreadCount); - if (isHoggish) { - hoggishPools.push_back(poolIdx); - } - booked += poolBooked; - consumed += poolConsumed; - AtomicSet(pool.LastFlags, (i64)isNeedy | ((i64)isStarved << 1) | ((i64)isHoggish << 2)); - LWPROBE(HarmonizeCheckPool, poolIdx, pool.Pool->GetName(), poolBooked, poolConsumed, lastSecondPoolBooked, lastSecondPoolConsumed, pool.GetThreadCount(), pool.MaxThreadCount, isStarved, isNeedy, isHoggish); - } - double budget = total - Max(booked, lastSecondBooked); - i16 budgetInt = static_cast<i16>(Max(budget, 0.0)); - if (budget < -0.1) { - isStarvedPresent = true; - } - for (size_t poolIdx = 0; poolIdx < Pools.size(); ++poolIdx) { - TPoolInfo& pool = Pools[poolIdx]; - AtomicSet(pool.PotentialMaxThreadCount, Min(pool.MaxThreadCount, budgetInt)); - } - double overbooked = consumed - booked; - if (overbooked < 0) { - isStarvedPresent = false; - } - - if (needyPools.size()) { - Sort(needyPools.begin(), needyPools.end(), [&] (i16 lhs, i16 rhs) { - if (Pools[lhs].Priority != Pools[rhs].Priority) { - return Pools[lhs].Priority > Pools[rhs].Priority; - } - return Pools[lhs].Pool->PoolId < Pools[rhs].Pool->PoolId; - }); - } - - if (isStarvedPresent) { - // last_starved_at_consumed_value = сумма по всем пулам consumed; - // TODO(cthulhu): использовать как лимит планвно устремлять этот лимит к total, - // использовать вместо total - if (beingStopped && beingStopped >= overbooked) { - // do nothing - } else { - for (ui16 poolIdx : PriorityOrder) { - TPoolInfo &pool = Pools[poolIdx]; - i64 threadCount = pool.GetThreadCount(); - while (threadCount > pool.DefaultThreadCount) { - pool.SetThreadCount(--threadCount); - AtomicIncrement(pool.DecreasingThreadsByStarvedState); - overbooked--; - sumOfAdditionalThreads--; - - LWPROBE(HarmonizeOperation, poolIdx, pool.Pool->GetName(), "decrease by starving", threadCount - 1, pool.DefaultThreadCount, pool.MaxThreadCount); - if (overbooked < 1) { - break; - } - } - if (overbooked < 1) { - break; - } - } - } - } else { - for (size_t needyPoolIdx : needyPools) { - TPoolInfo &pool = Pools[needyPoolIdx]; - i64 threadCount = pool.GetThreadCount(); - if (budget >= 1.0) { - if (threadCount + 1 <= pool.MaxThreadCount) { - AtomicIncrement(pool.IncreasingThreadsByNeedyState); - isNeedyByPool[needyPoolIdx] = false; - sumOfAdditionalThreads++; - pool.SetThreadCount(threadCount + 1); - budget -= 1.0; - LWPROBE(HarmonizeOperation, needyPoolIdx, pool.Pool->GetName(), "increase by needs", threadCount + 1, pool.DefaultThreadCount, pool.MaxThreadCount); - } - } - if constexpr (NFeatures::IsLocalQueues()) { - bool needToExpandLocalQueue = budget < 1.0 || threadCount >= pool.MaxThreadCount; - needToExpandLocalQueue &= (bool)pool.BasicPool; - needToExpandLocalQueue &= (pool.MaxThreadCount > 1); - needToExpandLocalQueue &= (pool.LocalQueueSize < NFeatures::TLocalQueuesFeatureFlags::MAX_LOCAL_QUEUE_SIZE); - if (needToExpandLocalQueue) { - pool.BasicPool->SetLocalQueueSize(++pool.LocalQueueSize); - } - } - } - } - - if (budget < 1.0) { - size_t takingAwayThreads = 0; - for (size_t needyPoolIdx : needyPools) { - TPoolInfo &pool = Pools[needyPoolIdx]; - i64 threadCount = pool.GetThreadCount(); - sumOfAdditionalThreads -= threadCount - pool.DefaultThreadCount; - if (sumOfAdditionalThreads < takingAwayThreads + 1) { - break; - } - if (!isNeedyByPool[needyPoolIdx]) { - continue; - } - AtomicIncrement(pool.IncreasingThreadsByExchange); - isNeedyByPool[needyPoolIdx] = false; - takingAwayThreads++; - pool.SetThreadCount(threadCount + 1); - - LWPROBE(HarmonizeOperation, needyPoolIdx, pool.Pool->GetName(), "increase by exchanging", threadCount + 1, pool.DefaultThreadCount, pool.MaxThreadCount); - } - - for (ui16 poolIdx : PriorityOrder) { - if (takingAwayThreads <= 0) { - break; - } - - TPoolInfo &pool = Pools[poolIdx]; - size_t threadCount = pool.GetThreadCount(); - size_t additionalThreadsCount = Max<size_t>(0L, threadCount - pool.DefaultThreadCount); - size_t currentTakingAwayThreads = Min(additionalThreadsCount, takingAwayThreads); - - if (!currentTakingAwayThreads) { - continue; - } - takingAwayThreads -= currentTakingAwayThreads; - pool.SetThreadCount(threadCount - currentTakingAwayThreads); - - AtomicAdd(pool.DecreasingThreadsByExchange, takingAwayThreads); - LWPROBE(HarmonizeOperation, poolIdx, pool.Pool->GetName(), "decrease by exchanging", threadCount - currentTakingAwayThreads, pool.DefaultThreadCount, pool.MaxThreadCount); - } - } - - for (size_t hoggishPoolIdx : hoggishPools) { - TPoolInfo &pool = Pools[hoggishPoolIdx]; - i64 threadCount = pool.GetThreadCount(); - if (pool.BasicPool && pool.LocalQueueSize > NFeatures::TLocalQueuesFeatureFlags::MIN_LOCAL_QUEUE_SIZE) { - pool.LocalQueueSize = std::min<ui16>(NFeatures::TLocalQueuesFeatureFlags::MIN_LOCAL_QUEUE_SIZE, pool.LocalQueueSize / 2); - pool.BasicPool->SetLocalQueueSize(pool.LocalQueueSize); - } - if (threadCount > pool.MinThreadCount) { - AtomicIncrement(pool.DecreasingThreadsByHoggishState); - LWPROBE(HarmonizeOperation, hoggishPoolIdx, pool.Pool->GetName(), "decrease by hoggish", threadCount - 1, pool.DefaultThreadCount, pool.MaxThreadCount); - pool.SetThreadCount(threadCount - 1); - } - } -} - -void THarmonizer::CalculatePriorityOrder() { - PriorityOrder.resize(Pools.size()); - Iota(PriorityOrder.begin(), PriorityOrder.end(), 0); - Sort(PriorityOrder.begin(), PriorityOrder.end(), [&] (i16 lhs, i16 rhs) { - if (Pools[lhs].Priority != Pools[rhs].Priority) { - return Pools[lhs].Priority < Pools[rhs].Priority; - } - return Pools[lhs].Pool->PoolId > Pools[rhs].Pool->PoolId; - }); -} - -void THarmonizer::Harmonize(ui64 ts) { - if (IsDisabled || NextHarmonizeTs > ts || !Lock.TryAcquire()) { - LWPROBE(TryToHarmonizeFailed, ts, NextHarmonizeTs, IsDisabled, false); - return; - } - // Check again under the lock - if (IsDisabled) { - LWPROBE(TryToHarmonizeFailed, ts, NextHarmonizeTs, IsDisabled, true); - Lock.Release(); - return; - } - // Will never reach this line disabled - ui64 previousNextHarmonizeTs = NextHarmonizeTs.exchange(ts + Us2Ts(1'000'000ull)); - LWPROBE(TryToHarmonizeSuccess, ts, NextHarmonizeTs, previousNextHarmonizeTs); - - if (PriorityOrder.empty()) { - CalculatePriorityOrder(); - } - - PullStats(ts); - HarmonizeImpl(ts); - - Lock.Release(); -} - -void THarmonizer::DeclareEmergency(ui64 ts) { - NextHarmonizeTs = ts; -} - -void THarmonizer::AddPool(IExecutorPool* pool, TSelfPingInfo *pingInfo) { - TGuard<TSpinLock> guard(Lock); - TPoolInfo poolInfo; - poolInfo.Pool = pool; - poolInfo.BasicPool = dynamic_cast<TBasicExecutorPool*>(pool); - poolInfo.DefaultThreadCount = pool->GetDefaultThreadCount(); - poolInfo.MinThreadCount = pool->GetMinThreadCount(); - poolInfo.MaxThreadCount = pool->GetMaxThreadCount(); - poolInfo.ThreadInfo.resize(poolInfo.MaxThreadCount); - poolInfo.Priority = pool->GetPriority(); - pool->SetThreadCount(poolInfo.DefaultThreadCount); - if (pingInfo) { - poolInfo.AvgPingCounter = pingInfo->AvgPingCounter; - poolInfo.AvgPingCounterWithSmallWindow = pingInfo->AvgPingCounterWithSmallWindow; - poolInfo.MaxAvgPingUs = pingInfo->MaxAvgPingUs; - } - if (poolInfo.BasicPool) { - poolInfo.WaitingStats.reset(new TWaitingStats<ui64>()); - poolInfo.MovingWaitingStats.reset(new TWaitingStats<double>()); - } - Pools.push_back(std::move(poolInfo)); - PriorityOrder.clear(); -} - -void THarmonizer::Enable(bool enable) { - TGuard<TSpinLock> guard(Lock); - IsDisabled = enable; -} - -IHarmonizer* MakeHarmonizer(ui64 ts) { - return new THarmonizer(ts); -} - -TPoolHarmonizerStats THarmonizer::GetPoolStats(i16 poolId) const { - const TPoolInfo &pool = Pools[poolId]; - ui64 flags = RelaxedLoad(&pool.LastFlags); - return TPoolHarmonizerStats{ - .IncreasingThreadsByNeedyState = static_cast<ui64>(RelaxedLoad(&pool.IncreasingThreadsByNeedyState)), - .IncreasingThreadsByExchange = static_cast<ui64>(RelaxedLoad(&pool.IncreasingThreadsByExchange)), - .DecreasingThreadsByStarvedState = static_cast<ui64>(RelaxedLoad(&pool.DecreasingThreadsByStarvedState)), - .DecreasingThreadsByHoggishState = static_cast<ui64>(RelaxedLoad(&pool.DecreasingThreadsByHoggishState)), - .DecreasingThreadsByExchange = static_cast<ui64>(RelaxedLoad(&pool.DecreasingThreadsByExchange)), - .MaxConsumedCpu = static_cast<i64>(RelaxedLoad(&pool.MaxConsumedCpu)), - .MinConsumedCpu = static_cast<i64>(RelaxedLoad(&pool.MinConsumedCpu)), - .MaxBookedCpu = static_cast<i64>(RelaxedLoad(&pool.MaxBookedCpu)), - .MinBookedCpu = static_cast<i64>(RelaxedLoad(&pool.MinBookedCpu)), - .PotentialMaxThreadCount = static_cast<i16>(RelaxedLoad(&pool.PotentialMaxThreadCount)), - .IsNeedy = static_cast<bool>(flags & 1), - .IsStarved = static_cast<bool>(flags & 2), - .IsHoggish = static_cast<bool>(flags & 4), - }; -} - -THarmonizerStats THarmonizer::GetStats() const { - return THarmonizerStats{ - .MaxConsumedCpu = static_cast<i64>(RelaxedLoad(&MaxConsumedCpu)), - .MinConsumedCpu = static_cast<i64>(RelaxedLoad(&MinConsumedCpu)), - .MaxBookedCpu = static_cast<i64>(RelaxedLoad(&MaxBookedCpu)), - .MinBookedCpu = static_cast<i64>(RelaxedLoad(&MinBookedCpu)), - .AvgAwakeningTimeUs = AvgAwakeningTimeUs, - .AvgWakingUpTimeUs = AvgWakingUpTimeUs, - }; -} - -} diff --git a/library/cpp/actors/core/harmonizer.h b/library/cpp/actors/core/harmonizer.h deleted file mode 100644 index ba98048e49..0000000000 --- a/library/cpp/actors/core/harmonizer.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include "defs.h" -#include "config.h" - -namespace NActors { - class IExecutorPool; - - template <typename T> - struct TWaitingStats; - - struct TPoolHarmonizerStats { - ui64 IncreasingThreadsByNeedyState = 0; - ui64 IncreasingThreadsByExchange = 0; - ui64 DecreasingThreadsByStarvedState = 0; - ui64 DecreasingThreadsByHoggishState = 0; - ui64 DecreasingThreadsByExchange = 0; - i64 MaxConsumedCpu = 0.0; - i64 MinConsumedCpu = 0.0; - i64 MaxBookedCpu = 0.0; - i64 MinBookedCpu = 0.0; - i16 PotentialMaxThreadCount = 0; - bool IsNeedy = false; - bool IsStarved = false; - bool IsHoggish = false; - }; - - struct THarmonizerStats { - i64 MaxConsumedCpu = 0.0; - i64 MinConsumedCpu = 0.0; - i64 MaxBookedCpu = 0.0; - i64 MinBookedCpu = 0.0; - - double AvgAwakeningTimeUs = 0; - double AvgWakingUpTimeUs = 0; - }; - - // Pool cpu harmonizer - class IHarmonizer { - public: - virtual ~IHarmonizer() {} - virtual void Harmonize(ui64 ts) = 0; - virtual void DeclareEmergency(ui64 ts) = 0; - virtual void AddPool(IExecutorPool* pool, TSelfPingInfo *pingInfo = nullptr) = 0; - virtual void Enable(bool enable) = 0; - virtual TPoolHarmonizerStats GetPoolStats(i16 poolId) const = 0; - virtual THarmonizerStats GetStats() const = 0; - }; - - IHarmonizer* MakeHarmonizer(ui64 ts); -} diff --git a/library/cpp/actors/core/hfunc.h b/library/cpp/actors/core/hfunc.h deleted file mode 100644 index 6d1aeeecc3..0000000000 --- a/library/cpp/actors/core/hfunc.h +++ /dev/null @@ -1,116 +0,0 @@ -#pragma once - -#include "actor.h" -#include "executor_thread.h" - -#include <util/system/defaults.h> - -#define HFuncCtx(TEvType, HandleFunc, Ctx) \ - case TEvType::EventType: { \ - typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \ - HandleFunc(*x, Ctx); \ - break; \ - } - -#define HFunc(TEvType, HandleFunc) \ - case TEvType::EventType: { \ - typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \ - HandleFunc(*x, this->ActorContext()); \ - break; \ - } - -#define hFunc(TEvType, HandleFunc) \ - case TEvType::EventType: { \ - typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \ - HandleFunc(*x); \ - break; \ - } - -#define HFuncTraced(TEvType, HandleFunc) \ - case TEvType::EventType: { \ - TRACE_EVENT_TYPE(Y_STRINGIZE(TEvType)); \ - TEvType::TPtr* x = reinterpret_cast<TEvType::TPtr*>(&ev); \ - HandleFunc(*x, this->ActorContext()); \ - break; \ - } - -#define hFuncTraced(TEvType, HandleFunc) \ - case TEvType::EventType: { \ - TRACE_EVENT_TYPE(Y_STRINGIZE(TEvType)); \ - typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \ - HandleFunc(*x); \ - break; \ - } - -#define HTemplFunc(TEvType, HandleFunc) \ - case TEvType::EventType: { \ - typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \ - HandleFunc(*x, this->ActorContext()); \ - break; \ - } - -#define hTemplFunc(TEvType, HandleFunc) \ - case TEvType::EventType: { \ - typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \ - HandleFunc(*x); \ - break; \ - } - -#define SFunc(TEvType, HandleFunc) \ - case TEvType::EventType: \ - HandleFunc(this->ActorContext()); \ - break; - -#define sFunc(TEvType, HandleFunc) \ - case TEvType::EventType: \ - HandleFunc(); \ - break; - -#define CFunc(TEventType, HandleFunc) \ - case TEventType: \ - HandleFunc(this->ActorContext()); \ - break; - -#define CFuncCtx(TEventType, HandleFunc, ctx) \ - case TEventType: \ - HandleFunc(ctx); \ - break; - -#define cFunc(TEventType, HandleFunc) \ - case TEventType: \ - HandleFunc(); \ - break; - -#define FFunc(TEventType, HandleFunc) \ - case TEventType: \ - HandleFunc(ev, this->ActorContext()); \ - break; - -#define fFunc(TEventType, HandleFunc) \ - case TEventType: \ - HandleFunc(ev); \ - break; - -#define IgnoreFunc(TEvType) \ - case TEvType::EventType: \ - break; - -#define ExceptionFunc(ExceptionType, HandleFunc) \ - catch (const ExceptionType& exception) { \ - HandleFunc(exception); \ - } - -#define ExceptionFuncEv(ExceptionType, HandleFunc) \ - catch (const ExceptionType& exception) { \ - HandleFunc(exception, ev); \ - } - -#define AnyExceptionFunc(HandleFunc) \ - catch (...) { \ - HandleFunc(); \ - } - -#define AnyExceptionFuncEv(HandleFunc) \ - catch (...) { \ - HandleFunc(ev); \ - } diff --git a/library/cpp/actors/core/interconnect.cpp b/library/cpp/actors/core/interconnect.cpp deleted file mode 100644 index b477f71e57..0000000000 --- a/library/cpp/actors/core/interconnect.cpp +++ /dev/null @@ -1,181 +0,0 @@ -#include "interconnect.h" -#include <util/digest/murmur.h> -#include <google/protobuf/text_format.h> - -namespace NActors { - - TNodeLocation::TNodeLocation(const NActorsInterconnect::TNodeLocation& location) { - const NProtoBuf::Descriptor *descriptor = NActorsInterconnect::TNodeLocation::descriptor(); - const NActorsInterconnect::TNodeLocation *locp = &location; - NActorsInterconnect::TNodeLocation temp; // for legacy location case - - // WalleConfig compatibility section - if (locp->HasBody()) { - if (locp == &location) { - temp.CopyFrom(*locp); - locp = &temp; - } - temp.SetUnit(::ToString(temp.GetBody())); - temp.ClearBody(); - } - - // legacy value processing - if (locp->HasDataCenterNum() || locp->HasRoomNum() || locp->HasRackNum() || locp->HasBodyNum()) { - if (locp == &location) { - temp.CopyFrom(*locp); - locp = &temp; - } - LegacyValue = TLegacyValue{temp.GetDataCenterNum(), temp.GetRoomNum(), temp.GetRackNum(), temp.GetBodyNum()}; - temp.ClearDataCenterNum(); - temp.ClearRoomNum(); - temp.ClearRackNum(); - temp.ClearBodyNum(); - - const NProtoBuf::Reflection *reflection = temp.GetReflection(); - bool fieldsFromNewFormat = false; - for (int i = 0, count = descriptor->field_count(); !fieldsFromNewFormat && i < count; ++i) { - fieldsFromNewFormat |= reflection->HasField(temp, descriptor->field(i)); - } - if (!fieldsFromNewFormat) { - const auto& v = LegacyValue->DataCenter; - const char *p = reinterpret_cast<const char*>(&v); - temp.SetDataCenter(TString(p, strnlen(p, sizeof(ui32)))); - temp.SetModule(::ToString(LegacyValue->Room)); - temp.SetRack(::ToString(LegacyValue->Rack)); - temp.SetUnit(::ToString(LegacyValue->Body)); - } - } - - auto makeString = [&] { - NProtoBuf::TextFormat::Printer p; - p.SetSingleLineMode(true); - TString s; - p.PrintToString(*locp, &s); - return s; - }; - - // modern format parsing - const NProtoBuf::Reflection *reflection = locp->GetReflection(); - for (int i = 0, count = descriptor->field_count(); i < count; ++i) { - const NProtoBuf::FieldDescriptor *field = descriptor->field(i); - if (reflection->HasField(*locp, field)) { - Y_ABORT_UNLESS(field->type() == NProtoBuf::FieldDescriptor::TYPE_STRING, "Location# %s", makeString().data()); - Items.emplace_back(TKeys::E(field->number()), reflection->GetString(*locp, field)); - } - } - const NProtoBuf::UnknownFieldSet& unknown = locp->unknown_fields(); - for (int i = 0, count = unknown.field_count(); i < count; ++i) { - const NProtoBuf::UnknownField& field = unknown.field(i); - Y_ABORT_UNLESS(field.type() == NProtoBuf::UnknownField::TYPE_LENGTH_DELIMITED, "Location# %s", makeString().data()); - Items.emplace_back(TKeys::E(field.number()), field.length_delimited()); - } - std::sort(Items.begin(), Items.end()); - } - - TNodeLocation::TNodeLocation(TFromSerialized, const TString& s) - : TNodeLocation(ParseLocation(s)) - {} - - TNodeLocation::TNodeLocation(const TString& DataCenter, const TString& Module, const TString& Rack, const TString& Unit) { - if (DataCenter) Items.emplace_back(TKeys::DataCenter, DataCenter); - if (Module) Items.emplace_back(TKeys::Module, Module); - if (Rack) Items.emplace_back(TKeys::Rack, Rack); - if (Unit) Items.emplace_back(TKeys::Unit, Unit); - } - - NActorsInterconnect::TNodeLocation TNodeLocation::ParseLocation(const TString& s) { - NActorsInterconnect::TNodeLocation res; - const bool success = res.ParseFromString(s); - Y_ABORT_UNLESS(success); - return res; - } - - TString TNodeLocation::ToStringUpTo(TKeys::E upToKey) const { - const NProtoBuf::Descriptor *descriptor = NActorsInterconnect::TNodeLocation::descriptor(); - - TStringBuilder res; - for (const auto& [key, value] : Items) { - if (upToKey < key) { - break; - } - TString name; - if (const NProtoBuf::FieldDescriptor *field = descriptor->FindFieldByNumber(key)) { - name = field->options().GetExtension(NActorsInterconnect::PrintName); - } else { - name = ::ToString(int(key)); - } - if (key != upToKey) { - res << name << "=" << value << "/"; - } else { - res << value; - } - } - return res; - } - - void TNodeLocation::Serialize(NActorsInterconnect::TNodeLocation *pb, bool compatibleWithOlderVersions) const { - const NProtoBuf::Descriptor *descriptor = NActorsInterconnect::TNodeLocation::descriptor(); - const NProtoBuf::Reflection *reflection = pb->GetReflection(); - NProtoBuf::UnknownFieldSet *unknown = pb->mutable_unknown_fields(); - for (const auto& [key, value] : Items) { - if (const NProtoBuf::FieldDescriptor *field = descriptor->FindFieldByNumber(key)) { - reflection->SetString(pb, field, value); - } else { - unknown->AddLengthDelimited(key)->assign(value); - } - } - if (compatibleWithOlderVersions) { - GetLegacyValue().Serialize(pb); - } - } - - TString TNodeLocation::GetSerializedLocation() const { - NActorsInterconnect::TNodeLocation pb; - Serialize(&pb, false); - TString s; - const bool success = pb.SerializeToString(&s); - Y_ABORT_UNLESS(success); - return s; - } - - TNodeLocation::TLegacyValue TNodeLocation::GetLegacyValue() const { - if (LegacyValue) { - return *LegacyValue; - } - - ui32 dataCenterId = 0, moduleId = 0, rackId = 0, unitId = 0; - - for (const auto& [key, value] : Items) { - switch (key) { - case TKeys::DataCenter: - memcpy(&dataCenterId, value.data(), Min<size_t>(sizeof(dataCenterId), value.length())); - break; - - case TKeys::Module: { - const bool success = TryFromString(value, moduleId); - Y_ABORT_UNLESS(success); - break; - } - - case TKeys::Rack: - // hacky way to obtain numeric id by a rack name - if (!TryFromString(value, rackId)) { - rackId = MurmurHash<ui32>(value.data(), value.length()); - } - break; - - case TKeys::Unit: { - const bool success = TryFromString(value, unitId); - Y_ABORT_UNLESS(success); - break; - } - - default: - Y_ABORT("unexpected legacy key# %d", key); - } - } - - return {dataCenterId, moduleId, rackId, unitId}; - } - -} // NActors diff --git a/library/cpp/actors/core/interconnect.h b/library/cpp/actors/core/interconnect.h deleted file mode 100644 index 46d4fd5303..0000000000 --- a/library/cpp/actors/core/interconnect.h +++ /dev/null @@ -1,268 +0,0 @@ -#pragma once - -#include "events.h" -#include "event_local.h" -#include <library/cpp/actors/protos/interconnect.pb.h> -#include <util/string/cast.h> -#include <util/string/builder.h> - -namespace NActors { - class TNodeLocation { - public: - struct TKeys { - enum E : int { - DataCenter = 10, - Module = 20, - Rack = 30, - Unit = 40, - }; - }; - - struct TLegacyValue { - ui32 DataCenter; - ui32 Room; - ui32 Rack; - ui32 Body; - - auto ConvertToTuple() const { return std::make_tuple(DataCenter, Room, Rack, Body); } - - int Compare(const TLegacyValue& other) const { - const auto x = ConvertToTuple(); - const auto y = other.ConvertToTuple(); - if (x < y) { - return -1; - } else if (y < x) { - return 1; - } else { - return 0; - } - } - - friend bool operator ==(const TLegacyValue& x, const TLegacyValue& y) { return x.Compare(y) == 0; } - - void Serialize(NActorsInterconnect::TNodeLocation *pb) const { - pb->SetDataCenterNum(DataCenter); - pb->SetRoomNum(Room); - pb->SetRackNum(Rack); - pb->SetBodyNum(Body); - } - }; - - private: - std::optional<TLegacyValue> LegacyValue; - std::vector<std::pair<TKeys::E, TString>> Items; - - public: - // generic ctors - TNodeLocation() = default; - TNodeLocation(const TNodeLocation&) = default; - TNodeLocation(TNodeLocation&&) = default; - TNodeLocation(const TString& DataCenter, const TString& Module = "", const TString& Rack = "", const TString& Unit = ""); - - // protobuf-parser ctor - explicit TNodeLocation(const NActorsInterconnect::TNodeLocation& location); - - // serialized protobuf ctor - static constexpr struct TFromSerialized {} FromSerialized {}; - TNodeLocation(TFromSerialized, const TString& s); - - // parser helper function - static NActorsInterconnect::TNodeLocation ParseLocation(const TString& s); - - // assignment operators - TNodeLocation& operator =(const TNodeLocation&) = default; - TNodeLocation& operator =(TNodeLocation&&) = default; - - // compatibleWithOlderVersions should be set to true when this protobuf is possibly going to be delivered to 21-4 - void Serialize(NActorsInterconnect::TNodeLocation *pb, bool compatibleWithOlderVersions) const; - TString GetSerializedLocation() const; - - TString GetDataCenterId() const { return ToStringUpTo(TKeys::DataCenter); } - TString GetModuleId() const { return ToStringUpTo(TKeys::Module); } - TString GetRackId() const { return ToStringUpTo(TKeys::Rack); } - TString GetUnitId() const { return ToStringUpTo(TKeys::Unit); } - TString ToString() const { return ToStringUpTo(TKeys::E(Max<int>())); } - TString ToStringUpTo(TKeys::E upToKey) const; - - TLegacyValue GetLegacyValue() const; - - const std::vector<std::pair<TKeys::E, TString>>& GetItems() const { return Items; } - - bool HasKey(TKeys::E key) const { - auto comp = [](const auto& p, TKeys::E value) { return p.first < value; }; - const auto it = std::lower_bound(Items.begin(), Items.end(), key, comp); - return it != Items.end() && it->first == key; - } - - int Compare(const TNodeLocation& other) const { - if (LegacyValue || other.LegacyValue) { - return GetLegacyValue().Compare(other.GetLegacyValue()); - } else if (Items < other.Items) { - return -1; - } else if (other.Items < Items) { - return 1; - } else { - return 0; - } - } - - void InheritLegacyValue(const TNodeLocation& other) { - LegacyValue = other.GetLegacyValue(); - } - - friend bool operator ==(const TNodeLocation& x, const TNodeLocation& y) { return x.Compare(y) == 0; } - friend bool operator !=(const TNodeLocation& x, const TNodeLocation& y) { return x.Compare(y) != 0; } - friend bool operator < (const TNodeLocation& x, const TNodeLocation& y) { return x.Compare(y) < 0; } - friend bool operator <=(const TNodeLocation& x, const TNodeLocation& y) { return x.Compare(y) <= 0; } - friend bool operator > (const TNodeLocation& x, const TNodeLocation& y) { return x.Compare(y) > 0; } - friend bool operator >=(const TNodeLocation& x, const TNodeLocation& y) { return x.Compare(y) >= 0; } - }; - - struct TEvInterconnect { - enum EEv { - EvForward = EventSpaceBegin(TEvents::ES_INTERCONNECT), - EvResolveNode, // resolve info about node (internal) - EvNodeAddress, // node info (internal) - EvConnectNode, // request proxy to establish connection (like: we would send something there soon) - EvAcceptIncoming, - EvNodeConnected, // node connected notify - EvNodeDisconnected, // node disconnected notify - EvRegisterNode, - EvRegisterNodeResult, - EvListNodes, - EvNodesInfo, - EvDisconnect, - EvGetNode, - EvNodeInfo, - EvClosePeerSocket, - EvCloseInputSession, - EvPoisonSession, - EvTerminate, - EvEnd - }; - - enum ESubscribes { - SubConnected, - SubDisconnected, - }; - - static_assert(EvEnd < EventSpaceEnd(TEvents::ES_INTERCONNECT), "expect EvEnd < EventSpaceEnd(TEvents::ES_INTERCONNECT)"); - - struct TEvResolveNode; - struct TEvNodeAddress; - - struct TEvConnectNode: public TEventBase<TEvConnectNode, EvConnectNode> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvConnectNode, "TEvInterconnect::TEvConnectNode") - }; - - struct TEvAcceptIncoming; - - struct TEvNodeConnected: public TEventLocal<TEvNodeConnected, EvNodeConnected> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvNodeConnected, "TEvInterconnect::TEvNodeConnected") - TEvNodeConnected(ui32 node) noexcept - : NodeId(node) - { - } - const ui32 NodeId; - }; - - struct TEvNodeDisconnected: public TEventLocal<TEvNodeDisconnected, EvNodeDisconnected> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvNodeDisconnected, "TEvInterconnect::TEvNodeDisconnected") - TEvNodeDisconnected(ui32 node) noexcept - : NodeId(node) - { - } - const ui32 NodeId; - }; - - struct TEvRegisterNode; - struct TEvRegisterNodeResult; - - struct TEvListNodes: public TEventLocal<TEvListNodes, EvListNodes> { - const bool SubscribeToStaticNodeChanges = false; - - TEvListNodes() = default; - - TEvListNodes(bool subscribeToStaticNodeChanges) - : SubscribeToStaticNodeChanges(subscribeToStaticNodeChanges) - {} - }; - - struct TNodeInfo { - ui32 NodeId; - TString Address; - TString Host; - TString ResolveHost; - ui16 Port; - TNodeLocation Location; - bool IsStatic = true; - - TNodeInfo() = default; - TNodeInfo(const TNodeInfo&) = default; - TNodeInfo& operator =(const TNodeInfo&) = default; - TNodeInfo(ui32 nodeId, - const TString& address, - const TString& host, - const TString& resolveHost, - ui16 port, - const TNodeLocation& location, - bool isStatic = true) - : NodeId(nodeId) - , Address(address) - , Host(host) - , ResolveHost(resolveHost) - , Port(port) - , Location(location) - , IsStatic(isStatic) - { - } - - operator ui32() const { - return NodeId; - } - }; - - struct TEvNodesInfo: public TEventLocal<TEvNodesInfo, EvNodesInfo> { - TVector<TNodeInfo> Nodes; - - const TNodeInfo* GetNodeInfo(ui32 nodeId) const { - for (const auto& x : Nodes) { - if (x.NodeId == nodeId) - return &x; - } - return nullptr; - } - }; - - struct TEvDisconnect; - - struct TEvGetNode: public TEventLocal<TEvGetNode, EvGetNode> { - ui32 NodeId; - TInstant Deadline; - - TEvGetNode(ui32 nodeId, TInstant deadline = TInstant::Max()) - : NodeId(nodeId) - , Deadline(deadline) - { - } - }; - - struct TEvNodeInfo: public TEventLocal<TEvNodeInfo, EvNodeInfo> { - TEvNodeInfo(ui32 nodeId) - : NodeId(nodeId) - { - } - - ui32 NodeId; - THolder<TNodeInfo> Node; - }; - - struct TEvClosePeerSocket : TEventLocal<TEvClosePeerSocket, EvClosePeerSocket> {}; - - struct TEvCloseInputSession : TEventLocal<TEvCloseInputSession, EvCloseInputSession> {}; - - struct TEvPoisonSession : TEventLocal<TEvPoisonSession, EvPoisonSession> {}; - - struct TEvTerminate : TEventLocal<TEvTerminate, EvTerminate> {}; - }; -} diff --git a/library/cpp/actors/core/invoke.h b/library/cpp/actors/core/invoke.h deleted file mode 100644 index c9e29effe2..0000000000 --- a/library/cpp/actors/core/invoke.h +++ /dev/null @@ -1,145 +0,0 @@ -#pragma once - -#include "actor_bootstrapped.h" -#include "events.h" -#include "event_local.h" - -#include <any> -#include <type_traits> -#include <utility> -#include <variant> - -#include <util/system/type_name.h> - -namespace NActors { - - struct TEvents::TEvInvokeResult - : TEventLocal<TEvInvokeResult, TSystem::InvokeResult> - { - using TProcessCallback = std::function<void(TEvInvokeResult&, const TActorContext&)>; - TProcessCallback ProcessCallback; - std::variant<std::any /* the value */, std::exception_ptr> Result; - - // This constructor creates TEvInvokeResult with the result of calling callback(args...) or exception_ptr, - // if exception occurs during evaluation. - template<typename TCallback, typename... TArgs> - TEvInvokeResult(TProcessCallback&& process, TCallback&& callback, TArgs&&... args) - : ProcessCallback(std::move(process)) - { - try { - if constexpr (std::is_void_v<std::invoke_result_t<TCallback, TArgs...>>) { - // just invoke callback without saving any value - std::invoke(std::forward<TCallback>(callback), std::forward<TArgs>(args)...); - } else { - Result.emplace<std::any>(std::invoke(std::forward<TCallback>(callback), std::forward<TArgs>(args)...)); - } - } catch (...) { - Result.emplace<std::exception_ptr>(std::current_exception()); - } - } - - void Process(const TActorContext& ctx) { - ProcessCallback(*this, ctx); - } - - template<typename TCallback> - std::invoke_result_t<TCallback, const TActorContext&> GetResult() { - using T = std::invoke_result_t<TCallback, const TActorContext&>; - return std::visit([](auto& arg) -> T { - using TArg = std::decay_t<decltype(arg)>; - if constexpr (std::is_same_v<TArg, std::exception_ptr>) { - std::rethrow_exception(arg); - } else if constexpr (std::is_void_v<T>) { - Y_ABORT_UNLESS(!arg.has_value()); - } else if (auto *value = std::any_cast<T>(&arg)) { - return std::move(*value); - } else { - Y_ABORT("unspported return type for TEvInvokeResult: actual# %s != expected# %s", - TypeName(arg.type()).data(), TypeName<T>().data()); - } - }, Result); - } - }; - - // Invoke Actor is used to make different procedure calls in specific threads pools. - // - // Actor is created by CreateInvokeActor(callback, complete) where `callback` is the function that will be invoked - // upon actor registration, which will issue then TEvInvokeResult to the parent actor with the result of called - // function. If the called function throws exception, then the exception will arrive in the result. Receiver of - // this message can either handle it by its own means calling ev.GetResult() (which will rethrow exception if it - // has occured in called function or return its return value; notice that when there is no return value, then - // GetResult() should also be called to prevent losing exception), or invoke ev.Process(), which will invoke - // callback provided as `complete` parameter to the CreateInvokeActor function. Complete handler is invoked with - // the result-getter lambda as the first argument and the actor system context as the second one. Result-getter - // should be called to obtain resulting value or exception like the GetResult() method of the TEvInvokeResult event. - // - // Notice that `callback` execution usually occurs in separate actor on separate mailbox and should not use parent - // actor's class. But `complete` handler is invoked in parent context and can use its contents. Do not forget to - // handle TEvInvokeResult event by calling Process/GetResult method, whichever is necessary. - - template<typename TCallback, typename TCompletion, class TEnum> - class TInvokeActor : public TActorBootstrapped<TInvokeActor<TCallback, TCompletion, TEnum>> { - private: - using TBase = TActorBootstrapped<TInvokeActor<TCallback, TCompletion, TEnum>>; - TCallback Callback; - TCompletion Complete; - const TEnum Activity; - static_assert(std::is_enum<TEnum>::value); - public: - TInvokeActor(TCallback&& callback, TCompletion&& complete, const TEnum activity) - : TBase(activity) - , Callback(std::move(callback)) - , Complete(std::move(complete)) - , Activity(activity) - {} - - void Bootstrap(const TActorId& parentId, const TActorContext& ctx) { - auto process = [complete = std::move(Complete)](TEvents::TEvInvokeResult& res, const TActorContext& ctx) { - complete([&] { return res.GetResult<TCallback>(); }, ctx); - }; - ctx.Send(parentId, new TEvents::TEvInvokeResult(std::move(process), std::move(Callback), ctx)); - TActorBootstrapped<TInvokeActor>::Die(ctx); - } - }; - - template<typename TEnum, typename TCallback, typename TCompletion> - std::unique_ptr<IActor> CreateInvokeActor(TCallback&& callback, TCompletion&& complete, const TEnum activity) { - return std::make_unique<TInvokeActor<std::decay_t<TCallback>, std::decay_t<TCompletion>, TEnum>>( - std::forward<TCallback>(callback), std::forward<TCompletion>(complete), activity); - } - - template <class TInvokeExecutor> - class TScheduledInvokeActivity: public TActor<TScheduledInvokeActivity<TInvokeExecutor>> { - private: - using TBase = TActor<TScheduledInvokeActivity<TInvokeExecutor>>; - const TMonotonic Timestamp; - TInvokeExecutor Executor; - public: - TScheduledInvokeActivity(TInvokeExecutor&& executor, const TMonotonic timestamp) - : TBase(&TBase::TThis::StateFunc) - , Timestamp(timestamp) - , Executor(std::move(executor)) { - } - - void StateFunc(STFUNC_SIG) { - Y_ABORT_UNLESS(ev->GetTypeRewrite() == TEvents::TSystem::Wakeup); - auto g = TBase::PassAwayGuard(); - Executor(); - } - - void Registered(TActorSystem* sys, const TActorId& owner) override { - sys->Schedule(Timestamp, new IEventHandle(TEvents::TSystem::Wakeup, 0, TBase::SelfId(), owner, nullptr, 0)); - } - }; - - template<class TInvokeExecutor> - void ScheduleInvokeActivity(TInvokeExecutor&& executor, const TDuration d) { - TActivationContext::Register(new TScheduledInvokeActivity<TInvokeExecutor>(std::move(executor), TMonotonic::Now() + d)); - } - - template<class TInvokeExecutor> - void ScheduleInvokeActivity(TInvokeExecutor&& executor, const TMonotonic timestamp) { - TActivationContext::Register(new TScheduledInvokeActivity<TInvokeExecutor>(std::move(executor), timestamp)); - } - -} // NActors diff --git a/library/cpp/actors/core/io_dispatcher.cpp b/library/cpp/actors/core/io_dispatcher.cpp deleted file mode 100644 index c7d28c63e0..0000000000 --- a/library/cpp/actors/core/io_dispatcher.cpp +++ /dev/null @@ -1,236 +0,0 @@ -#include "io_dispatcher.h" -#include "actor_bootstrapped.h" -#include "hfunc.h" -#include <util/system/mutex.h> -#include <util/system/condvar.h> -#include <util/system/thread.h> -#include <map> -#include <list> - -namespace NActors { - - class TIoDispatcherActor : public TActorBootstrapped<TIoDispatcherActor> { - enum { - EvNotifyThreadStopped = EventSpaceBegin(TEvents::ES_PRIVATE), - }; - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // IO task queue - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - class TTask { - TInstant Timestamp; - std::function<void()> Callback; - - public: - TTask(TInstant timestamp, TEvInvokeQuery *ev) - : Timestamp(timestamp) - , Callback(std::move(ev->Callback)) - {} - - void Execute() { - Callback(); - } - - TInstant GetTimestamp() const { - return Timestamp; - } - }; - - class TTaskQueue { - std::list<TTask> Tasks; - TMutex Mutex; - TCondVar CondVar; - size_t NumThreadsToStop = 0; - - public: - void Enqueue(TInstant timestamp, TEvInvokeQuery *ev) { - std::list<TTask> list; - list.emplace_back(timestamp, ev); - with_lock (Mutex) { - Tasks.splice(Tasks.end(), std::move(list)); - } - CondVar.Signal(); - } - - bool Dequeue(std::list<TTask>& list, bool *sendNotify) { - with_lock (Mutex) { - CondVar.Wait(Mutex, [&] { return NumThreadsToStop || !Tasks.empty(); }); - if (NumThreadsToStop) { - *sendNotify = NumThreadsToStop != Max<size_t>(); - if (*sendNotify) { - --NumThreadsToStop; - } - return false; - } else { - list.splice(list.end(), Tasks, Tasks.begin()); - return true; - } - } - } - - void Stop() { - with_lock (Mutex) { - NumThreadsToStop = Max<size_t>(); - } - CondVar.BroadCast(); - } - - void StopOne() { - with_lock (Mutex) { - ++NumThreadsToStop; - Y_ABORT_UNLESS(NumThreadsToStop); - } - CondVar.Signal(); - } - - std::optional<TInstant> GetEarliestTaskTimestamp() { - with_lock (Mutex) { - return Tasks.empty() ? std::nullopt : std::make_optional(Tasks.front().GetTimestamp()); - } - } - }; - - TTaskQueue TaskQueue; - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // IO dispatcher threads - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - class TThread : public ISimpleThread { - TIoDispatcherActor& Actor; - TActorSystem* const ActorSystem; - - public: - TThread(TIoDispatcherActor& actor, TActorSystem *actorSystem) - : Actor(actor) - , ActorSystem(actorSystem) - { - Start(); - } - - void *ThreadProc() override { - SetCurrentThreadName("kikimr IO"); - for (;;) { - std::list<TTask> tasks; - bool sendNotify; - if (!Actor.TaskQueue.Dequeue(tasks, &sendNotify)) { - if (sendNotify) { - ActorSystem->Send(new IEventHandle(EvNotifyThreadStopped, 0, Actor.SelfId(), TActorId(), - nullptr, TThread::CurrentThreadId())); - } - break; - } - for (TTask& task : tasks) { - task.Execute(); - ++*Actor.TasksCompleted; - } - } - return nullptr; - } - }; - - static constexpr size_t MinThreadCount = 4; - static constexpr size_t MaxThreadCount = 64; - std::map<TThread::TId, std::unique_ptr<TThread>> Threads; - size_t NumRunningThreads = 0; - - void StartThread() { - auto thread = std::make_unique<TThread>(*this, TlsActivationContext->ExecutorThread.ActorSystem); - const TThread::TId id = thread->Id(); - Threads.emplace(id, std::move(thread)); - *NumThreads = ++NumRunningThreads; - ++*ThreadsStarted; - } - - void StopThread() { - Y_ABORT_UNLESS(Threads.size()); - TaskQueue.StopOne(); - *NumThreads = --NumRunningThreads; - ++*ThreadsStopped; - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Counters - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - NMonitoring::TDynamicCounters::TCounterPtr NumThreads; - NMonitoring::TDynamicCounters::TCounterPtr TasksAdded; - NMonitoring::TDynamicCounters::TCounterPtr TasksCompleted; - NMonitoring::TDynamicCounters::TCounterPtr ThreadsStarted; - NMonitoring::TDynamicCounters::TCounterPtr ThreadsStopped; - - public: - TIoDispatcherActor(const NMonitoring::TDynamicCounterPtr& counters) - : NumThreads(counters->GetCounter("NumThreads")) - , TasksAdded(counters->GetCounter("TasksAdded", true)) - , TasksCompleted(counters->GetCounter("TasksCompleted", true)) - , ThreadsStarted(counters->GetCounter("ThreadsStarted", true)) - , ThreadsStopped(counters->GetCounter("ThreadsStopped", true)) - {} - - ~TIoDispatcherActor() override { - TaskQueue.Stop(); - } - - static constexpr char ActorName[] = "IO_DISPATCHER_ACTOR"; - - void Bootstrap() { - while (NumRunningThreads < MinThreadCount) { - StartThread(); - } - HandleWakeup(); - Become(&TThis::StateFunc); - } - - void HandleThreadStopped(TAutoPtr<IEventHandle> ev) { - auto it = Threads.find(ev->Cookie); - Y_ABORT_UNLESS(it != Threads.end()); - it->second->Join(); - Threads.erase(it); - } - - void Handle(TEvInvokeQuery::TPtr ev) { - ++*TasksAdded; - TaskQueue.Enqueue(TActivationContext::Now(), ev->Get()); - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Thread usage counter logic - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::optional<TInstant> IdleTimestamp; - static constexpr TDuration ThreadStartTime = TDuration::MilliSeconds(500); - static constexpr TDuration ThreadStopTime = TDuration::MilliSeconds(500); - - void HandleWakeup() { - const TInstant now = TActivationContext::Now(); - std::optional<TInstant> earliest = TaskQueue.GetEarliestTaskTimestamp(); - if (earliest) { - if (now >= *earliest + ThreadStartTime && NumRunningThreads < MaxThreadCount) { - StartThread(); - } - IdleTimestamp.reset(); - } else if (!IdleTimestamp) { - IdleTimestamp = now; - } else if (now >= *IdleTimestamp + ThreadStopTime) { - IdleTimestamp.reset(); - if (NumRunningThreads > MinThreadCount) { - StopThread(); - } - } - Schedule(TDuration::MilliSeconds(100), new TEvents::TEvWakeup); - } - - STRICT_STFUNC(StateFunc, { - fFunc(EvNotifyThreadStopped, HandleThreadStopped); - hFunc(TEvInvokeQuery, Handle); - cFunc(TEvents::TSystem::Wakeup, HandleWakeup); - cFunc(TEvents::TSystem::Poison, PassAway); - }) - }; - - IActor *CreateIoDispatcherActor(const NMonitoring::TDynamicCounterPtr& counters) { - return new TIoDispatcherActor(counters); - } - -} // NActors diff --git a/library/cpp/actors/core/io_dispatcher.h b/library/cpp/actors/core/io_dispatcher.h deleted file mode 100644 index b0e4e60d1a..0000000000 --- a/library/cpp/actors/core/io_dispatcher.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include "actor.h" -#include "event_local.h" -#include "events.h" -#include "actorsystem.h" -#include "executor_thread.h" -#include "executelater.h" - -namespace NActors { - - struct TEvInvokeQuery : TEventLocal<TEvInvokeQuery, TEvents::TSystem::InvokeQuery> { - std::function<void()> Callback; - - TEvInvokeQuery(std::function<void()>&& callback) - : Callback(std::move(callback)) - {} - }; - - inline TActorId MakeIoDispatcherActorId() { - return TActorId(0, TStringBuf("IoDispatcher", 12)); - } - - extern IActor *CreateIoDispatcherActor(const NMonitoring::TDynamicCounterPtr& counters); - - /* InvokeIoCallback enqueues callback() to be executed in IO thread pool and then return result in TEvInvokeResult - * message to parentId actor. - */ - template<typename TCallback> - static void InvokeIoCallback(TCallback&& callback, ui32 poolId, IActor::EActivityType activityType) { - if (!TActivationContext::Send(new IEventHandle(MakeIoDispatcherActorId(), TActorId(), - new TEvInvokeQuery(callback)))) { - TActivationContext::Register(CreateExecuteLaterActor(std::move(callback), activityType), TActorId(), - TMailboxType::HTSwap, poolId); - } - } - -} // NActors diff --git a/library/cpp/actors/core/lease.h b/library/cpp/actors/core/lease.h deleted file mode 100644 index 650ae7b122..0000000000 --- a/library/cpp/actors/core/lease.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include "defs.h" - -namespace NActors { - // Value representing specific worker's permission for exclusive use of CPU till specific deadline - struct TLease { - // Lower WorkerBits store current fast worker id - // All other higher bits store expiration (hard preemption) timestamp - using TValue = ui64; - TValue Value; - - static constexpr ui64 WorkerIdMask = ui64((1ull << WorkerBits) - 1); - static constexpr ui64 ExpireTsMask = ~WorkerIdMask; - - explicit constexpr TLease(ui64 value) - : Value(value) - {} - - constexpr TLease(TWorkerId workerId, ui64 expireTs) - : Value((workerId & WorkerIdMask) | (expireTs & ExpireTsMask)) - {} - - TWorkerId GetWorkerId() const { - return Value & WorkerIdMask; - } - - TLease NeverExpire() const { - return TLease(Value | ExpireTsMask); - } - - bool IsNeverExpiring() const { - return (Value & ExpireTsMask) == ExpireTsMask; - } - - ui64 GetExpireTs() const { - // Do not truncate worker id - // NOTE: it decrease accuracy, but improves performance - return Value; - } - - ui64 GetPreciseExpireTs() const { - return Value & ExpireTsMask; - } - - operator TValue() const { - return Value; - } - }; - - // Special expire timestamp values - static constexpr ui64 NeverExpire = ui64(-1); - - // Special hard-preemption-in-progress lease - static constexpr TLease HardPreemptionLease = TLease(TLease::WorkerIdMask, NeverExpire); -} diff --git a/library/cpp/actors/core/log.cpp b/library/cpp/actors/core/log.cpp deleted file mode 100644 index 1a8880d15d..0000000000 --- a/library/cpp/actors/core/log.cpp +++ /dev/null @@ -1,768 +0,0 @@ -#include "log.h" - -static_assert(int(NActors::NLog::PRI_EMERG) == int(::TLOG_EMERG), "expect int(NActors::NLog::PRI_EMERG) == int(::TLOG_EMERG)"); -static_assert(int(NActors::NLog::PRI_ALERT) == int(::TLOG_ALERT), "expect int(NActors::NLog::PRI_ALERT) == int(::TLOG_ALERT)"); -static_assert(int(NActors::NLog::PRI_CRIT) == int(::TLOG_CRIT), "expect int(NActors::NLog::PRI_CRIT) == int(::TLOG_CRIT)"); -static_assert(int(NActors::NLog::PRI_ERROR) == int(::TLOG_ERR), "expect int(NActors::NLog::PRI_ERROR) == int(::TLOG_ERR)"); -static_assert(int(NActors::NLog::PRI_WARN) == int(::TLOG_WARNING), "expect int(NActors::NLog::PRI_WARN) == int(::TLOG_WARNING)"); -static_assert(int(NActors::NLog::PRI_NOTICE) == int(::TLOG_NOTICE), "expect int(NActors::NLog::PRI_NOTICE) == int(::TLOG_NOTICE)"); -static_assert(int(NActors::NLog::PRI_INFO) == int(::TLOG_INFO), "expect int(NActors::NLog::PRI_INFO) == int(::TLOG_INFO)"); -static_assert(int(NActors::NLog::PRI_DEBUG) == int(::TLOG_DEBUG), "expect int(NActors::NLog::PRI_DEBUG) == int(::TLOG_DEBUG)"); -static_assert(int(NActors::NLog::PRI_TRACE) == int(::TLOG_RESOURCES), "expect int(NActors::NLog::PRI_TRACE) == int(::TLOG_RESOURCES)"); - -namespace { - struct TRecordWithNewline { - ELogPriority Priority; - TTempBuf Buf; - - TRecordWithNewline(const TLogRecord& rec) - : Priority(rec.Priority) - , Buf(rec.Len + 1) - { - Buf.Append(rec.Data, rec.Len); - *Buf.Proceed(1) = '\n'; - } - - operator TLogRecord() const { - return TLogRecord(Priority, Buf.Data(), Buf.Filled()); - } - }; -} - -namespace NActors { - TLoggerActor::TLoggerActor(TIntrusivePtr<NLog::TSettings> settings, - TAutoPtr<TLogBackend> logBackend, - TIntrusivePtr<NMonitoring::TDynamicCounters> counters) - : TActor(&TLoggerActor::StateFunc) - , Settings(settings) - , LogBackend(logBackend.Release()) - , Metrics(std::make_unique<TLoggerCounters>(counters)) - , LogBuffer(*Metrics, *Settings) - { - } - - TLoggerActor::TLoggerActor(TIntrusivePtr<NLog::TSettings> settings, - std::shared_ptr<TLogBackend> logBackend, - TIntrusivePtr<NMonitoring::TDynamicCounters> counters) - : TActor(&TLoggerActor::StateFunc) - , Settings(settings) - , LogBackend(logBackend) - , Metrics(std::make_unique<TLoggerCounters>(counters)) - , LogBuffer(*Metrics, *Settings) - { - } - - TLoggerActor::TLoggerActor(TIntrusivePtr<NLog::TSettings> settings, - TAutoPtr<TLogBackend> logBackend, - std::shared_ptr<NMonitoring::TMetricRegistry> metrics) - : TActor(&TLoggerActor::StateFunc) - , Settings(settings) - , LogBackend(logBackend.Release()) - , Metrics(std::make_unique<TLoggerMetrics>(metrics)) - , LogBuffer(*Metrics, *Settings) - { - } - - TLoggerActor::TLoggerActor(TIntrusivePtr<NLog::TSettings> settings, - std::shared_ptr<TLogBackend> logBackend, - std::shared_ptr<NMonitoring::TMetricRegistry> metrics) - : TActor(&TLoggerActor::StateFunc) - , Settings(settings) - , LogBackend(logBackend) - , Metrics(std::make_unique<TLoggerMetrics>(metrics)) - , LogBuffer(*Metrics, *Settings) - { - } - - TLoggerActor::~TLoggerActor() { - } - - void TLoggerActor::Log(TInstant time, NLog::EPriority priority, NLog::EComponent component, const char* c, ...) { - Metrics->IncDirectMsgs(); - if (Settings && Settings->Satisfies(priority, component, 0ull)) { - va_list params; - va_start(params, c); - TString formatted; - vsprintf(formatted, c, params); - - auto ok = OutputRecord(time, NLog::EPrio(priority), component, formatted); - Y_UNUSED(ok); - va_end(params); - } - } - - void TLoggerActor::Throttle(const NLog::TSettings& settings) { - // throttling via Sleep was removed since it causes unexpected - // incidents when users try to set AllowDrop=false. - Y_UNUSED(settings); - } - - void TLoggerActor::FlushLogBufferMessage() { - if (!LogBuffer.IsEmpty()) { - NLog::TEvLog *log = LogBuffer.Pop(); - if (!OutputRecord(log)) { - BecomeDefunct(); - } - delete log; - } - } - - void TLoggerActor::FlushLogBufferMessageEvent(TFlushLogBuffer::TPtr& ev, const NActors::TActorContext& ctx) { - Y_UNUSED(ev); - FlushLogBufferMessage(); - - ui64 ignoredCount = LogBuffer.GetIgnoredCount(); - if (ignoredCount > 0) { - NLog::EPrio prio = LogBuffer.GetIgnoredHighestPrio(); - TString message = Sprintf("Logger overflow! Ignored %" PRIu64 " log records with priority [%s] or lower!", ignoredCount, PriorityToString(prio)); - if (!OutputRecord(ctx.Now(), NActors::NLog::EPrio::Error, Settings->LoggerComponent, message)) { - BecomeDefunct(); - } - LogBuffer.ClearIgnoredCount(); - } - - if (!LogBuffer.IsEmpty()) { - ctx.Send(ctx.SelfID, ev->Release().Release()); - } - } - - void TLoggerActor::WriteMessageStat(const NLog::TEvLog& ev) { - Metrics->IncActorMsgs(); - - const auto prio = ev.Level.ToPrio(); - - switch (prio) { - case ::NActors::NLog::EPrio::Alert: - Metrics->IncAlertMsgs(); - break; - case ::NActors::NLog::EPrio::Emerg: - Metrics->IncEmergMsgs(); - break; - default: - break; - } - - } - - void TLoggerActor::HandleLogEvent(NLog::TEvLog::TPtr& ev, const NActors::TActorContext& ctx) { - i64 delayMillisec = (ctx.Now() - ev->Get()->Stamp).MilliSeconds(); - WriteMessageStat(*ev->Get()); - if (Settings->AllowDrop) { - if (PassedCount > 10 && delayMillisec > (i64)Settings->TimeThresholdMs || !LogBuffer.IsEmpty() || LogBuffer.CheckLogIgnoring()) { - if (LogBuffer.IsEmpty() && !LogBuffer.CheckLogIgnoring()) { - ctx.Send(ctx.SelfID, new TFlushLogBuffer()); - } - LogBuffer.AddLog(ev->Release().Release()); - PassedCount = 0; - - if (delayMillisec < (i64)Settings->TimeThresholdMs && !LogBuffer.CheckLogIgnoring()) { - FlushLogBufferMessage(); - } - return; - } - - PassedCount++; - } - - if (!OutputRecord(ev->Get())) { - BecomeDefunct(); - } - } - - void TLoggerActor::BecomeDefunct() { - Become(&TThis::StateDefunct); - Schedule(WakeupInterval, new TEvents::TEvWakeup); - } - - void TLoggerActor::HandleLogComponentLevelRequest(TLogComponentLevelRequest::TPtr& ev, const NActors::TActorContext& ctx) { - Metrics->IncLevelRequests(); - TString explanation; - int code = Settings->SetLevel(ev->Get()->Priority, ev->Get()->Component, explanation); - ctx.Send(ev->Sender, new TLogComponentLevelResponse(code, explanation)); - } - - void TLoggerActor::RenderComponentPriorities(IOutputStream& str) { - using namespace NLog; - HTML(str) { - TAG(TH4) { - str << "Priority Settings for the Components"; - } - TABLE_SORTABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() { - str << "Component"; - } - TABLEH() { - str << "Level"; - } - TABLEH() { - str << "Sampling Level"; - } - TABLEH() { - str << "Sampling Rate"; - } - } - } - TABLEBODY() { - for (EComponent i = Settings->MinVal; i < Settings->MaxVal; i++) { - auto name = Settings->ComponentName(i); - if (!*name) - continue; - NLog::TComponentSettings componentSettings = Settings->GetComponentSettings(i); - - TABLER() { - TABLED() { - str << "<a href='logger?c=" << i << "'>" << name << "</a>"; - } - TABLED() { - str << PriorityToString(EPrio(componentSettings.Raw.X.Level)); - } - TABLED() { - str << PriorityToString(EPrio(componentSettings.Raw.X.SamplingLevel)); - } - TABLED() { - str << componentSettings.Raw.X.SamplingRate; - } - } - } - } - } - } - } - - /* - * Logger INFO: - * 1. Current priority settings from components - * 2. Number of log messages (via actors events, directly) - * 3. Number of messages per components, per priority - * 4. Log level changes (last N changes) - */ - void TLoggerActor::HandleMonInfo(NMon::TEvHttpInfo::TPtr& ev, const TActorContext& ctx) { - const auto& params = ev->Get()->Request.GetParams(); - NLog::EComponent component = NLog::InvalidComponent; - NLog::EPriority priority = NLog::PRI_DEBUG; - NLog::EPriority samplingPriority = NLog::PRI_DEBUG; - ui32 samplingRate = 0; - bool hasComponent = false; - bool hasPriority = false; - bool hasSamplingPriority = false; - bool hasSamplingRate = false; - bool hasAllowDrop = false; - int allowDrop = 0; - if (params.Has("c")) { - if (TryFromString(params.Get("c"), component) && (component == NLog::InvalidComponent || Settings->IsValidComponent(component))) { - hasComponent = true; - if (params.Has("p")) { - int rawPriority; - if (TryFromString(params.Get("p"), rawPriority) && NLog::TSettings::IsValidPriority((NLog::EPriority)rawPriority)) { - priority = (NLog::EPriority)rawPriority; - hasPriority = true; - } - } - if (params.Has("sp")) { - int rawPriority; - if (TryFromString(params.Get("sp"), rawPriority) && NLog::TSettings::IsValidPriority((NLog::EPriority)rawPriority)) { - samplingPriority = (NLog::EPriority)rawPriority; - hasSamplingPriority = true; - } - } - if (params.Has("sr")) { - if (TryFromString(params.Get("sr"), samplingRate)) { - hasSamplingRate = true; - } - } - } - } - if (params.Has("allowdrop")) { - if (TryFromString(params.Get("allowdrop"), allowDrop)) { - hasAllowDrop = true; - } - } - - TStringStream str; - if (hasComponent && !hasPriority && !hasSamplingPriority && !hasSamplingRate) { - NLog::TComponentSettings componentSettings = Settings->GetComponentSettings(component); - ui32 samplingRate = componentSettings.Raw.X.SamplingRate; - HTML(str) { - DIV_CLASS("row") { - DIV_CLASS("col-md-12") { - TAG(TH4) { - str << "Current log settings for " << Settings->ComponentName(component) << Endl; - } - UL() { - LI() { - str << "Priority: " - << NLog::PriorityToString(NLog::EPrio(componentSettings.Raw.X.Level)); - } - LI() { - str << "Sampling priority: " - << NLog::PriorityToString(NLog::EPrio(componentSettings.Raw.X.SamplingLevel)); - } - LI() { - str << "Sampling rate: " - << samplingRate; - } - } - } - } - - DIV_CLASS("row") { - DIV_CLASS("col-md-12") { - TAG(TH4) { - str << "Change priority" << Endl; - } - UL() { - for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) { - LI() { - str << "<a href='logger?c=" << component << "&p=" << p << "'>" - << NLog::PriorityToString(NLog::EPrio(p)) << "</a>"; - } - } - } - TAG(TH4) { - str << "Change sampling priority" << Endl; - } - UL() { - for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) { - LI() { - str << "<a href='logger?c=" << component << "&sp=" << p << "'>" - << NLog::PriorityToString(NLog::EPrio(p)) << "</a>"; - } - } - } - TAG(TH4) { - str << "Change sampling rate" << Endl; - } - str << "<form method=\"GET\">" << Endl; - str << "Rate: <input type=\"number\" name=\"sr\" value=\"" << samplingRate << "\"/>" << Endl; - str << "<input type=\"hidden\" name=\"c\" value=\"" << component << "\">" << Endl; - str << "<input class=\"btn btn-primary\" type=\"submit\" value=\"Change\"/>" << Endl; - str << "</form>" << Endl; - TAG(TH4) { - str << "<a href='logger'>Cancel</a>" << Endl; - } - } - } - } - - } else { - TString explanation; - if (hasComponent && hasPriority) { - Settings->SetLevel(priority, component, explanation); - } - if (hasComponent && hasSamplingPriority) { - Settings->SetSamplingLevel(samplingPriority, component, explanation); - } - if (hasComponent && hasSamplingRate) { - Settings->SetSamplingRate(samplingRate, component, explanation); - } - if (hasAllowDrop) { - Settings->SetAllowDrop(allowDrop); - } - - HTML(str) { - if (!explanation.empty()) { - DIV_CLASS("row") { - DIV_CLASS("col-md-12 alert alert-info") { - str << explanation; - } - } - } - - DIV_CLASS("row") { - DIV_CLASS("col-md-6") { - RenderComponentPriorities(str); - } - DIV_CLASS("col-md-6") { - TAG(TH4) { - str << "Change priority for all components"; - } - TABLE_CLASS("table table-condensed") { - TABLEHEAD() { - TABLER() { - TABLEH() { - str << "Priority"; - } - } - } - TABLEBODY() { - for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) { - TABLER() { - TABLED() { - str << "<a href = 'logger?c=-1&p=" << p << "'>" - << NLog::PriorityToString(NLog::EPrio(p)) << "</a>"; - } - } - } - } - } - TAG(TH4) { - str << "Change sampling priority for all components"; - } - TABLE_CLASS("table table-condensed") { - TABLEHEAD() { - TABLER() { - TABLEH() { - str << "Priority"; - } - } - } - TABLEBODY() { - for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) { - TABLER() { - TABLED() { - str << "<a href = 'logger?c=-1&sp=" << p << "'>" - << NLog::PriorityToString(NLog::EPrio(p)) << "</a>"; - } - } - } - } - } - TAG(TH4) { - str << "Change sampling rate for all components"; - } - str << "<form method=\"GET\">" << Endl; - str << "Rate: <input type=\"number\" name=\"sr\" value=\"0\"/>" << Endl; - str << "<input type=\"hidden\" name=\"c\" value=\"-1\">" << Endl; - str << "<input class=\"btn btn-primary\" type=\"submit\" value=\"Change\"/>" << Endl; - str << "</form>" << Endl; - TAG(TH4) { - str << "Drop log entries in case of overflow: " - << (Settings->AllowDrop ? "Enabled" : "Disabled"); - } - str << "<form method=\"GET\">" << Endl; - str << "<input type=\"hidden\" name=\"allowdrop\" value=\"" << (Settings->AllowDrop ? "0" : "1") << "\"/>" << Endl; - str << "<input class=\"btn btn-primary\" type=\"submit\" value=\"" << (Settings->AllowDrop ? "Disable" : "Enable") << "\"/>" << Endl; - str << "</form>" << Endl; - } - } - Metrics->GetOutputHtml(str); - } - } - - ctx.Send(ev->Sender, new NMon::TEvHttpInfoRes(str.Str())); - } - - constexpr size_t TimeBufSize = 512; - - bool TLoggerActor::OutputRecord(NLog::TEvLog *evLog) noexcept { - return OutputRecord(evLog->Stamp, evLog->Level.ToPrio(), evLog->Component, evLog->Line); - } - - bool TLoggerActor::OutputRecord(TInstant time, NLog::EPrio priority, NLog::EComponent component, - const TString& formatted) noexcept try { - const auto logPrio = ::ELogPriority(ui16(priority)); - - char buf[TimeBufSize]; - switch (Settings->Format) { - case NActors::NLog::TSettings::PLAIN_FULL_FORMAT: { - TStringBuilder logRecord; - if (Settings->UseLocalTimestamps) { - logRecord << FormatLocalTimestamp(time, buf); - } else { - logRecord << time; - } - logRecord - << Settings->MessagePrefix - << " :" << Settings->ComponentName(component) - << " " << PriorityToString(priority) - << ": " << formatted; - LogBackend->WriteData( - TLogRecord(logPrio, logRecord.data(), logRecord.size())); - } break; - - case NActors::NLog::TSettings::PLAIN_SHORT_FORMAT: { - TStringBuilder logRecord; - logRecord - << Settings->ComponentName(component) - << ": " << formatted; - LogBackend->WriteData( - TLogRecord(logPrio, logRecord.data(), logRecord.size())); - } break; - - case NActors::NLog::TSettings::JSON_FORMAT: { - NJsonWriter::TBuf json; - json.BeginObject() - .WriteKey("@timestamp") - .WriteString(Settings->UseLocalTimestamps ? FormatLocalTimestamp(time, buf) : time.ToString().data()) - .WriteKey("microseconds") - .WriteULongLong(time.MicroSeconds()) - .WriteKey("host") - .WriteString(Settings->ShortHostName) - .WriteKey("cluster") - .WriteString(Settings->ClusterName) - .WriteKey("priority") - .WriteString(PriorityToString(priority)) - .WriteKey("npriority") - .WriteInt((int)priority) - .WriteKey("component") - .WriteString(Settings->ComponentName(component)) - .WriteKey("tag") - .WriteString("KIKIMR") - .WriteKey("revision") - .WriteInt(GetProgramSvnRevision()) - .WriteKey("message") - .WriteString(formatted) - .EndObject(); - auto logRecord = json.Str(); - LogBackend->WriteData( - TLogRecord(logPrio, logRecord.data(), logRecord.size())); - } break; - } - - return true; - } catch (...) { - return false; - } - - void TLoggerActor::HandleLogEventDrop(const NLog::TEvLog::TPtr& ev) { - WriteMessageStat(*ev->Get()); - Metrics->IncDroppedMsgs(); - } - - void TLoggerActor::HandleWakeup() { - Become(&TThis::StateFunc); - } - - const char* TLoggerActor::FormatLocalTimestamp(TInstant time, char* buf) { - struct tm localTime; - time.LocalTime(&localTime); - int r = strftime(buf, TimeBufSize, "%Y-%m-%d-%H-%M-%S", &localTime); - Y_ABORT_UNLESS(r != 0); - return buf; - } - - TAutoPtr<TLogBackend> CreateSysLogBackend(const TString& ident, - bool logPError, bool logCons) { - int flags = 0; - if (logPError) - flags |= TSysLogBackend::LogPerror; - if (logCons) - flags |= TSysLogBackend::LogCons; - - return new TSysLogBackend(ident.data(), TSysLogBackend::TSYSLOG_LOCAL1, flags); - } - - class TStderrBackend: public TLogBackend { - public: - TStderrBackend() { - } - void WriteData(const TLogRecord& rec) override { -#ifdef _MSC_VER - if (IsDebuggerPresent()) { - TString x; - x.reserve(rec.Len + 2); - x.append(rec.Data, rec.Len); - x.append('\n'); - OutputDebugString(x.c_str()); - } -#endif - bool isOk = false; - do { - try { - TRecordWithNewline r(rec); - Cerr.Write(r.Buf.Data(), r.Buf.Filled()); - isOk = true; - } catch (TSystemError err) { - // Interrupted system call - Y_UNUSED(err); - } - } while (!isOk); - } - - void ReopenLog() override { - } - - private: - const TString Indent; - }; - - class TLineFileLogBackend: public TFileLogBackend { - public: - TLineFileLogBackend(const TString& path) - : TFileLogBackend(path) - { - } - - // Append newline after every record - void WriteData(const TLogRecord& rec) override { - TFileLogBackend::WriteData(TRecordWithNewline(rec)); - } - }; - - class TCompositeLogBackend: public TLogBackend { - public: - TCompositeLogBackend(TVector<TAutoPtr<TLogBackend>>&& underlyingBackends) - : UnderlyingBackends(std::move(underlyingBackends)) - { - } - - void WriteData(const TLogRecord& rec) override { - for (auto& b: UnderlyingBackends) { - b->WriteData(rec); - } - } - - void ReopenLog() override { - } - - private: - TVector<TAutoPtr<TLogBackend>> UnderlyingBackends; - }; - - TAutoPtr<TLogBackend> CreateStderrBackend() { - return new TStderrBackend(); - } - - TAutoPtr<TLogBackend> CreateFileBackend(const TString& fileName) { - return new TLineFileLogBackend(fileName); - } - - TAutoPtr<TLogBackend> CreateNullBackend() { - return new TNullLogBackend(); - } - - TAutoPtr<TLogBackend> CreateCompositeLogBackend(TVector<TAutoPtr<TLogBackend>>&& underlyingBackends) { - return new TCompositeLogBackend(std::move(underlyingBackends)); - } - - class TLogContext: TNonCopyable { - private: - class TStackedContext { - private: - const TLogContextGuard* Guard; - std::optional<NLog::EComponent> Component; - mutable std::optional<TString> CurrentHeader; - public: - TStackedContext(const TLogContextGuard* guard, std::optional<NLog::EComponent>&& component) - : Guard(guard) - , Component(std::move(component)) - { - - } - - ui64 GetId() const { - return Guard->GetId(); - } - - const std::optional<NLog::EComponent>& GetComponent() const { - return Component; - } - - TString GetCurrentHeader() const { - if (!CurrentHeader) { - CurrentHeader = Guard->GetResult(); - } - return *CurrentHeader; - } - }; - - std::vector<TStackedContext> Stack; - public: - void Push(const TLogContextGuard& context) { - std::optional<NLog::EComponent> component; - if (Stack.empty() || context.GetComponent()) { - component = context.GetComponent(); - } else { - component = Stack.back().GetComponent(); - } - Stack.emplace_back(&context, std::move(component)); - } - - void Pop(const TLogContextGuard& context) { - Y_ABORT_UNLESS(Stack.size() && Stack.back().GetId() == context.GetId()); - Stack.pop_back(); - } - - std::optional<NLog::EComponent> GetCurrentComponent() const { - if (Stack.empty()) { - return {}; - } - return Stack.back().GetComponent(); - } - - TString GetCurrentHeader() { - TStringBuilder sb; - for (auto&& i : Stack) { - sb << i.GetCurrentHeader(); - } - return sb; - } - }; - - namespace { - Y_POD_THREAD(ui64) GuardId; - Y_THREAD(TLogContext) TlsLogContext; - - } - - TLogContextGuard::~TLogContextGuard() { - TlsLogContext.Get().Pop(*this); - } - - TLogContextGuard::TLogContextGuard(const TLogContextBuilder& builder) - : TBase(builder.GetResult()) - , Component(builder.GetComponent()) - , Id(++GuardId) - { - TlsLogContext.Get().Push(*this); - } - - int TLogContextGuard::GetCurrentComponent(const ::NActors::NLog::EComponent defComponent) { - return TlsLogContext.Get().GetCurrentComponent().value_or(defComponent); - } - - TLogRecordConstructor::TLogRecordConstructor() { - TBase::WriteDirectly(TlsLogContext.Get().GetCurrentHeader()); - } - - TFormattedRecordWriter::TFormattedRecordWriter(::NActors::NLog::EPriority priority, ::NActors::NLog::EComponent component) - : ActorContext(NActors::TlsActivationContext ? &NActors::TlsActivationContext->AsActorContext() : nullptr) - , Priority(priority) - , Component(component) { - TBase::WriteDirectly(TlsLogContext.Get().GetCurrentHeader()); - } - - TFormattedRecordWriter::~TFormattedRecordWriter() { - if (ActorContext) { - ::NActors::MemLogAdapter(*ActorContext, Priority, Component, TBase::GetResult()); - } else { - Cerr << "FALLBACK_ACTOR_LOGGING;priority=" << Priority << ";component=" << Component << ";" << TBase::GetResult() << Endl; - } - } - - TVerifyFormattedRecordWriter::TVerifyFormattedRecordWriter(const TString& conditionText) - : ConditionText(conditionText) { - TBase::WriteDirectly(TlsLogContext.Get().GetCurrentHeader()); - TBase::Write("verification", ConditionText); - - } - - TVerifyFormattedRecordWriter::~TVerifyFormattedRecordWriter() { - const TString data = TBase::GetResult(); - Y_ABORT("%s", data.data()); - } - - TEnsureFormattedRecordWriter::TEnsureFormattedRecordWriter(const TString& conditionText) - : ConditionText(conditionText) { - TBase::WriteDirectly(TlsLogContext.Get().GetCurrentHeader()); - TBase::Write("verification", ConditionText); - - } - - TEnsureFormattedRecordWriter::~TEnsureFormattedRecordWriter() noexcept(false) { - const TString data = TBase::GetResult(); - if (NActors::TlsActivationContext) { - ::NActors::MemLogAdapter(NActors::TlsActivationContext->AsActorContext(), NLog::EPriority::PRI_ERROR, 0, data); - } else { - Cerr << "FALLBACK_EXCEPTION_LOGGING;component=EXCEPTION;" << data << Endl; - } - if (!std::uncaught_exceptions()) { - Y_ENSURE(false, data.data()); - } else { - Y_ABORT("%s", data.data()); - } - } - -} diff --git a/library/cpp/actors/core/log.h b/library/cpp/actors/core/log.h deleted file mode 100644 index 9f1d367932..0000000000 --- a/library/cpp/actors/core/log.h +++ /dev/null @@ -1,627 +0,0 @@ -#pragma once - -#include "defs.h" - -#include "log_iface.h" -#include "log_settings.h" -#include "log_metrics.h" -#include "log_buffer.h" -#include "actorsystem.h" -#include "events.h" -#include "event_local.h" -#include "hfunc.h" -#include "mon.h" - -#include <util/generic/vector.h> -#include <util/string/printf.h> -#include <util/string/builder.h> -#include <util/system/yassert.h> -#include <library/cpp/logger/all.h> -#include <library/cpp/json/writer/json.h> -#include <library/cpp/svnversion/svnversion.h> - -#include <library/cpp/actors/memory_log/memlog.h> - -// TODO: limit number of messages per second -// TODO: make TLogComponentLevelRequest/Response network messages - -#define IS_LOG_PRIORITY_ENABLED(priority, component) \ - [p = static_cast<::NActors::NLog::EPriority>(priority), c = static_cast<::NActors::NLog::EComponent>(component)]() -> bool { \ - ::NActors::TActivationContext *context = ::NActors::TlsActivationContext; \ - return !context || context->LoggerSettings()->Satisfies(p, c, 0ull); \ - }() - -#define IS_EMERG_LOG_ENABLED(component) IS_LOG_PRIORITY_ENABLED(NActors::NLog::PRI_EMERG, component) -#define IS_ALERT_LOG_ENABLED(component) IS_LOG_PRIORITY_ENABLED(NActors::NLog::PRI_ALERT, component) -#define IS_CRIT_LOG_ENABLED(component) IS_LOG_PRIORITY_ENABLED(NActors::NLog::PRI_CRIT, component) -#define IS_ERROR_LOG_ENABLED(component) IS_LOG_PRIORITY_ENABLED(NActors::NLog::PRI_ERROR, component) -#define IS_WARN_LOG_ENABLED(component) IS_LOG_PRIORITY_ENABLED(NActors::NLog::PRI_WARN, component) -#define IS_NOTICE_LOG_ENABLED(component) IS_LOG_PRIORITY_ENABLED(NActors::NLog::PRI_NOTICE, component) -#define IS_INFO_LOG_ENABLED(component) IS_LOG_PRIORITY_ENABLED(NActors::NLog::PRI_INFO, component) -#define IS_DEBUG_LOG_ENABLED(component) IS_LOG_PRIORITY_ENABLED(NActors::NLog::PRI_DEBUG, component) -#define IS_TRACE_LOG_ENABLED(component) IS_LOG_PRIORITY_ENABLED(NActors::NLog::PRI_TRACE, component) - -#define LOG_LOG_SAMPLED_BY(actorCtxOrSystem, priority, component, sampleBy, ...) \ - do { \ - ::NActors::NLog::TSettings* mSettings = static_cast<::NActors::NLog::TSettings*>((actorCtxOrSystem).LoggerSettings()); \ - ::NActors::NLog::EPriority mPriority = static_cast<::NActors::NLog::EPriority>(priority); \ - ::NActors::NLog::EComponent mComponent = static_cast<::NActors::NLog::EComponent>(component); \ - if (mSettings && mSettings->Satisfies(mPriority, mComponent, sampleBy)) { \ - ::NActors::MemLogAdapter( \ - actorCtxOrSystem, priority, component, __VA_ARGS__); \ - } \ - } while (0) /**/ - -#define LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, priority, component, sampleBy, stream) \ - LOG_LOG_SAMPLED_BY(actorCtxOrSystem, priority, component, sampleBy, [&]() -> TString { \ - TStringBuilder logStringBuilder; \ - logStringBuilder << stream; \ - return std::move(logStringBuilder); \ - }()) - -#define LOG_LOG(actorCtxOrSystem, priority, component, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, priority, component, 0ull, __VA_ARGS__) -#define LOG_LOG_S(actorCtxOrSystem, priority, component, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, priority, component, 0ull, stream) - -// use these macros for logging via actor system or actor context -#define LOG_EMERG(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, __VA_ARGS__) -#define LOG_ALERT(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, __VA_ARGS__) -#define LOG_CRIT(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, __VA_ARGS__) -#define LOG_ERROR(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, __VA_ARGS__) -#define LOG_WARN(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, __VA_ARGS__) -#define LOG_NOTICE(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_NOTICE, component, __VA_ARGS__) -#define LOG_INFO(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, __VA_ARGS__) -#define LOG_DEBUG(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, __VA_ARGS__) -#define LOG_TRACE(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, __VA_ARGS__) - -#define LOG_EMERG_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, stream) -#define LOG_ALERT_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, stream) -#define LOG_CRIT_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, stream) -#define LOG_ERROR_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, stream) -#define LOG_WARN_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, stream) -#define LOG_NOTICE_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_NOTICE, component, stream) -#define LOG_INFO_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, stream) -#define LOG_DEBUG_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, stream) -#define LOG_TRACE_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, stream) - -#define ALOG_EMERG(component, stream) LOG_LOG_S(*NActors::TlsActivationContext, NActors::NLog::PRI_EMERG, component, stream) -#define ALOG_ALERT(component, stream) LOG_LOG_S(*NActors::TlsActivationContext, NActors::NLog::PRI_ALERT, component, stream) -#define ALOG_CRIT(component, stream) LOG_LOG_S(*NActors::TlsActivationContext, NActors::NLog::PRI_CRIT, component, stream) -#define ALOG_ERROR(component, stream) LOG_LOG_S(*NActors::TlsActivationContext, NActors::NLog::PRI_ERROR, component, stream) -#define ALOG_WARN(component, stream) LOG_LOG_S(*NActors::TlsActivationContext, NActors::NLog::PRI_WARN, component, stream) -#define ALOG_NOTICE(component, stream) LOG_LOG_S(*NActors::TlsActivationContext, NActors::NLog::PRI_NOTICE, component, stream) -#define ALOG_INFO(component, stream) LOG_LOG_S(*NActors::TlsActivationContext, NActors::NLog::PRI_INFO, component, stream) -#define ALOG_DEBUG(component, stream) LOG_LOG_S(*NActors::TlsActivationContext, NActors::NLog::PRI_DEBUG, component, stream) -#define ALOG_TRACE(component, stream) LOG_LOG_S(*NActors::TlsActivationContext, NActors::NLog::PRI_TRACE, component, stream) - -#define LOG_EMERG_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, sampleBy, __VA_ARGS__) -#define LOG_ALERT_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, sampleBy, __VA_ARGS__) -#define LOG_CRIT_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, sampleBy, __VA_ARGS__) -#define LOG_ERROR_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, sampleBy, __VA_ARGS__) -#define LOG_WARN_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, sampleBy, __VA_ARGS__) -#define LOG_NOTICE_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_NOTICE, component, sampleBy, __VA_ARGS__) -#define LOG_INFO_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, sampleBy, __VA_ARGS__) -#define LOG_DEBUG_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, sampleBy, __VA_ARGS__) -#define LOG_TRACE_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, sampleBy, __VA_ARGS__) - -#define LOG_EMERG_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, sampleBy, stream) -#define LOG_ALERT_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, sampleBy, stream) -#define LOG_CRIT_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, sampleBy, stream) -#define LOG_ERROR_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, sampleBy, stream) -#define LOG_WARN_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, sampleBy, stream) -#define LOG_NOTICE_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_NOTICE, component, sampleBy, stream) -#define LOG_INFO_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, sampleBy, stream) -#define LOG_DEBUG_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, sampleBy, stream) -#define LOG_TRACE_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, sampleBy, stream) - -// Log Throttling -#define LOG_LOG_THROTTLE(throttler, actorCtxOrSystem, priority, component, ...) \ - do { \ - if ((throttler).Kick()) { \ - LOG_LOG(actorCtxOrSystem, priority, component, __VA_ARGS__); \ - } \ - } while (0) /**/ - -#define LOG_LOG_S_THROTTLE(throttler, actorCtxOrSystem, priority, component, stream) \ - do { \ - if ((throttler).Kick()) { \ - LOG_LOG_S(actorCtxOrSystem, priority, component, stream); \ - } \ - } while (0) /**/ - -#define TRACE_EVENT(component) \ - const auto& currentTracer = component; \ - if (ev->HasEvent()) { \ - LOG_TRACE(*TlsActivationContext, currentTracer, "%s, received event# %" PRIu32 ", Sender %s, Recipient %s: %s", \ - __FUNCTION__, ev->Type, ev->Sender.ToString().data(), SelfId().ToString().data(), ev->ToString().substr(0, 1000).data()); \ - } else { \ - LOG_TRACE(*TlsActivationContext, currentTracer, "%s, received event# %" PRIu32 ", Sender %s, Recipient %s", \ - __FUNCTION__, ev->Type, ev->Sender.ToString().data(), ev->Recipient.ToString().data()); \ - } -#define TRACE_EVENT_TYPE(eventType) LOG_TRACE(*TlsActivationContext, currentTracer, "%s, processing event %s", __FUNCTION__, eventType) - -class TLog; -class TLogBackend; - -namespace NActors { - class TLoggerActor; - - //////////////////////////////////////////////////////////////////////////////// - // SET LOG LEVEL FOR A COMPONENT - //////////////////////////////////////////////////////////////////////////////// - class TLogComponentLevelRequest: public TEventLocal<TLogComponentLevelRequest, int(NLog::EEv::LevelReq)> { - public: - // set given priority for the component - TLogComponentLevelRequest(NLog::EPriority priority, NLog::EComponent component) - : Priority(priority) - , Component(component) - { - } - - // set given priority for all components - TLogComponentLevelRequest(NLog::EPriority priority) - : Priority(priority) - , Component(NLog::InvalidComponent) - { - } - - protected: - NLog::EPriority Priority; - NLog::EComponent Component; - - friend class TLoggerActor; - }; - - class TLogComponentLevelResponse: public TEventLocal<TLogComponentLevelResponse, int(NLog::EEv::LevelResp)> { - public: - TLogComponentLevelResponse(int code, const TString& explanation) - : Code(code) - , Explanation(explanation) - { - } - - int GetCode() const { - return Code; - } - - const TString& GetExplanation() const { - return Explanation; - } - - protected: - int Code; - TString Explanation; - }; - - class TFlushLogBuffer: public TEventLocal<TFlushLogBuffer, int(NLog::EEv::Buffer)> { - public: - TFlushLogBuffer() { - } - }; - - //////////////////////////////////////////////////////////////////////////////// - // LOGGER ACTOR - //////////////////////////////////////////////////////////////////////////////// - class TLoggerActor: public TActor<TLoggerActor> { - public: - static IActor::EActivityType ActorActivityType() { - return IActor::EActivityType::LOG_ACTOR; - } - - TLoggerActor(TIntrusivePtr<NLog::TSettings> settings, - TAutoPtr<TLogBackend> logBackend, - TIntrusivePtr<NMonitoring::TDynamicCounters> counters); - TLoggerActor(TIntrusivePtr<NLog::TSettings> settings, - std::shared_ptr<TLogBackend> logBackend, - TIntrusivePtr<NMonitoring::TDynamicCounters> counters); - TLoggerActor(TIntrusivePtr<NLog::TSettings> settings, - TAutoPtr<TLogBackend> logBackend, - std::shared_ptr<NMonitoring::TMetricRegistry> metrics); - TLoggerActor(TIntrusivePtr<NLog::TSettings> settings, - std::shared_ptr<TLogBackend> logBackend, - std::shared_ptr<NMonitoring::TMetricRegistry> metrics); - ~TLoggerActor(); - - void StateFunc(TAutoPtr<IEventHandle>& ev) { - switch (ev->GetTypeRewrite()) { - HFunc(TFlushLogBuffer, FlushLogBufferMessageEvent); - HFunc(NLog::TEvLog, HandleLogEvent); - HFunc(TLogComponentLevelRequest, HandleLogComponentLevelRequest); - HFunc(NMon::TEvHttpInfo, HandleMonInfo); - } - } - - STFUNC(StateDefunct) { - switch (ev->GetTypeRewrite()) { - hFunc(NLog::TEvLog, HandleLogEventDrop); - HFunc(TLogComponentLevelRequest, HandleLogComponentLevelRequest); - HFunc(NMon::TEvHttpInfo, HandleMonInfo); - cFunc(TEvents::TEvWakeup::EventType, HandleWakeup); - } - } - - // Directly call logger instead of sending a message - void Log(TInstant time, NLog::EPriority priority, NLog::EComponent component, const char* c, ...); - - static void Throttle(const NLog::TSettings& settings); - - private: - TIntrusivePtr<NLog::TSettings> Settings; - std::shared_ptr<TLogBackend> LogBackend; - ui64 PassedCount = 0; - TDuration WakeupInterval{TDuration::Seconds(5)}; - std::unique_ptr<ILoggerMetrics> Metrics; - TLogBuffer LogBuffer; - - void BecomeDefunct(); - void FlushLogBufferMessageEvent(TFlushLogBuffer::TPtr& ev, const NActors::TActorContext& ctx); - void HandleLogEvent(NLog::TEvLog::TPtr& ev, const TActorContext& ctx); - void HandleLogEventDrop(const NLog::TEvLog::TPtr& ev); - void HandleLogComponentLevelRequest(TLogComponentLevelRequest::TPtr& ev, const TActorContext& ctx); - void HandleMonInfo(NMon::TEvHttpInfo::TPtr& ev, const TActorContext& ctx); - void HandleWakeup(); - [[nodiscard]] bool OutputRecord(NLog::TEvLog *evLog) noexcept; - [[nodiscard]] bool OutputRecord(TInstant time, NLog::EPrio priority, NLog::EComponent component, const TString& formatted) noexcept; - void RenderComponentPriorities(IOutputStream& str); - void FlushLogBufferMessage(); - void WriteMessageStat(const NLog::TEvLog& ev); - static const char* FormatLocalTimestamp(TInstant time, char* buf); - }; - - //////////////////////////////////////////////////////////////////////////////// - // LOG THROTTLING - // TTrivialLogThrottler -- log a message every 'period' duration - // Use case: - // TTrivialLogThrottler throttler(TDuration::Minutes(1)); - // .... - // LOG_LOG_THROTTLE(throttler, ctx, NActors::NLog::PRI_ERROR, SOME, "Error"); - //////////////////////////////////////////////////////////////////////////////// - class TTrivialLogThrottler { - public: - TTrivialLogThrottler(TDuration period) - : Period(period) - { - } - - // return value: - // true -- write to log - // false -- don't write to log, throttle - bool Kick() { - auto now = TInstant::Now(); - if (now >= (LastWrite + Period)) { - LastWrite = now; - return true; - } else { - return false; - } - } - - private: - TInstant LastWrite; - TDuration Period; - }; - - //////////////////////////////////////////////////////////////////////////////// - // SYSLOG BACKEND - //////////////////////////////////////////////////////////////////////////////// - TAutoPtr<TLogBackend> CreateSysLogBackend(const TString& ident, - bool logPError, bool logCons); - TAutoPtr<TLogBackend> CreateStderrBackend(); - TAutoPtr<TLogBackend> CreateFileBackend(const TString& fileName); - TAutoPtr<TLogBackend> CreateNullBackend(); - TAutoPtr<TLogBackend> CreateCompositeLogBackend(TVector<TAutoPtr<TLogBackend>>&& underlyingBackends); - - ///////////////////////////////////////////////////////////////////// - // Logging adaptors for memory log and logging into filesystem - ///////////////////////////////////////////////////////////////////// - - namespace NDetail { - inline void Y_PRINTF_FORMAT(2, 3) PrintfV(TString& dst, const char* format, ...) { - va_list params; - va_start(params, format); - vsprintf(dst, format, params); - va_end(params); - } - - inline void PrintfV(TString& dst, const char* format, va_list params) { - vsprintf(dst, format, params); - } - } // namespace NDetail - - template <typename TCtx> - inline void DeliverLogMessage(TCtx& ctx, NLog::EPriority mPriority, NLog::EComponent mComponent, TString &&str) - { - const NLog::TSettings *mSettings = ctx.LoggerSettings(); - TLoggerActor::Throttle(*mSettings); - ctx.Send(new IEventHandle(mSettings->LoggerActorId, TActorId(), new NLog::TEvLog(mPriority, mComponent, std::move(str)))); - } - - template <typename TCtx, typename... TArgs> - inline void MemLogAdapter( - TCtx& actorCtxOrSystem, - NLog::EPriority mPriority, - NLog::EComponent mComponent, - const char* format, TArgs&&... params) { - TString Formatted; - - - if constexpr (sizeof... (params) > 0) { - NDetail::PrintfV(Formatted, format, std::forward<TArgs>(params)...); - } else { - NDetail::PrintfV(Formatted, "%s", format); - } - - MemLogWrite(Formatted.data(), Formatted.size(), true); - DeliverLogMessage(actorCtxOrSystem, mPriority, mComponent, std::move(Formatted)); - } - - template <typename TCtx> - Y_WRAPPER inline void MemLogAdapter( - TCtx& actorCtxOrSystem, - NLog::EPriority mPriority, - NLog::EComponent mComponent, - const TString& str) { - - MemLogWrite(str.data(), str.size(), true); - DeliverLogMessage(actorCtxOrSystem, mPriority, mComponent, TString(str)); - } - - template <typename TCtx> - Y_WRAPPER inline void MemLogAdapter( - TCtx& actorCtxOrSystem, - NLog::EPriority mPriority, - NLog::EComponent mComponent, - TString&& str) { - - MemLogWrite(str.data(), str.size(), true); - DeliverLogMessage(actorCtxOrSystem, mPriority, mComponent, std::move(str)); - } - - class TRecordWriter: public TStringBuilder { - private: - const TActorContext* ActorContext = nullptr; - ::NActors::NLog::EPriority Priority = ::NActors::NLog::EPriority::PRI_INFO; - ::NActors::NLog::EComponent Component = 0; - public: - TRecordWriter(::NActors::NLog::EPriority priority, ::NActors::NLog::EComponent component) - : ActorContext(NActors::TlsActivationContext ? &NActors::TlsActivationContext->AsActorContext() : nullptr) - , Priority(priority) - , Component(component) { - - } - - ~TRecordWriter() { - if (ActorContext) { - ::NActors::MemLogAdapter(*ActorContext, Priority, Component, *this); - } else { - Cerr << "FALLBACK_ACTOR_LOGGING;priority=" << Priority << ";component=" << Component << ";" << static_cast<const TStringBuilder&>(*this) << Endl; - } - } - }; - - class TFormatedStreamWriter: TNonCopyable { - private: - TStringBuilder Builder; - protected: - template <class TKey, class TValue> - TFormatedStreamWriter& Write(const TKey& pName, const TValue& pValue) { - Builder << pName << "=" << pValue << ";"; - return *this; - } - - template <class TKey, class TValue> - TFormatedStreamWriter& Write(const TKey& pName, const std::optional<TValue>& pValue) { - if (pValue) { - Builder << pName << "=" << *pValue << ";"; - } else { - Builder << pName << "=NO_VALUE_OPTIONAL;"; - } - return *this; - } - - TFormatedStreamWriter& WriteDirectly(const TString& data) { - Builder << data; - return *this; - } - public: - TFormatedStreamWriter() = default; - TFormatedStreamWriter(const TString& info) { - Builder << info; - } - const TString& GetResult() const { - return Builder; - } - }; - - class TLogContextBuilder: public TFormatedStreamWriter { - private: - using TBase = TFormatedStreamWriter; - std::optional<::NActors::NLog::EComponent> Component; - TLogContextBuilder(std::optional<::NActors::NLog::EComponent> component) - : Component(component) { - } - public: - - template <class TKey, class TValue> - TLogContextBuilder& operator()(const TKey& pName, const TValue& pValue) { - TBase::Write(pName, pValue); - return *this; - } - - const std::optional<::NActors::NLog::EComponent>& GetComponent() const { - return Component; - } - - static TLogContextBuilder Build(std::optional<::NActors::NLog::EComponent> component = {}) { - return TLogContextBuilder(component); - } - }; - - class TLogContextGuard: public TFormatedStreamWriter { - private: - using TBase = TFormatedStreamWriter; - std::optional<::NActors::NLog::EComponent> Component; - const ui64 Id = 0; - public: - TLogContextGuard(const TLogContextBuilder& builder); - - ~TLogContextGuard(); - - static int GetCurrentComponent(const ::NActors::NLog::EComponent defComponent = 0); - - const std::optional<::NActors::NLog::EComponent>& GetComponent() const { - return Component; - } - - ui64 GetId() const { - return Id; - } - - template <class TKey, class TValue> - TLogContextGuard& Write(const TKey& pName, const TValue& pValue) { - TBase::Write(pName, pValue); - return *this; - } - - }; - - class TLogRecordConstructor: public TFormatedStreamWriter { - private: - using TBase = TFormatedStreamWriter; - public: - - TLogRecordConstructor(); - - template <class TKey, class TValue> - TLogRecordConstructor& operator()(const TKey& pName, const TValue& pValue) { - TBase::Write(pName, pValue); - return *this; - } - }; - - class TFormattedRecordWriter: public TFormatedStreamWriter { - private: - using TBase = TFormatedStreamWriter; - const TActorContext* ActorContext = nullptr; - ::NActors::NLog::EPriority Priority = ::NActors::NLog::EPriority::PRI_INFO; - ::NActors::NLog::EComponent Component = 0; - public: - - TFormattedRecordWriter(::NActors::NLog::EPriority priority, ::NActors::NLog::EComponent component); - - template <class TKey, class TValue> - TFormattedRecordWriter& operator()(const TKey& pName, const TValue& pValue) { - TBase::Write(pName, pValue); - return *this; - } - - ~TFormattedRecordWriter(); - }; - - class TVerifyFormattedRecordWriter: public TFormatedStreamWriter { - private: - using TBase = TFormatedStreamWriter; - const TString ConditionText; - public: - - TVerifyFormattedRecordWriter(const TString& conditionText); - - template <class TKey, class TValue> - TVerifyFormattedRecordWriter& operator()(const TKey& pName, const TValue& pValue) { - TBase::Write(pName, pValue); - return *this; - } - - ~TVerifyFormattedRecordWriter(); - }; - - class TEnsureFormattedRecordWriter: public TFormatedStreamWriter { - private: - using TBase = TFormatedStreamWriter; - const TString ConditionText; - public: - - TEnsureFormattedRecordWriter(const TString& conditionText); - - template <class TKey, class TValue> - TEnsureFormattedRecordWriter& operator()(const TKey& pName, const TValue& pValue) { - TBase::Write(pName, pValue); - return *this; - } - - ~TEnsureFormattedRecordWriter() noexcept(false); - }; -} - -#define AFL_VERIFY(condition) if (condition); else NActors::TVerifyFormattedRecordWriter(#condition)("fline", TStringBuilder() << TStringBuf(__FILE__).RAfter(LOCSLASH_C) << ":" << __LINE__) -#define AFL_ENSURE(condition) if (condition); else NActors::TEnsureFormattedRecordWriter(#condition)("fline", TStringBuilder() << TStringBuf(__FILE__).RAfter(LOCSLASH_C) << ":" << __LINE__) - -#ifndef NDEBUG -/// Assert that depend on NDEBUG macro and outputs message like printf -#define AFL_VERIFY_DEBUG AFL_VERIFY -#else -#define AFL_VERIFY_DEBUG(condition) if (true); else NActors::TVerifyFormattedRecordWriter(#condition)("fline", TStringBuilder() << TStringBuf(__FILE__).RAfter(LOCSLASH_C) << ":" << __LINE__) -#endif - -#define ACTORS_FORMATTED_LOG(mPriority, mComponent) \ - if (NActors::TlsActivationContext && !IS_LOG_PRIORITY_ENABLED(mPriority, mComponent));\ - else NActors::TFormattedRecordWriter(\ - static_cast<::NActors::NLog::EPriority>(mPriority), static_cast<::NActors::NLog::EComponent>(mComponent)\ - )("fline", TStringBuilder() << TStringBuf(__FILE__).RAfter(LOCSLASH_C) << ":" << __LINE__) - -#define ACTORS_LOG_STREAM(mPriority, mComponent) \ - if (NActors::TlsActivationContext && !IS_LOG_PRIORITY_ENABLED(mPriority, mComponent));\ - else NActors::TRecordWriter(\ - static_cast<::NActors::NLog::EPriority>(mPriority), static_cast<::NActors::NLog::EComponent>(mComponent)\ - ) << TStringBuf(__FILE__).RAfter(LOCSLASH_C) << ":" << __LINE__ << " :" - -#define ALS_TRACE(component) ACTORS_LOG_STREAM(NActors::NLog::PRI_TRACE, component) -#define ALS_DEBUG(component) ACTORS_LOG_STREAM(NActors::NLog::PRI_DEBUG, component) -#define ALS_INFO(component) ACTORS_LOG_STREAM(NActors::NLog::PRI_INFO, component) -#define ALS_NOTICE(component) ACTORS_LOG_STREAM(NActors::NLog::PRI_NOTICE, component) -#define ALS_WARN(component) ACTORS_LOG_STREAM(NActors::NLog::PRI_WARN, component) -#define ALS_ERROR(component) ACTORS_LOG_STREAM(NActors::NLog::PRI_ERROR, component) -#define ALS_CRIT(component) ACTORS_LOG_STREAM(NActors::NLog::PRI_CRIT, component) -#define ALS_ALERT(component) ACTORS_LOG_STREAM(NActors::NLog::PRI_ALERT, component) -#define ALS_EMERG(component) ACTORS_LOG_STREAM(NActors::NLog::PRI_EMERG, component) - -#define AFL_TRACE(component) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_TRACE, component) -#define AFL_DEBUG(component) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_DEBUG, component) -#define AFL_INFO(component) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_INFO, component) -#define AFL_NOTICE(component) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_NOTICE, component) -#define AFL_WARN(component) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_WARN, component) -#define AFL_ERROR(component) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_ERROR, component) -#define AFL_CRIT(component) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_CRIT, component) -#define AFL_ALERT(component) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_ALERT, component) -#define AFL_EMERG(component) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_EMERG, component) - -#define DETECT_LOG_MACRO(_1, _2, NAME, ...) NAME - -#define BASE_CFL_TRACE2(k, v) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_TRACE, ::NActors::TLogContextGuard::GetCurrentComponent())(k, v) -#define BASE_CFL_DEBUG2(k, v) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_DEBUG, ::NActors::TLogContextGuard::GetCurrentComponent())(k, v) -#define BASE_CFL_INFO2(k, v) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_INFO, ::NActors::TLogContextGuard::GetCurrentComponent())(k, v) -#define BASE_CFL_NOTICE2(k, v) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_NOTICE, ::NActors::TLogContextGuard::GetCurrentComponent())(k, v) -#define BASE_CFL_WARN2(k, v) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_WARN, ::NActors::TLogContextGuard::GetCurrentComponent())(k, v) -#define BASE_CFL_ERROR2(k, v) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_ERROR, ::NActors::TLogContextGuard::GetCurrentComponent())(k, v) -#define BASE_CFL_CRIT2(k, v) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_CRIT, ::NActors::TLogContextGuard::GetCurrentComponent())(k, v) -#define BASE_CFL_ALERT2(k, v) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_ALERT, ::NActors::TLogContextGuard::GetCurrentComponent())(k, v) -#define BASE_CFL_EMERG2(k, v) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_EMERG, ::NActors::TLogContextGuard::GetCurrentComponent())(k, v) - -#define BASE_CFL_TRACE1(defaultComponent) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_TRACE, ::NActors::TLogContextGuard::GetCurrentComponent(defaultComponent)) -#define BASE_CFL_DEBUG1(defaultComponent) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_DEBUG, ::NActors::TLogContextGuard::GetCurrentComponent(defaultComponent)) -#define BASE_CFL_INFO1(defaultComponent) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_INFO, ::NActors::TLogContextGuard::GetCurrentComponent(defaultComponent)) -#define BASE_CFL_NOTICE1(defaultComponent) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_NOTICE, ::NActors::TLogContextGuard::GetCurrentComponent(defaultComponent)) -#define BASE_CFL_WARN1(defaultComponent) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_WARN, ::NActors::TLogContextGuard::GetCurrentComponent(defaultComponent)) -#define BASE_CFL_ERROR1(defaultComponent) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_ERROR, ::NActors::TLogContextGuard::GetCurrentComponent(defaultComponent)) -#define BASE_CFL_CRIT1(defaultComponent) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_CRIT, ::NActors::TLogContextGuard::GetCurrentComponent(defaultComponent)) -#define BASE_CFL_ALERT1(defaultComponent) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_ALERT, ::NActors::TLogContextGuard::GetCurrentComponent(defaultComponent)) -#define BASE_CFL_EMERG1(defaultComponent) ACTORS_FORMATTED_LOG(NActors::NLog::PRI_EMERG, ::NActors::TLogContextGuard::GetCurrentComponent(defaultComponent)) - -#define ACFL_TRACE(...) DETECT_LOG_MACRO(__VA_ARGS__, BASE_CFL_TRACE2, BASE_CFL_TRACE1)(__VA_ARGS__) -#define ACFL_DEBUG(...) DETECT_LOG_MACRO(__VA_ARGS__, BASE_CFL_DEBUG2, BASE_CFL_DEBUG1)(__VA_ARGS__) -#define ACFL_INFO(...) DETECT_LOG_MACRO(__VA_ARGS__, BASE_CFL_INFO2, BASE_CFL_INFO1)(__VA_ARGS__) -#define ACFL_NOTICE(...) DETECT_LOG_MACRO(__VA_ARGS__, BASE_CFL_NOTICE2, BASE_CFL_NOTICE1)(__VA_ARGS__) -#define ACFL_WARN(...) DETECT_LOG_MACRO(__VA_ARGS__, BASE_CFL_WARN2, BASE_CFL_WARN1)(__VA_ARGS__) -#define ACFL_ERROR(...) DETECT_LOG_MACRO(__VA_ARGS__, BASE_CFL_ERROR2, BASE_CFL_ERROR1)(__VA_ARGS__) -#define ACFL_CRIT(...) DETECT_LOG_MACRO(__VA_ARGS__, BASE_CFL_CRIT2, BASE_CFL_CRIT1)(__VA_ARGS__) -#define ACFL_ALERT(...) DETECT_LOG_MACRO(__VA_ARGS__, BASE_CFL_ALERT2, BASE_CFL_ALERT1)(__VA_ARGS__) -#define ACFL_EMERG(...) DETECT_LOG_MACRO(__VA_ARGS__, BASE_CFL_EMERG2, BASE_CFL_EMERG1)(__VA_ARGS__) diff --git a/library/cpp/actors/core/log_buffer.cpp b/library/cpp/actors/core/log_buffer.cpp deleted file mode 100644 index 8c80f1d054..0000000000 --- a/library/cpp/actors/core/log_buffer.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "log_buffer.h" - -#include <util/system/yassert.h> -#include <algorithm> - -using namespace NActors::NLog; - -namespace NActors { -TLogBuffer::TLogBuffer(ILoggerMetrics &metrics, const NLog::TSettings &settings) - : Metrics(metrics) - , Settings(settings) -{} - -size_t TLogBuffer::GetLogCostInBytes(NLog::TEvLog *log) const { - return LOG_STRUCTURE_BYTES + log->Line.length(); -} - -ui16 TLogBuffer::GetPrioIndex(NLog::EPrio prio) { - return Min(ui16(prio), ui16(LOG_PRIORITIES_NUMBER - 1)); -} - -TIntrusiveList<NLog::TEvLog, NLog::TEvLogBufferLevelListTag> &TLogBuffer::GetPrioLogs(NLog::EPrio prio) { - return PrioLogsList[GetPrioIndex(prio)]; -} - -void TLogBuffer::AddLog(NLog::TEvLog *log) { - NLog::EPrio prio = log->Level.ToPrio(); - if (!CheckSize(log) && prio > NLog::EPrio::Emerg) { // always keep logs with prio Emerg = 0 - HandleIgnoredLog(log); - return; - } - - SizeBytes += GetLogCostInBytes(log); - Logs.PushBack(log); - GetPrioLogs(prio).PushBack(log); -} - -NLog::TEvLog* TLogBuffer::Pop() { - NLog::TEvLog* log = Logs.PopFront(); - static_cast<TIntrusiveListItem<TEvLog, TEvLogBufferLevelListTag>&>(*log).Unlink(); - - SizeBytes -= GetLogCostInBytes(log); - - return log; -} - -bool TLogBuffer::IsEmpty() const { - return Logs.Empty(); -} - -bool TLogBuffer::CheckLogIgnoring() const { - return IgnoredCount > 0; -} - -bool TLogBuffer::CheckSize(NLog::TEvLog *log) { - size_t startSizeBytes = SizeBytes; - - size_t logSize = GetLogCostInBytes(log); - if (SizeBytes + logSize <= Settings.BufferSizeLimitBytes) { - return true; - } - - ui16 scanHighestPrio = Max((ui16)1, GetPrioIndex(log->Level.ToPrio())); // always keep logs with prio Emerg = 0 - for (ui16 scanPrio = LOG_PRIORITIES_NUMBER - 1; scanPrio >= scanHighestPrio; scanPrio--) { - TIntrusiveList<NLog::TEvLog, NLog::TEvLogBufferLevelListTag> &scanLogs = PrioLogsList[scanPrio]; - while (!scanLogs.Empty()) { - NLog::TEvLog* log = scanLogs.PopFront(); - SizeBytes -= GetLogCostInBytes(log); - HandleIgnoredLog(log); - - if (SizeBytes + logSize <= Settings.BufferSizeLimitBytes) { - return true; - } - } - } - - if (startSizeBytes > SizeBytes) { - return true; - } - - return false; -} - -void TLogBuffer::HandleIgnoredLog(NLog::TEvLog *log) { - ui16 logPrio = GetPrioIndex(log->Level.ToPrio()); - Metrics.IncIgnoredMsgs(); - if (IgnoredHighestPrio > logPrio) { - IgnoredHighestPrio = logPrio; - } - IgnoredCount++; - delete log; -} - -ui64 TLogBuffer::GetIgnoredCount() { - return IgnoredCount; -} - -NLog::EPrio TLogBuffer::GetIgnoredHighestPrio() { - NLog::EPrio prio = static_cast<NLog::EPrio>(IgnoredHighestPrio); - return prio; -} - -void TLogBuffer::ClearIgnoredCount() { - IgnoredHighestPrio = LOG_PRIORITIES_NUMBER - 1; - IgnoredCount = 0; -} - -} diff --git a/library/cpp/actors/core/log_buffer.h b/library/cpp/actors/core/log_buffer.h deleted file mode 100644 index 60bc09cc85..0000000000 --- a/library/cpp/actors/core/log_buffer.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include "log_metrics.h" -#include "log_iface.h" -#include "log_settings.h" - -#include <util/generic/intrlist.h> - -namespace NActors { -class TLogBuffer { - static const size_t LOG_STRUCTURE_BYTES = sizeof(NLog::TEvLog); - static const ui16 LOG_PRIORITIES_NUMBER = 9; - - ILoggerMetrics &Metrics; - const NLog::TSettings &Settings; - - TIntrusiveListWithAutoDelete<NLog::TEvLog, TDelete, NLog::TEvLogBufferMainListTag> Logs; - TIntrusiveList<NLog::TEvLog, NLog::TEvLogBufferLevelListTag> PrioLogsList[LOG_PRIORITIES_NUMBER]; - - ui64 SizeBytes = 0; - ui64 IgnoredCount = 0; - ui16 IgnoredHighestPrio = LOG_PRIORITIES_NUMBER - 1; - - size_t GetLogCostInBytes(NLog::TEvLog *log) const; - void HandleIgnoredLog(NLog::TEvLog *log); - bool CheckSize(NLog::TEvLog *log); - static inline ui16 GetPrioIndex(NLog::EPrio); - inline TIntrusiveList<NLog::TEvLog, NLog::TEvLogBufferLevelListTag> &GetPrioLogs(NLog::EPrio); - - public: - TLogBuffer(ILoggerMetrics &metrics, const NLog::TSettings &Settings); - void AddLog(NLog::TEvLog *log); - NLog::TEvLog *Pop(); - bool IsEmpty() const; - bool CheckLogIgnoring() const; - ui64 GetIgnoredCount(); - NLog::EPrio GetIgnoredHighestPrio(); - void ClearIgnoredCount(); -}; -} diff --git a/library/cpp/actors/core/log_iface.h b/library/cpp/actors/core/log_iface.h deleted file mode 100644 index b0195f5581..0000000000 --- a/library/cpp/actors/core/log_iface.h +++ /dev/null @@ -1,117 +0,0 @@ -#pragma once - -#include "events.h" -#include "event_local.h" - -namespace NActors { - namespace NLog { - using EComponent = int; - - enum EPriority : ui16 { // migrate it to EPrio whenever possible - PRI_EMERG /* "EMERG" */, - PRI_ALERT /* "ALERT" */, - PRI_CRIT /* "CRIT" */, - PRI_ERROR /* "ERROR" */, - PRI_WARN /* "WARN" */, - PRI_NOTICE /* "NOTICE" */, - PRI_INFO /* "INFO" */, - PRI_DEBUG /* "DEBUG" */, - PRI_TRACE /* "TRACE" */ - }; - - enum class EPrio : ui16 { - Emerg = 0, - Alert = 1, - Crit = 2, - Error = 3, - Warn = 4, - Notice = 5, - Info = 6, - Debug = 7, - Trace = 8, - }; - - struct TLevel { - TLevel(ui32 raw) - : Raw(raw) - { - } - - TLevel(EPrio prio) - : Raw((ui16(prio) + 1) << 8) - { - } - - EPrio ToPrio() const noexcept { - const auto major = Raw >> 8; - - return major > 0 ? EPrio(major - 1) : EPrio::Emerg; - } - - bool IsUrgentAbortion() const noexcept { - return (Raw >> 8) == 0; - } - - /* Generalized monotonic level value composed with major and minor - levels. Minor is used for verbosity within major, basic EPrio - mapped to (EPrio + 1, 0) and Major = 0 is reserved as special - space with meaning like EPrio::Emerg but with extened actions. - Thus logger should map Major = 0 to EPrio::Emerg if it have no - idea how to handle special emergency actions. - */ - - ui32 Raw = 0; // ((ui16(EPrio) + 1) << 8) | ui8(minor) - }; - - enum class EEv { - Log = EventSpaceBegin(TEvents::ES_LOGGER), - LevelReq, - LevelResp, - Ignored, - Buffer, - End - }; - - static_assert(int(EEv::End) < EventSpaceEnd(TEvents::ES_LOGGER), ""); - - struct TEvLogBufferMainListTag {}; - struct TEvLogBufferLevelListTag {}; - - class TEvLog - : public TEventLocal<TEvLog, int(EEv::Log)> - , public TIntrusiveListItem<TEvLog, TEvLogBufferMainListTag> - , public TIntrusiveListItem<TEvLog, TEvLogBufferLevelListTag> - { - public: - TEvLog(TInstant stamp, TLevel level, EComponent comp, const TString &line) - : Stamp(stamp) - , Level(level) - , Component(comp) - , Line(line) - { - } - - TEvLog(TInstant stamp, TLevel level, EComponent comp, TString &&line) - : Stamp(stamp) - , Level(level) - , Component(comp) - , Line(std::move(line)) - { - } - - TEvLog(EPriority prio, EComponent comp, TString line, TInstant time = TInstant::Now()) - : Stamp(time) - , Level(EPrio(prio)) - , Component(comp) - , Line(std::move(line)) - { - } - - const TInstant Stamp = TInstant::Max(); - const TLevel Level; - const EComponent Component = 0; - TString Line; - }; - - } -} diff --git a/library/cpp/actors/core/log_metrics.h b/library/cpp/actors/core/log_metrics.h deleted file mode 100644 index 5005b2b776..0000000000 --- a/library/cpp/actors/core/log_metrics.h +++ /dev/null @@ -1,152 +0,0 @@ -#pragma once - -#include <library/cpp/monlib/dynamic_counters/counters.h> -#include <library/cpp/monlib/metrics/metric_registry.h> -#include <library/cpp/monlib/service/pages/templates.h> - -namespace NActors { -class ILoggerMetrics { -public: - virtual ~ILoggerMetrics() = default; - - virtual void IncActorMsgs() = 0; - virtual void IncDirectMsgs() = 0; - virtual void IncLevelRequests() = 0; - virtual void IncIgnoredMsgs() = 0; - virtual void IncAlertMsgs() = 0; - virtual void IncEmergMsgs() = 0; - virtual void IncDroppedMsgs() = 0; - - virtual void GetOutputHtml(IOutputStream&) = 0; -}; - -class TLoggerCounters : public ILoggerMetrics { -public: - TLoggerCounters(TIntrusivePtr<NMonitoring::TDynamicCounters> counters) - : DynamicCounters(counters) - { - ActorMsgs_ = DynamicCounters->GetCounter("ActorMsgs", true); - DirectMsgs_ = DynamicCounters->GetCounter("DirectMsgs", true); - LevelRequests_ = DynamicCounters->GetCounter("LevelRequests", true); - IgnoredMsgs_ = DynamicCounters->GetCounter("IgnoredMsgs", true); - DroppedMsgs_ = DynamicCounters->GetCounter("DroppedMsgs", true); - - AlertMsgs_ = DynamicCounters->GetCounter("AlertMsgs", true); - EmergMsgs_ = DynamicCounters->GetCounter("EmergMsgs", true); - } - - ~TLoggerCounters() = default; - - void IncActorMsgs() override { - ++*ActorMsgs_; - } - void IncDirectMsgs() override { - ++*DirectMsgs_; - } - void IncLevelRequests() override { - ++*LevelRequests_; - } - void IncIgnoredMsgs() override { - ++*IgnoredMsgs_; - } - void IncAlertMsgs() override { - ++*AlertMsgs_; - } - void IncEmergMsgs() override { - ++*EmergMsgs_; - } - void IncDroppedMsgs() override { - DroppedMsgs_->Inc(); - } - - void GetOutputHtml(IOutputStream& str) override { - HTML(str) { - DIV_CLASS("row") { - DIV_CLASS("col-md-12") { - TAG(TH4) { - str << "Counters" << Endl; - } - DynamicCounters->OutputHtml(str); - } - } - } - } - -private: - NMonitoring::TDynamicCounters::TCounterPtr ActorMsgs_; - NMonitoring::TDynamicCounters::TCounterPtr DirectMsgs_; - NMonitoring::TDynamicCounters::TCounterPtr LevelRequests_; - NMonitoring::TDynamicCounters::TCounterPtr IgnoredMsgs_; - NMonitoring::TDynamicCounters::TCounterPtr AlertMsgs_; - NMonitoring::TDynamicCounters::TCounterPtr EmergMsgs_; - // Dropped while the logger backend was unavailable - NMonitoring::TDynamicCounters::TCounterPtr DroppedMsgs_; - - TIntrusivePtr<NMonitoring::TDynamicCounters> DynamicCounters; -}; - -class TLoggerMetrics : public ILoggerMetrics { -public: - TLoggerMetrics(std::shared_ptr<NMonitoring::TMetricRegistry> metrics) - : Metrics(metrics) - { - ActorMsgs_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.actor_msgs"}}); - DirectMsgs_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.direct_msgs"}}); - LevelRequests_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.level_requests"}}); - IgnoredMsgs_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.ignored_msgs"}}); - DroppedMsgs_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.dropped_msgs"}}); - - AlertMsgs_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.alert_msgs"}}); - EmergMsgs_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.emerg_msgs"}}); - } - - ~TLoggerMetrics() = default; - - void IncActorMsgs() override { - ActorMsgs_->Inc(); - } - void IncDirectMsgs() override { - DirectMsgs_->Inc(); - } - void IncLevelRequests() override { - LevelRequests_->Inc(); - } - void IncIgnoredMsgs() override { - IgnoredMsgs_->Inc(); - } - void IncAlertMsgs() override { - AlertMsgs_->Inc(); - } - void IncEmergMsgs() override { - EmergMsgs_->Inc(); - } - void IncDroppedMsgs() override { - DroppedMsgs_->Inc(); - } - - void GetOutputHtml(IOutputStream& str) override { - HTML(str) { - DIV_CLASS("row") { - DIV_CLASS("col-md-12") { - TAG(TH4) { - str << "Metrics" << Endl; - } - // TODO: Now, TMetricRegistry does not have the GetOutputHtml function - } - } - } - } - -private: - NMonitoring::TRate* ActorMsgs_; - NMonitoring::TRate* DirectMsgs_; - NMonitoring::TRate* LevelRequests_; - NMonitoring::TRate* IgnoredMsgs_; - NMonitoring::TRate* AlertMsgs_; - NMonitoring::TRate* EmergMsgs_; - // Dropped while the logger backend was unavailable - NMonitoring::TRate* DroppedMsgs_; - - std::shared_ptr<NMonitoring::TMetricRegistry> Metrics; -}; -} diff --git a/library/cpp/actors/core/log_settings.cpp b/library/cpp/actors/core/log_settings.cpp deleted file mode 100644 index fafaf892eb..0000000000 --- a/library/cpp/actors/core/log_settings.cpp +++ /dev/null @@ -1,232 +0,0 @@ -#include "log_settings.h" - -#include <util/stream/str.h> - -namespace NActors { - namespace NLog { - TSettings::TSettings(const TActorId& loggerActorId, const EComponent loggerComponent, - EComponent minVal, EComponent maxVal, EComponentToStringFunc func, - EPriority defPriority, EPriority defSamplingPriority, - ui32 defSamplingRate, ui64 timeThresholdMs, ui64 bufferSizeLimitBytes) - : LoggerActorId(loggerActorId) - , LoggerComponent(loggerComponent) - , TimeThresholdMs(timeThresholdMs) - , BufferSizeLimitBytes(bufferSizeLimitBytes) - , AllowDrop(true) - , ThrottleDelay(TDuration::MilliSeconds(100)) - , MinVal(0) - , MaxVal(0) - , Mask(0) - , DefPriority(defPriority) - , DefSamplingPriority(defSamplingPriority) - , DefSamplingRate(defSamplingRate) - , UseLocalTimestamps(false) - , Format(PLAIN_FULL_FORMAT) - , ShortHostName("") - , ClusterName("") - { - Append(minVal, maxVal, func); - } - - TSettings::TSettings(const TActorId& loggerActorId, const EComponent loggerComponent, - EPriority defPriority, EPriority defSamplingPriority, - ui32 defSamplingRate, ui64 timeThresholdMs, ui64 bufferSizeLimitBytes) - : LoggerActorId(loggerActorId) - , LoggerComponent(loggerComponent) - , TimeThresholdMs(timeThresholdMs) - , BufferSizeLimitBytes(bufferSizeLimitBytes) - , AllowDrop(true) - , ThrottleDelay(TDuration::MilliSeconds(100)) - , MinVal(0) - , MaxVal(0) - , Mask(0) - , DefPriority(defPriority) - , DefSamplingPriority(defSamplingPriority) - , DefSamplingRate(defSamplingRate) - , UseLocalTimestamps(false) - , Format(PLAIN_FULL_FORMAT) - , ShortHostName("") - , ClusterName("") - { - } - - void TSettings::Append(EComponent minVal, EComponent maxVal, EComponentToStringFunc func) { - Y_ABORT_UNLESS(minVal >= 0, "NLog::TSettings: minVal must be non-negative"); - Y_ABORT_UNLESS(maxVal > minVal, "NLog::TSettings: maxVal must be greater than minVal"); - - // update bounds - if (!MaxVal || minVal < MinVal) { - MinVal = minVal; - } - - if (!MaxVal || maxVal > MaxVal) { - MaxVal = maxVal; - - // expand ComponentNames to the new bounds - auto oldMask = Mask; - Mask = PowerOf2Mask(MaxVal); - - TArrayHolder<TAtomic> oldComponentInfo(new TAtomic[Mask + 1]); - ComponentInfo.Swap(oldComponentInfo); - int startVal = oldMask ? oldMask + 1 : 0; - for (int i = 0; i < startVal; i++) { - AtomicSet(ComponentInfo[i], AtomicGet(oldComponentInfo[i])); - } - - TComponentSettings defSetting(DefPriority, DefSamplingPriority, DefSamplingRate); - for (int i = startVal; i < Mask + 1; i++) { - AtomicSet(ComponentInfo[i], defSetting.Raw.Data); - } - - ComponentNames.resize(Mask + 1); - } - - // assign new names but validate if newly added members were not used before - for (int i = minVal; i <= maxVal; i++) { - Y_ABORT_UNLESS(!ComponentNames[i], "component name at %d already set: %s", - i, ComponentNames[i].data()); - ComponentNames[i] = func(i); - } - } - - int TSettings::SetLevelImpl( - const TString& name, bool isSampling, - EPriority priority, EComponent component, TString& explanation) { - TString titleName(name); - titleName.to_title(); - - // check priority - if (!IsValidPriority(priority)) { - TStringStream str; - str << "Invalid " << name; - explanation = str.Str(); - return 1; - } - - if (component == InvalidComponent) { - for (int i = 0; i < Mask + 1; i++) { - TComponentSettings settings = AtomicGet(ComponentInfo[i]); - if (isSampling) { - settings.Raw.X.SamplingLevel = priority; - } else { - settings.Raw.X.Level = priority; - } - AtomicSet(ComponentInfo[i], settings.Raw.Data); - } - - TStringStream str; - - str << titleName - << " for all components has been changed to " - << PriorityToString(EPrio(priority)); - explanation = str.Str(); - return 0; - } else { - if (!IsValidComponent(component)) { - explanation = "Invalid component"; - return 1; - } - TComponentSettings settings = AtomicGet(ComponentInfo[component]); - EPriority oldPriority; - if (isSampling) { - oldPriority = (EPriority)settings.Raw.X.SamplingLevel; - settings.Raw.X.SamplingLevel = priority; - } else { - oldPriority = (EPriority)settings.Raw.X.Level; - settings.Raw.X.Level = priority; - } - AtomicSet(ComponentInfo[component], settings.Raw.Data); - TStringStream str; - str << titleName << " for the component " << ComponentNames[component] - << " has been changed from " << PriorityToString(EPrio(oldPriority)) - << " to " << PriorityToString(EPrio(priority)); - explanation = str.Str(); - return 0; - } - } - - int TSettings::SetLevel(EPriority priority, EComponent component, TString& explanation) { - return SetLevelImpl("priority", false, - priority, component, explanation); - } - - int TSettings::SetSamplingLevel(EPriority priority, EComponent component, TString& explanation) { - return SetLevelImpl("sampling priority", true, - priority, component, explanation); - } - - int TSettings::SetSamplingRate(ui32 sampling, EComponent component, TString& explanation) { - if (component == InvalidComponent) { - for (int i = 0; i < Mask + 1; i++) { - TComponentSettings settings = AtomicGet(ComponentInfo[i]); - settings.Raw.X.SamplingRate = sampling; - AtomicSet(ComponentInfo[i], settings.Raw.Data); - } - TStringStream str; - str << "Sampling rate for all components has been changed to " << sampling; - explanation = str.Str(); - } else { - if (!IsValidComponent(component)) { - explanation = "Invalid component"; - return 1; - } - TComponentSettings settings = AtomicGet(ComponentInfo[component]); - ui32 oldSampling = settings.Raw.X.SamplingRate; - settings.Raw.X.SamplingRate = sampling; - AtomicSet(ComponentInfo[component], settings.Raw.Data); - TStringStream str; - str << "Sampling rate for the component " << ComponentNames[component] - << " has been changed from " << oldSampling - << " to " << sampling; - explanation = str.Str(); - } - return 0; - } - - int TSettings::PowerOf2Mask(int val) { - int mask = 1; - while ((val & mask) != val) { - mask <<= 1; - mask |= 1; - } - return mask; - } - - bool TSettings::IsValidPriority(EPriority priority) { - return priority == PRI_EMERG || priority == PRI_ALERT || - priority == PRI_CRIT || priority == PRI_ERROR || - priority == PRI_WARN || priority == PRI_NOTICE || - priority == PRI_INFO || priority == PRI_DEBUG || priority == PRI_TRACE; - } - - bool TSettings::IsValidComponent(EComponent component) { - return (MinVal <= component) && (component <= MaxVal) && !ComponentNames[component].empty(); - } - - void TSettings::SetAllowDrop(bool val) { - AllowDrop = val; - } - - void TSettings::SetThrottleDelay(TDuration value) { - ThrottleDelay = value; - } - - void TSettings::SetUseLocalTimestamps(bool value) { - UseLocalTimestamps = value; - } - - EComponent TSettings::FindComponent(const TStringBuf& componentName) const { - if (componentName.empty()) - return InvalidComponent; - - for (EComponent component = MinVal; component <= MaxVal; ++component) { - if (ComponentNames[component] == componentName) - return component; - } - - return InvalidComponent; - } - - } - -} diff --git a/library/cpp/actors/core/log_settings.h b/library/cpp/actors/core/log_settings.h deleted file mode 100644 index f62f55c200..0000000000 --- a/library/cpp/actors/core/log_settings.h +++ /dev/null @@ -1,175 +0,0 @@ -#pragma once - -#include "log_iface.h" -#include <util/generic/vector.h> -#include <util/digest/murmur.h> -#include <util/random/easy.h> - -namespace NActors { - namespace NLog { - inline const char* PriorityToString(EPrio priority) { - switch (priority) { - case EPrio::Emerg: - return "EMERG"; - case EPrio::Alert: - return "ALERT"; - case EPrio::Crit: - return "CRIT"; - case EPrio::Error: - return "ERROR"; - case EPrio::Warn: - return "WARN"; - case EPrio::Notice: - return "NOTICE"; - case EPrio::Info: - return "INFO"; - case EPrio::Debug: - return "DEBUG"; - case EPrio::Trace: - return "TRACE"; - default: - return "UNKNOWN"; - } - } - - // You can structure your program to have multiple logical components. - // In this case you can set different log priorities for different - // components. And you can change component's priority while system - // is running. Suspect a component has a bug? Turn DEBUG priority level on - // for this component. - static const int InvalidComponent = -1; - - // Functions converts EComponent id to string - using EComponentToStringFunc = std::function<const TString&(EComponent)>; - - // Log settings - struct TComponentSettings { - union { - struct { - ui32 SamplingRate; - ui8 SamplingLevel; - ui8 Level; - } X; - - ui64 Data; - } Raw; - - TComponentSettings(TAtomicBase data) { - Raw.Data = (ui64)data; - } - - TComponentSettings(ui8 level, ui8 samplingLevel, ui32 samplingRate) { - Raw.X.Level = level; - Raw.X.SamplingLevel = samplingLevel; - Raw.X.SamplingRate = samplingRate; - } - }; - - struct TSettings: public TThrRefBase { - public: - TActorId LoggerActorId; - EComponent LoggerComponent; - ui64 TimeThresholdMs; - ui64 BufferSizeLimitBytes; - bool AllowDrop; - TDuration ThrottleDelay; - TArrayHolder<TAtomic> ComponentInfo; - TVector<TString> ComponentNames; - EComponent MinVal; - EComponent MaxVal; - EComponent Mask; - EPriority DefPriority; - EPriority DefSamplingPriority; - ui32 DefSamplingRate; - bool UseLocalTimestamps; - - enum ELogFormat { - PLAIN_FULL_FORMAT, - PLAIN_SHORT_FORMAT, - JSON_FORMAT - }; - ELogFormat Format; - TString ShortHostName; - TString ClusterName; - TString MessagePrefix; - - // The best way to provide minVal, maxVal and func is to have - // protobuf enumeration of components. In this case protoc - // automatically generates YOURTYPE_MIN, YOURTYPE_MAX and - // YOURTYPE_Name for you. - TSettings(const TActorId& loggerActorId, const EComponent loggerComponent, - EComponent minVal, EComponent maxVal, EComponentToStringFunc func, - EPriority defPriority, EPriority defSamplingPriority = PRI_DEBUG, - ui32 defSamplingRate = 0, ui64 timeThresholdMs = 1000, ui64 bufferSizeLimitBytes = 1024 * 1024 * 300); - - TSettings(const TActorId& loggerActorId, const EComponent loggerComponent, - EPriority defPriority, EPriority defSamplingPriority = PRI_DEBUG, - ui32 defSamplingRate = 0, ui64 timeThresholdMs = 1000, ui64 bufferSizeLimitBytes = 1024 * 1024 * 300); - - void Append(EComponent minVal, EComponent maxVal, EComponentToStringFunc func); - - template <typename T> - void Append(T minVal, T maxVal, const TString& (*func)(T)) { - Append( - static_cast<EComponent>(minVal), - static_cast<EComponent>(maxVal), - [func](EComponent c) -> const TString& { - return func(static_cast<T>(c)); - } - ); - } - - inline bool Satisfies(EPriority priority, EComponent component, ui64 sampleBy = 0) const { - // by using Mask we don't get outside of array boundaries - TComponentSettings settings = GetComponentSettings(component); - if (priority > settings.Raw.X.Level) { - if (priority > settings.Raw.X.SamplingLevel) { - return false; // priority > both levels ==> do not log - } - // priority <= sampling level ==> apply sampling - ui32 samplingRate = settings.Raw.X.SamplingRate; - if (samplingRate) { - ui32 samplingValue = sampleBy ? MurmurHash<ui32>((const char*)&sampleBy, sizeof(sampleBy)) - : samplingRate != 1 ? RandomNumber<ui32>() : 0; - return (samplingValue % samplingRate == 0); - } else { - // sampling rate not set ==> do not log - return false; - } - } else { - // priority <= log level ==> log - return true; - } - } - - inline TComponentSettings GetComponentSettings(EComponent component) const { - Y_DEBUG_ABORT_UNLESS((component & Mask) == component); - // by using Mask we don't get outside of array boundaries - return TComponentSettings(AtomicGet(ComponentInfo[component & Mask])); - } - - const char* ComponentName(EComponent component) const { - Y_DEBUG_ABORT_UNLESS((component & Mask) == component); - return ComponentNames[component & Mask].data(); - } - - int SetLevel(EPriority priority, EComponent component, TString& explanation); - int SetSamplingLevel(EPriority priority, EComponent component, TString& explanation); - int SetSamplingRate(ui32 sampling, EComponent component, TString& explanation); - EComponent FindComponent(const TStringBuf& componentName) const; - static int PowerOf2Mask(int val); - static bool IsValidPriority(EPriority priority); - bool IsValidComponent(EComponent component); - void SetAllowDrop(bool val); - void SetThrottleDelay(TDuration value); - void SetUseLocalTimestamps(bool value); - - private: - int SetLevelImpl( - const TString& name, bool isSampling, - EPriority priority, EComponent component, TString& explanation); - }; - - } - -} diff --git a/library/cpp/actors/core/log_ut.cpp b/library/cpp/actors/core/log_ut.cpp deleted file mode 100644 index 995e3c4121..0000000000 --- a/library/cpp/actors/core/log_ut.cpp +++ /dev/null @@ -1,251 +0,0 @@ -#include "log.h" - -#include <library/cpp/testing/unittest/registar.h> - -#include <library/cpp/actors/testlib/test_runtime.h> - -using namespace NMonitoring; -using namespace NActors; -using namespace NActors::NLog; - -namespace { - const TString& ServiceToString(int) { - static const TString FAKE{"FAKE"}; - return FAKE; - } - - TIntrusivePtr<TSettings> DefaultSettings() { - auto loggerId = TActorId{0, "Logger"}; - auto s = MakeIntrusive<TSettings>(loggerId, 0, EPriority::PRI_TRACE); - s->SetAllowDrop(false); - s->Append(0, 1, ServiceToString); - return s; - } - - TIntrusivePtr<TSettings> DroppingSettings(ui64 timeThresholdMs) { - auto loggerId = TActorId{0, "Logger"}; - auto s = MakeIntrusive<TSettings>( - loggerId, - 0, - EPriority::PRI_TRACE, - EPriority::PRI_DEBUG, - (ui32)0, - timeThresholdMs, - (ui64)0); - s->Append(0, 1, ServiceToString); - return s; - } - - TIntrusivePtr<TSettings> BufferSettings(ui64 bufferSizeLimitBytes) { - auto loggerId = TActorId{0, "Logger"}; - auto s = MakeIntrusive<TSettings>( - loggerId, - 0, - EPriority::PRI_TRACE, - EPriority::PRI_DEBUG, - (ui32)0, - (ui32)0, - bufferSizeLimitBytes); - s->Append(0, 1, ServiceToString); - s->SetAllowDrop(true); - return s; - } - - TIntrusivePtr<TSettings> NoBufferSettings() { - return BufferSettings(0); - } - - class TMockBackend: public TLogBackend { - public: - using TWriteImpl = std::function<void(const TLogRecord&)>; - using TReopenImpl = std::function<void()>; - - static void REOPEN_NOP() { } - - TMockBackend(TWriteImpl writeImpl, TReopenImpl reopenImpl = REOPEN_NOP) - : WriteImpl_{writeImpl} - , ReopenImpl_{reopenImpl} - { - } - - void WriteData(const TLogRecord& r) override { - WriteImpl_(r); - } - - void ReopenLog() override { } - - void SetWriteImpl(TWriteImpl writeImpl) { - WriteImpl_ = writeImpl; - } - - private: - TWriteImpl WriteImpl_; - TReopenImpl ReopenImpl_; - }; - - void ThrowAlways(const TLogRecord&) { - ythrow yexception(); - }; - - struct TFixture { - TFixture( - TIntrusivePtr<TSettings> settings, - TMockBackend::TWriteImpl writeImpl = ThrowAlways) - { - Runtime.Initialize(); - LogBackend.reset(new TMockBackend{writeImpl}); - LoggerActor = Runtime.Register(new TLoggerActor{settings, LogBackend, Counters}); - Runtime.SetScheduledEventFilter([] (auto&&, auto&&, auto&&, auto) { - return false; - }); - } - - TFixture(TMockBackend::TWriteImpl writeImpl = ThrowAlways) - : TFixture(DefaultSettings(), writeImpl) - {} - - void WriteLog() { - Runtime.Send(new IEventHandle{LoggerActor, {}, new TEvLog(TInstant::Zero(), TLevel{EPrio::Emerg}, 0, "foo")}); - } - - void WriteLog(TInstant ts, EPrio prio = EPrio::Emerg, TString msg = "foo") { - Runtime.Send(new IEventHandle{LoggerActor, {}, new TEvLog(ts, TLevel{prio}, 0, msg)}); - } - - void FlushLogBuffer() { - Runtime.Send(new IEventHandle{LoggerActor, {}, new TFlushLogBuffer()}); - } - - void Wakeup() { - Runtime.Send(new IEventHandle{LoggerActor, {}, new TEvents::TEvWakeup}); - } - - TIntrusivePtr<TDynamicCounters> Counters{MakeIntrusive<TDynamicCounters>()}; - std::shared_ptr<TMockBackend> LogBackend; - TActorId LoggerActor; - TTestActorRuntimeBase Runtime; - }; -} - - -Y_UNIT_TEST_SUITE(TLoggerActorTest) { - Y_UNIT_TEST(NoCrashOnWriteFailure) { - TFixture test; - test.WriteLog(); - // everything is okay as long as we get here - } - - Y_UNIT_TEST(SubsequentWritesAreIgnored) { - size_t count{0}; - auto countWrites = [&count] (auto&& r) { - count++; - ThrowAlways(r); - }; - - TFixture test{countWrites}; - test.WriteLog(); - UNIT_ASSERT_VALUES_EQUAL(count, 1); - - // at this point we should have started dropping messages - for (auto i = 0; i < 5; ++i) { - test.WriteLog(); - } - - UNIT_ASSERT_VALUES_EQUAL(count, 1); - } - - Y_UNIT_TEST(LoggerCanRecover) { - TFixture test; - test.WriteLog(); - - TVector<TString> messages; - auto acceptWrites = [&] (const TLogRecord& r) { - messages.emplace_back(r.Data, r.Len); - }; - - auto scheduled = test.Runtime.CaptureScheduledEvents(); - UNIT_ASSERT_VALUES_EQUAL(scheduled.size(), 1); - - test.LogBackend->SetWriteImpl(acceptWrites); - test.Wakeup(); - - const auto COUNT = 10; - for (auto i = 0; i < COUNT; ++i) { - test.WriteLog(); - } - - UNIT_ASSERT_VALUES_EQUAL(messages.size(), COUNT); - } - - Y_UNIT_TEST(ShouldObeyTimeThresholdMsWhenOverloaded) { - TFixture test{DroppingSettings(5000)}; - - TVector<TString> messages; - auto acceptWrites = [&] (const TLogRecord& r) { - messages.emplace_back(r.Data, r.Len); - }; - - test.LogBackend->SetWriteImpl(acceptWrites); - test.Wakeup(); - - const auto COUNT = 11; - for (auto i = 0; i < COUNT; ++i) { - test.WriteLog(); - } - - UNIT_ASSERT_VALUES_EQUAL(messages.size(), COUNT); - - test.Runtime.AdvanceCurrentTime(TDuration::Seconds(20)); - auto now = test.Runtime.GetCurrentTime(); - - test.WriteLog(now - TDuration::Seconds(5)); - - UNIT_ASSERT_VALUES_EQUAL(messages.size(), COUNT + 1); - - test.WriteLog(now - TDuration::Seconds(6)); - - UNIT_ASSERT_VALUES_EQUAL(messages.size(), COUNT + 1); - } - - int BufferTest(TFixture &test, const int COUNT) { - TVector<TString> messages; - auto acceptWrites = [&] (const TLogRecord& r) { - messages.emplace_back(r.Data, r.Len); - }; - - test.LogBackend->SetWriteImpl(acceptWrites); - test.Wakeup(); - test.Runtime.AdvanceCurrentTime(TDuration::Days(1)); - auto now = test.Runtime.GetCurrentTime(); - - for (auto i = 0; i < COUNT; ++i) { - test.WriteLog(now - TDuration::Seconds(10), EPrio::Debug, std::to_string(i)); - } - - for (auto i = 0; i < COUNT; ++i) { - test.FlushLogBuffer(); - } - - for (ui64 i = 0; i < messages.size(); ++i) { - Cerr << messages[i] << Endl; - } - - return messages.size(); - } - - Y_UNIT_TEST(ShouldUseLogBufferWhenOverloaded) { - TFixture test{BufferSettings(1024 * 1024 * 300)}; - const auto LOG_COUNT = 100; - auto outputLogSize = BufferTest(test, LOG_COUNT); - - UNIT_ASSERT_VALUES_EQUAL(outputLogSize, LOG_COUNT); - } - - Y_UNIT_TEST(ShouldLoseLogsIfBufferZeroSize) { - TFixture test{NoBufferSettings()}; - const auto LOG_COUNT = 100; - auto outputLogSize = BufferTest(test, LOG_COUNT); - - UNIT_ASSERT(outputLogSize < LOG_COUNT); - } -} diff --git a/library/cpp/actors/core/mailbox.cpp b/library/cpp/actors/core/mailbox.cpp deleted file mode 100644 index d11ff9cbcb..0000000000 --- a/library/cpp/actors/core/mailbox.cpp +++ /dev/null @@ -1,590 +0,0 @@ -#include "mailbox.h" -#include "actorsystem.h" -#include "actor.h" - -#include <library/cpp/actors/util/datetime.h> - -#include <util/system/sanitizers.h> - -namespace NActors { - TMailboxTable::TMailboxTable() - : LastAllocatedLine(0) - , AllocatedMailboxCount(0) - , CachedSimpleMailboxes(0) - , CachedRevolvingMailboxes(0) - , CachedHTSwapMailboxes(0) - , CachedReadAsFilledMailboxes(0) - , CachedTinyReadAsFilledMailboxes(0) - { - memset((void*)Lines, 0, sizeof(Lines)); - } - - bool IsGoodForCleanup(const TMailboxHeader* header) { - switch (AtomicLoad(&header->ExecutionState)) { - case TMailboxHeader::TExecutionState::Inactive: - case TMailboxHeader::TExecutionState::Scheduled: - return true; - case TMailboxHeader::TExecutionState::Leaving: - case TMailboxHeader::TExecutionState::Executing: - case TMailboxHeader::TExecutionState::LeavingMarked: - return false; - case TMailboxHeader::TExecutionState::Free: - case TMailboxHeader::TExecutionState::FreeScheduled: - return true; - case TMailboxHeader::TExecutionState::FreeLeaving: - case TMailboxHeader::TExecutionState::FreeExecuting: - case TMailboxHeader::TExecutionState::FreeLeavingMarked: - return false; - default: - Y_ABORT(); - } - } - - template <typename TMailbox> - void DestructMailboxLine(ui8* begin, ui8* end) { - const ui32 sx = TMailbox::AlignedSize(); - for (ui8* x = begin; x + sx <= end; x += sx) { - TMailbox* mailbox = reinterpret_cast<TMailbox*>(x); - Y_ABORT_UNLESS(IsGoodForCleanup(mailbox)); - mailbox->ExecutionState = Max<ui32>(); - mailbox->~TMailbox(); - } - } - - template <typename TMailbox> - bool CleanupMailboxLine(ui8* begin, ui8* end) { - const ui32 sx = TMailbox::AlignedSize(); - bool done = true; - for (ui8* x = begin; x + sx <= end; x += sx) { - TMailbox* mailbox = reinterpret_cast<TMailbox*>(x); - Y_ABORT_UNLESS(IsGoodForCleanup(mailbox)); - done &= mailbox->CleanupActors() && mailbox->CleanupEvents(); - } - return done; - } - - TMailboxTable::~TMailboxTable() { - // on cleanup we must traverse everything and free stuff - for (ui32 i = 0; i < LastAllocatedLine; ++i) { - if (TMailboxLineHeader* lineHeader = Lines[i]) { - switch (lineHeader->MailboxType) { - case TMailboxType::Simple: - DestructMailboxLine<TSimpleMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - case TMailboxType::Revolving: - DestructMailboxLine<TRevolvingMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - case TMailboxType::HTSwap: - DestructMailboxLine<THTSwapMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - case TMailboxType::ReadAsFilled: - DestructMailboxLine<TReadAsFilledMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - case TMailboxType::TinyReadAsFilled: - DestructMailboxLine<TTinyReadAsFilledMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - default: - Y_ABORT(); - } - - lineHeader->~TMailboxLineHeader(); - free(lineHeader); - Lines[i] = nullptr; - } - } - - while (MailboxCacheSimple.Pop(0)) - ; - while (MailboxCacheRevolving.Pop(0)) - ; - while (MailboxCacheHTSwap.Pop(0)) - ; - while (MailboxCacheReadAsFilled.Pop(0)) - ; - while (MailboxCacheTinyReadAsFilled.Pop(0)) - ; - } - - bool TMailboxTable::Cleanup() { - bool done = true; - for (ui32 i = 0; i < LastAllocatedLine; ++i) { - if (TMailboxLineHeader* lineHeader = Lines[i]) { - switch (lineHeader->MailboxType) { - case TMailboxType::Simple: - done &= CleanupMailboxLine<TSimpleMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - case TMailboxType::Revolving: - done &= CleanupMailboxLine<TRevolvingMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - case TMailboxType::HTSwap: - done &= CleanupMailboxLine<THTSwapMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - case TMailboxType::ReadAsFilled: - done &= CleanupMailboxLine<TReadAsFilledMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - case TMailboxType::TinyReadAsFilled: - done &= CleanupMailboxLine<TTinyReadAsFilledMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize); - break; - default: - Y_ABORT(); - } - } - } - return done; - } - - TMailboxHeader* TMailboxTable::Get(ui32 hint) { - // get line - const ui32 lineIndex = (hint & LineIndexMask) >> LineIndexShift; - const ui32 lineHint = hint & LineHintMask; - - Y_ABORT_UNLESS((lineIndex < MaxLines) && (lineHint < LineSize / 64)); - if (lineHint == 0) - return nullptr; - - if (TMailboxLineHeader* const x = AtomicLoad(Lines + lineIndex)) { - switch (x->MailboxType) { - case TMailboxType::Simple: - return TSimpleMailbox::Get(lineHint, x); - case TMailboxType::Revolving: - return TRevolvingMailbox::Get(lineHint, x); - case TMailboxType::HTSwap: - return THTSwapMailbox::Get(lineHint, x); - case TMailboxType::ReadAsFilled: - return TReadAsFilledMailbox::Get(lineHint, x); - case TMailboxType::TinyReadAsFilled: - return TTinyReadAsFilledMailbox::Get(lineHint, x); - default: - Y_DEBUG_ABORT_UNLESS(false); - break; - } - } - - return nullptr; - } - - template <TMailboxTable::TEPScheduleActivationFunction EPSpecificScheduleActivation> - bool TMailboxTable::GenericSendTo(TAutoPtr<IEventHandle>& ev, IExecutorPool* executorPool) { - const TActorId& recipient = ev->GetRecipientRewrite(); - const ui32 hint = recipient.Hint(); - - // copy-paste from Get to avoid duplicated type-switches - const ui32 lineIndex = (hint & LineIndexMask) >> LineIndexShift; - const ui32 lineHint = hint & LineHintMask; - - Y_ABORT_UNLESS((lineIndex < MaxLines) && (lineHint < LineSize / 64)); - if (lineHint == 0) - return false; - - if (TMailboxLineHeader* const x = AtomicLoad(Lines + lineIndex)) { - switch (x->MailboxType) { - case TMailboxType::Simple: { - TSimpleMailbox* const mailbox = TSimpleMailbox::Get(lineHint, x); - mailbox->Push(recipient.LocalId()); -#if (!defined(_tsan_enabled_)) - Y_DEBUG_ABORT_UNLESS(mailbox->Type == (ui32)x->MailboxType); -#endif - mailbox->Queue.Push(ev.Release()); - if (mailbox->MarkForSchedule()) { - RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); - (executorPool->*EPSpecificScheduleActivation)(hint); - } - } - return true; - case TMailboxType::Revolving: { - // The actorid could be stale and coming from a different machine. If local process has restarted than - // the stale actorid coming from a remote machine might be referencing an actor with simple mailbox - // which is smaller than revolving mailbox. In this cases 'lineHint' index might be greater than actual - // array size. Normally its ok to store stale event to other actor's valid mailbox beacuse Receive will - // compare receiver actor id and discard stale event. But in this case we should discard the event right away - // instead of trying to enque it to a mailbox at invalid address. - // NOTE: lineHint is 1-based - static_assert(TSimpleMailbox::AlignedSize() <= TRevolvingMailbox::AlignedSize(), - "We expect that one line can store more simple mailboxes than revolving mailboxes"); - if (lineHint > TRevolvingMailbox::MaxMailboxesInLine()) - return false; - - TRevolvingMailbox* const mailbox = TRevolvingMailbox::Get(lineHint, x); - mailbox->Push(recipient.LocalId()); -#if (!defined(_tsan_enabled_)) - Y_DEBUG_ABORT_UNLESS(mailbox->Type == (ui32)x->MailboxType); -#endif - mailbox->QueueWriter.Push(ev.Release()); - if (mailbox->MarkForSchedule()) { - RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); - (executorPool->*EPSpecificScheduleActivation)(hint); - } - } - return true; - case TMailboxType::HTSwap: { - THTSwapMailbox* const mailbox = THTSwapMailbox::Get(lineHint, x); - mailbox->Push(recipient.LocalId()); -#if (!defined(_tsan_enabled_)) - Y_DEBUG_ABORT_UNLESS(mailbox->Type == (ui32)x->MailboxType); -#endif - mailbox->Queue.Push(ev.Release()); - if (mailbox->MarkForSchedule()) { - RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); - (executorPool->*EPSpecificScheduleActivation)(hint); - } - } - return true; - case TMailboxType::ReadAsFilled: { - if (lineHint > TReadAsFilledMailbox::MaxMailboxesInLine()) - return false; - - TReadAsFilledMailbox* const mailbox = TReadAsFilledMailbox::Get(lineHint, x); - mailbox->Push(recipient.LocalId()); -#if (!defined(_tsan_enabled_)) - Y_DEBUG_ABORT_UNLESS(mailbox->Type == (ui32)x->MailboxType); -#endif - mailbox->Queue.Push(ev.Release()); - if (mailbox->MarkForSchedule()) { - RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); - (executorPool->*EPSpecificScheduleActivation)(hint); - } - } - return true; - case TMailboxType::TinyReadAsFilled: { - if (lineHint > TTinyReadAsFilledMailbox::MaxMailboxesInLine()) - return false; - - TTinyReadAsFilledMailbox* const mailbox = TTinyReadAsFilledMailbox::Get(lineHint, x); - mailbox->Push(recipient.LocalId()); -#if (!defined(_tsan_enabled_)) - Y_DEBUG_ABORT_UNLESS(mailbox->Type == (ui32)x->MailboxType); -#endif - mailbox->Queue.Push(ev.Release()); - if (mailbox->MarkForSchedule()) { - RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast()); - (executorPool->*EPSpecificScheduleActivation)(hint); - } - } - return true; - default: - Y_ABORT("unknown mailbox type"); - } - } - - return false; - } - - ui32 TMailboxTable::AllocateMailbox(TMailboxType::EType type, ui64 revolvingCounter) { - ui32 x = TryAllocateMailbox(type, revolvingCounter); - if (x == 0) - x = AllocateNewLine(type); - return x; - } - - ui32 TMailboxTable::TryAllocateMailbox(TMailboxType::EType type, ui64 revolvingCounter) { - switch (type) { - case TMailboxType::Simple: - do { - if (ui32 ret = MailboxCacheSimple.Pop(revolvingCounter)) { - AtomicDecrement(CachedSimpleMailboxes); - return ret; - } - } while (AtomicGet(CachedSimpleMailboxes) > (MailboxCacheSimple.Concurrency * 512)); - return 0; - case TMailboxType::Revolving: - do { - if (ui32 ret = MailboxCacheRevolving.Pop(revolvingCounter)) { - AtomicDecrement(CachedRevolvingMailboxes); - return ret; - } - } while (AtomicGet(CachedRevolvingMailboxes) > (MailboxCacheRevolving.Concurrency * 512)); - return 0; - case TMailboxType::HTSwap: - do { - if (ui32 ret = MailboxCacheHTSwap.Pop(revolvingCounter)) { - AtomicDecrement(CachedHTSwapMailboxes); - return ret; - } - } while (AtomicGet(CachedHTSwapMailboxes) > (MailboxCacheHTSwap.Concurrency * 512)); - return 0; - case TMailboxType::ReadAsFilled: - do { - if (ui32 ret = MailboxCacheReadAsFilled.Pop(revolvingCounter)) { - AtomicDecrement(CachedReadAsFilledMailboxes); - return ret; - } - } while (AtomicGet(CachedReadAsFilledMailboxes) > (MailboxCacheReadAsFilled.Concurrency * 512)); - return 0; - case TMailboxType::TinyReadAsFilled: - do { - if (ui32 ret = MailboxCacheTinyReadAsFilled.Pop(revolvingCounter)) { - AtomicDecrement(CachedTinyReadAsFilledMailboxes); - return ret; - } - } while (AtomicGet(CachedTinyReadAsFilledMailboxes) > (MailboxCacheTinyReadAsFilled.Concurrency * 512)); - return 0; - default: - Y_ABORT("Unknown mailbox type"); - } - } - - - template - bool TMailboxTable::GenericSendTo<&IExecutorPool::ScheduleActivation>(TAutoPtr<IEventHandle>& ev, IExecutorPool* executorPool); - template - bool TMailboxTable::GenericSendTo<&IExecutorPool::SpecificScheduleActivation>(TAutoPtr<IEventHandle>& ev, IExecutorPool* executorPool); - - void TMailboxTable::ReclaimMailbox(TMailboxType::EType type, ui32 hint, ui64 revolvingCounter) { - if (hint != 0) { - switch (type) { - case TMailboxType::Simple: - MailboxCacheSimple.Push(hint, revolvingCounter); - AtomicIncrement(CachedSimpleMailboxes); - break; - case TMailboxType::Revolving: - MailboxCacheRevolving.Push(hint, revolvingCounter); - AtomicIncrement(CachedRevolvingMailboxes); - break; - case TMailboxType::HTSwap: - MailboxCacheHTSwap.Push(hint, revolvingCounter); - AtomicIncrement(CachedHTSwapMailboxes); - break; - case TMailboxType::ReadAsFilled: - MailboxCacheReadAsFilled.Push(hint, revolvingCounter); - AtomicIncrement(CachedReadAsFilledMailboxes); - break; - case TMailboxType::TinyReadAsFilled: - MailboxCacheTinyReadAsFilled.Push(hint, revolvingCounter); - AtomicIncrement(CachedTinyReadAsFilledMailboxes); - break; - default: - Y_ABORT(); - } - } - } - - TMailboxHeader::TMailboxHeader(TMailboxType::EType type) - : ExecutionState(TExecutionState::Free) - , Reserved(0) - , Type(type) - , ActorPack(TMailboxActorPack::Simple) - , Knobs(0) - { - ActorsInfo.Simple.ActorId = 0; - ActorsInfo.Simple.Actor = nullptr; - } - - TMailboxHeader::~TMailboxHeader() { - CleanupActors(); - } - - bool TMailboxHeader::CleanupActors() { - bool done = true; - switch (ActorPack) { - case TMailboxActorPack::Simple: { - if (ActorsInfo.Simple.ActorId != 0) { - delete ActorsInfo.Simple.Actor; - done = false; - } - break; - } - case TMailboxActorPack::Map: { - for (auto& [actorId, actor] : *ActorsInfo.Map.ActorsMap) { - delete actor; - } - delete ActorsInfo.Map.ActorsMap; - done = false; - break; - } - case TMailboxActorPack::Array: { - for (ui64 i = 0; i < ActorsInfo.Array.ActorsCount; ++i) { - delete ActorsInfo.Array.ActorsArray->Actors[i].Actor; - } - delete ActorsInfo.Array.ActorsArray; - done = false; - break; - } - } - ActorPack = TMailboxActorPack::Simple; - ActorsInfo.Simple.ActorId = 0; - ActorsInfo.Simple.Actor = nullptr; - return done; - } - - std::pair<ui32, ui32> TMailboxHeader::CountMailboxEvents(ui64 localActorId, ui32 maxTraverse) { - switch (Type) { - case TMailboxType::Simple: - return static_cast<TMailboxTable::TSimpleMailbox*>(this)->CountSimpleMailboxEvents(localActorId, maxTraverse); - case TMailboxType::Revolving: - return static_cast<TMailboxTable::TRevolvingMailbox*>(this)->CountRevolvingMailboxEvents(localActorId, maxTraverse); - default: - return {0, 0}; - } - } - - TMailboxUsageImpl<true>::~TMailboxUsageImpl() { - while (auto *e = PendingEventQueue.Pop()) { - delete e; - } - } - - void TMailboxUsageImpl<true>::Push(ui64 localId) { - PendingEventQueue.Push(new TPendingEvent{localId, GetCycleCountFast()}); - } - - void TMailboxUsageImpl<true>::ProcessEvents(TMailboxHeader *mailbox) { - while (std::unique_ptr<TPendingEvent> e{PendingEventQueue.Pop()}) { - if (IActor *actor = mailbox->FindActor(e->LocalId)) { - actor->OnEnqueueEvent(e->Timestamp); - } - } - } - - TMailboxTable::TSimpleMailbox::TSimpleMailbox() - : TMailboxHeader(TMailboxType::Simple) - , ScheduleMoment(0) - { - } - - TMailboxTable::TSimpleMailbox::~TSimpleMailbox() { - CleanupEvents(); - } - - bool TMailboxTable::TSimpleMailbox::CleanupEvents() { - const bool done = (Queue.Head() == nullptr); - while (IEventHandle* ev = Queue.Pop()) - delete ev; - return done; - } - - std::pair<ui32, ui32> TMailboxTable::TSimpleMailbox::CountSimpleMailboxEvents(ui64 localActorId, ui32 maxTraverse) { - ui32 local = 0; - ui32 total = 0; - - auto it = Queue.ReadIterator(); - while (IEventHandle* x = it.Next()) { - ++total; - if (x->GetRecipientRewrite().LocalId() == localActorId) - ++local; - if (total >= maxTraverse) - break; - } - - return std::make_pair(local, total); - } - - TMailboxTable::TRevolvingMailbox::TRevolvingMailbox() - : TMailboxHeader(TMailboxType::Revolving) - , QueueWriter(QueueReader) - , Reserved1(0) - , Reserved2(0) - , ScheduleMoment(0) - { - } - - TMailboxTable::TRevolvingMailbox::~TRevolvingMailbox() { - CleanupEvents(); - } - - bool TMailboxTable::TRevolvingMailbox::CleanupEvents() { - const bool done = (QueueReader.Head() == nullptr); - while (IEventHandle* ev = QueueReader.Pop()) - delete ev; - return done; - } - - std::pair<ui32, ui32> TMailboxTable::TRevolvingMailbox::CountRevolvingMailboxEvents(ui64 localActorId, ui32 maxTraverse) { - ui32 local = 0; - ui32 total = 0; - - auto it = QueueReader.Iterator(); - - while (IEventHandle* x = it.Next()) { - ++total; - if (x->GetRecipientRewrite().LocalId() == localActorId) - ++local; - if (total >= maxTraverse) - break; - } - - return std::make_pair(local, total); - } - - template <typename T> - static ui32 InitNewLine(ui8* x, ui8* end) { - const ui32 sx = T::AlignedSize(); - - for (ui32 index = 1; x + sx <= end; x += sx, ++index) - ::new (x) T(); - - return sx; - } - - ui32 TMailboxTable::AllocateNewLine(TMailboxType::EType type) { - ui8* ptr = (ui8*)malloc(LineSize); - ui8* end = ptr + LineSize; - - const ui32 lineIndex = (ui32)AtomicIncrement(LastAllocatedLine) - 1; - const ui32 lineIndexMask = (lineIndex << LineIndexShift) & LineIndexMask; - - // first 64 bytes is TMailboxLineHeader - TMailboxLineHeader* header = ::new (ptr) TMailboxLineHeader(type, lineIndex); - - ui8* x = ptr + 64; - ui32 sx = 0; - TMailboxCache* cache = nullptr; - TAtomic* counter = nullptr; - - switch (type) { - case TMailboxType::Simple: - sx = InitNewLine<TSimpleMailbox>(x, end); - cache = &MailboxCacheSimple; - counter = &CachedSimpleMailboxes; - break; - case TMailboxType::Revolving: - sx = InitNewLine<TRevolvingMailbox>(x, end); - cache = &MailboxCacheRevolving; - counter = &CachedRevolvingMailboxes; - break; - case TMailboxType::HTSwap: - sx = InitNewLine<THTSwapMailbox>(x, end); - cache = &MailboxCacheHTSwap; - counter = &CachedHTSwapMailboxes; - break; - case TMailboxType::ReadAsFilled: - sx = InitNewLine<TReadAsFilledMailbox>(x, end); - cache = &MailboxCacheReadAsFilled; - counter = &CachedReadAsFilledMailboxes; - break; - case TMailboxType::TinyReadAsFilled: - sx = InitNewLine<TTinyReadAsFilledMailbox>(x, end); - cache = &MailboxCacheTinyReadAsFilled; - counter = &CachedTinyReadAsFilledMailboxes; - break; - default: - Y_ABORT(); - } - - AtomicStore(Lines + lineIndex, header); - - ui32 ret = lineIndexMask | 1; - - ui32 index = 2; - for (ui32 endIndex = LineSize / sx; index != endIndex;) { - const ui32 bufSize = 8; - ui32 buf[bufSize]; - ui32 bufIndex; - for (bufIndex = 0; index != endIndex && bufIndex != bufSize; ++bufIndex, ++index) - buf[bufIndex] = lineIndexMask | index; - cache->PushBulk(buf, bufIndex, index); - AtomicAdd(*counter, bufIndex); - } - - AtomicAdd(AllocatedMailboxCount, index - 1); - - return ret; - } - - bool TMailboxTable::SendTo(TAutoPtr<IEventHandle>& ev, IExecutorPool* executorPool) { - return GenericSendTo<&IExecutorPool::ScheduleActivation>(ev, executorPool); - } - - bool TMailboxTable::SpecificSendTo(TAutoPtr<IEventHandle>& ev, IExecutorPool* executorPool) { - return GenericSendTo<&IExecutorPool::SpecificScheduleActivation>(ev, executorPool); - } -} diff --git a/library/cpp/actors/core/mailbox.h b/library/cpp/actors/core/mailbox.h deleted file mode 100644 index 4697dedcfd..0000000000 --- a/library/cpp/actors/core/mailbox.h +++ /dev/null @@ -1,571 +0,0 @@ -#pragma once - -#include "defs.h" -#include "event.h" -#include "executor_pool.h" -#include "mailbox_queue_simple.h" -#include "mailbox_queue_revolving.h" -#include <library/cpp/actors/util/unordered_cache.h> -#include <library/cpp/threading/queue/mpsc_htswap.h> -#include <library/cpp/threading/queue/mpsc_read_as_filled.h> -#include <util/generic/hash.h> -#include <util/system/hp_timer.h> -#include <util/generic/ptr.h> -// TODO: clean all broken arcadia atomic stuff and replace with intrinsics - -namespace NActors { - class IActor; - class IExecutorPool; - - const ui64 ARRAY_CAPACITY = 8; - - // structure of hint: - // 1 bit: is service or direct hint - // 2 bits: pool index - // 17 bits: line - // 12 bits: index of mailbox inside of line - - struct TMailboxHeader; - - template<bool> - struct TMailboxUsageImpl { - void Push(ui64 /*localId*/) {} - void ProcessEvents(TMailboxHeader* /*mailbox*/) {} - }; - - template<> - struct TMailboxUsageImpl<true> { - struct TPendingEvent { - ui64 LocalId; - ui64 Timestamp; - }; - NThreading::TReadAsFilledQueue<TPendingEvent> PendingEventQueue; - - ~TMailboxUsageImpl(); - void Push(ui64 localId); - void ProcessEvents(TMailboxHeader *mailbox); - }; - - struct TMailboxHeader - : TMailboxUsageImpl<ActorLibCollectUsageStats> - { - struct TMailboxActorPack { - enum EType { - Simple = 0, - Array = 1, - Map = 2 - }; - }; - - using TActorMap = THashMap<ui64, IActor*>; - - struct TExecutionState { - enum EState { - // normal states - Inactive = 0, - Scheduled = 1, - Leaving = 2, - Executing = 3, - LeavingMarked = 4, - // states for free mailboxes (they can still be scheduled so we need duplicates) - Free = 5, - FreeScheduled = 6, - FreeLeaving = 7, - FreeExecuting = 8, - FreeLeavingMarked = 9, - }; - }; - - volatile ui32 ExecutionState; - ui32 Reserved : 4; // never changes, always zero - ui32 Type : 4; // never changes - ui32 ActorPack : 2; - ui32 Knobs : 22; - - struct TActorPair { - IActor *Actor; - ui64 ActorId; - }; - - struct alignas(64) TActorArray { - TActorPair Actors[ARRAY_CAPACITY]; - }; - - union TActorsInfo { - TActorPair Simple; - struct { - TActorArray* ActorsArray; - ui64 ActorsCount; - } Array; - struct { - TActorMap* ActorsMap; - } Map; - } ActorsInfo; - - TMailboxHeader(TMailboxType::EType type); - ~TMailboxHeader(); - - bool CleanupActors(); - - // this interface is used exclusively by executor thread, so implementation is there - - bool MarkForSchedule(); // we put something in queue, check should we schedule? - - bool LockForExecution(); // we got activation, try to lock mailbox - bool LockFromFree(); // try to claim mailbox from recycled (could fail if other thread process garbage) - - void UnlockFromExecution1(); // prepare for releasing lock - bool UnlockFromExecution2(bool wouldReschedule); // proceed with releasing lock - bool UnlockAsFree(bool wouldReschedule); // preceed with releasing lock, but mark as free one - - bool IsEmpty() const noexcept { - return (ActorPack == TMailboxActorPack::Simple && ActorsInfo.Simple.ActorId == 0); - } - - template<typename T> - void ForEach(T&& callback) noexcept { - switch (ActorPack) { - case TMailboxActorPack::Simple: - if (ActorsInfo.Simple.ActorId) { - callback(ActorsInfo.Simple.ActorId, ActorsInfo.Simple.Actor); - } - break; - - case TMailboxActorPack::Map: - for (const auto& [actorId, actor] : *ActorsInfo.Map.ActorsMap) { - callback(actorId, actor); - } - break; - - case TMailboxActorPack::Array: - for (ui64 i = 0; i < ActorsInfo.Array.ActorsCount; ++i) { - auto& row = ActorsInfo.Array.ActorsArray->Actors[i]; - callback(row.ActorId, row.Actor); - } - break; - } - } - - IActor* FindActor(ui64 localActorId) noexcept { - switch (ActorPack) { - case TMailboxActorPack::Simple: { - if (ActorsInfo.Simple.ActorId == localActorId) - return ActorsInfo.Simple.Actor; - break; - } - case TMailboxActorPack::Map: { - TActorMap::iterator it = ActorsInfo.Map.ActorsMap->find(localActorId); - if (it != ActorsInfo.Map.ActorsMap->end()) - return it->second; - break; - } - case TMailboxActorPack::Array: { - for (ui64 i = 0; i < ActorsInfo.Array.ActorsCount; ++i) { - if (ActorsInfo.Array.ActorsArray->Actors[i].ActorId == localActorId) { - return ActorsInfo.Array.ActorsArray->Actors[i].Actor; - } - } - break; - } - default: - Y_ABORT(); - } - return nullptr; - } - - void AttachActor(ui64 localActorId, IActor* actor) noexcept { - switch (ActorPack) { - case TMailboxActorPack::Simple: { - if (ActorsInfo.Simple.ActorId == 0) { - ActorsInfo.Simple.ActorId = localActorId; - ActorsInfo.Simple.Actor = actor; - return; - } else { - auto ar = new TActorArray; - ar->Actors[0] = ActorsInfo.Simple; - ar->Actors[1] = TActorPair{actor, localActorId}; - ActorsInfo.Array.ActorsCount = 2; - ActorPack = TMailboxActorPack::Array; - ActorsInfo.Array.ActorsArray = ar; - } - break; - } - case TMailboxActorPack::Map: { - ActorsInfo.Map.ActorsMap->insert(TActorMap::value_type(localActorId, actor)); - break; - } - case TMailboxActorPack::Array: { - if (ActorsInfo.Array.ActorsCount == ARRAY_CAPACITY) { - TActorMap* mp = new TActorMap(); - for (ui64 i = 0; i < ARRAY_CAPACITY; ++i) { - mp->emplace(ActorsInfo.Array.ActorsArray->Actors[i].ActorId, ActorsInfo.Array.ActorsArray->Actors[i].Actor); - } - mp->emplace(localActorId, actor); - ActorPack = TMailboxActorPack::Map; - ActorsInfo.Array.ActorsCount = 0; - delete ActorsInfo.Array.ActorsArray; - ActorsInfo.Map.ActorsMap = mp; - } else { - ActorsInfo.Array.ActorsArray->Actors[ActorsInfo.Array.ActorsCount++] = TActorPair{actor, localActorId}; - } - break; - } - default: - Y_ABORT(); - } - } - - IActor* DetachActor(ui64 localActorId) noexcept { - Y_DEBUG_ABORT_UNLESS(FindActor(localActorId) != nullptr); - - IActor* actorToDestruct = nullptr; - - switch (ActorPack) { - case TMailboxActorPack::Simple: { - Y_ABORT_UNLESS(ActorsInfo.Simple.ActorId == localActorId); - actorToDestruct = ActorsInfo.Simple.Actor; - - ActorsInfo.Simple.ActorId = 0; - ActorsInfo.Simple.Actor = nullptr; - break; - } - case TMailboxActorPack::Map: { - TActorMap::iterator it = ActorsInfo.Map.ActorsMap->find(localActorId); - Y_ABORT_UNLESS(it != ActorsInfo.Map.ActorsMap->end()); - - actorToDestruct = it->second; - ActorsInfo.Map.ActorsMap->erase(it); - - if (ActorsInfo.Map.ActorsMap->size() == ARRAY_CAPACITY) { - auto ar = new TActorArray; - ui64 i = 0; - for (auto& [actorId, actor] : *ActorsInfo.Map.ActorsMap) { - ar->Actors[i++] = TActorPair{actor, actorId}; - } - delete ActorsInfo.Map.ActorsMap; - ActorPack = TMailboxActorPack::Array; - ActorsInfo.Array.ActorsArray = ar; - ActorsInfo.Array.ActorsCount = ARRAY_CAPACITY; - } - break; - } - case TMailboxActorPack::Array: { - bool found = false; - for (ui64 i = 0; i < ActorsInfo.Array.ActorsCount; ++i) { - if (ActorsInfo.Array.ActorsArray->Actors[i].ActorId == localActorId) { - found = true; - actorToDestruct = ActorsInfo.Array.ActorsArray->Actors[i].Actor; - ActorsInfo.Array.ActorsArray->Actors[i] = ActorsInfo.Array.ActorsArray->Actors[ActorsInfo.Array.ActorsCount - 1]; - ActorsInfo.Array.ActorsCount -= 1; - break; - } - } - Y_ABORT_UNLESS(found); - - if (ActorsInfo.Array.ActorsCount == 1) { - const TActorPair Actor = ActorsInfo.Array.ActorsArray->Actors[0]; - delete ActorsInfo.Array.ActorsArray; - ActorPack = TMailboxActorPack::Simple; - ActorsInfo.Simple = Actor; - } - break; - } - } - - return actorToDestruct; - } - - std::pair<ui32, ui32> CountMailboxEvents(ui64 localActorId, ui32 maxTraverse); - }; - - class TMailboxTable : TNonCopyable { - private: - struct TMailboxLineHeader { - const TMailboxType::EType MailboxType; - const ui32 Index; - // some more stuff in first cache line, then goes mailboxes - ui8 Padding[52]; - - TMailboxLineHeader(TMailboxType::EType type, ui32 index) - : MailboxType(type) - , Index(index) - { - } - }; - static_assert(sizeof(TMailboxLineHeader) <= 64, "expect sizeof(TMailboxLineHeader) <= 64"); - - constexpr static ui64 MaxLines = 131000; // somewhat less then 2^17. - constexpr static ui64 LineSize = 262144; // 64 * 2^12. - - TAtomic LastAllocatedLine; - TAtomic AllocatedMailboxCount; - - typedef TUnorderedCache<ui32, 512, 4> TMailboxCache; - TMailboxCache MailboxCacheSimple; - TAtomic CachedSimpleMailboxes; - TMailboxCache MailboxCacheRevolving; - TAtomic CachedRevolvingMailboxes; - TMailboxCache MailboxCacheHTSwap; - TAtomic CachedHTSwapMailboxes; - TMailboxCache MailboxCacheReadAsFilled; - TAtomic CachedReadAsFilledMailboxes; - TMailboxCache MailboxCacheTinyReadAsFilled; - TAtomic CachedTinyReadAsFilledMailboxes; - - // and here goes large chunk of lines - // presented as array of static size to avoid sync on access - TMailboxLineHeader* volatile Lines[MaxLines]; - - ui32 AllocateNewLine(TMailboxType::EType type); - ui32 TryAllocateMailbox(TMailboxType::EType type, ui64 revolvingCounter); - - public: - TMailboxTable(); - ~TMailboxTable(); - - bool Cleanup(); // returns true if nothing found to destruct (so nothing new is possible to be created) - - static const ui32 LineIndexShift = 12; - static const ui32 LineIndexMask = 0x1FFFFu << LineIndexShift; - static const ui32 LineHintMask = 0xFFFu; - static const ui32 PoolIndexShift = TActorId::PoolIndexShift; - static const ui32 PoolIndexMask = TActorId::PoolIndexMask; - - static ui32 LineIndex(ui32 hint) { - return ((hint & LineIndexMask) >> LineIndexShift); - } - static ui32 PoolIndex(ui32 hint) { - return TActorId::PoolIndex(hint); - } - - TMailboxHeader* Get(ui32 hint); - ui32 AllocateMailbox(TMailboxType::EType type, ui64 revolvingCounter); - void ReclaimMailbox(TMailboxType::EType type, ui32 hint, ui64 revolvingCounter); - ui64 GetAllocatedMailboxCount() const { - return RelaxedLoad(&AllocatedMailboxCount); - } - - private: - typedef void (IExecutorPool::*TEPScheduleActivationFunction)(ui32 activation); - - template <TEPScheduleActivationFunction EPSpecificScheduleActivation> - bool GenericSendTo(TAutoPtr<IEventHandle>& ev, IExecutorPool* executorPool); - - public: - bool SendTo(TAutoPtr<IEventHandle>& ev, IExecutorPool* executorPool); - bool SpecificSendTo(TAutoPtr<IEventHandle>& ev, IExecutorPool* executorPool); - - struct TSimpleMailbox: public TMailboxHeader { - // 4 bytes - state - // 4 bytes - knobs - // 8 bytes - actorid - // 8 bytes - actor* - TSimpleMailboxQueue<IEventHandle*, 64> Queue; // 24 + 8 bytes (body, lock) - NHPTimer::STime ScheduleMoment; - - TSimpleMailbox(); - ~TSimpleMailbox(); - - IEventHandle* Pop() { - return Queue.Pop(); - } - IEventHandle* Head() { - return Queue.Head(); - } - - static TSimpleMailbox* Get(ui32 hint, void* line) { - return (TSimpleMailbox*)((ui8*)line + 64 + (hint - 1) * AlignedSize()); // - } - static const TMailboxType::EType MailboxType = TMailboxType::Simple; - constexpr static ui32 AlignedSize() { - return ((sizeof(TSimpleMailbox) + 63) / 64) * 64; - } - - std::pair<ui32, ui32> CountSimpleMailboxEvents(ui64 localActorId, ui32 maxTraverse); - bool CleanupEvents(); - }; - - struct TRevolvingMailbox: public TMailboxHeader { - // 4 bytes - state - // 4 bytes - knobs - // 8 bytes - actorid - // 8 bytes - actor* - TRevolvingMailboxQueue<IEventHandle*, 3, 128>::TReader QueueReader; // 8 * 3 + 4 * 3 + (padding): 40 bytes - // here goes next cache-line, so less writers<-> reader interference - TRevolvingMailboxQueue<IEventHandle*, 3, 128>::TWriter QueueWriter; // 8 * 3 + 4 * 3 + 8 : 48 bytes - ui32 Reserved1; - ui32 Reserved2; - NHPTimer::STime ScheduleMoment; - - TRevolvingMailbox(); - ~TRevolvingMailbox(); - - IEventHandle* Pop() { - return QueueReader.Pop(); - } - IEventHandle* Head() { - return QueueReader.Head(); - } - - static TRevolvingMailbox* Get(ui32 hint, void* line) { - return (TRevolvingMailbox*)((ui8*)line + 64 + (hint - 1) * AlignedSize()); - } - - constexpr static ui64 MaxMailboxesInLine() { - return (LineSize - 64) / AlignedSize(); - } - static const TMailboxType::EType MailboxType = TMailboxType::Revolving; - constexpr static ui32 AlignedSize() { - return ((sizeof(TRevolvingMailbox) + 63) / 64) * 64; - } - - std::pair<ui32, ui32> CountRevolvingMailboxEvents(ui64 localActorId, ui32 maxTraverse); - bool CleanupEvents(); - }; - - struct THTSwapMailbox: public TMailboxHeader { - using TQueueType = NThreading::THTSwapQueue<IEventHandle*>; - - TQueueType Queue; - NHPTimer::STime ScheduleMoment; - char Padding_[16]; - - THTSwapMailbox() - : TMailboxHeader(TMailboxType::HTSwap) - , ScheduleMoment(0) - { - } - - ~THTSwapMailbox() { - CleanupEvents(); - } - - IEventHandle* Pop() { - return Queue.Pop(); - } - - IEventHandle* Head() { - return Queue.Peek(); - } - - static THTSwapMailbox* Get(ui32 hint, void* line) { - return (THTSwapMailbox*)((ui8*)line + 64 + (hint - 1) * AlignedSize()); - } - - constexpr static ui64 MaxMailboxesInLine() { - return (LineSize - 64) / AlignedSize(); - } - - static const TMailboxType::EType MailboxType = TMailboxType::HTSwap; - - constexpr static ui32 AlignedSize() { - return ((sizeof(THTSwapMailbox) + 63) / 64) * 64; - } - - bool CleanupEvents() { - const bool done = (Queue.Peek() == nullptr); - while (IEventHandle* ev = Queue.Pop()) - delete ev; - return done; - } - }; - - struct TReadAsFilledMailbox: public TMailboxHeader { - using TQueueType = NThreading::TReadAsFilledQueue<IEventHandle>; - - TQueueType Queue; - NHPTimer::STime ScheduleMoment; - char Padding_[8]; - - TReadAsFilledMailbox() - : TMailboxHeader(TMailboxType::ReadAsFilled) - , ScheduleMoment(0) - { - } - - ~TReadAsFilledMailbox() { - CleanupEvents(); - } - - IEventHandle* Pop() { - return Queue.Pop(); - } - - IEventHandle* Head() { - return Queue.Peek(); - } - - static TReadAsFilledMailbox* Get(ui32 hint, void* line) { - return (TReadAsFilledMailbox*)((ui8*)line + 64 + (hint - 1) * AlignedSize()); - } - - constexpr static ui64 MaxMailboxesInLine() { - return (LineSize - 64) / AlignedSize(); - } - - static const TMailboxType::EType MailboxType = - TMailboxType::ReadAsFilled; - - constexpr static ui32 AlignedSize() { - return ((sizeof(TReadAsFilledMailbox) + 63) / 64) * 64; - } - - bool CleanupEvents() { - const bool done = (Queue.Peek() == nullptr); - while (IEventHandle* ev = Queue.Pop()) - delete ev; - return done; - } - }; - - struct TTinyReadAsFilledMailbox: public TMailboxHeader { - using TQueueType = NThreading::TReadAsFilledQueue< - IEventHandle, - NThreading::TRaFQueueBunchSize<4>>; - - TQueueType Queue; - NHPTimer::STime ScheduleMoment; - char Padding_[8]; - - TTinyReadAsFilledMailbox() - : TMailboxHeader(TMailboxType::TinyReadAsFilled) - , ScheduleMoment(0) - { - } - - ~TTinyReadAsFilledMailbox() { - CleanupEvents(); - } - - IEventHandle* Pop() { - return Queue.Pop(); - } - - IEventHandle* Head() { - return Queue.Peek(); - } - - static TTinyReadAsFilledMailbox* Get(ui32 hint, void* line) { - return (TTinyReadAsFilledMailbox*)((ui8*)line + 64 + (hint - 1) * AlignedSize()); - } - - constexpr static ui64 MaxMailboxesInLine() { - return (LineSize - 64) / AlignedSize(); - } - - static const TMailboxType::EType MailboxType = - TMailboxType::TinyReadAsFilled; - - constexpr static ui32 AlignedSize() { - return ((sizeof(TTinyReadAsFilledMailbox) + 63) / 64) * 64; - } - - bool CleanupEvents() { - const bool done = (Queue.Peek() == nullptr); - while (IEventHandle* ev = Queue.Pop()) - delete ev; - return done; - } - }; - }; -} diff --git a/library/cpp/actors/core/mailbox_queue_revolving.h b/library/cpp/actors/core/mailbox_queue_revolving.h deleted file mode 100644 index e1a25dd352..0000000000 --- a/library/cpp/actors/core/mailbox_queue_revolving.h +++ /dev/null @@ -1,214 +0,0 @@ -#pragma once - -#include "defs.h" -#include <library/cpp/actors/util/queue_chunk.h> - -namespace NActors { - // add some concurrency to basic queue to avoid hangs under contention (we pay with memory, so use only when really expect contention) - // ordering: every completed push guarantied to seen before any not-yet-initiated push. parallel pushes could reorder (and that is natural for concurrent queues). - // try to place reader/writer on different cache-lines to avoid congestion b/w reader and writers. - // if strict ordering does not matter - look at TManyOneQueue. - - template <typename T, ui32 TWriteConcurrency = 3, ui32 TSize = 128> - class TRevolvingMailboxQueue { - static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value"); - - struct TValTagPair { - volatile T Value; - volatile ui64 Tag; - }; - - typedef TQueueChunk<TValTagPair, TSize> TChunk; - - static_assert(sizeof(TAtomic) == sizeof(TChunk*), "expect sizeof(TAtomic) == sizeof(TChunk*)"); - static_assert(sizeof(TAtomic) == sizeof(ui64), "expect sizeof(TAtomic) == sizeof(ui64)"); - - public: - class TWriter; - - class TReader { - TChunk* ReadFrom[TWriteConcurrency]; - ui32 ReadPosition[TWriteConcurrency]; - - friend class TRevolvingMailboxQueue<T, TWriteConcurrency, TSize>::TWriter; // for access to ReadFrom in constructor - - bool ChunkHead(ui32 idx, ui64* tag, T* value) { - TChunk* head = ReadFrom[idx]; - const ui32 pos = ReadPosition[idx]; - if (pos != TChunk::EntriesCount) { - if (const T xval = AtomicLoad(&head->Entries[pos].Value)) { - const ui64 xtag = head->Entries[pos].Tag; - if (xtag < *tag) { - *value = xval; - *tag = xtag; - return true; - } - } - } else if (TChunk* next = AtomicLoad(&head->Next)) { - ReadFrom[idx] = next; - delete head; - ReadPosition[idx] = 0; - return ChunkHead(idx, tag, value); - } - - return false; - } - - T Head(bool pop) { - ui64 tag = Max<ui64>(); - T ret = T{}; - ui32 idx = 0; - - for (ui32 i = 0; i < TWriteConcurrency; ++i) - if (ChunkHead(i, &tag, &ret)) - idx = i; - - // w/o second pass we could reorder updates with 'already scanned' range - if (ret) { - for (ui32 i = 0; i < TWriteConcurrency; ++i) - if (ChunkHead(i, &tag, &ret)) - idx = i; - } - - if (pop && ret) - ++ReadPosition[idx]; - - return ret; - } - - public: - TReader() { - for (ui32 i = 0; i != TWriteConcurrency; ++i) { - ReadFrom[i] = new TChunk(); - ReadPosition[i] = 0; - } - } - - ~TReader() { - Y_DEBUG_ABORT_UNLESS(Head() == 0); - for (ui32 i = 0; i < TWriteConcurrency; ++i) - delete ReadFrom[i]; - } - - T Pop() { - return Head(true); - } - - T Head() { - return Head(false); - } - - class TReadIterator { - TChunk* ReadFrom[TWriteConcurrency]; - ui32 ReadPosition[TWriteConcurrency]; - - bool ChunkHead(ui32 idx, ui64* tag, T* value) { - TChunk* head = ReadFrom[idx]; - const ui32 pos = ReadPosition[idx]; - if (pos != TChunk::EntriesCount) { - if (const T xval = AtomicLoad(&head->Entries[pos].Value)) { - const ui64 xtag = head->Entries[pos].Tag; - if (xtag < *tag) { - *value = xval; - *tag = xtag; - return true; - } - } - } else if (TChunk* next = AtomicLoad(&head->Next)) { - ReadFrom[idx] = next; - ReadPosition[idx] = 0; - return ChunkHead(idx, tag, value); - } - - return false; - } - - public: - TReadIterator(TChunk* const* readFrom, const ui32* readPosition) { - memcpy(ReadFrom, readFrom, TWriteConcurrency * sizeof(TChunk*)); - memcpy(ReadPosition, readPosition, TWriteConcurrency * sizeof(ui32)); - } - - T Next() { - ui64 tag = Max<ui64>(); - T ret = T{}; - ui32 idx = 0; - - for (ui32 i = 0; i < TWriteConcurrency; ++i) - if (ChunkHead(i, &tag, &ret)) - idx = i; - - // w/o second pass we could reorder updates with 'already scanned' range - if (ret) { - for (ui32 i = 0; i < TWriteConcurrency; ++i) - if (ChunkHead(i, &tag, &ret)) - idx = i; - } - - if (ret) - ++ReadPosition[idx]; - - return ret; - } - }; - - TReadIterator Iterator() const { - return TReadIterator(ReadFrom, ReadPosition); - } - }; - - class TWriter { - TChunk* volatile WriteTo[TWriteConcurrency]; - volatile ui64 Tag; - ui32 WritePosition[TWriteConcurrency]; - - public: - TWriter(const TReader& reader) - : Tag(0) - { - for (ui32 i = 0; i != TWriteConcurrency; ++i) { - WriteTo[i] = reader.ReadFrom[i]; - WritePosition[i] = 0; - } - } - - bool TryPush(T x) { - Y_ABORT_UNLESS(x != 0); - - for (ui32 i = 0; i != TWriteConcurrency; ++i) { - if (RelaxedLoad(&WriteTo[i]) != nullptr) { - if (TChunk* writeTo = AtomicSwap(&WriteTo[i], nullptr)) { - const ui64 nextTag = AtomicIncrement(Tag); - Y_DEBUG_ABORT_UNLESS(nextTag < Max<ui64>()); - const ui32 writePosition = WritePosition[i]; - if (writePosition != TChunk::EntriesCount) { - writeTo->Entries[writePosition].Tag = nextTag; - AtomicStore(&writeTo->Entries[writePosition].Value, x); - ++WritePosition[i]; - } else { - TChunk* next = new TChunk(); - next->Entries[0].Tag = nextTag; - next->Entries[0].Value = x; - AtomicStore(&writeTo->Next, next); - writeTo = next; - WritePosition[i] = 1; - } - AtomicStore(WriteTo + i, writeTo); - return true; - } - } - } - return false; - } - - ui32 Push(T x) { - ui32 spins = 0; - while (!TryPush(x)) { - ++spins; - SpinLockPause(); - } - return spins; - } - }; - }; -} diff --git a/library/cpp/actors/core/mailbox_queue_simple.h b/library/cpp/actors/core/mailbox_queue_simple.h deleted file mode 100644 index 2e44c21adb..0000000000 --- a/library/cpp/actors/core/mailbox_queue_simple.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include "defs.h" -#include <library/cpp/actors/util/ticket_lock.h> -#include <library/cpp/actors/util/queue_oneone_inplace.h> - -namespace NActors { - // dead-simple one-one queue, based on serializability guaranties of x64 and ticket lock to ensure writer unicity. - template <typename T, ui32 TSize> - class TSimpleMailboxQueue { - TOneOneQueueInplace<T, TSize> Queue; - TTicketLock Lock; - - public: - ui32 Push(T x) noexcept { - const ui32 spins = Lock.Acquire(); - Queue.Push(x); - Lock.Release(); - return spins; - } - - T Head() { - return Queue.Head(); - } - - T Pop() { - return Queue.Pop(); - } - - typename TOneOneQueueInplace<T, TSize>::TReadIterator ReadIterator() { - return Queue.Iterator(); - } - }; -} diff --git a/library/cpp/actors/core/mon.h b/library/cpp/actors/core/mon.h deleted file mode 100644 index ba5debbd17..0000000000 --- a/library/cpp/actors/core/mon.h +++ /dev/null @@ -1,267 +0,0 @@ -#pragma once - -#include "events.h" -#include "event_local.h" -#include <library/cpp/monlib/service/monservice.h> -#include <library/cpp/monlib/service/pages/mon_page.h> - -namespace NActors { - namespace NMon { - enum { - HttpInfo = EventSpaceBegin(NActors::TEvents::ES_MON), - HttpInfoRes, - RemoteHttpInfo, - RemoteHttpInfoRes, - RemoteJsonInfoRes, - RemoteBinaryInfoRes, - End - }; - - static_assert(End < EventSpaceEnd(NActors::TEvents::ES_MON), "expect End < EventSpaceEnd(NActors::TEvents::ES_MON)"); - - // request info from an actor in HTML format - struct TEvHttpInfo: public NActors::TEventLocal<TEvHttpInfo, HttpInfo> { - TEvHttpInfo(const NMonitoring::IMonHttpRequest& request, int subReqId = 0) - : Request(request) - , SubRequestId(subReqId) - { - } - - TEvHttpInfo(const NMonitoring::IMonHttpRequest& request, const TString& userToken) - : Request(request) - , UserToken(userToken) - , SubRequestId(0) - { - } - - const NMonitoring::IMonHttpRequest& Request; - TString UserToken; // built and serialized - // SubRequestId != 0 means that we assemble reply from multiple parts and SubRequestId contains this part id - int SubRequestId; - }; - - // base class for HTTP info response - struct IEvHttpInfoRes: public NActors::TEventLocal<IEvHttpInfoRes, HttpInfoRes> { - enum EContentType { - Html, - Custom, - }; - - IEvHttpInfoRes() { - } - - virtual ~IEvHttpInfoRes() { - } - - virtual void Output(IOutputStream& out) const = 0; - virtual EContentType GetContentType() const = 0; - }; - - // Ready to output HTML in TString - struct TEvHttpInfoRes: public IEvHttpInfoRes { - TEvHttpInfoRes(const TString& answer, int subReqId = 0, EContentType contentType = Html) - : Answer(answer) - , SubRequestId(subReqId) - , ContentType(contentType) - { - } - - void Output(IOutputStream& out) const override { - out << Answer; - } - - EContentType GetContentType() const override { - return ContentType; - } - - const TString Answer; - const int SubRequestId; - const EContentType ContentType; - }; - - struct TEvRemoteHttpInfo: public NActors::TEventBase<TEvRemoteHttpInfo, RemoteHttpInfo> { - TEvRemoteHttpInfo() = default; - - TEvRemoteHttpInfo(const TString& query, HTTP_METHOD method = HTTP_METHOD_UNDEFINED) - : Query(query) - , Method(method) - { - } - - TEvRemoteHttpInfo(NActorsProto::TRemoteHttpInfo info) - : Query(MakeSerializedQuery(info)) - , ExtendedQuery(std::move(info)) - {} - - static TString MakeSerializedQuery(const NActorsProto::TRemoteHttpInfo& info) { - TString s(1, '\0'); - const bool success = info.AppendToString(&s); - Y_ABORT_UNLESS(success); - return s; - } - - TString Query; - HTTP_METHOD Method = HTTP_METHOD_UNDEFINED; - std::optional<NActorsProto::TRemoteHttpInfo> ExtendedQuery; - - TString PathInfo() const { - if (ExtendedQuery) { - return ExtendedQuery->GetPath(); - } else { - const size_t pos = Query.find('?'); - return (pos == TString::npos) ? TString() : Query.substr(0, pos); - } - } - - TCgiParameters Cgi() const { - if (ExtendedQuery) { - TCgiParameters params; - for (const auto& kv : ExtendedQuery->GetQueryParams()) { - params.emplace(kv.GetKey(), kv.GetValue()); - } - return params; - } else { - const size_t pos = Query.find('?'); - return TCgiParameters((pos == TString::npos) ? TString() : Query.substr(pos + 1)); - } - } - - HTTP_METHOD GetMethod() const { - return ExtendedQuery ? static_cast<HTTP_METHOD>(ExtendedQuery->GetMethod()) : Method; - } - - TString ToStringHeader() const override { - return "TEvRemoteHttpInfo"; - } - - bool SerializeToArcadiaStream(TChunkSerializer *serializer) const override { - return serializer->WriteString(&Query); - } - - ui32 CalculateSerializedSize() const override { - return Query.size(); - } - - bool IsSerializable() const override { - return true; - } - - static IEventBase* Load(TEventSerializedData* bufs) { - TString s = bufs->GetString(); - if (s.size() && s[0] == '\0') { - TRope::TConstIterator iter = bufs->GetBeginIter(); - ui64 size = bufs->GetSize(); - iter += 1, --size; // skip '\0' - TRopeStream stream(iter, size); - - auto res = std::make_unique<TEvRemoteHttpInfo>(); - res->Query = s; - res->ExtendedQuery.emplace(); - const bool success = res->ExtendedQuery->ParseFromZeroCopyStream(&stream); - Y_ABORT_UNLESS(success); - return res.release(); - } else { - return new TEvRemoteHttpInfo(s); - } - } - }; - - struct TEvRemoteHttpInfoRes: public NActors::TEventBase<TEvRemoteHttpInfoRes, RemoteHttpInfoRes> { - TEvRemoteHttpInfoRes() { - } - - TEvRemoteHttpInfoRes(const TString& html) - : Html(html) - { - } - - TString Html; - - TString ToStringHeader() const override { - return "TEvRemoteHttpInfoRes"; - } - - bool SerializeToArcadiaStream(TChunkSerializer *serializer) const override { - return serializer->WriteString(&Html); - } - - ui32 CalculateSerializedSize() const override { - return Html.size(); - } - - bool IsSerializable() const override { - return true; - } - - static IEventBase* Load(TEventSerializedData* bufs) { - return new TEvRemoteHttpInfoRes(bufs->GetString()); - } - }; - - struct TEvRemoteJsonInfoRes: public NActors::TEventBase<TEvRemoteJsonInfoRes, RemoteJsonInfoRes> { - TEvRemoteJsonInfoRes() { - } - - TEvRemoteJsonInfoRes(const TString& json) - : Json(json) - { - } - - TString Json; - - TString ToStringHeader() const override { - return "TEvRemoteJsonInfoRes"; - } - - bool SerializeToArcadiaStream(TChunkSerializer *serializer) const override { - return serializer->WriteString(&Json); - } - - ui32 CalculateSerializedSize() const override { - return Json.size(); - } - - bool IsSerializable() const override { - return true; - } - - static IEventBase* Load(TEventSerializedData* bufs) { - return new TEvRemoteJsonInfoRes(bufs->GetString()); - } - }; - - struct TEvRemoteBinaryInfoRes: public NActors::TEventBase<TEvRemoteBinaryInfoRes, RemoteBinaryInfoRes> { - TEvRemoteBinaryInfoRes() { - } - - TEvRemoteBinaryInfoRes(const TString& blob) - : Blob(blob) - { - } - - TString Blob; - - TString ToStringHeader() const override { - return "TEvRemoteBinaryInfoRes"; - } - - bool SerializeToArcadiaStream(TChunkSerializer *serializer) const override { - return serializer->WriteString(&Blob); - } - - ui32 CalculateSerializedSize() const override { - return Blob.size(); - } - - bool IsSerializable() const override { - return true; - } - - static IEventBase* Load(TEventSerializedData* bufs) { - return new TEvRemoteBinaryInfoRes(bufs->GetString()); - } - }; - - } - -} diff --git a/library/cpp/actors/core/mon_stats.h b/library/cpp/actors/core/mon_stats.h deleted file mode 100644 index 4fb49d70c0..0000000000 --- a/library/cpp/actors/core/mon_stats.h +++ /dev/null @@ -1,191 +0,0 @@ -#pragma once - -#include "defs.h" -//#include "actor.h" -#include <library/cpp/actors/util/local_process_key.h> -#include <library/cpp/monlib/metrics/histogram_snapshot.h> -#include <util/system/hp_timer.h> - -namespace NActors { - struct TLogHistogram : public NMonitoring::IHistogramSnapshot { - TLogHistogram() { - memset(Buckets, 0, sizeof(Buckets)); - } - - inline void Add(ui64 val, ui64 inc = 1) { - size_t ind = 0; -#if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ == 7 - asm volatile("" :: - : "memory"); -#endif - if (val > 1) { - ind = GetValueBitCount(val - 1); - } -#if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ == 7 - asm volatile("" :: - : "memory"); -#endif - RelaxedStore(&TotalSamples, RelaxedLoad(&TotalSamples) + inc); - RelaxedStore(&Buckets[ind], RelaxedLoad(&Buckets[ind]) + inc); - } - - void Aggregate(const TLogHistogram& other) { - const ui64 inc = RelaxedLoad(&other.TotalSamples); - RelaxedStore(&TotalSamples, RelaxedLoad(&TotalSamples) + inc); - for (size_t i = 0; i < Y_ARRAY_SIZE(Buckets); ++i) { - Buckets[i] += RelaxedLoad(&other.Buckets[i]); - } - } - - // IHistogramSnapshot - ui32 Count() const override { - return Y_ARRAY_SIZE(Buckets); - } - - NMonitoring::TBucketBound UpperBound(ui32 index) const override { - Y_ASSERT(index < Y_ARRAY_SIZE(Buckets)); - if (index == 0) { - return 1; - } - return NMonitoring::TBucketBound(1ull << (index - 1)) * 2.0; - } - - NMonitoring::TBucketValue Value(ui32 index) const override { - Y_ASSERT(index < Y_ARRAY_SIZE(Buckets)); - return Buckets[index]; - } - - ui64 TotalSamples = 0; - ui64 Buckets[65]; - }; - - struct TExecutorPoolStats { - ui64 MaxUtilizationTime = 0; - ui64 IncreasingThreadsByNeedyState = 0; - ui64 IncreasingThreadsByExchange = 0; - ui64 DecreasingThreadsByStarvedState = 0; - ui64 DecreasingThreadsByHoggishState = 0; - ui64 DecreasingThreadsByExchange = 0; - i64 MaxConsumedCpuUs = 0; - i64 MinConsumedCpuUs = 0; - i64 MaxBookedCpuUs = 0; - i64 MinBookedCpuUs = 0; - double SpinningTimeUs = 0; - double SpinThresholdUs = 0; - i16 WrongWakenedThreadCount = 0; - i16 CurrentThreadCount = 0; - i16 PotentialMaxThreadCount = 0; - i16 DefaultThreadCount = 0; - i16 MaxThreadCount = 0; - bool IsNeedy = false; - bool IsStarved = false; - bool IsHoggish = false; - }; - - struct TExecutorThreadStats { - ui64 SentEvents = 0; - ui64 ReceivedEvents = 0; - ui64 PreemptedEvents = 0; // Number of events experienced hard preemption - ui64 NonDeliveredEvents = 0; - ui64 EmptyMailboxActivation = 0; - ui64 CpuUs = 0; // microseconds thread was executing on CPU (accounts for preemtion) - ui64 SafeElapsedTicks = 0; - ui64 WorstActivationTimeUs = 0; - NHPTimer::STime ElapsedTicks = 0; - NHPTimer::STime ParkedTicks = 0; - NHPTimer::STime BlockedTicks = 0; - TLogHistogram ActivationTimeHistogram; - TLogHistogram EventDeliveryTimeHistogram; - TLogHistogram EventProcessingCountHistogram; - TLogHistogram EventProcessingTimeHistogram; - TVector<NHPTimer::STime> ElapsedTicksByActivity; - TVector<ui64> ReceivedEventsByActivity; - TVector<i64> ActorsAliveByActivity; // the sum should be positive, but per-thread might be negative - TVector<ui64> ScheduledEventsByActivity; - TVector<ui64> StuckActorsByActivity; - TVector<std::array<ui64, 10>> UsageByActivity; - ui64 PoolActorRegistrations = 0; - ui64 PoolDestroyedActors = 0; - ui64 PoolAllocatedMailboxes = 0; - ui64 MailboxPushedOutByTailSending = 0; - ui64 MailboxPushedOutBySoftPreemption = 0; - ui64 MailboxPushedOutByTime = 0; - ui64 MailboxPushedOutByEventCount = 0; - ui64 NotEnoughCpuExecutions = 0; - - TExecutorThreadStats() // must be not empty as 0 used as default - : ElapsedTicksByActivity(TLocalProcessKeyStateIndexLimiter::GetMaxKeysCount()) - , ReceivedEventsByActivity(TLocalProcessKeyStateIndexLimiter::GetMaxKeysCount()) - , ActorsAliveByActivity(TLocalProcessKeyStateIndexLimiter::GetMaxKeysCount()) - , ScheduledEventsByActivity(TLocalProcessKeyStateIndexLimiter::GetMaxKeysCount()) - , StuckActorsByActivity(TLocalProcessKeyStateIndexLimiter::GetMaxKeysCount()) - , UsageByActivity(TLocalProcessKeyStateIndexLimiter::GetMaxKeysCount()) - {} - - template <typename T> - static void AggregateOne(TVector<T>& self, const TVector<T>& other) { - const size_t selfSize = self.size(); - const size_t otherSize = other.size(); - if (selfSize < otherSize) - self.resize(otherSize); - for (size_t at = 0; at < otherSize; ++at) - self[at] += RelaxedLoad(&other[at]); - } - - void Aggregate(const TExecutorThreadStats& other) { - SentEvents += RelaxedLoad(&other.SentEvents); - ReceivedEvents += RelaxedLoad(&other.ReceivedEvents); - PreemptedEvents += RelaxedLoad(&other.PreemptedEvents); - NonDeliveredEvents += RelaxedLoad(&other.NonDeliveredEvents); - EmptyMailboxActivation += RelaxedLoad(&other.EmptyMailboxActivation); - CpuUs += RelaxedLoad(&other.CpuUs); - SafeElapsedTicks += RelaxedLoad(&other.SafeElapsedTicks); - RelaxedStore( - &WorstActivationTimeUs, - std::max(RelaxedLoad(&WorstActivationTimeUs), RelaxedLoad(&other.WorstActivationTimeUs))); - ElapsedTicks += RelaxedLoad(&other.ElapsedTicks); - ParkedTicks += RelaxedLoad(&other.ParkedTicks); - BlockedTicks += RelaxedLoad(&other.BlockedTicks); - MailboxPushedOutByTailSending += RelaxedLoad(&other.MailboxPushedOutByTailSending); - MailboxPushedOutBySoftPreemption += RelaxedLoad(&other.MailboxPushedOutBySoftPreemption); - MailboxPushedOutByTime += RelaxedLoad(&other.MailboxPushedOutByTime); - MailboxPushedOutByEventCount += RelaxedLoad(&other.MailboxPushedOutByEventCount); - NotEnoughCpuExecutions += RelaxedLoad(&other.NotEnoughCpuExecutions); - - ActivationTimeHistogram.Aggregate(other.ActivationTimeHistogram); - EventDeliveryTimeHistogram.Aggregate(other.EventDeliveryTimeHistogram); - EventProcessingCountHistogram.Aggregate(other.EventProcessingCountHistogram); - EventProcessingTimeHistogram.Aggregate(other.EventProcessingTimeHistogram); - - AggregateOne(ElapsedTicksByActivity, other.ElapsedTicksByActivity); - AggregateOne(ReceivedEventsByActivity, other.ReceivedEventsByActivity); - AggregateOne(ActorsAliveByActivity, other.ActorsAliveByActivity); - AggregateOne(ScheduledEventsByActivity, other.ScheduledEventsByActivity); - AggregateOne(StuckActorsByActivity, other.StuckActorsByActivity); - - if (UsageByActivity.size() < other.UsageByActivity.size()) { - UsageByActivity.resize(other.UsageByActivity.size()); - } - for (size_t i = 0; i < UsageByActivity.size(); ++i) { - for (size_t j = 0; j < 10; ++j) { - UsageByActivity[i][j] += RelaxedLoad(&other.UsageByActivity[i][j]); - } - } - - RelaxedStore( - &PoolActorRegistrations, - std::max(RelaxedLoad(&PoolActorRegistrations), RelaxedLoad(&other.PoolActorRegistrations))); - RelaxedStore( - &PoolDestroyedActors, - std::max(RelaxedLoad(&PoolDestroyedActors), RelaxedLoad(&other.PoolDestroyedActors))); - RelaxedStore( - &PoolAllocatedMailboxes, - std::max(RelaxedLoad(&PoolAllocatedMailboxes), RelaxedLoad(&other.PoolAllocatedMailboxes))); - } - - size_t MaxActivityType() const { - return ActorsAliveByActivity.size(); - } - }; - -} diff --git a/library/cpp/actors/core/mon_ut.cpp b/library/cpp/actors/core/mon_ut.cpp deleted file mode 100644 index fa5dbbe71e..0000000000 --- a/library/cpp/actors/core/mon_ut.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include <library/cpp/testing/unittest/registar.h> -#include <library/cpp/actors/core/mon.h> - -using namespace NActors; -using namespace NMon; - -Y_UNIT_TEST_SUITE(ActorSystemMon) { - Y_UNIT_TEST(SerializeEv) { - NActorsProto::TRemoteHttpInfo info; - info.SetPath("hello"); - - auto ev = std::make_unique<TEvRemoteHttpInfo>(info); - UNIT_ASSERT(ev->ExtendedQuery); - UNIT_ASSERT_VALUES_EQUAL(ev->ExtendedQuery->GetPath(), info.GetPath()); - UNIT_ASSERT_VALUES_EQUAL(ev->PathInfo(), info.GetPath()); - - TAllocChunkSerializer ser; - const bool success = ev->SerializeToArcadiaStream(&ser); - Y_ABORT_UNLESS(success); - auto buffer = ser.Release(ev->CreateSerializationInfo()); - std::unique_ptr<TEvRemoteHttpInfo> restored(dynamic_cast<TEvRemoteHttpInfo*>(TEvRemoteHttpInfo::Load(buffer.Get()))); - UNIT_ASSERT(restored->Query == ev->Query); - UNIT_ASSERT(restored->Query.size()); - UNIT_ASSERT(restored->Query[0] == '\0'); - UNIT_ASSERT(restored->ExtendedQuery); - UNIT_ASSERT_VALUES_EQUAL(restored->ExtendedQuery->GetPath(), ev->ExtendedQuery->GetPath()); - UNIT_ASSERT_VALUES_EQUAL(restored->PathInfo(), ev->PathInfo()); - } -} diff --git a/library/cpp/actors/core/monotonic.cpp b/library/cpp/actors/core/monotonic.cpp deleted file mode 100644 index 581d80d849..0000000000 --- a/library/cpp/actors/core/monotonic.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "monotonic.h" diff --git a/library/cpp/actors/core/monotonic.h b/library/cpp/actors/core/monotonic.h deleted file mode 100644 index 2c53785390..0000000000 --- a/library/cpp/actors/core/monotonic.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include <util/datetime/base.h> -#include <library/cpp/time_provider/monotonic.h> - -namespace NActors { - -using NMonotonic::GetMonotonicMicroSeconds; - -using TMonotonic = NMonotonic::TMonotonic; - -} // namespace NActors diff --git a/library/cpp/actors/core/monotonic_provider.cpp b/library/cpp/actors/core/monotonic_provider.cpp deleted file mode 100644 index f8d91a4eec..0000000000 --- a/library/cpp/actors/core/monotonic_provider.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "monotonic_provider.h" diff --git a/library/cpp/actors/core/monotonic_provider.h b/library/cpp/actors/core/monotonic_provider.h deleted file mode 100644 index befe4f7b90..0000000000 --- a/library/cpp/actors/core/monotonic_provider.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include <library/cpp/time_provider/monotonic_provider.h> - -namespace NActors { - -using IMonotonicTimeProvider = NMonotonic::IMonotonicTimeProvider; - -using NMonotonic::CreateDefaultMonotonicTimeProvider; - -} // namespace NActors diff --git a/library/cpp/actors/core/performance_ut.cpp b/library/cpp/actors/core/performance_ut.cpp deleted file mode 100644 index 3c1a0ed143..0000000000 --- a/library/cpp/actors/core/performance_ut.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include "actorsystem.h" -#include "av_bootstrapped.h" -#include "actor_virtual.h" -#include "actor_bootstrapped.h" -#include "config.h" -#include "event_local.h" -#include "executor_pool_basic.h" -#include "executor_pool_io.h" -#include "executor_pool_base.h" -#include "scheduler_basic.h" - -#include <library/cpp/actors/testlib/test_runtime.h> -#include <library/cpp/testing/unittest/registar.h> - -using namespace NActors; - -Y_UNIT_TEST_SUITE(ActorSystemPerformance) { - - class TQueueTestRuntime { - std::unique_ptr<TActorSystem> ActorSystem; - public: - TQueueTestRuntime() { - auto setup = MakeHolder<TActorSystemSetup>(); - setup->NodeId = 1; - setup->ExecutorsCount = 2; - setup->Executors.Reset(new TAutoPtr<IExecutorPool>[2]); - setup->Executors[0].Reset(new TBasicExecutorPool(0, 4, 20)); - setup->Executors[1].Reset(new TIOExecutorPool(1, 10)); - - setup->Scheduler.Reset(new TBasicSchedulerThread(TSchedulerConfig(512, 100))); - - ActorSystem.reset(new TActorSystem{ setup }); - } - - void Start() { - ActorSystem->Start(); - } - - void Stop() { - ActorSystem->Stop(); - ActorSystem.reset(); - } - - void Send(std::unique_ptr<IEventHandle>&& ev) { - ActorSystem->Send(ev.release()); - } - - void Register(IActor* actor) { - ActorSystem->Register(actor); - } - }; - - enum EEvSubscribe { - EvDolbExecute, - EvEnd - }; - - class TEventLocalDolbilkaOld: public NActors::TEventLocal<TEventLocalDolbilkaOld, EvDolbExecute> { - public: - - }; - - class TDolbilkaCommon { - protected: - ui32 Counter = 0; - ui32 CounterLimit = 10000000; - const TInstant Start = Now(); - std::atomic<TDuration> Duration; - std::atomic<bool> Ready = false; - public: - bool MakeStep() { - if (++Counter >= CounterLimit) { - TDolbilkaCommon::Finish(); - return false; - } - return true; - } - TDuration GetDurationInProgress() const { - return Now() - Start; - } - double GetOperationDuration() const { - return 1.0 * Duration.load().MicroSeconds() / Counter * 1000; - } - void Finish() { - if (!Ready.exchange(true)) { - Duration = GetDurationInProgress(); - } - } - bool IsFinished() const { - return Ready; - } - }; - - class TDolbilkaOld: public TDolbilkaCommon, public NActors::TActorBootstrapped<TDolbilkaOld> { - private: - using TBase = NActors::TActorBootstrapped<TDolbilkaOld>; - public: - - STFUNC(StateInit) { - switch (ev->GetTypeRewrite()) { - HFunc(TEventLocalDolbilkaOld, Handle); - default: - Y_ABORT_UNLESS(false); - } - } - - void Handle(TEventLocalDolbilkaOld::TPtr& /*ev*/, const TActorContext&) { - if (MakeStep()) { - Sender<TEventLocalDolbilkaOld>().SendTo(SelfId()); - } - } - - void Bootstrap() { - Become(&TThis::StateInit); - Sender<TEventLocalDolbilkaOld>().SendTo(SelfId()); - } - }; - - class TDolbilkaNew; - class TEventLocalDolbilkaNew: public NActors::TEventLocalForActor<TEventLocalDolbilkaNew, TDolbilkaNew> { - public: - - }; - - class TDolbilkaNew: public TDolbilkaCommon, public NActors::TActorAutoStart { - private: - using TBase = NActors::TActorAutoStart; - protected: - virtual void DoOnStart(const TActorId& /*senderActorId*/) override { - Sender<TEventLocalDolbilkaNew>().SendTo(SelfId()); - } - - public: - void ProcessEvent(NActors::TEventContext<TEventLocalDolbilkaNew>& /*ev*/) { - if (MakeStep()) { - Sender<TEventLocalDolbilkaNew>().SendTo(SelfId()); - } - } - }; - - class IDolbilkaSimple { - public: - virtual ~IDolbilkaSimple() = default; - virtual bool ProcessEvent() = 0; - }; - - class TDolbilkaSimple: public TDolbilkaCommon, public IDolbilkaSimple { - private: -// TMutex Mutex; - public: - virtual bool ProcessEvent() override { -// TGuard<TMutex> g(Mutex); - return MakeStep(); - } - }; - - Y_UNIT_TEST(PerfTest) { - THolder<TQueueTestRuntime> runtime(new TQueueTestRuntime); - runtime->Start(); - TDolbilkaNew* dNew = new TDolbilkaNew; - runtime->Register(dNew); - while (dNew->GetDurationInProgress() < TDuration::Seconds(1000) && !dNew->IsFinished()) { - Sleep(TDuration::Seconds(1)); - } - Y_ABORT_UNLESS(dNew->IsFinished()); - TDolbilkaOld* dOld = new TDolbilkaOld; - runtime->Register(dOld); - while (dOld->GetDurationInProgress() < TDuration::Seconds(1000) && !dOld->IsFinished()) { - Sleep(TDuration::Seconds(1)); - } - Y_ABORT_UNLESS(dOld->IsFinished()); - std::unique_ptr<TDolbilkaSimple> dSimple(new TDolbilkaSimple); - IDolbilkaSimple* dSimpleIface = dSimple.get(); - while (dSimpleIface->ProcessEvent()) { - - } - Cerr << "DURATION_OLD: " << 1.0 * dOld->GetOperationDuration() << "ns" << Endl; - Cerr << "DURATION_NEW: " << 1.0 * dNew->GetOperationDuration() << "ns" << Endl; - Cerr << "DURATION_SIMPLE: " << 1.0 * dSimple->GetOperationDuration() << "ns" << Endl; - - } -} diff --git a/library/cpp/actors/core/probes.cpp b/library/cpp/actors/core/probes.cpp deleted file mode 100644 index 7ace83e102..0000000000 --- a/library/cpp/actors/core/probes.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "probes.h" - -#include "actorsystem.h" - -#include <util/string/builder.h> - -LWTRACE_DEFINE_PROVIDER(ACTORLIB_PROVIDER); - -namespace NActors { - TVector<NLWTrace::TDashboard> LWTraceDashboards(TActorSystemSetup* setup) { - TVector<NLWTrace::TDashboard> result; - - NLWTrace::TDashboard slowDash; - ui32 pools = setup->GetExecutorsCount(); - size_t top = 30; - slowDash.SetName("ActorSystem slow events"); - slowDash.SetDescription(TStringBuilder() << "TOP" << top << " slow event executions >1M cycles for every pool (refresh page to update)"); - for (ui32 pool = 0; pool < pools; pool++) { - auto* row = slowDash.AddRows(); - auto* cell = row->AddCells(); - cell->SetTitle(TStringBuilder() << pool << ":" << setup->GetPoolName(pool)); - cell->SetUrl(TStringBuilder() << "?mode=log&id=.ACTORLIB_PROVIDER.SlowEvent.ppoolId=" << pool << "&s=eventMs&reverse=y&head=30"); - } - result.push_back(slowDash); - - return result; - } -} diff --git a/library/cpp/actors/core/probes.h b/library/cpp/actors/core/probes.h deleted file mode 100644 index 531923b5ad..0000000000 --- a/library/cpp/actors/core/probes.h +++ /dev/null @@ -1,221 +0,0 @@ -#pragma once - -#include <library/cpp/lwtrace/all.h> -#include <util/generic/vector.h> - -#define LWACTORID(x) (x).RawX1(), (x).RawX2(), (x).NodeId(), (x).PoolID() -#define LWTYPE_ACTORID ui64, ui64, ui32, ui32 -#define LWNAME_ACTORID(n) n "Raw1", n "Raw2", n "NodeId", n "PoolId" - -#define ACTORLIB_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ - PROBE(SlowEvent, GROUPS("ActorLibSlow"), \ - TYPES(ui32, double, TString, TString, TString), \ - NAMES("poolId", "eventMs", "eventType", "actorId", "actorType")) \ - PROBE(EventSlowDelivery, GROUPS("ActorLibSlow"), \ - TYPES(ui32, double, double, ui64, TString, TString, TString), \ - NAMES("poolId", "deliveryMs", "sinceActivationMs", "eventProcessedBefore", "eventType", "actorId", "actorType")) \ - PROBE(SlowActivation, GROUPS("ActorLibSlow"), \ - TYPES(ui32, double), \ - NAMES("poolId", "activationMs")) \ - PROBE(SlowRegisterNew, GROUPS("ActorLibSlow"), \ - TYPES(ui32, double), \ - NAMES("poolId", "registerNewMs")) \ - PROBE(SlowRegisterAdd, GROUPS("ActorLibSlow"), \ - TYPES(ui32, double), \ - NAMES("poolId", "registerAddMs")) \ - PROBE(MailboxPushedOutByTailSending, GROUPS("ActorLibMailbox", "ActorLibMailboxPushedOut"), \ - TYPES(ui32, TString, ui32, TDuration, ui64, TString, TString), \ - NAMES("poolId", "pool", "eventsProcessed", "procTimeMs", "workerId", "actorId", "actorType")) \ - PROBE(MailboxPushedOutBySoftPreemption, GROUPS("ActorLibMailbox", "ActorLibMailboxPushedOut"), \ - TYPES(ui32, TString, ui32, TDuration, ui64, TString, TString), \ - NAMES("poolId", "pool", "eventsProcessed", "procTimeMs", "workerId", "actorId", "actorType")) \ - PROBE(MailboxPushedOutByTime, GROUPS("ActorLibMailbox", "ActorLibMailboxPushedOut"), \ - TYPES(ui32, TString, ui32, TDuration, ui64, TString, TString), \ - NAMES("poolId", "pool", "eventsProcessed", "procTimeMs", "workerId", "actorId", "actorType")) \ - PROBE(MailboxPushedOutByEventCount, GROUPS("ActorLibMailbox", "ActorLibMailboxPushedOut"), \ - TYPES(ui32, TString, ui32, TDuration, ui64, TString, TString), \ - NAMES("poolId", "pool", "eventsProcessed", "procTimeMs", "workerId", "actorId", "actorType")) \ - PROBE(MailboxEmpty, GROUPS("ActorLibMailbox"), \ - TYPES(ui32, TString, ui32, TDuration, ui64, TString, TString), \ - NAMES("poolId", "pool", "eventsProcessed", "procTimeMs", "workerId", "actorId", "actorType")) \ - PROBE(ActivationBegin, GROUPS(), \ - TYPES(ui32, ui32, ui32, double), \ - NAMES("cpu", "poolId", "workerId", "expireMs")) \ - PROBE(ActivationEnd, GROUPS(), \ - TYPES(ui32, ui32, ui32), \ - NAMES("cpu", "poolId", "workerId")) \ - PROBE(ExecutorThreadStats, GROUPS("ActorLibStats"), \ - TYPES(ui32, TString, ui64, ui64, ui64, double, double), \ - NAMES("poolId", "pool", "workerId", "execCount", "readyActivationCount", "execMs", "nonExecMs")) \ - PROBE(SlowICReadLoopAdjustSize, GROUPS("ActorLibSlowIC"), \ - TYPES(double), \ - NAMES("icReadLoopAdjustSizeMs")) \ - PROBE(SlowICReadFromSocket, GROUPS("ActorLibSlowIC"), \ - TYPES(double), \ - NAMES("icReadFromSocketMs")) \ - PROBE(SlowICReadLoopSend, GROUPS("ActorLibSlowIC"), \ - TYPES(double), \ - NAMES("icReadLoopSendMs")) \ - PROBE(SlowICAllocPacketBuffer, GROUPS("ActorLibSlowIC"), \ - TYPES(ui32, double), \ - NAMES("peerId", "icAllocPacketBufferMs")) \ - PROBE(SlowICFillSendingBuffer, GROUPS("ActorLibSlowIC"), \ - TYPES(ui32, double), \ - NAMES("peerId", "icFillSendingBufferMs")) \ - PROBE(SlowICPushSentPackets, GROUPS("ActorLibSlowIC"), \ - TYPES(ui32, double), \ - NAMES("peerId", "icPushSentPacketsMs")) \ - PROBE(SlowICPushSendQueue, GROUPS("ActorLibSlowIC"), \ - TYPES(ui32, double), \ - NAMES("peerId", "icPushSendQueueMs")) \ - PROBE(SlowICWriteData, GROUPS("ActorLibSlowIC"), \ - TYPES(ui32, double), \ - NAMES("peerId", "icWriteDataMs")) \ - PROBE(SlowICDropConfirmed, GROUPS("ActorLibSlowIC"), \ - TYPES(ui32, double), \ - NAMES("peerId", "icDropConfirmedMs")) \ - PROBE(ActorsystemScheduler, GROUPS("Durations"), \ - TYPES(ui64, ui64, ui32, ui32, ui64, ui64), \ - NAMES("timeUs", "timerfd_expirations", "eventsGottenFromQueues", "eventsSent", \ - "eventsInSendQueue", "eventSchedulingErrorUs")) \ - PROBE(ForwardEvent, GROUPS("Orbit", "InterconnectSessionTCP"), \ - TYPES(ui32, ui32, ui32, LWTYPE_ACTORID, LWTYPE_ACTORID, ui64, ui32), \ - NAMES("peerId", "type", "flags", LWNAME_ACTORID("r"), LWNAME_ACTORID("s"), \ - "cookie", "eventSerializedSize")) \ - PROBE(EnqueueEvent, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, ui64, TDuration, ui16, ui64, ui64), \ - NAMES("peerId", "numEventsInReadyChannels", "enqueueBlockedTotalMs", "channelId", "queueSizeInEvents", "queueSizeInBytes")) \ - PROBE(SerializeToPacketBegin, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, ui16, ui64), \ - NAMES("peerId", "channelId", "outputQueueSize")) \ - PROBE(SerializeToPacketEnd, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, ui16, ui64, ui64), \ - NAMES("peerId", "channelId", "outputQueueSize", "offsetInPacket")) \ - PROBE(FillSendingBuffer, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, ui32, ui64, TDuration), \ - NAMES("peerId", "taskBytesGenerated", "numEventsInReadyChannelsBehind", "fillBlockedTotalMs")) \ - PROBE(PacketGenerated, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, ui64, ui64, ui64, ui64), \ - NAMES("peerId", "bytesUnwritten", "inflightBytes", "packetsGenerated", "packetSize")) \ - PROBE(PacketWrittenToSocket, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, ui64, bool, ui64, ui64, TDuration, int), \ - NAMES("peerId", "packetsWrittenToSocket", "triedWriting", "packetDataSize", "bytesUnwritten", "writeBlockedTotalMs", "fd")) \ - PROBE(GenerateTraffic, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, double, ui64, ui32, ui64), \ - NAMES("peerId", "generateTrafficMs", "dataBytesSent", "generatedPackets", "generatedBytes")) \ - PROBE(WriteToSocket, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, ui64, ui64, ui64, ui64, TDuration, int), \ - NAMES("peerId", "bytesWritten", "packetsWritten", "packetsWrittenToSocket", "bytesUnwritten", "writeBlockedTotalMs", "fd")) \ - PROBE(UpdateFromInputSession, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, double), \ - NAMES("peerId", "pingMs")) \ - PROBE(UnblockByDropConfirmed, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, double), \ - NAMES("peerId", "updateDeliveryMs")) \ - PROBE(DropConfirmed, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, ui64, ui64), \ - NAMES("peerId", "droppedBytes", "inflightBytes")) \ - PROBE(StartRam, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32), \ - NAMES("peerId")) \ - PROBE(FinishRam, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, double), \ - NAMES("peerId", "ramMs")) \ - PROBE(SkipGenerateTraffic, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, double), \ - NAMES("peerId", "elapsedSinceRamMs")) \ - PROBE(StartBatching, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, double), \ - NAMES("peerId", "batchPeriodMs")) \ - PROBE(FinishBatching, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, double), \ - NAMES("peerId", "finishBatchDeliveryMs")) \ - PROBE(BlockedWrite, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, double, ui64), \ - NAMES("peerId", "sendQueueSize", "writtenBytes")) \ - PROBE(ReadyWrite, GROUPS("InterconnectSessionTCP"), \ - TYPES(ui32, double, double), \ - NAMES("peerId", "readyWriteDeliveryMs", "blockMs")) \ - PROBE(EpollStartWaitIn, GROUPS("EpollThread"), \ - TYPES(), \ - NAMES()) \ - PROBE(EpollFinishWaitIn, GROUPS("EpollThread"), \ - TYPES(i32), \ - NAMES("eventsCount")) \ - PROBE(EpollWaitOut, GROUPS("EpollThread"), \ - TYPES(i32), \ - NAMES("eventsCount")) \ - PROBE(EpollSendReadyRead, GROUPS("EpollThread"), \ - TYPES(bool, bool, int), \ - NAMES("hangup", "event", "fd")) \ - PROBE(EpollSendReadyWrite, GROUPS("EpollThread"), \ - TYPES(bool, bool, int), \ - NAMES("hangup", "event", "fd")) \ - PROBE(HardPreemption, GROUPS("UnitedWorker"), \ - TYPES(ui32, ui32, ui32, ui32), \ - NAMES("cpu", "prevPoolId", "prevWorkerId", "nextWorkerId")) \ - PROBE(SetPreemptionTimer, GROUPS("UnitedWorker", "PreemptionTimer"), \ - TYPES(ui32, ui32, int, double, double), \ - NAMES("cpu", "workerId", "fd", "nowMs", "preemptMs")) \ - PROBE(ResetPreemptionTimer, GROUPS("UnitedWorker", "PreemptionTimer"), \ - TYPES(ui32, ui32, int, double, double), \ - NAMES("cpu", "workerId", "fd", "nowMs", "preemptMs")) \ - PROBE(SlowWorkerActionRace, GROUPS("UnitedWorker"), \ - TYPES(ui32, ui32, ui64), \ - NAMES("cpu", "poolId", "slowPoolsMask")) \ - PROBE(PoolStats, GROUPS("PoolCpuBalancer"), \ - TYPES(ui32, TString, ui64, ui8, ui8, double, double, double, ui64, ui64, ui64), \ - NAMES("poolId", "pool", "currentCpus", "loadClass", "priority", "scaleFactor", "cpuIdle", "cpuLoad", "importance", "addImportance", "subImportance")) \ - PROBE(MoveCpu, GROUPS("PoolCpuBalancer"), \ - TYPES(ui32, ui64, TString, TString, ui32), \ - NAMES("fromPoolId", "toPoolId", "fromPool", "toPool", "cpu")) \ - PROBE(ThreadCount, GROUPS("BasicThreadPool"), \ - TYPES(ui32, TString, ui32, ui32, ui32, ui32), \ - NAMES("poolId", "pool", "threacCount", "minThreadCount", "maxThreadCount", "defaultThreadCount")) \ - PROBE(HarmonizeCheckPool, GROUPS("Harmonizer"), \ - TYPES(ui32, TString, double, double, double, double, ui32, ui32, bool, bool, bool), \ - NAMES("poolId", "pool", "booked", "consumed", "lastSecondBooked", "lastSecondConsumed", "threadCount", "maxThreadCount", "isStarved", "isNeedy", "isHoggish")) \ - PROBE(WakingUpConsumption, GROUPS("Harmonizer"), \ - TYPES(double, double, double, double, double), \ - NAMES("avgWakingUpUs", "realAvgWakingUpUs", "avgAwakeningUs", "realAvgAwakeningUs", "total")) \ - PROBE(ChangeSpinThreshold, GROUPS("Harmonizer"), \ - TYPES(ui32, TString, ui64, double, ui64), \ - NAMES("poolId", "pool", "spinThreshold", "spinThresholdUs", "bucketIdx")) \ - PROBE(WaitingHistogram, GROUPS("Harmonizer"), \ - TYPES(ui32, TString, double, double, ui64), \ - NAMES("poolId", "pool", "fromUs", "toUs", "count")) \ - PROBE(HarmonizeOperation, GROUPS("Harmonizer"), \ - TYPES(ui32, TString, TString, ui32, ui32, ui32), \ - NAMES("poolId", "pool", "operation", "newCount", "minCount", "maxCount")) \ - PROBE(TryToHarmonize, GROUPS("Harmonizer"), \ - TYPES(ui32, TString), \ - NAMES("poolId", "pool")) \ - PROBE(SavedValues, GROUPS("Harmonizer"), \ - TYPES(ui32, TString, TString, double, double, double, double, double, double, double, double), \ - NAMES("poolId", "pool", "valueName", "[0]", "[1]", "[2]", "[3]", "[4]", "[5]", "[6]", "[7]")) \ - PROBE(RegisterValue, GROUPS("Harmonizer"), \ - TYPES(ui64, ui64, ui64, ui64, double, double, double), \ - NAMES("ts", "lastTs", "dTs", "8sTs", "us", "lastUs", "dUs")) \ - PROBE(TryToHarmonizeFailed, GROUPS("Harmonizer"), \ - TYPES(ui64, ui64, bool, bool), \ - NAMES("ts", "nextHarmonizeTs", "isDisabled", "withLock")) \ - PROBE(TryToHarmonizeSuccess, GROUPS("Harmonizer"), \ - TYPES(ui64, ui64, ui64), \ - NAMES("ts", "nextHarmonizeTs", "previousNextHarmonizeTs")) \ - PROBE(SpinCycles, GROUPS("Harmonizer"), \ - TYPES(ui32, TString, ui64, bool), \ - NAMES("poolId", "pool", "spinPauseCount", "IsInterrupted")) \ - PROBE(WaitingHistogramPerThread, GROUPS("Harmonizer"), \ - TYPES(ui32, TString, ui32, double, double, ui64), \ - NAMES("poolId", "pool", "threadIdx", "fromUs", "toUs", "count")) \ - PROBE(ChangeSpinThresholdPerThread, GROUPS("Harmonizer"), \ - TYPES(ui32, TString, ui32, ui64, double, ui64), \ - NAMES("poolId", "pool", "threadIdx", "spinThreshold", "spinThresholdUs", "bucketIdx")) \ - /**/ - -LWTRACE_DECLARE_PROVIDER(ACTORLIB_PROVIDER) - -namespace NActors { - struct TActorSystemSetup; - TVector<NLWTrace::TDashboard> LWTraceDashboards(TActorSystemSetup* setup); -} diff --git a/library/cpp/actors/core/process_stats.cpp b/library/cpp/actors/core/process_stats.cpp deleted file mode 100644 index f9028537c5..0000000000 --- a/library/cpp/actors/core/process_stats.cpp +++ /dev/null @@ -1,358 +0,0 @@ -#include "actorsystem.h" -#include "actor_bootstrapped.h" -#include "hfunc.h" -#include "process_stats.h" - -#include <library/cpp/monlib/dynamic_counters/counters.h> -#include <library/cpp/monlib/metrics/metric_registry.h> - -#include <util/datetime/uptime.h> -#include <util/system/defaults.h> -#include <util/stream/file.h> -#include <util/system/fs.h> -#include <util/string/vector.h> -#include <util/string/split.h> - -#ifndef _win_ -#include <sys/user.h> -#endif - -namespace NActors { -#ifdef _linux_ - - namespace { - template <typename TVal> - static bool ExtractVal(const TString& str, const TString& name, TVal& res) { - if (!str.StartsWith(name)) - return false; - size_t pos = name.size(); - while (pos < str.size() && (str[pos] == ' ' || str[pos] == '\t')) { - pos++; - } - res = atol(str.data() + pos); - return true; - } - - float TicksPerMillisec() { -#ifdef _SC_CLK_TCK - return sysconf(_SC_CLK_TCK) / 1000.0; -#else - return 1.f; -#endif - } - } - - bool TProcStat::Fill(pid_t pid) { - try { - TString strPid(ToString(pid)); - TFileInput proc("/proc/" + strPid + "/status"); - TString str; - while (proc.ReadLine(str)) { - if (ExtractVal(str, "VmRSS:", Rss)) - continue; - if (ExtractVal(str, "voluntary_ctxt_switches:", VolCtxSwtch)) - continue; - if (ExtractVal(str, "nonvoluntary_ctxt_switches:", NonvolCtxSwtch)) - continue; - } - // Convert from kB to bytes - Rss *= 1024; - - float tickPerMillisec = TicksPerMillisec(); - - TFileInput procStat("/proc/" + strPid + "/stat"); - procStat.ReadLine(str); - if (!str.empty()) { - sscanf(str.data(), - "%d %*s %c %d %d %d %d %d %u %lu %lu " - "%lu %lu %lu %lu %ld %ld %ld %ld %ld " - "%ld %llu %lu %ld %lu", - &Pid, &State, &Ppid, &Pgrp, &Session, &TtyNr, &TPgid, &Flags, &MinFlt, &CMinFlt, - &MajFlt, &CMajFlt, &Utime, &Stime, &CUtime, &CStime, &Priority, &Nice, &NumThreads, - &ItRealValue, &StartTime, &Vsize, &RssPages, &RssLim); - Utime /= tickPerMillisec; - Stime /= tickPerMillisec; - CUtime /= tickPerMillisec; - CStime /= tickPerMillisec; - SystemUptime = ::Uptime(); - Uptime = SystemUptime - TDuration::MilliSeconds(StartTime / TicksPerMillisec()); - } - - TFileInput statm("/proc/" + strPid + "/statm"); - statm.ReadLine(str); - TVector<TString> fields; - StringSplitter(str).Split(' ').SkipEmpty().Collect(&fields); - if (fields.size() >= 7) { - ui64 resident = FromString<ui64>(fields[1]); - ui64 shared = FromString<ui64>(fields[2]); - if (PageSize == 0) { - PageSize = ObtainPageSize(); - } - FileRss = shared * PageSize; - AnonRss = (resident - shared) * PageSize; - } - - TFileInput cgroup("/proc/" + strPid + "/cgroup"); - TString line; - TString memoryCGroup; - while (cgroup.ReadLine(line) > 0) { - StringSplitter(line).Split(':').Collect(&fields); - if (fields.size() > 2 && fields[1] == "memory") { - memoryCGroup = fields[2]; - break; - } - } - - TString cgroupFileName = "/sys/fs/cgroup/memory" + memoryCGroup + "/memory.limit_in_bytes"; - if (!NFs::Exists(cgroupFileName)) { - // fallback for mk8s - cgroupFileName = "/sys/fs/cgroup/memory/memory.limit_in_bytes"; - } - TFileInput limit(cgroupFileName); - if (limit.ReadLine(line) > 0) { - CGroupMemLim = FromString<ui64>(line); - if (CGroupMemLim > (1ULL << 40)) { - CGroupMemLim = 0; - } - } - - } catch (...) { - return false; - } - return true; - } - - long TProcStat::ObtainPageSize() { - long sz = sysconf(_SC_PAGESIZE); - return sz; - } - -#else - - bool TProcStat::Fill(pid_t pid) { - Y_UNUSED(pid); - return false; - } - - long TProcStat::ObtainPageSize() { - return 0; - } - -#endif - -namespace { - // Periodically collects process stats and exposes them as mon counters - template <typename TDerived> - class TProcStatCollectingActor: public TActorBootstrapped<TProcStatCollectingActor<TDerived>> { - public: - static constexpr IActor::EActivityType ActorActivityType() { - return IActor::EActivityType::ACTORLIB_STATS; - } - - TProcStatCollectingActor(TDuration interval) - : Interval(interval) - { - } - - void Bootstrap(const TActorContext& ctx) { - TryUpdateCounters(); - ctx.Schedule(Interval, new TEvents::TEvWakeup()); - static_cast<TDerived*>(this)->Become(&TDerived::StateWork); - } - - STFUNC(StateWork) { - switch (ev->GetTypeRewrite()) { - CFunc(TEvents::TSystem::Wakeup, Wakeup); - } - } - - private: - void Wakeup(const TActorContext& ctx) { - TryUpdateCounters(); - ctx.Schedule(Interval, new TEvents::TEvWakeup()); - } - - void TryUpdateCounters() { - if (ProcStat.Fill(getpid())) { - static_cast<TDerived*>(this)->UpdateCounters(ProcStat); - } - } - - private: - const TDuration Interval; - TProcStat ProcStat; - }; - - // Periodically collects process stats and exposes them as mon counters - class TDynamicCounterCollector: public TProcStatCollectingActor<TDynamicCounterCollector> { - using TBase = TProcStatCollectingActor<TDynamicCounterCollector>; - public: - TDynamicCounterCollector( - ui32 intervalSeconds, - NMonitoring::TDynamicCounterPtr counters) - : TBase{TDuration::Seconds(intervalSeconds)} - { - ProcStatGroup = counters->GetSubgroup("counters", "utils"); - - VmSize = ProcStatGroup->GetCounter("Process/VmSize", false); - AnonRssSize = ProcStatGroup->GetCounter("Process/AnonRssSize", false); - FileRssSize = ProcStatGroup->GetCounter("Process/FileRssSize", false); - CGroupMemLimit = ProcStatGroup->GetCounter("Process/CGroupMemLimit", false); - UserTime = ProcStatGroup->GetCounter("Process/UserTime", true); - SysTime = ProcStatGroup->GetCounter("Process/SystemTime", true); - MinorPageFaults = ProcStatGroup->GetCounter("Process/MinorPageFaults", true); - MajorPageFaults = ProcStatGroup->GetCounter("Process/MajorPageFaults", true); - UptimeSeconds = ProcStatGroup->GetCounter("Process/UptimeSeconds", false); - NumThreads = ProcStatGroup->GetCounter("Process/NumThreads", false); - SystemUptimeSeconds = ProcStatGroup->GetCounter("System/UptimeSeconds", false); - } - - void UpdateCounters(const TProcStat& procStat) { - *VmSize = procStat.Vsize; - *AnonRssSize = procStat.AnonRss; - *FileRssSize = procStat.FileRss; - if (procStat.CGroupMemLim) { - *CGroupMemLimit = procStat.CGroupMemLim; - } - *UserTime = procStat.Utime; - *SysTime = procStat.Stime; - *MinorPageFaults = procStat.MinFlt; - *MajorPageFaults = procStat.MajFlt; - *UptimeSeconds = procStat.Uptime.Seconds(); - *NumThreads = procStat.NumThreads; - *SystemUptimeSeconds = procStat.Uptime.Seconds(); - } - - private: - NMonitoring::TDynamicCounterPtr ProcStatGroup; - NMonitoring::TDynamicCounters::TCounterPtr VmSize; - NMonitoring::TDynamicCounters::TCounterPtr AnonRssSize; - NMonitoring::TDynamicCounters::TCounterPtr FileRssSize; - NMonitoring::TDynamicCounters::TCounterPtr CGroupMemLimit; - NMonitoring::TDynamicCounters::TCounterPtr UserTime; - NMonitoring::TDynamicCounters::TCounterPtr SysTime; - NMonitoring::TDynamicCounters::TCounterPtr MinorPageFaults; - NMonitoring::TDynamicCounters::TCounterPtr MajorPageFaults; - NMonitoring::TDynamicCounters::TCounterPtr UptimeSeconds; - NMonitoring::TDynamicCounters::TCounterPtr NumThreads; - NMonitoring::TDynamicCounters::TCounterPtr SystemUptimeSeconds; - }; - - class TRegistryCollector: public TProcStatCollectingActor<TRegistryCollector> { - using TBase = TProcStatCollectingActor<TRegistryCollector>; - public: - TRegistryCollector(TDuration interval, NMonitoring::TMetricRegistry& registry) - : TBase{interval} - { - VmSize = registry.IntGauge({{"sensor", "process.VmSize"}}); - AnonRssSize = registry.IntGauge({{"sensor", "process.AnonRssSize"}}); - FileRssSize = registry.IntGauge({{"sensor", "process.FileRssSize"}}); - CGroupMemLimit = registry.IntGauge({{"sensor", "process.CGroupMemLimit"}}); - UptimeSeconds = registry.IntGauge({{"sensor", "process.UptimeSeconds"}}); - NumThreads = registry.IntGauge({{"sensor", "process.NumThreads"}}); - SystemUptimeSeconds = registry.IntGauge({{"sensor", "system.UptimeSeconds"}}); - - UserTime = registry.Rate({{"sensor", "process.UserTime"}}); - SysTime = registry.Rate({{"sensor", "process.SystemTime"}}); - MinorPageFaults = registry.Rate({{"sensor", "process.MinorPageFaults"}}); - MajorPageFaults = registry.Rate({{"sensor", "process.MajorPageFaults"}}); - } - - void UpdateCounters(const TProcStat& procStat) { - VmSize->Set(procStat.Vsize); - AnonRssSize->Set(procStat.AnonRss); - FileRssSize->Set(procStat.FileRss); - CGroupMemLimit->Set(procStat.CGroupMemLim); - UptimeSeconds->Set(procStat.Uptime.Seconds()); - NumThreads->Set(procStat.NumThreads); - SystemUptimeSeconds->Set(procStat.SystemUptime.Seconds()); - - // it is ok here to reset and add metric value, because mutation - // is performed in siglethreaded context - - UserTime->Reset(); - UserTime->Add(procStat.Utime); - - SysTime->Reset(); - SysTime->Add(procStat.Stime); - - MinorPageFaults->Reset(); - MinorPageFaults->Add(procStat.MinFlt); - - MajorPageFaults->Reset(); - MajorPageFaults->Add(procStat.MajFlt); - } - - private: - NMonitoring::TIntGauge* VmSize; - NMonitoring::TIntGauge* AnonRssSize; - NMonitoring::TIntGauge* FileRssSize; - NMonitoring::TIntGauge* CGroupMemLimit; - NMonitoring::TRate* UserTime; - NMonitoring::TRate* SysTime; - NMonitoring::TRate* MinorPageFaults; - NMonitoring::TRate* MajorPageFaults; - NMonitoring::TIntGauge* UptimeSeconds; - NMonitoring::TIntGauge* NumThreads; - NMonitoring::TIntGauge* SystemUptimeSeconds; - }; - - class TRegistryCollectorShared: public TProcStatCollectingActor<TRegistryCollectorShared> { - using TBase = TProcStatCollectingActor<TRegistryCollectorShared>; - public: - TRegistryCollectorShared(TDuration interval, std::weak_ptr<NMonitoring::TMetricRegistry> registry) - : TBase{interval} - , Registry(std::move(registry)) - { - } - - void UpdateCounters(const TProcStat& procStat) { - std::shared_ptr<NMonitoring::TMetricRegistry> registry = Registry.lock(); - if (registry) { - registry->IntGauge({{"sensor", "process.VmSize"}})->Set(procStat.Vsize); - registry->IntGauge({{"sensor", "process.AnonRssSize"}})->Set(procStat.AnonRss); - registry->IntGauge({{"sensor", "process.FileRssSize"}})->Set(procStat.FileRss); - registry->IntGauge({{"sensor", "process.CGroupMemLimit"}})->Set(procStat.CGroupMemLim); - registry->IntGauge({{"sensor", "process.UptimeSeconds"}})->Set(procStat.Uptime.Seconds()); - registry->IntGauge({{"sensor", "process.NumThreads"}})->Set(procStat.NumThreads); - registry->IntGauge({{"sensor", "system.UptimeSeconds"}})->Set(procStat.SystemUptime.Seconds()); - - // it is ok here to reset and add metric value, because mutation - // is performed in siglethreaded context - - NMonitoring::TRate* userTime = registry->Rate({{"sensor", "process.UserTime"}}); - NMonitoring::TRate* sysTime = registry->Rate({{"sensor", "process.SystemTime"}}); - NMonitoring::TRate* minorPageFaults = registry->Rate({{"sensor", "process.MinorPageFaults"}}); - NMonitoring::TRate* majorPageFaults = registry->Rate({{"sensor", "process.MajorPageFaults"}}); - - userTime->Reset(); - userTime->Add(procStat.Utime); - - sysTime->Reset(); - sysTime->Add(procStat.Stime); - - minorPageFaults->Reset(); - minorPageFaults->Add(procStat.MinFlt); - - majorPageFaults->Reset(); - majorPageFaults->Add(procStat.MajFlt); - } - } - - private: - std::weak_ptr<NMonitoring::TMetricRegistry> Registry; - }; -} // namespace - - IActor* CreateProcStatCollector(ui32 intervalSec, NMonitoring::TDynamicCounterPtr counters) { - return new TDynamicCounterCollector(intervalSec, counters); - } - - IActor* CreateProcStatCollector(TDuration interval, NMonitoring::TMetricRegistry& registry) { - return new TRegistryCollector(interval, registry); - } - - IActor* CreateProcStatCollector(TDuration interval, std::weak_ptr<NMonitoring::TMetricRegistry> registry) { - return new TRegistryCollectorShared(interval, std::move(registry)); - } -} diff --git a/library/cpp/actors/core/process_stats.h b/library/cpp/actors/core/process_stats.h deleted file mode 100644 index 5681f0eb1a..0000000000 --- a/library/cpp/actors/core/process_stats.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include "defs.h" -#include "actor.h" - -#include <library/cpp/monlib/dynamic_counters/counters.h> - -namespace NMonitoring { - class TMetricRegistry; -} - -namespace NActors { - struct TProcStat { - ui64 Rss; - ui64 VolCtxSwtch; - ui64 NonvolCtxSwtch; - - int Pid; - char State; - int Ppid; - int Pgrp; - int Session; - int TtyNr; - int TPgid; - unsigned Flags; - unsigned long MinFlt; - unsigned long CMinFlt; - unsigned long MajFlt; - unsigned long CMajFlt; - unsigned long Utime; - unsigned long Stime; - long CUtime; - long CStime; - long Priority; - long Nice; - long NumThreads; - long ItRealValue; - // StartTime is measured from system boot - unsigned long long StartTime; - unsigned long Vsize; - long RssPages; - unsigned long RssLim; - ui64 FileRss; - ui64 AnonRss; - ui64 CGroupMemLim = 0; - - TDuration Uptime; - TDuration SystemUptime; - // ... - - TProcStat() { - Zero(*this); - Y_UNUSED(PageSize); - } - - bool Fill(pid_t pid); - - private: - long PageSize = 0; - - long ObtainPageSize(); - }; - - IActor* CreateProcStatCollector(ui32 intervalSec, NMonitoring::TDynamicCounterPtr counters); - IActor* CreateProcStatCollector(TDuration interval, NMonitoring::TMetricRegistry& registry); - IActor* CreateProcStatCollector(TDuration interval, std::weak_ptr<NMonitoring::TMetricRegistry> registry); -} diff --git a/library/cpp/actors/core/scheduler_actor.cpp b/library/cpp/actors/core/scheduler_actor.cpp deleted file mode 100644 index 73fd6bd183..0000000000 --- a/library/cpp/actors/core/scheduler_actor.cpp +++ /dev/null @@ -1,279 +0,0 @@ -#include "actor_bootstrapped.h" -#include "hfunc.h" -#include "probes.h" -#include "scheduler_actor.h" -#include "scheduler_queue.h" - -#include <library/cpp/actors/interconnect/poller_actor.h> -#include <util/system/hp_timer.h> - -#ifdef __linux__ -#include <sys/timerfd.h> -#include <errno.h> - -LWTRACE_USING(ACTORLIB_PROVIDER); - -namespace NActors { - class TTimerDescriptor: public TSharedDescriptor { - const int Descriptor; - - public: - TTimerDescriptor() - : Descriptor(timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)) - { - Y_ABORT_UNLESS(Descriptor != -1, "timerfd_create() failed with %s", strerror(errno)); - } - - ~TTimerDescriptor() override { - close(Descriptor); - } - - int GetDescriptor() override { - return Descriptor; - } - }; - - class TSchedulerActor: public TActor<TSchedulerActor> { - const TSchedulerConfig Cfg; - TIntrusivePtr<TSharedDescriptor> TimerDescriptor; - - TVector<NSchedulerQueue::TReader*> Readers; - - TActorId PollerActor; - TPollerToken::TPtr PollerToken; - - ui64 RealTime; - ui64 MonotonicTime; - - ui64 ActiveTick; - typedef TMap<ui64, TAutoPtr<NSchedulerQueue::TQueueType>> TMomentMap; // intrasecond queues - typedef THashMap<ui64, TAutoPtr<TMomentMap>> TScheduleMap; // over-second schedule - - TScheduleMap ScheduleMap; - - THolder<NThreading::TLegacyFuture<void, false>> MainCycle; - - static const ui64 IntrasecondThreshold = 1048576; // ~second - TAutoPtr<TMomentMap> ActiveSec; - volatile ui64* CurrentTimestamp = nullptr; - volatile ui64* CurrentMonotonic = nullptr; - TDeque<TAutoPtr<IEventHandle>> EventsToBeSent; - - public: - static constexpr IActor::EActivityType ActorActivityType() { - return IActor::EActivityType::ACTOR_SYSTEM_SCHEDULER_ACTOR; - } - - TSchedulerActor(const TSchedulerConfig& cfg) - : TActor(&TSchedulerActor::StateFunc) - , Cfg(cfg) - , TimerDescriptor(new TTimerDescriptor()) - , PollerActor(MakePollerActorId()) - { - Y_ASSERT(Cfg.ResolutionMicroseconds != 0); - Y_ASSERT(Cfg.ProgressThreshold != 0); - Become(&TSchedulerActor::StateFunc); - } - - void Handle(TEvSchedulerInitialize::TPtr& ev, const TActorContext& ctx) { - const TEvSchedulerInitialize& evInitialize = *ev->Get(); - Y_ASSERT(evInitialize.ScheduleReaders.size() != 0); - Readers.resize(evInitialize.ScheduleReaders.size()); - Copy(evInitialize.ScheduleReaders.begin(), evInitialize.ScheduleReaders.end(), Readers.begin()); - - Y_ASSERT(evInitialize.CurrentTimestamp != nullptr); - CurrentTimestamp = evInitialize.CurrentTimestamp; - - Y_ASSERT(evInitialize.CurrentMonotonic != nullptr); - CurrentMonotonic = evInitialize.CurrentMonotonic; - - struct itimerspec new_time; - memset(&new_time, 0, sizeof(new_time)); - new_time.it_value.tv_nsec = Cfg.ResolutionMicroseconds * 1000; - new_time.it_interval.tv_nsec = Cfg.ResolutionMicroseconds * 1000; - int ret = timerfd_settime(TimerDescriptor->GetDescriptor(), 0, &new_time, NULL); - Y_ABORT_UNLESS(ret != -1, "timerfd_settime() failed with %s", strerror(errno)); - const bool success = ctx.Send(PollerActor, new TEvPollerRegister(TimerDescriptor, SelfId(), {})); - Y_ABORT_UNLESS(success); - - RealTime = RelaxedLoad(CurrentTimestamp); - MonotonicTime = RelaxedLoad(CurrentMonotonic); - - ActiveTick = AlignUp<ui64>(MonotonicTime, IntrasecondThreshold); - } - - void Handle(TEvPollerRegisterResult::TPtr ev, const TActorContext& ctx) { - PollerToken = ev->Get()->PollerToken; - HandleSchedule(ctx); - } - - void UpdateTime() { - RealTime = TInstant::Now().MicroSeconds(); - MonotonicTime = Max(MonotonicTime, GetMonotonicMicroSeconds()); - AtomicStore(CurrentTimestamp, RealTime); - AtomicStore(CurrentMonotonic, MonotonicTime); - } - - void TryUpdateTime(NHPTimer::STime* lastTimeUpdate) { - NHPTimer::STime hpnow; - GetTimeFast(&hpnow); - const ui64 elapsedCycles = hpnow > *lastTimeUpdate ? hpnow - *lastTimeUpdate : 0; - if (elapsedCycles > Cfg.ResolutionMicroseconds * (NHPTimer::GetCyclesPerSecond() / IntrasecondThreshold)) { - UpdateTime(); - GetTimeFast(lastTimeUpdate); - } - } - - void HandleSchedule(const TActorContext& ctx) { - for (;;) { - NHPTimer::STime schedulingStart; - GetTimeFast(&schedulingStart); - NHPTimer::STime lastTimeUpdate = schedulingStart; - - ui64 expired; - ssize_t bytesRead; - bytesRead = read(TimerDescriptor->GetDescriptor(), &expired, sizeof(expired)); - if (bytesRead == -1) { - if (errno == EAGAIN) { - PollerToken->Request(true, false); - break; - } else if (errno == EINTR) { - continue; - } - } - Y_ABORT_UNLESS(bytesRead == sizeof(expired), "Error while reading from timerfd, strerror# %s", strerror(errno)); - UpdateTime(); - - ui32 eventsGottenFromQueues = 0; - // collect everything from queues - for (ui32 i = 0; i != Readers.size(); ++i) { - while (NSchedulerQueue::TEntry* x = Readers[i]->Pop()) { - const ui64 instant = AlignUp<ui64>(x->InstantMicroseconds, Cfg.ResolutionMicroseconds); - IEventHandle* const ev = x->Ev; - ISchedulerCookie* const cookie = x->Cookie; - - // check is cookie still valid? looks like it will hurt performance w/o sagnificant memory save - - if (instant <= ActiveTick) { - if (!ActiveSec) - ActiveSec.Reset(new TMomentMap()); - TAutoPtr<NSchedulerQueue::TQueueType>& queue = (*ActiveSec)[instant]; - if (!queue) - queue.Reset(new NSchedulerQueue::TQueueType()); - queue->Writer.Push(instant, ev, cookie); - } else { - const ui64 intrasecond = AlignUp<ui64>(instant, IntrasecondThreshold); - TAutoPtr<TMomentMap>& msec = ScheduleMap[intrasecond]; - if (!msec) - msec.Reset(new TMomentMap()); - TAutoPtr<NSchedulerQueue::TQueueType>& queue = (*msec)[instant]; - if (!queue) - queue.Reset(new NSchedulerQueue::TQueueType()); - queue->Writer.Push(instant, ev, cookie); - } - ++eventsGottenFromQueues; - TryUpdateTime(&lastTimeUpdate); - } - } - - ui64 eventSchedulingErrorUs = 0; - // send everything triggered on schedule - for (;;) { - while (!!ActiveSec && !ActiveSec->empty()) { - TMomentMap::iterator it = ActiveSec->begin(); - if (it->first <= MonotonicTime) { - if (NSchedulerQueue::TQueueType* q = it->second.Get()) { - while (NSchedulerQueue::TEntry* x = q->Reader.Pop()) { - Y_DEBUG_ABORT_UNLESS(x->InstantMicroseconds <= ActiveTick); - if (eventSchedulingErrorUs == 0 && MonotonicTime > x->InstantMicroseconds) { - eventSchedulingErrorUs = MonotonicTime - x->InstantMicroseconds; - } - IEventHandle* ev = x->Ev; - ISchedulerCookie* cookie = x->Cookie; - if (cookie) { - if (cookie->Detach()) { - EventsToBeSent.push_back(ev); - } else { - delete ev; - } - } else { - EventsToBeSent.push_back(ev); - } - TryUpdateTime(&lastTimeUpdate); - } - } - ActiveSec->erase(it); - } else { - break; - } - } - - if (ActiveTick <= MonotonicTime) { - Y_DEBUG_ABORT_UNLESS(!ActiveSec || ActiveSec->empty()); - ActiveSec.Destroy(); - ActiveTick += IntrasecondThreshold; - TScheduleMap::iterator it = ScheduleMap.find(ActiveTick); - if (it != ScheduleMap.end()) { - ActiveSec = it->second; - ScheduleMap.erase(it); - } - continue; - } - - // ok, if we are here - then nothing is ready, so send step complete - break; - } - - // Send all from buffer queue - const ui64 eventsToBeSentSize = EventsToBeSent.size(); - ui32 sentCount = 0; - if (eventsToBeSentSize > Cfg.RelaxedSendThresholdEventsPerCycle) { - sentCount = Cfg.RelaxedSendPaceEventsPerCycle + - (eventsToBeSentSize - Cfg.RelaxedSendThresholdEventsPerCycle) / 2; - } else { - sentCount = Min(eventsToBeSentSize, Cfg.RelaxedSendPaceEventsPerCycle); - } - for (ui32 i = 0; i < sentCount; ++i) { - ctx.Send(EventsToBeSent.front().Release()); - EventsToBeSent.pop_front(); - } - - NHPTimer::STime hpnow; - GetTimeFast(&hpnow); - const ui64 processingTime = hpnow > schedulingStart ? hpnow - schedulingStart : 0; - const ui64 elapsedTimeMicroseconds = processingTime / (NHPTimer::GetCyclesPerSecond() / IntrasecondThreshold); - LWPROBE(ActorsystemScheduler, elapsedTimeMicroseconds, expired, eventsGottenFromQueues, sentCount, - eventsToBeSentSize, eventSchedulingErrorUs); - TryUpdateTime(&lastTimeUpdate); - } - } - - STRICT_STFUNC(StateFunc, - HFunc(TEvSchedulerInitialize, Handle) - CFunc(TEvPollerReady::EventType, HandleSchedule) - CFunc(TEvents::TSystem::PoisonPill, Die) - HFunc(TEvPollerRegisterResult, Handle) - ) - }; - - IActor* CreateSchedulerActor(const TSchedulerConfig& cfg) { - if (cfg.UseSchedulerActor) { - return new TSchedulerActor(cfg); - } else { - return nullptr; - } - } - -} - -#else // linux - -namespace NActors { - IActor* CreateSchedulerActor(const TSchedulerConfig& cfg) { - Y_UNUSED(cfg); - return nullptr; - } - -} - -#endif // linux diff --git a/library/cpp/actors/core/scheduler_actor.h b/library/cpp/actors/core/scheduler_actor.h deleted file mode 100644 index c2c561b43d..0000000000 --- a/library/cpp/actors/core/scheduler_actor.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "actor.h" -#include "event_local.h" -#include "events.h" -#include "scheduler_basic.h" - -namespace NActors { - struct TEvSchedulerInitialize : TEventLocal<TEvSchedulerInitialize, TEvents::TSystem::Bootstrap> { - TVector<NSchedulerQueue::TReader*> ScheduleReaders; - volatile ui64* CurrentTimestamp; - volatile ui64* CurrentMonotonic; - - TEvSchedulerInitialize(const TVector<NSchedulerQueue::TReader*>& scheduleReaders, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) - : ScheduleReaders(scheduleReaders) - , CurrentTimestamp(currentTimestamp) - , CurrentMonotonic(currentMonotonic) - { - } - }; - - IActor* CreateSchedulerActor(const TSchedulerConfig& cfg); - - inline TActorId MakeSchedulerActorId() { - char x[12] = {'s', 'c', 'h', 'e', 'd', 'u', 'l', 'e', 'r', 's', 'e', 'r'}; - return TActorId(0, TStringBuf(x, 12)); - } - -} diff --git a/library/cpp/actors/core/scheduler_actor_ut.cpp b/library/cpp/actors/core/scheduler_actor_ut.cpp deleted file mode 100644 index 09b7369d36..0000000000 --- a/library/cpp/actors/core/scheduler_actor_ut.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "actor_coroutine.h" -#include "actorsystem.h" -#include "executor_pool_basic.h" -#include "scheduler_actor.h" -#include "scheduler_basic.h" -#include "events.h" -#include "event_local.h" -#include "hfunc.h" -#include <library/cpp/actors/interconnect/poller_actor.h> -#include <library/cpp/testing/unittest/registar.h> - -#include <util/system/sanitizers.h> - -using namespace NActors; - -Y_UNIT_TEST_SUITE(SchedulerActor) { - class TTestActor: public TActorBootstrapped<TTestActor> { - TManualEvent& DoneEvent; - TAtomic& EventsProcessed; - TInstant LastWakeup; - const TAtomicBase EventsTotalCount; - const TDuration ScheduleDelta; - - public: - TTestActor(TManualEvent& doneEvent, TAtomic& eventsProcessed, TAtomicBase eventsTotalCount, ui32 scheduleDeltaMs) - : DoneEvent(doneEvent) - , EventsProcessed(eventsProcessed) - , EventsTotalCount(eventsTotalCount) - , ScheduleDelta(TDuration::MilliSeconds(scheduleDeltaMs)) - { - } - - void Bootstrap(const TActorContext& ctx) { - LastWakeup = ctx.Now(); - Become(&TThis::StateFunc); - ctx.Schedule(ScheduleDelta, new TEvents::TEvWakeup()); - } - - void Handle(TEvents::TEvWakeup::TPtr& /*ev*/, const TActorContext& ctx) { - const TInstant now = ctx.Now(); - UNIT_ASSERT(now - LastWakeup >= ScheduleDelta); - LastWakeup = now; - - if (AtomicIncrement(EventsProcessed) == EventsTotalCount) { - DoneEvent.Signal(); - } else { - ctx.Schedule(ScheduleDelta, new TEvents::TEvWakeup()); - } - } - - STRICT_STFUNC(StateFunc, {HFunc(TEvents::TEvWakeup, Handle)}) - }; - - void Test(TAtomicBase eventsTotalCount, ui32 scheduleDeltaMs) { - THolder<TActorSystemSetup> setup = MakeHolder<TActorSystemSetup>(); - setup->NodeId = 0; - setup->ExecutorsCount = 1; - setup->Executors.Reset(new TAutoPtr<IExecutorPool>[setup->ExecutorsCount]); - for (ui32 i = 0; i < setup->ExecutorsCount; ++i) { - setup->Executors[i] = new TBasicExecutorPool(i, 5, 10, "basic"); - } - // create poller actor (whether platform supports it) - TActorId pollerActorId; - if (IActor* poller = CreatePollerActor()) { - pollerActorId = MakePollerActorId(); - setup->LocalServices.emplace_back(pollerActorId, TActorSetupCmd(poller, TMailboxType::ReadAsFilled, 0)); - } - TActorId schedulerActorId; - if (IActor* schedulerActor = CreateSchedulerActor(TSchedulerConfig())) { - schedulerActorId = MakeSchedulerActorId(); - setup->LocalServices.emplace_back(schedulerActorId, TActorSetupCmd(schedulerActor, TMailboxType::ReadAsFilled, 0)); - } - setup->Scheduler = CreateSchedulerThread(TSchedulerConfig()); - - TActorSystem actorSystem(setup); - - actorSystem.Start(); - - TManualEvent doneEvent; - TAtomic eventsProcessed = 0; - actorSystem.Register(new TTestActor(doneEvent, eventsProcessed, eventsTotalCount, scheduleDeltaMs)); - doneEvent.WaitI(); - - UNIT_ASSERT(AtomicGet(eventsProcessed) == eventsTotalCount); - - actorSystem.Stop(); - } - - Y_UNIT_TEST(LongEvents) { - Test(10, 500); - } - - Y_UNIT_TEST(MediumEvents) { - Test(100, 50); - } - - Y_UNIT_TEST(QuickEvents) { - Test(1000, 5); - } -} diff --git a/library/cpp/actors/core/scheduler_basic.cpp b/library/cpp/actors/core/scheduler_basic.cpp deleted file mode 100644 index 5d66224f05..0000000000 --- a/library/cpp/actors/core/scheduler_basic.cpp +++ /dev/null @@ -1,275 +0,0 @@ -#include "scheduler_basic.h" -#include "scheduler_queue.h" -#include "actor.h" - -#include <library/cpp/actors/util/datetime.h> -#include <library/cpp/actors/util/thread.h> - -#ifdef BALLOC -#include <library/cpp/balloc/optional/operators.h> -#endif - -namespace NActors { - - struct TBasicSchedulerThread::TMonCounters { - NMonitoring::TDynamicCounters::TCounterPtr TimeDelayMs; - NMonitoring::TDynamicCounters::TCounterPtr QueueSize; - NMonitoring::TDynamicCounters::TCounterPtr EventsSent; - NMonitoring::TDynamicCounters::TCounterPtr EventsDropped; - NMonitoring::TDynamicCounters::TCounterPtr EventsAdded; - NMonitoring::TDynamicCounters::TCounterPtr Iterations; - NMonitoring::TDynamicCounters::TCounterPtr Sleeps; - NMonitoring::TDynamicCounters::TCounterPtr ElapsedMicrosec; - - TMonCounters(const NMonitoring::TDynamicCounterPtr& counters) - : TimeDelayMs(counters->GetCounter("Scheduler/TimeDelayMs", false)) - , QueueSize(counters->GetCounter("Scheduler/QueueSize", false)) - , EventsSent(counters->GetCounter("Scheduler/EventsSent", true)) - , EventsDropped(counters->GetCounter("Scheduler/EventsDropped", true)) - , EventsAdded(counters->GetCounter("Scheduler/EventsAdded", true)) - , Iterations(counters->GetCounter("Scheduler/Iterations", true)) - , Sleeps(counters->GetCounter("Scheduler/Sleeps", true)) - , ElapsedMicrosec(counters->GetCounter("Scheduler/ElapsedMicrosec", true)) - { } - }; - - TBasicSchedulerThread::TBasicSchedulerThread(const TSchedulerConfig& config) - : Config(config) - , MonCounters(Config.MonCounters ? new TMonCounters(Config.MonCounters) : nullptr) - , ActorSystem(nullptr) - , CurrentTimestamp(nullptr) - , CurrentMonotonic(nullptr) - , TotalReaders(0) - , StopFlag(false) - , ScheduleMap(3600) - { - Y_ABORT_UNLESS(!Config.UseSchedulerActor, "Cannot create scheduler thread because Config.UseSchedulerActor# true"); - } - - TBasicSchedulerThread::~TBasicSchedulerThread() { - Y_ABORT_UNLESS(!MainCycle); - } - - void TBasicSchedulerThread::CycleFunc() { -#ifdef BALLOC - ThreadDisableBalloc(); -#endif - ::SetCurrentThreadName("Scheduler"); - - ui64 currentMonotonic = RelaxedLoad(CurrentMonotonic); - ui64 throttledMonotonic = currentMonotonic; - - ui64 activeTick = AlignUp<ui64>(throttledMonotonic, IntrasecondThreshold); - TAutoPtr<TMomentMap> activeSec; - - NHPTimer::STime hpprev = GetCycleCountFast(); - ui64 nextTimestamp = TInstant::Now().MicroSeconds(); - ui64 nextMonotonic = Max(currentMonotonic, GetMonotonicMicroSeconds()); - - while (!AtomicLoad(&StopFlag)) { - { - const ui64 delta = nextMonotonic - throttledMonotonic; - const ui64 elapsedDelta = nextMonotonic - currentMonotonic; - const ui64 threshold = Max(Min(Config.ProgressThreshold, 2 * elapsedDelta), ui64(1)); - - throttledMonotonic = (delta > threshold) ? throttledMonotonic + threshold : nextMonotonic; - - if (MonCounters) { - *MonCounters->TimeDelayMs = (nextMonotonic - throttledMonotonic) / 1000; - } - } - AtomicStore(CurrentTimestamp, nextTimestamp); - AtomicStore(CurrentMonotonic, nextMonotonic); - currentMonotonic = nextMonotonic; - - if (MonCounters) { - ++*MonCounters->Iterations; - } - - bool somethingDone = false; - - // first step - send everything triggered on schedule - ui64 eventsSent = 0; - ui64 eventsDropped = 0; - for (;;) { - while (!!activeSec && !activeSec->empty()) { - TMomentMap::iterator it = activeSec->begin(); - if (it->first <= throttledMonotonic) { - if (NSchedulerQueue::TQueueType* q = it->second.Get()) { - while (NSchedulerQueue::TEntry* x = q->Reader.Pop()) { - somethingDone = true; - Y_DEBUG_ABORT_UNLESS(x->InstantMicroseconds <= activeTick); - IEventHandle* ev = x->Ev; - ISchedulerCookie* cookie = x->Cookie; - // TODO: lazy send with backoff queue to not hang over contended mailboxes - if (cookie) { - if (cookie->Detach()) { - ActorSystem->Send(ev); - ++eventsSent; - } else { - delete ev; - ++eventsDropped; - } - } else { - ActorSystem->Send(ev); - ++eventsSent; - } - } - } - activeSec->erase(it); - } else - break; - } - - if (activeTick <= throttledMonotonic) { - Y_DEBUG_ABORT_UNLESS(!activeSec || activeSec->empty()); - activeSec.Destroy(); - activeTick += IntrasecondThreshold; - TScheduleMap::iterator it = ScheduleMap.find(activeTick); - if (it != ScheduleMap.end()) { - activeSec = it->second; - ScheduleMap.erase(it); - } - continue; - } - - // ok, if we are here - then nothing is ready, so send step complete - break; - } - - // second step - collect everything from queues - - ui64 eventsAdded = 0; - for (ui32 i = 0; i != TotalReaders; ++i) { - while (NSchedulerQueue::TEntry* x = Readers[i]->Pop()) { - somethingDone = true; - const ui64 instant = AlignUp<ui64>(x->InstantMicroseconds, Config.ResolutionMicroseconds); - IEventHandle* const ev = x->Ev; - ISchedulerCookie* const cookie = x->Cookie; - - // check is cookie still valid? looks like it will hurt performance w/o sagnificant memory save - - if (instant <= activeTick) { - if (!activeSec) - activeSec.Reset(new TMomentMap()); - TAutoPtr<NSchedulerQueue::TQueueType>& queue = (*activeSec)[instant]; - if (!queue) - queue.Reset(new NSchedulerQueue::TQueueType()); - queue->Writer.Push(instant, ev, cookie); - } else { - const ui64 intrasecond = AlignUp<ui64>(instant, IntrasecondThreshold); - TAutoPtr<TMomentMap>& msec = ScheduleMap[intrasecond]; - if (!msec) - msec.Reset(new TMomentMap()); - TAutoPtr<NSchedulerQueue::TQueueType>& queue = (*msec)[instant]; - if (!queue) - queue.Reset(new NSchedulerQueue::TQueueType()); - queue->Writer.Push(instant, ev, cookie); - } - - ++eventsAdded; - } - } - - NHPTimer::STime hpnow = GetCycleCountFast(); - - if (MonCounters) { - *MonCounters->QueueSize -= eventsSent + eventsDropped; - *MonCounters->QueueSize += eventsAdded; - *MonCounters->EventsSent += eventsSent; - *MonCounters->EventsDropped += eventsDropped; - *MonCounters->EventsAdded += eventsAdded; - *MonCounters->ElapsedMicrosec += NHPTimer::GetSeconds(hpnow - hpprev) * 1000000; - } - - hpprev = hpnow; - nextTimestamp = TInstant::Now().MicroSeconds(); - nextMonotonic = Max(currentMonotonic, GetMonotonicMicroSeconds()); - - // ok complete, if nothing left - sleep - if (!somethingDone) { - const ui64 nextInstant = AlignDown<ui64>(throttledMonotonic + Config.ResolutionMicroseconds, Config.ResolutionMicroseconds); - if (nextMonotonic >= nextInstant) // already in next time-slice - continue; - - const ui64 delta = nextInstant - nextMonotonic; - if (delta < Config.SpinThreshold) // not so much time left, just spin - continue; - - if (MonCounters) { - ++*MonCounters->Sleeps; - } - - NanoSleep(delta * 1000); // ok, looks like we should sleep a bit. - - // Don't count sleep in elapsed microseconds - hpprev = GetCycleCountFast(); - nextTimestamp = TInstant::Now().MicroSeconds(); - nextMonotonic = Max(currentMonotonic, GetMonotonicMicroSeconds()); - } - } - // ok, die! - } - - void TBasicSchedulerThread::Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) { - ActorSystem = actorSystem; - CurrentTimestamp = currentTimestamp; - CurrentMonotonic = currentMonotonic; - *CurrentTimestamp = TInstant::Now().MicroSeconds(); - *CurrentMonotonic = GetMonotonicMicroSeconds(); - } - - void TBasicSchedulerThread::PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) { - Y_ABORT_UNLESS(scheduleReadersCount > 0); - TotalReaders = scheduleReadersCount; - Readers.Reset(new NSchedulerQueue::TReader*[scheduleReadersCount]); - Copy(readers, readers + scheduleReadersCount, Readers.Get()); - } - - void TBasicSchedulerThread::PrepareStart() { - // Called after actor system is initialized, but before executor threads - // are started, giving us a chance to update current timestamp with a - // more recent value, taking initialization time into account. This is - // safe to do, since scheduler thread is not started yet, so no other - // threads are updating time concurrently. - AtomicStore(CurrentTimestamp, TInstant::Now().MicroSeconds()); - AtomicStore(CurrentMonotonic, Max(RelaxedLoad(CurrentMonotonic), GetMonotonicMicroSeconds())); - } - - void TBasicSchedulerThread::Start() { - MainCycle.Reset(new NThreading::TLegacyFuture<void, false>(std::bind(&TBasicSchedulerThread::CycleFunc, this))); - } - - void TBasicSchedulerThread::PrepareStop() { - AtomicStore(&StopFlag, true); - } - - void TBasicSchedulerThread::Stop() { - MainCycle->Get(); - MainCycle.Destroy(); - } - -} - -#ifdef __linux__ - -namespace NActors { - ISchedulerThread* CreateSchedulerThread(const TSchedulerConfig& config) { - if (config.UseSchedulerActor) { - return new TMockSchedulerThread(); - } else { - return new TBasicSchedulerThread(config); - } - } - -} - -#else // __linux__ - -namespace NActors { - ISchedulerThread* CreateSchedulerThread(const TSchedulerConfig& config) { - return new TBasicSchedulerThread(config); - } -} - -#endif // __linux__ diff --git a/library/cpp/actors/core/scheduler_basic.h b/library/cpp/actors/core/scheduler_basic.h deleted file mode 100644 index 2ccde39235..0000000000 --- a/library/cpp/actors/core/scheduler_basic.h +++ /dev/null @@ -1,81 +0,0 @@ -#pragma once - -#include "actorsystem.h" -#include "monotonic.h" -#include "scheduler_queue.h" -#include <library/cpp/actors/util/queue_chunk.h> -#include <library/cpp/threading/future/legacy_future.h> -#include <util/generic/hash.h> -#include <util/generic/map.h> - -namespace NActors { - - class TBasicSchedulerThread: public ISchedulerThread { - // TODO: replace with NUMA-local threads and per-thread schedules - const TSchedulerConfig Config; - - struct TMonCounters; - const THolder<TMonCounters> MonCounters; - - TActorSystem* ActorSystem; - volatile ui64* CurrentTimestamp; - volatile ui64* CurrentMonotonic; - - ui32 TotalReaders; - TArrayHolder<NSchedulerQueue::TReader*> Readers; - - volatile bool StopFlag; - - typedef TMap<ui64, TAutoPtr<NSchedulerQueue::TQueueType>> TMomentMap; // intrasecond queues - typedef THashMap<ui64, TAutoPtr<TMomentMap>> TScheduleMap; // over-second schedule - - TScheduleMap ScheduleMap; - - THolder<NThreading::TLegacyFuture<void, false>> MainCycle; - - static const ui64 IntrasecondThreshold = 1048576; // ~second - - void CycleFunc(); - - public: - TBasicSchedulerThread(const TSchedulerConfig& config = TSchedulerConfig()); - ~TBasicSchedulerThread(); - - void Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) override; - void PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) override; - - void PrepareStart() override; - void Start() override; - void PrepareStop() override; - void Stop() override; - }; - - class TMockSchedulerThread: public ISchedulerThread { - public: - virtual ~TMockSchedulerThread() override { - } - - void Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) override { - Y_UNUSED(actorSystem); - *currentTimestamp = TInstant::Now().MicroSeconds(); - *currentMonotonic = GetMonotonicMicroSeconds(); - } - - void PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) override { - Y_UNUSED(readers); - Y_UNUSED(scheduleReadersCount); - } - - void Start() override { - } - - void PrepareStop() override { - } - - void Stop() override { - } - }; - - ISchedulerThread* CreateSchedulerThread(const TSchedulerConfig& cfg); - -} diff --git a/library/cpp/actors/core/scheduler_cookie.cpp b/library/cpp/actors/core/scheduler_cookie.cpp deleted file mode 100644 index b975a80c07..0000000000 --- a/library/cpp/actors/core/scheduler_cookie.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "scheduler_cookie.h" - -namespace NActors { - class TSchedulerCookie2Way: public ISchedulerCookie { - TAtomic Value; - - public: - TSchedulerCookie2Way() - : Value(2) - { - } - - bool IsArmed() noexcept override { - return (AtomicGet(Value) == 2); - } - - bool Detach() noexcept override { - const ui64 x = AtomicDecrement(Value); - if (x == 1) - return true; - - if (x == 0) { - delete this; - return false; - } - - Y_ABORT(); - } - - bool DetachEvent() noexcept override { - Y_ABORT(); - } - }; - - ISchedulerCookie* ISchedulerCookie::Make2Way() { - return new TSchedulerCookie2Way(); - } - - class TSchedulerCookie3Way: public ISchedulerCookie { - TAtomic Value; - - public: - TSchedulerCookie3Way() - : Value(3) - { - } - - bool IsArmed() noexcept override { - return (AtomicGet(Value) == 3); - } - - bool Detach() noexcept override { - const ui64 x = AtomicDecrement(Value); - if (x == 2) - return true; - if (x == 1) - return false; - if (x == 0) { - delete this; - return false; - } - - Y_ABORT(); - } - - bool DetachEvent() noexcept override { - const ui64 x = AtomicDecrement(Value); - if (x == 2) - return false; - if (x == 1) - return true; - if (x == 0) { - delete this; - return false; - } - - Y_ABORT(); - } - }; - - ISchedulerCookie* ISchedulerCookie::Make3Way() { - return new TSchedulerCookie3Way(); - } -} diff --git a/library/cpp/actors/core/scheduler_cookie.h b/library/cpp/actors/core/scheduler_cookie.h deleted file mode 100644 index 2c20ca67f3..0000000000 --- a/library/cpp/actors/core/scheduler_cookie.h +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once - -#include "defs.h" -#include <util/generic/noncopyable.h> - -namespace NActors { - class ISchedulerCookie : TNonCopyable { - protected: - virtual ~ISchedulerCookie() { - } - - public: - virtual bool Detach() noexcept = 0; - virtual bool DetachEvent() noexcept = 0; - virtual bool IsArmed() noexcept = 0; - - static ISchedulerCookie* Make2Way(); - static ISchedulerCookie* Make3Way(); - }; - - class TSchedulerCookieHolder : TNonCopyable { - ISchedulerCookie* Cookie; - - public: - TSchedulerCookieHolder() - : Cookie(nullptr) - { - } - - TSchedulerCookieHolder(ISchedulerCookie* x) - : Cookie(x) - { - } - - ~TSchedulerCookieHolder() { - Detach(); - } - - bool operator==(const TSchedulerCookieHolder& x) const noexcept { - return (Cookie == x.Cookie); - } - - ISchedulerCookie* Get() const { - return Cookie; - } - - ISchedulerCookie* Release() { - ISchedulerCookie* result = Cookie; - Cookie = nullptr; - return result; - } - - void Reset(ISchedulerCookie* cookie) { - Detach(); - Cookie = cookie; - } - - bool Detach() noexcept { - if (Cookie) { - const bool res = Cookie->Detach(); - Cookie = nullptr; - return res; - } else { - return false; - } - } - - bool DetachEvent() noexcept { - if (Cookie) { - const bool res = Cookie->DetachEvent(); - Cookie = nullptr; - return res; - } else { - return false; - } - } - }; -} diff --git a/library/cpp/actors/core/scheduler_queue.h b/library/cpp/actors/core/scheduler_queue.h deleted file mode 100644 index 8d827e1ce4..0000000000 --- a/library/cpp/actors/core/scheduler_queue.h +++ /dev/null @@ -1,123 +0,0 @@ -#pragma once - -#include "scheduler_cookie.h" - -#include <library/cpp/actors/util/queue_chunk.h> -#include <library/cpp/actors/core/event.h> - -namespace NActors { - class IEventHandle; - class ISchedulerCookie; - - namespace NSchedulerQueue { - struct TEntry { - ui64 InstantMicroseconds; - IEventHandle* Ev; - ISchedulerCookie* Cookie; - }; - - struct TChunk : TQueueChunkDerived<TEntry, 512, TChunk> {}; - - class TReader; - class TWriter; - class TWriterWithPadding; - - class TReader : ::TNonCopyable { - TChunk* ReadFrom; - ui32 ReadPosition; - - friend class TWriter; - - public: - TReader() - : ReadFrom(new TChunk()) - , ReadPosition(0) - { - } - - ~TReader() { - while (TEntry* x = Pop()) { - if (x->Cookie) - x->Cookie->Detach(); - delete x->Ev; - } - delete ReadFrom; - } - - TEntry* Pop() { - TChunk* head = ReadFrom; - if (ReadPosition != TChunk::EntriesCount) { - if (AtomicLoad(&head->Entries[ReadPosition].InstantMicroseconds) != 0) - return const_cast<TEntry*>(&head->Entries[ReadPosition++]); - else - return nullptr; - } else if (TChunk* next = AtomicLoad(&head->Next)) { - ReadFrom = next; - delete head; - ReadPosition = 0; - return Pop(); - } - - return nullptr; - } - }; - - class TWriter : ::TNonCopyable { - TChunk* WriteTo; - ui32 WritePosition; - - public: - TWriter() - : WriteTo(nullptr) - , WritePosition(0) - { - } - - void Init(const TReader& reader) { - WriteTo = reader.ReadFrom; - WritePosition = 0; - } - - void Push(ui64 instantMicrosends, IEventHandle* ev, ISchedulerCookie* cookie) { - if (Y_UNLIKELY(instantMicrosends == 0)) { - // Protect against Pop() getting stuck forever - instantMicrosends = 1; - } - if (WritePosition != TChunk::EntriesCount) { - volatile TEntry& entry = WriteTo->Entries[WritePosition]; - entry.Cookie = cookie; - entry.Ev = ev; - AtomicStore(&entry.InstantMicroseconds, instantMicrosends); - ++WritePosition; - } else { - TChunk* next = new TChunk(); - volatile TEntry& entry = next->Entries[0]; - entry.Cookie = cookie; - entry.Ev = ev; - entry.InstantMicroseconds = instantMicrosends; - AtomicStore(&WriteTo->Next, next); - WriteTo = next; - WritePosition = 1; - } - } - }; - - class TWriterWithPadding: public TWriter { - private: - ui8 CacheLinePadding[64 - sizeof(TWriter)]; - - void UnusedCacheLinePadding() { - Y_UNUSED(CacheLinePadding); - } - }; - - struct TQueueType { - TReader Reader; - TWriter Writer; - - TQueueType() { - Writer.Init(Reader); - } - }; - } -} diff --git a/library/cpp/actors/core/servicemap.h b/library/cpp/actors/core/servicemap.h deleted file mode 100644 index d72e50cae5..0000000000 --- a/library/cpp/actors/core/servicemap.h +++ /dev/null @@ -1,168 +0,0 @@ -#pragma once - -#include "defs.h" - -namespace NActors { - // wait-free one writer multi reader hash-tree for service mapping purposes - // on fast updates on same key - could lead to false-negatives, we don't care as such cases are broken from service-map app logic - - template <typename TKey, typename TValue, typename THash, ui64 BaseSize = 256 * 1024, ui64 ExtCount = 4, ui64 ExtBranching = 4> - class TServiceMap : TNonCopyable { - struct TEntry : TNonCopyable { - ui32 CounterIn; - ui32 CounterOut; - TKey Key; - TValue Value; - - TEntry() - : CounterIn(0) - , CounterOut(0) - , Key() - , Value() - { - } - }; - - struct TBranch : TNonCopyable { - TEntry Entries[ExtCount]; - TBranch* Branches[ExtBranching]; - - TBranch() { - Fill(Branches, Branches + ExtBranching, (TBranch*)nullptr); - } - }; - - ui32 Counter; - TBranch* Line[BaseSize]; - - bool ScanBranch(TBranch* branch, const TKey& key, ui64 hash, TValue& ret) { - for (ui32 i = 0; i != ExtCount; ++i) { - const TEntry& entry = branch->Entries[i]; - const ui32 counterIn = AtomicLoad(&entry.CounterIn); - if (counterIn != 0 && entry.Key == key) { - ret = entry.Value; - const ui32 counterOut = AtomicLoad(&entry.CounterOut); - if (counterOut == counterIn) - return true; - } - } - - const ui64 hash0 = hash % ExtBranching; - if (TBranch* next = AtomicLoad(branch->Branches + hash0)) - return ScanBranch(next, key, hash / ExtBranching, ret); - - return false; - } - - void ScanZeroOld(TBranch* branch, const TKey& key, ui64 hash, TEntry** zeroEntry, TEntry*& oldEntry) { - for (ui32 i = 0; i != ExtCount; ++i) { - TEntry& entry = branch->Entries[i]; - if (entry.CounterIn == 0) { - if (zeroEntry && !*zeroEntry) { - *zeroEntry = &entry; - if (oldEntry != nullptr) - return; - } - } else { - if (entry.Key == key) { - oldEntry = &entry; - if (!zeroEntry || *zeroEntry) - return; - } - } - } - - const ui64 hash0 = hash % ExtBranching; - if (TBranch* next = branch->Branches[hash0]) { - ScanZeroOld(next, key, hash / ExtBranching, zeroEntry, oldEntry); - } else { // found tail, if zeroEntry requested, but not yet found - insert one - if (zeroEntry && !*zeroEntry) { - TBranch* next = new TBranch(); - *zeroEntry = next->Entries; - AtomicStore(branch->Branches + hash0, next); - } - } - } - - public: - TServiceMap() - : Counter(0) - { - Fill(Line, Line + BaseSize, (TBranch*)nullptr); - } - - ~TServiceMap() { - for (ui64 i = 0; i < BaseSize; ++i) { - delete Line[i]; - } - } - - TValue Find(const TKey& key) { - THash hashOp; - const ui64 hash = hashOp(key); - const ui64 hash0 = hash % BaseSize; - - if (TBranch* branch = AtomicLoad(Line + hash0)) { - TValue ret; - if (ScanBranch(branch, key, hash / BaseSize, ret)) - return ret; - } - - return TValue(); - } - - // returns true on update, false on insert - TValue Update(const TKey& key, const TValue& value) { - THash hashOp; - const ui64 hash = hashOp(key); - const ui64 hash0 = hash % BaseSize; - - TEntry* zeroEntry = nullptr; - TEntry* oldEntry = nullptr; - - if (TBranch* branch = Line[hash0]) { - ScanZeroOld(branch, key, hash / BaseSize, &zeroEntry, oldEntry); - } else { - TBranch* next = new TBranch(); - zeroEntry = next->Entries; - AtomicStore(Line + hash0, next); - } - - // now we got both entries, first - push new one - const ui32 counter = AtomicUi32Increment(&Counter); - AtomicStore(&zeroEntry->CounterOut, counter); - zeroEntry->Key = key; - zeroEntry->Value = value; - AtomicStore(&zeroEntry->CounterIn, counter); - - if (oldEntry != nullptr) { - const TValue ret = oldEntry->Value; - AtomicStore<ui32>(&oldEntry->CounterOut, 0); - AtomicStore<ui32>(&oldEntry->CounterIn, 0); - return ret; - } else { - return TValue(); - } - } - - bool Erase(const TKey& key) { - THash hashOp; - const ui64 hash = hashOp(key); - const ui64 hash0 = hash % BaseSize; - - TEntry* oldEntry = 0; - - if (TBranch* branch = Line[hash0]) { - ScanZeroOld(branch, key, hash / BaseSize, 0, oldEntry); - } - - if (oldEntry != 0) { - AtomicStore<ui32>(&oldEntry->CounterOut, 0); - AtomicStore<ui32>(&oldEntry->CounterIn, 0); - return true; - } else { - return false; - } - } - }; -} diff --git a/library/cpp/actors/core/thread_context.h b/library/cpp/actors/core/thread_context.h deleted file mode 100644 index 13e493f855..0000000000 --- a/library/cpp/actors/core/thread_context.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "defs.h" - -#include <util/system/tls.h> - - -namespace NActors { - - class IExecutorPool; - - template <typename T> - struct TWaitingStats; - - struct TThreadContext { - IExecutorPool *Pool = nullptr; - ui32 CapturedActivation = 0; - ESendingType CapturedType = ESendingType::Lazy; - ESendingType SendingType = ESendingType::Common; - bool IsEnoughCpu = true; - ui32 WriteTurn = 0; - TWorkerId WorkerId; - ui16 LocalQueueSize = 0; - TWaitingStats<ui64> *WaitingStats = nullptr; - bool IsCurrentRecipientAService = false; - }; - - extern Y_POD_THREAD(TThreadContext*) TlsThreadContext; // in actor.cpp - -} diff --git a/library/cpp/actors/core/tsan.supp b/library/cpp/actors/core/tsan.supp deleted file mode 100644 index ca5be0c0f0..0000000000 --- a/library/cpp/actors/core/tsan.supp +++ /dev/null @@ -1,3 +0,0 @@ -# tsan reports potential deadlock which is false-positive. -# See: https://github.com/google/sanitizers/issues/814 -deadlock:NActors::TActorCoro::StateFunc diff --git a/library/cpp/actors/core/ut/CMakeLists.darwin-arm64.txt b/library/cpp/actors/core/ut/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 83199b12b6..0000000000 --- a/library/cpp/actors/core/ut/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,88 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-core-ut) -target_include_directories(library-cpp-actors-core-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core -) -target_link_libraries(library-cpp-actors-core-ut PUBLIC - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - cpp-actors-testlib -) -target_link_options(library-cpp-actors-core-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-core-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_coroutine_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/benchmark_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actorsystem_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/performance_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/ask_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/balancer_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_pb_payload_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_pb_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_basic_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_united_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/mon_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_actor_ut.cpp -) -set_property( - TARGET - library-cpp-actors-core-ut - PROPERTY - SPLIT_FACTOR - 10 -) -add_yunittest( - NAME - library-cpp-actors-core-ut - TEST_TARGET - library-cpp-actors-core-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-core-ut - system_allocator -) -vcs_info(library-cpp-actors-core-ut) diff --git a/library/cpp/actors/core/ut/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/core/ut/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index e56713f557..0000000000 --- a/library/cpp/actors/core/ut/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,89 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-core-ut) -target_include_directories(library-cpp-actors-core-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core -) -target_link_libraries(library-cpp-actors-core-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - cpp-actors-testlib -) -target_link_options(library-cpp-actors-core-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-core-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_coroutine_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/benchmark_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actorsystem_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/performance_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/ask_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/balancer_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_pb_payload_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_pb_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_basic_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_united_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/mon_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_actor_ut.cpp -) -set_property( - TARGET - library-cpp-actors-core-ut - PROPERTY - SPLIT_FACTOR - 10 -) -add_yunittest( - NAME - library-cpp-actors-core-ut - TEST_TARGET - library-cpp-actors-core-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-core-ut - system_allocator -) -vcs_info(library-cpp-actors-core-ut) diff --git a/library/cpp/actors/core/ut/CMakeLists.linux-aarch64.txt b/library/cpp/actors/core/ut/CMakeLists.linux-aarch64.txt deleted file mode 100644 index bfd1f0f226..0000000000 --- a/library/cpp/actors/core/ut/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,92 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-core-ut) -target_include_directories(library-cpp-actors-core-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core -) -target_link_libraries(library-cpp-actors-core-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - cpp-actors-testlib -) -target_link_options(library-cpp-actors-core-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-core-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_coroutine_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/benchmark_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actorsystem_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/performance_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/ask_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/balancer_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_pb_payload_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_pb_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_basic_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_united_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/mon_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_actor_ut.cpp -) -set_property( - TARGET - library-cpp-actors-core-ut - PROPERTY - SPLIT_FACTOR - 10 -) -add_yunittest( - NAME - library-cpp-actors-core-ut - TEST_TARGET - library-cpp-actors-core-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-core-ut - cpp-malloc-jemalloc -) -vcs_info(library-cpp-actors-core-ut) diff --git a/library/cpp/actors/core/ut/CMakeLists.linux-x86_64.txt b/library/cpp/actors/core/ut/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 145a291b45..0000000000 --- a/library/cpp/actors/core/ut/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,94 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-core-ut) -target_include_directories(library-cpp-actors-core-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core -) -target_link_libraries(library-cpp-actors-core-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - cpp-actors-testlib -) -target_link_options(library-cpp-actors-core-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-core-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_coroutine_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/benchmark_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actorsystem_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/performance_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/ask_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/balancer_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_pb_payload_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_pb_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_basic_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_united_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/mon_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_actor_ut.cpp -) -set_property( - TARGET - library-cpp-actors-core-ut - PROPERTY - SPLIT_FACTOR - 10 -) -add_yunittest( - NAME - library-cpp-actors-core-ut - TEST_TARGET - library-cpp-actors-core-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-core-ut - cpp-malloc-tcmalloc - libs-tcmalloc-no_percpu_cache -) -vcs_info(library-cpp-actors-core-ut) diff --git a/library/cpp/actors/core/ut/CMakeLists.txt b/library/cpp/actors/core/ut/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/core/ut/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/core/ut/CMakeLists.windows-x86_64.txt b/library/cpp/actors/core/ut/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 8e7e6bd499..0000000000 --- a/library/cpp/actors/core/ut/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,82 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-core-ut) -target_include_directories(library-cpp-actors-core-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core -) -target_link_libraries(library-cpp-actors-core-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - cpp-actors-testlib -) -target_sources(library-cpp-actors-core-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_coroutine_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/benchmark_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actor_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/actorsystem_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/performance_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/ask_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/balancer_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_pb_payload_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/event_pb_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_basic_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/executor_pool_united_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/mon_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/scheduler_actor_ut.cpp -) -set_property( - TARGET - library-cpp-actors-core-ut - PROPERTY - SPLIT_FACTOR - 10 -) -add_yunittest( - NAME - library-cpp-actors-core-ut - TEST_TARGET - library-cpp-actors-core-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-core-ut - system_allocator -) -vcs_info(library-cpp-actors-core-ut) diff --git a/library/cpp/actors/core/ut/ya.make b/library/cpp/actors/core/ut/ya.make deleted file mode 100644 index 44803e7619..0000000000 --- a/library/cpp/actors/core/ut/ya.make +++ /dev/null @@ -1,43 +0,0 @@ -UNITTEST_FOR(library/cpp/actors/core) - -FORK_SUBTESTS() -IF (SANITIZER_TYPE) - SIZE(LARGE) - TIMEOUT(1200) - TAG(ya:fat) - SPLIT_FACTOR(20) - REQUIREMENTS( - ram:32 - ) -ELSE() - SIZE(MEDIUM) - TIMEOUT(600) - REQUIREMENTS( - ram:16 - ) -ENDIF() - - -PEERDIR( - library/cpp/actors/interconnect - library/cpp/actors/testlib -) - -SRCS( - actor_coroutine_ut.cpp - benchmark_ut.cpp - actor_ut.cpp - actorsystem_ut.cpp - performance_ut.cpp - ask_ut.cpp - balancer_ut.cpp - event_pb_payload_ut.cpp - event_pb_ut.cpp - executor_pool_basic_ut.cpp - executor_pool_united_ut.cpp - log_ut.cpp - mon_ut.cpp - scheduler_actor_ut.cpp -) - -END() diff --git a/library/cpp/actors/core/ut_fat/CMakeLists.darwin-arm64.txt b/library/cpp/actors/core/ut_fat/CMakeLists.darwin-arm64.txt deleted file mode 100644 index c5420870b1..0000000000 --- a/library/cpp/actors/core/ut_fat/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,70 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-core-ut_fat) -target_link_libraries(library-cpp-actors-core-ut_fat PUBLIC - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-core -) -target_link_options(library-cpp-actors-core-ut_fat PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-core-ut_fat PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/ut_fat/actor_benchmark.cpp -) -set_property( - TARGET - library-cpp-actors-core-ut_fat - PROPERTY - SPLIT_FACTOR - 20 -) -add_yunittest( - NAME - library-cpp-actors-core-ut_fat - TEST_TARGET - library-cpp-actors-core-ut_fat - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut_fat - PROPERTY - LABELS - LARGE -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut_fat - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut_fat - PROPERTY - TIMEOUT - 1200 -) -target_allocator(library-cpp-actors-core-ut_fat - system_allocator -) -vcs_info(library-cpp-actors-core-ut_fat) diff --git a/library/cpp/actors/core/ut_fat/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/core/ut_fat/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 88a9860fc1..0000000000 --- a/library/cpp/actors/core/ut_fat/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,71 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-core-ut_fat) -target_link_libraries(library-cpp-actors-core-ut_fat PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-core -) -target_link_options(library-cpp-actors-core-ut_fat PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-core-ut_fat PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/ut_fat/actor_benchmark.cpp -) -set_property( - TARGET - library-cpp-actors-core-ut_fat - PROPERTY - SPLIT_FACTOR - 20 -) -add_yunittest( - NAME - library-cpp-actors-core-ut_fat - TEST_TARGET - library-cpp-actors-core-ut_fat - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut_fat - PROPERTY - LABELS - LARGE -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut_fat - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut_fat - PROPERTY - TIMEOUT - 1200 -) -target_allocator(library-cpp-actors-core-ut_fat - system_allocator -) -vcs_info(library-cpp-actors-core-ut_fat) diff --git a/library/cpp/actors/core/ut_fat/CMakeLists.linux-aarch64.txt b/library/cpp/actors/core/ut_fat/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 653d98fe60..0000000000 --- a/library/cpp/actors/core/ut_fat/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,74 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-core-ut_fat) -target_link_libraries(library-cpp-actors-core-ut_fat PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-core -) -target_link_options(library-cpp-actors-core-ut_fat PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-core-ut_fat PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/ut_fat/actor_benchmark.cpp -) -set_property( - TARGET - library-cpp-actors-core-ut_fat - PROPERTY - SPLIT_FACTOR - 20 -) -add_yunittest( - NAME - library-cpp-actors-core-ut_fat - TEST_TARGET - library-cpp-actors-core-ut_fat - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut_fat - PROPERTY - LABELS - LARGE -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut_fat - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut_fat - PROPERTY - TIMEOUT - 1200 -) -target_allocator(library-cpp-actors-core-ut_fat - cpp-malloc-jemalloc -) -vcs_info(library-cpp-actors-core-ut_fat) diff --git a/library/cpp/actors/core/ut_fat/CMakeLists.linux-x86_64.txt b/library/cpp/actors/core/ut_fat/CMakeLists.linux-x86_64.txt deleted file mode 100644 index e929e6f394..0000000000 --- a/library/cpp/actors/core/ut_fat/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,76 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-core-ut_fat) -target_link_libraries(library-cpp-actors-core-ut_fat PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-core -) -target_link_options(library-cpp-actors-core-ut_fat PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-core-ut_fat PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/ut_fat/actor_benchmark.cpp -) -set_property( - TARGET - library-cpp-actors-core-ut_fat - PROPERTY - SPLIT_FACTOR - 20 -) -add_yunittest( - NAME - library-cpp-actors-core-ut_fat - TEST_TARGET - library-cpp-actors-core-ut_fat - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut_fat - PROPERTY - LABELS - LARGE -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut_fat - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut_fat - PROPERTY - TIMEOUT - 1200 -) -target_allocator(library-cpp-actors-core-ut_fat - cpp-malloc-tcmalloc - libs-tcmalloc-no_percpu_cache -) -vcs_info(library-cpp-actors-core-ut_fat) diff --git a/library/cpp/actors/core/ut_fat/CMakeLists.txt b/library/cpp/actors/core/ut_fat/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/core/ut_fat/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/core/ut_fat/CMakeLists.windows-x86_64.txt b/library/cpp/actors/core/ut_fat/CMakeLists.windows-x86_64.txt deleted file mode 100644 index cd693cd949..0000000000 --- a/library/cpp/actors/core/ut_fat/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,64 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-core-ut_fat) -target_link_libraries(library-cpp-actors-core-ut_fat PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-core -) -target_sources(library-cpp-actors-core-ut_fat PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/core/ut_fat/actor_benchmark.cpp -) -set_property( - TARGET - library-cpp-actors-core-ut_fat - PROPERTY - SPLIT_FACTOR - 20 -) -add_yunittest( - NAME - library-cpp-actors-core-ut_fat - TEST_TARGET - library-cpp-actors-core-ut_fat - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut_fat - PROPERTY - LABELS - LARGE -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut_fat - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-core-ut_fat - PROPERTY - TIMEOUT - 1200 -) -target_allocator(library-cpp-actors-core-ut_fat - system_allocator -) -vcs_info(library-cpp-actors-core-ut_fat) diff --git a/library/cpp/actors/core/ut_fat/actor_benchmark.cpp b/library/cpp/actors/core/ut_fat/actor_benchmark.cpp deleted file mode 100644 index d47cae6ebb..0000000000 --- a/library/cpp/actors/core/ut_fat/actor_benchmark.cpp +++ /dev/null @@ -1,46 +0,0 @@ - - -#include <library/cpp/actors/core/actor_benchmark_helper.h> - -#include <library/cpp/testing/unittest/registar.h> - - -using namespace NActors; -using namespace NActors::NTests; - - -struct THeavyActorBenchmarkSettings : TActorBenchmarkSettings { - static constexpr ui32 TotalEventsAmountPerThread = 1'000'000; - - static constexpr auto MailboxTypes = { - TMailboxType::HTSwap, - }; -}; - - -Y_UNIT_TEST_SUITE(HeavyActorBenchmark) { - - using TActorBenchmark = ::NActors::NTests::TActorBenchmark<THeavyActorBenchmarkSettings>; - using TSettings = TActorBenchmark::TSettings; - - - Y_UNIT_TEST(SendActivateReceiveCSV) { - std::vector<ui32> threadsList; - for (ui32 threads = 1; threads <= 28; threads++) { - threadsList.push_back(threads); - } - std::vector<ui32> actorPairsList = {512}; - TActorBenchmark::RunSendActivateReceiveCSV(threadsList, actorPairsList, {1,100, 200}, TDuration::Seconds(1)); - } - - Y_UNIT_TEST(StarSendActivateReceiveCSV) { - std::vector<ui32> threadsList; - for (ui32 threads = 1; threads <= 28; threads++) { - threadsList.push_back(threads); - } - std::vector<ui32> actorPairsList = {512}; - std::vector<ui32> starsList = {10}; - TActorBenchmark::RunStarSendActivateReceiveCSV(threadsList, actorPairsList, starsList); - } - -} diff --git a/library/cpp/actors/core/ut_fat/ya.make b/library/cpp/actors/core/ut_fat/ya.make deleted file mode 100644 index 937e59720d..0000000000 --- a/library/cpp/actors/core/ut_fat/ya.make +++ /dev/null @@ -1,32 +0,0 @@ -UNITTEST() - -FORK_SUBTESTS() - -IF (SANITIZER_TYPE) - SIZE(LARGE) - TIMEOUT(2400) - TAG(ya:fat) - SPLIT_FACTOR(20) - REQUIREMENTS( - ram:32 - ) -ELSE() - SIZE(LARGE) - TIMEOUT(1200) - TAG(ya:fat) - SPLIT_FACTOR(20) - REQUIREMENTS( - ram:16 - ) -ENDIF() - - -PEERDIR( - library/cpp/actors/core -) - -SRCS( - actor_benchmark.cpp -) - -END() diff --git a/library/cpp/actors/core/worker_context.cpp b/library/cpp/actors/core/worker_context.cpp deleted file mode 100644 index ada6c997d4..0000000000 --- a/library/cpp/actors/core/worker_context.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "worker_context.h" -#include "probes.h" - -namespace NActors { - LWTRACE_USING(ACTORLIB_PROVIDER); - -} diff --git a/library/cpp/actors/core/worker_context.h b/library/cpp/actors/core/worker_context.h deleted file mode 100644 index b51ff55cd3..0000000000 --- a/library/cpp/actors/core/worker_context.h +++ /dev/null @@ -1,192 +0,0 @@ -#pragma once - -#include "defs.h" - -//#include "actorsystem.h" -#include "event.h" -#include "executor_pool.h" -#include "lease.h" -#include "mailbox.h" -#include "mon_stats.h" - -#include <library/cpp/actors/util/cpumask.h> -#include <library/cpp/actors/util/datetime.h> -#include <library/cpp/actors/util/intrinsics.h> -#include <library/cpp/actors/util/thread.h> - -#include <library/cpp/lwtrace/shuttle.h> - -namespace NActors { - struct TWorkerContext { - TWorkerId WorkerId; - const TCpuId CpuId; - TLease Lease; - IExecutorPool* Executor = nullptr; - TMailboxTable* MailboxTable = nullptr; - ui64 TimePerMailboxTs = 0; - ui32 EventsPerMailbox = 0; - ui64 SoftDeadlineTs = ui64(-1); - TExecutorThreadStats* Stats = &WorkerStats; // pool stats - TExecutorThreadStats WorkerStats; - TPoolId PoolId = MaxPools; - mutable NLWTrace::TOrbit Orbit; - bool IsNeededToWaitNextActivation = true; - i64 HPStart = 0; - ui32 ExecutedEvents = 0; - - TWorkerContext(TWorkerId workerId, TCpuId cpuId) - : WorkerId(workerId) - , CpuId(cpuId) - , Lease(WorkerId, NeverExpire) - {} - -#ifdef ACTORSLIB_COLLECT_EXEC_STATS - void GetCurrentStats(TExecutorThreadStats& statsCopy) const { - statsCopy = TExecutorThreadStats(); - statsCopy.Aggregate(*Stats); - } - - void AddElapsedCycles(ui32 activityType, i64 elapsed) { - Y_DEBUG_ABORT_UNLESS(activityType < Stats->MaxActivityType()); - RelaxedStore(&Stats->ElapsedTicks, RelaxedLoad(&Stats->ElapsedTicks) + elapsed); - RelaxedStore(&Stats->ElapsedTicksByActivity[activityType], RelaxedLoad(&Stats->ElapsedTicksByActivity[activityType]) + elapsed); - } - - void AddParkedCycles(i64 elapsed) { - RelaxedStore(&Stats->ParkedTicks, RelaxedLoad(&Stats->ParkedTicks) + elapsed); - } - - void AddBlockedCycles(i64 elapsed) { - RelaxedStore(&Stats->BlockedTicks, RelaxedLoad(&Stats->BlockedTicks) + elapsed); - } - - void IncrementSentEvents() { - RelaxedStore(&Stats->SentEvents, RelaxedLoad(&Stats->SentEvents) + 1); - } - - void IncrementPreemptedEvents() { - RelaxedStore(&Stats->PreemptedEvents, RelaxedLoad(&Stats->PreemptedEvents) + 1); - } - - void DecrementActorsAliveByActivity(ui32 activityType) { - if (activityType >= Stats->MaxActivityType()) { - activityType = 0; - } - RelaxedStore(&Stats->ActorsAliveByActivity[activityType], Stats->ActorsAliveByActivity[activityType] - 1); - } - - inline void IncrementNonDeliveredEvents() { - RelaxedStore(&Stats->NonDeliveredEvents, RelaxedLoad(&Stats->NonDeliveredEvents) + 1); - } - - inline void IncrementMailboxPushedOutByTailSending() { - RelaxedStore(&Stats->MailboxPushedOutByTailSending, RelaxedLoad(&Stats->MailboxPushedOutByTailSending) + 1); - } - - inline void IncrementMailboxPushedOutBySoftPreemption() { - RelaxedStore(&Stats->MailboxPushedOutBySoftPreemption, RelaxedLoad(&Stats->MailboxPushedOutBySoftPreemption) + 1); - } - - inline void IncrementMailboxPushedOutByTime() { - RelaxedStore(&Stats->MailboxPushedOutByTime, RelaxedLoad(&Stats->MailboxPushedOutByTime) + 1); - } - - inline void IncrementMailboxPushedOutByEventCount() { - RelaxedStore(&Stats->MailboxPushedOutByEventCount, RelaxedLoad(&Stats->MailboxPushedOutByEventCount) + 1); - } - - inline void IncrementEmptyMailboxActivation() { - RelaxedStore(&Stats->EmptyMailboxActivation, RelaxedLoad(&Stats->EmptyMailboxActivation) + 1); - } - - double AddActivationStats(i64 scheduleTs, i64 deliveredTs) { - i64 ts = deliveredTs > scheduleTs ? deliveredTs - scheduleTs : 0; - double usec = NHPTimer::GetSeconds(ts) * 1000000.0; - Stats->ActivationTimeHistogram.Add(usec); - RelaxedStore(&Stats->WorstActivationTimeUs, Max(Stats->WorstActivationTimeUs, (ui64)usec)); - return usec; - } - - ui64 AddEventDeliveryStats(i64 sentTs, i64 deliveredTs) { - ui64 usecDeliv = deliveredTs > sentTs ? NHPTimer::GetSeconds(deliveredTs - sentTs) * 1000000 : 0; - Stats->EventDeliveryTimeHistogram.Add(usecDeliv); - return usecDeliv; - } - - i64 AddEventProcessingStats(i64 deliveredTs, i64 processedTs, ui32 activityType, ui64 scheduled) { - i64 elapsed = processedTs - deliveredTs; - ui64 usecElapsed = NHPTimer::GetSeconds(elapsed) * 1000000; - activityType = (activityType >= Stats->MaxActivityType()) ? 0 : activityType; - Stats->EventProcessingCountHistogram.Add(usecElapsed); - Stats->EventProcessingTimeHistogram.Add(usecElapsed, elapsed); - RelaxedStore(&Stats->ReceivedEvents, RelaxedLoad(&Stats->ReceivedEvents) + 1); - RelaxedStore(&Stats->ReceivedEventsByActivity[activityType], RelaxedLoad(&Stats->ReceivedEventsByActivity[activityType]) + 1); - RelaxedStore(&Stats->ScheduledEventsByActivity[activityType], RelaxedLoad(&Stats->ScheduledEventsByActivity[activityType]) + scheduled); - AddElapsedCycles(activityType, elapsed); - return elapsed; - } - - void UpdateActorsStats(size_t dyingActorsCnt) { - if (dyingActorsCnt) { - AtomicAdd(Executor->DestroyedActors, dyingActorsCnt); - } - RelaxedStore(&Stats->PoolDestroyedActors, (ui64)RelaxedLoad(&Executor->DestroyedActors)); - RelaxedStore(&Stats->PoolActorRegistrations, (ui64)RelaxedLoad(&Executor->ActorRegistrations)); - RelaxedStore(&Stats->PoolAllocatedMailboxes, MailboxTable->GetAllocatedMailboxCount()); - } - - void UpdateThreadTime() { - RelaxedStore(&WorkerStats.SafeElapsedTicks, (ui64)RelaxedLoad(&WorkerStats.ElapsedTicks)); - RelaxedStore(&WorkerStats.CpuUs, ThreadCPUTime()); - } - - void IncreaseNotEnoughCpuExecutions() { - RelaxedStore(&WorkerStats.NotEnoughCpuExecutions, - (ui64)RelaxedLoad(&WorkerStats.NotEnoughCpuExecutions) + 1); - } -#else - void GetCurrentStats(TExecutorThreadStats&) const {} - inline void AddElapsedCycles(ui32, i64) {} - inline void AddParkedCycles(i64) {} - inline void AddBlockedCycles(i64) {} - inline void IncrementSentEvents() {} - inline void IncrementPreemptedEvents() {} - inline void IncrementMailboxPushedOutByTailSending() {} - inline void IncrementMailboxPushedOutBySoftPreemption() {} - inline void IncrementMailboxPushedOutByTime() {} - inline void IncrementMailboxPushedOutByEventCount() {} - inline void IncrementEmptyMailboxActivation() {} - void DecrementActorsAliveByActivity(ui32) {} - void IncrementNonDeliveredEvents() {} - double AddActivationStats(i64, i64) { return 0; } - ui64 AddEventDeliveryStats(i64, i64) { return 0; } - i64 AddEventProcessingStats(i64, i64, ui32, ui64) { return 0; } - void UpdateActorsStats(size_t, IExecutorPool*) {} - void UpdateThreadTime() {} - void IncreaseNotEnoughCpuExecutions() {} -#endif - - void Switch(IExecutorPool* executor, - TMailboxTable* mailboxTable, - ui64 timePerMailboxTs, - ui32 eventsPerMailbox, - ui64 softDeadlineTs, - TExecutorThreadStats* stats) - { - Executor = executor; - MailboxTable = mailboxTable; - TimePerMailboxTs = timePerMailboxTs; - EventsPerMailbox = eventsPerMailbox; - SoftDeadlineTs = softDeadlineTs; - Stats = stats; - PoolId = Executor ? Executor->PoolId : MaxPools; - } - - void SwitchToIdle() { - Executor = nullptr; - MailboxTable = nullptr; - //Stats = &WorkerStats; // TODO: in actorsystem 2.0 idle stats cannot be related to specific pool - PoolId = MaxPools; - } - }; -} diff --git a/library/cpp/actors/core/ya.make b/library/cpp/actors/core/ya.make deleted file mode 100644 index 8dadea5fdc..0000000000 --- a/library/cpp/actors/core/ya.make +++ /dev/null @@ -1,133 +0,0 @@ -LIBRARY() - -NO_WSHADOW() - -IF (PROFILE_MEMORY_ALLOCATIONS) - CFLAGS(-DPROFILE_MEMORY_ALLOCATIONS) -ENDIF() - -IF (ALLOCATOR == "B" OR ALLOCATOR == "BS" OR ALLOCATOR == "C") - CXXFLAGS(-DBALLOC) - PEERDIR( - library/cpp/balloc/optional - ) -ENDIF() - -SRCS( - actor_bootstrapped.cpp - actor_coroutine.cpp - actor_coroutine.h - actor.cpp - actor.h - actor_virtual.cpp - actorid.cpp - actorid.h - actorsystem.cpp - actorsystem.h - ask.cpp - ask.h - av_bootstrapped.cpp - balancer.h - balancer.cpp - buffer.cpp - buffer.h - callstack.cpp - callstack.h - config.h - cpu_manager.cpp - cpu_manager.h - cpu_state.h - defs.h - event.cpp - event.h - event_load.cpp - event_local.h - event_pb.cpp - event_pb.h - events.h - events_undelivered.cpp - executelater.h - executor_pool_base.cpp - executor_pool_base.h - executor_pool_basic.cpp - executor_pool_basic.h - executor_pool_io.cpp - executor_pool_io.h - executor_pool_united.cpp - executor_pool_united.h - executor_thread.cpp - executor_thread.h - harmonizer.cpp - harmonizer.h - hfunc.h - interconnect.cpp - interconnect.h - invoke.h - io_dispatcher.cpp - io_dispatcher.h - lease.h - log.cpp - log.h - log_settings.cpp - log_settings.h - log_buffer.cpp - log_buffer.h - log_metrics.h - mailbox.cpp - mailbox.h - mailbox_queue_revolving.h - mailbox_queue_simple.h - mon.h - mon_stats.h - monotonic.cpp - monotonic.h - monotonic_provider.cpp - monotonic_provider.h - worker_context.cpp - worker_context.h - probes.cpp - probes.h - process_stats.cpp - process_stats.h - scheduler_actor.cpp - scheduler_actor.h - scheduler_basic.cpp - scheduler_basic.h - scheduler_cookie.cpp - scheduler_cookie.h - scheduler_queue.h - servicemap.h -) - -GENERATE_ENUM_SERIALIZATION(defs.h) -GENERATE_ENUM_SERIALIZATION(actor.h) -GENERATE_ENUM_SERIALIZATION(log_iface.h) - -PEERDIR( - library/cpp/actors/actor_type - library/cpp/actors/memory_log - library/cpp/actors/prof - library/cpp/actors/protos - library/cpp/actors/util - library/cpp/execprofile - library/cpp/json/writer - library/cpp/logger - library/cpp/lwtrace - library/cpp/monlib/dynamic_counters - library/cpp/svnversion - library/cpp/time_provider - library/cpp/threading/future -) - -IF (SANITIZER_TYPE == "thread") - SUPPRESSIONS( - tsan.supp - ) -ENDIF() - -END() - -RECURSE_FOR_TESTS( - ut - ut_fat -) diff --git a/library/cpp/actors/cppcoro/CMakeLists.darwin-arm64.txt b/library/cpp/actors/cppcoro/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 9795130141..0000000000 --- a/library/cpp/actors/cppcoro/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,24 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(corobenchmark) -add_subdirectory(ut) - -add_library(cpp-actors-cppcoro) -target_link_libraries(cpp-actors-cppcoro PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core -) -target_sources(cpp-actors-cppcoro PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/await_callback.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_group.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_result.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task.cpp -) diff --git a/library/cpp/actors/cppcoro/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/cppcoro/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 9795130141..0000000000 --- a/library/cpp/actors/cppcoro/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,24 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(corobenchmark) -add_subdirectory(ut) - -add_library(cpp-actors-cppcoro) -target_link_libraries(cpp-actors-cppcoro PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core -) -target_sources(cpp-actors-cppcoro PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/await_callback.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_group.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_result.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task.cpp -) diff --git a/library/cpp/actors/cppcoro/CMakeLists.linux-aarch64.txt b/library/cpp/actors/cppcoro/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 514824dad2..0000000000 --- a/library/cpp/actors/cppcoro/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,25 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(corobenchmark) -add_subdirectory(ut) - -add_library(cpp-actors-cppcoro) -target_link_libraries(cpp-actors-cppcoro PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-actors-core -) -target_sources(cpp-actors-cppcoro PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/await_callback.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_group.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_result.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task.cpp -) diff --git a/library/cpp/actors/cppcoro/CMakeLists.linux-x86_64.txt b/library/cpp/actors/cppcoro/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 514824dad2..0000000000 --- a/library/cpp/actors/cppcoro/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,25 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(corobenchmark) -add_subdirectory(ut) - -add_library(cpp-actors-cppcoro) -target_link_libraries(cpp-actors-cppcoro PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-actors-core -) -target_sources(cpp-actors-cppcoro PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/await_callback.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_group.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_result.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task.cpp -) diff --git a/library/cpp/actors/cppcoro/CMakeLists.txt b/library/cpp/actors/cppcoro/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/cppcoro/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/cppcoro/CMakeLists.windows-x86_64.txt b/library/cpp/actors/cppcoro/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 9795130141..0000000000 --- a/library/cpp/actors/cppcoro/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,24 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(corobenchmark) -add_subdirectory(ut) - -add_library(cpp-actors-cppcoro) -target_link_libraries(cpp-actors-cppcoro PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core -) -target_sources(cpp-actors-cppcoro PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/await_callback.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_group.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_result.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task.cpp -) diff --git a/library/cpp/actors/cppcoro/await_callback.cpp b/library/cpp/actors/cppcoro/await_callback.cpp deleted file mode 100644 index 5132131a8e..0000000000 --- a/library/cpp/actors/cppcoro/await_callback.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "await_callback.h" diff --git a/library/cpp/actors/cppcoro/await_callback.h b/library/cpp/actors/cppcoro/await_callback.h deleted file mode 100644 index fcb2eb78f9..0000000000 --- a/library/cpp/actors/cppcoro/await_callback.h +++ /dev/null @@ -1,100 +0,0 @@ -#include <coroutine> -#include <exception> -#include <concepts> - -namespace NActors { - - namespace NDetail { - - template<class TAwaitable> - decltype(auto) GetAwaiter(TAwaitable&& awaitable) { - if constexpr (requires { ((TAwaitable&&) awaitable).operator co_await(); }) { - return ((TAwaitable&&) awaitable).operator co_await(); - } else if constexpr (requires { operator co_await((TAwaitable&&) awaitable); }) { - return operator co_await((TAwaitable&&) awaitable); - } else { - return ((TAwaitable&&) awaitable); - } - } - - template<class TAwaitable> - using TAwaitResult = decltype(GetAwaiter(std::declval<TAwaitable>()).await_resume()); - - template<class TCallback, class TResult> - class TCallbackResult { - public: - TCallbackResult(TCallback& callback) - : Callback(callback) - {} - - template<class TRealResult> - void return_value(TRealResult&& result) noexcept { - Callback(std::forward<TRealResult>(result)); - } - - private: - TCallback& Callback; - }; - - template<class TCallback> - class TCallbackResult<TCallback, void> { - public: - TCallbackResult(TCallback& callback) - : Callback(callback) - {} - - void return_void() noexcept { - Callback(); - } - - private: - TCallback& Callback; - }; - - template<class TAwaitable, class TCallback> - class TAwaitThenCallbackPromise - : public TCallbackResult<TCallback, TAwaitResult<TAwaitable>> - { - public: - using THandle = std::coroutine_handle<TAwaitThenCallbackPromise<TAwaitable, TCallback>>; - - TAwaitThenCallbackPromise(TAwaitable&, TCallback& callback) - : TCallbackResult<TCallback, TAwaitResult<TAwaitable>>(callback) - {} - - THandle get_return_object() noexcept { - return THandle::from_promise(*this); - } - - static auto initial_suspend() noexcept { return std::suspend_never{}; } - static auto final_suspend() noexcept { return std::suspend_never{}; } - - void unhandled_exception() noexcept { - std::terminate(); - } - }; - - template<class TAwaitable, class TCallback> - class TAwaitThenCallback { - public: - using promise_type = TAwaitThenCallbackPromise<TAwaitable, TCallback>; - - using THandle = typename promise_type::THandle; - - TAwaitThenCallback(THandle) noexcept {} - }; - - } // namespace NDetail - - /** - * Awaits the awaitable and calls callback with the result. - * - * Note: program terminates if awaitable or callback throw an exception. - */ - template<class TAwaitable, class TCallback> - NDetail::TAwaitThenCallback<TAwaitable, TCallback> AwaitThenCallback(TAwaitable awaitable, TCallback) { - // Note: underlying promise takes callback argument address and calls it when we return - co_return co_await std::move(awaitable); - } - -} // namespace NActors diff --git a/library/cpp/actors/cppcoro/corobenchmark/CMakeLists.darwin-arm64.txt b/library/cpp/actors/cppcoro/corobenchmark/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 1043b6f834..0000000000 --- a/library/cpp/actors/cppcoro/corobenchmark/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,30 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(corobenchmark) -target_link_libraries(corobenchmark PUBLIC - contrib-libs-cxxsupp - yutil - testing-benchmark-main - cpp-actors-cppcoro -) -target_link_options(corobenchmark PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(corobenchmark PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/corobenchmark/main.cpp -) -target_allocator(corobenchmark - system_allocator -) -vcs_info(corobenchmark) diff --git a/library/cpp/actors/cppcoro/corobenchmark/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/cppcoro/corobenchmark/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 1b98f8aac0..0000000000 --- a/library/cpp/actors/cppcoro/corobenchmark/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,31 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(corobenchmark) -target_link_libraries(corobenchmark PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - testing-benchmark-main - cpp-actors-cppcoro -) -target_link_options(corobenchmark PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(corobenchmark PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/corobenchmark/main.cpp -) -target_allocator(corobenchmark - system_allocator -) -vcs_info(corobenchmark) diff --git a/library/cpp/actors/cppcoro/corobenchmark/CMakeLists.linux-aarch64.txt b/library/cpp/actors/cppcoro/corobenchmark/CMakeLists.linux-aarch64.txt deleted file mode 100644 index f12dfdad8d..0000000000 --- a/library/cpp/actors/cppcoro/corobenchmark/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,34 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(corobenchmark) -target_link_libraries(corobenchmark PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - testing-benchmark-main - cpp-actors-cppcoro -) -target_link_options(corobenchmark PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(corobenchmark PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/corobenchmark/main.cpp -) -target_allocator(corobenchmark - cpp-malloc-jemalloc -) -vcs_info(corobenchmark) diff --git a/library/cpp/actors/cppcoro/corobenchmark/CMakeLists.linux-x86_64.txt b/library/cpp/actors/cppcoro/corobenchmark/CMakeLists.linux-x86_64.txt deleted file mode 100644 index e5b37926d1..0000000000 --- a/library/cpp/actors/cppcoro/corobenchmark/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,36 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(corobenchmark) -target_link_libraries(corobenchmark PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - testing-benchmark-main - cpp-actors-cppcoro -) -target_link_options(corobenchmark PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(corobenchmark PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/corobenchmark/main.cpp -) -target_allocator(corobenchmark - cpp-malloc-tcmalloc - libs-tcmalloc-no_percpu_cache -) -vcs_info(corobenchmark) diff --git a/library/cpp/actors/cppcoro/corobenchmark/CMakeLists.txt b/library/cpp/actors/cppcoro/corobenchmark/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/cppcoro/corobenchmark/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/cppcoro/corobenchmark/CMakeLists.windows-x86_64.txt b/library/cpp/actors/cppcoro/corobenchmark/CMakeLists.windows-x86_64.txt deleted file mode 100644 index c9a8359b4b..0000000000 --- a/library/cpp/actors/cppcoro/corobenchmark/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,24 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(corobenchmark) -target_link_libraries(corobenchmark PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - testing-benchmark-main - cpp-actors-cppcoro -) -target_sources(corobenchmark PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/corobenchmark/main.cpp -) -target_allocator(corobenchmark - system_allocator -) -vcs_info(corobenchmark) diff --git a/library/cpp/actors/cppcoro/corobenchmark/main.cpp b/library/cpp/actors/cppcoro/corobenchmark/main.cpp deleted file mode 100644 index 49504e7105..0000000000 --- a/library/cpp/actors/cppcoro/corobenchmark/main.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include <library/cpp/actors/cppcoro/task.h> -#include <library/cpp/actors/cppcoro/await_callback.h> -#include <library/cpp/testing/benchmark/bench.h> - -using namespace NActors; - -namespace { - - int LastValue = 0; - - Y_NO_INLINE int NextFuncValue() { - return ++LastValue; - } - - Y_NO_INLINE void IterateFuncValues(size_t iterations) { - for (size_t i = 0; i < iterations; ++i) { - int value = NextFuncValue(); - Y_DO_NOT_OPTIMIZE_AWAY(value); - } - } - - Y_NO_INLINE TTask<int> NextTaskValue() { - co_return ++LastValue; - } - - Y_NO_INLINE TTask<void> IterateTaskValues(size_t iterations) { - for (size_t i = 0; i < iterations; ++i) { - int value = co_await NextTaskValue(); - Y_DO_NOT_OPTIMIZE_AWAY(value); - } - } - - std::coroutine_handle<> Paused; - - struct { - static bool await_ready() noexcept { - return false; - } - static void await_suspend(std::coroutine_handle<> h) noexcept { - Paused = h; - } - static int await_resume() noexcept { - return ++LastValue; - } - } Pause; - - Y_NO_INLINE TTask<void> IteratePauseValues(size_t iterations) { - for (size_t i = 0; i < iterations; ++i) { - int value = co_await Pause; - Y_DO_NOT_OPTIMIZE_AWAY(value); - } - } - -} // namespace - -Y_CPU_BENCHMARK(FuncCalls, iface) { - IterateFuncValues(iface.Iterations()); -} - -Y_CPU_BENCHMARK(TaskCalls, iface) { - bool finished = false; - AwaitThenCallback(IterateTaskValues(iface.Iterations()), [&]{ - finished = true; - }); - Y_ABORT_UNLESS(finished); -} - -Y_CPU_BENCHMARK(CoroAwaits, iface) { - bool finished = false; - AwaitThenCallback(IteratePauseValues(iface.Iterations()), [&]{ - finished = true; - }); - while (!finished) { - std::exchange(Paused, {}).resume(); - } -} diff --git a/library/cpp/actors/cppcoro/corobenchmark/ya.make b/library/cpp/actors/cppcoro/corobenchmark/ya.make deleted file mode 100644 index ef5ad4135c..0000000000 --- a/library/cpp/actors/cppcoro/corobenchmark/ya.make +++ /dev/null @@ -1,11 +0,0 @@ -Y_BENCHMARK() - -PEERDIR( - library/cpp/actors/cppcoro -) - -SRCS( - main.cpp -) - -END() diff --git a/library/cpp/actors/cppcoro/task.cpp b/library/cpp/actors/cppcoro/task.cpp deleted file mode 100644 index 204c27c573..0000000000 --- a/library/cpp/actors/cppcoro/task.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "task.h" diff --git a/library/cpp/actors/cppcoro/task.h b/library/cpp/actors/cppcoro/task.h deleted file mode 100644 index bb5a385db2..0000000000 --- a/library/cpp/actors/cppcoro/task.h +++ /dev/null @@ -1,228 +0,0 @@ -#pragma once -#include "task_result.h" -#include <util/system/yassert.h> -#include <coroutine> -#include <utility> - -namespace NActors { - - template<class T> - class TTask; - - /** - * This exception is commonly thrown when task is cancelled - */ - class TTaskCancelled : public std::exception { - public: - const char* what() const noexcept { - return "Task cancelled"; - } - }; - - namespace NDetail { - - template<class T> - class TTaskPromise; - - template<class T> - using TTaskHandle = std::coroutine_handle<TTaskPromise<T>>; - - template<class T> - class TTaskAwaiter { - public: - explicit TTaskAwaiter(TTaskHandle<T> handle) - : Handle(handle) - { - Y_DEBUG_ABORT_UNLESS(Handle); - } - - TTaskAwaiter(TTaskAwaiter&& rhs) - : Handle(std::exchange(rhs.Handle, {})) - {} - - TTaskAwaiter& operator=(const TTaskAwaiter&) = delete; - TTaskAwaiter& operator=(TTaskAwaiter&&) = delete; - - ~TTaskAwaiter() noexcept { - if (Handle) { - Handle.destroy(); - } - } - - // We can only await a task that has not started yet - static bool await_ready() noexcept { return false; } - - // Some arbitrary continuation c suspended and awaits the task - TTaskHandle<T> await_suspend(std::coroutine_handle<> c) noexcept { - Y_DEBUG_ABORT_UNLESS(Handle); - Handle.promise().SetContinuation(c); - return Handle; - } - - TTaskResult<T>&& await_resume() noexcept { - Y_DEBUG_ABORT_UNLESS(Handle); - return std::move(Handle.promise().Result); - } - - private: - TTaskHandle<T> Handle; - }; - - template<class T> - class TTaskResultAwaiter final : public TTaskAwaiter<T> { - public: - using TTaskAwaiter<T>::TTaskAwaiter; - - T&& await_resume() { - return TTaskAwaiter<T>::await_resume().Value(); - } - }; - - template<> - class TTaskResultAwaiter<void> final : public TTaskAwaiter<void> { - public: - using TTaskAwaiter<void>::TTaskAwaiter; - - void await_resume() { - TTaskAwaiter<void>::await_resume().Value(); - } - }; - - template<class T> - class TTaskResultHandlerBase { - public: - void unhandled_exception() noexcept { - Result.SetException(std::current_exception()); - } - - protected: - TTaskResult<T> Result; - }; - - template<class T> - class TTaskResultHandler : public TTaskResultHandlerBase<T> { - public: - template<class TResult> - void return_value(TResult&& value) { - this->Result.SetValue(std::forward<TResult>(value)); - } - }; - - template<> - class TTaskResultHandler<void> : public TTaskResultHandlerBase<void> { - public: - void return_void() noexcept { - this->Result.SetValue(); - } - }; - - template<class T> - class TTaskPromise final - : public TTaskResultHandler<T> - { - friend class TTaskAwaiter<T>; - - public: - TTask<T> get_return_object() noexcept; - - static auto initial_suspend() noexcept { return std::suspend_always{}; } - - struct TFinalSuspend { - static bool await_ready() noexcept { return false; } - static void await_resume() noexcept { Y_ABORT("unexpected coroutine resume"); } - - static std::coroutine_handle<> await_suspend(std::coroutine_handle<TTaskPromise<T>> h) noexcept { - auto next = std::exchange(h.promise().Continuation, std::noop_coroutine()); - Y_DEBUG_ABORT_UNLESS(next, "Task finished without a continuation"); - return next; - } - }; - - static auto final_suspend() noexcept { return TFinalSuspend{}; } - - private: - void SetContinuation(std::coroutine_handle<> continuation) noexcept { - Y_DEBUG_ABORT_UNLESS(!Continuation, "Task can only be awaited once"); - Continuation = continuation; - } - - private: - std::coroutine_handle<> Continuation; - }; - - } // namespace NDetail - - /** - * Represents a task that has not been started yet - */ - template<class T> - class TTask final { - public: - using promise_type = NDetail::TTaskPromise<T>; - using value_type = T; - - public: - TTask() noexcept = default; - - explicit TTask(NDetail::TTaskHandle<T> handle) noexcept - : Handle(handle) - {} - - TTask(TTask&& rhs) noexcept - : Handle(std::exchange(rhs.Handle, {})) - {} - - ~TTask() { - if (Handle) { - Handle.destroy(); - } - } - - TTask& operator=(TTask&& rhs) noexcept { - if (Y_LIKELY(this != &rhs)) { - auto handle = std::exchange(Handle, {}); - Handle = std::exchange(rhs.Handle, {}); - if (handle) { - handle.destroy(); - } - } - return *this; - } - - /** - * Returns true for a valid task object - */ - explicit operator bool() const noexcept { - return bool(Handle); - } - - /** - * Starts task and returns TTaskResult<T> when it completes - */ - auto WhenDone() && noexcept { - Y_DEBUG_ABORT_UNLESS(Handle, "Cannot await an empty task"); - return NDetail::TTaskAwaiter<T>(std::exchange(Handle, {})); - } - - /** - * Starts task and returns its result when it completes - */ - auto operator co_await() && noexcept { - Y_DEBUG_ABORT_UNLESS(Handle, "Cannot await an empty task"); - return NDetail::TTaskResultAwaiter<T>(std::exchange(Handle, {})); - } - - private: - NDetail::TTaskHandle<T> Handle; - }; - - namespace NDetail { - - template<class T> - inline TTask<T> TTaskPromise<T>::get_return_object() noexcept { - return TTask<T>(TTaskHandle<T>::from_promise(*this)); - } - - } // namespace NDetail - -} // namespace NActors diff --git a/library/cpp/actors/cppcoro/task_actor.cpp b/library/cpp/actors/cppcoro/task_actor.cpp deleted file mode 100644 index 8a9451c8e5..0000000000 --- a/library/cpp/actors/cppcoro/task_actor.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include "task_actor.h" -#include "await_callback.h" -#include <library/cpp/actors/core/actor.h> -#include <library/cpp/actors/core/hfunc.h> - -namespace NActors { - - class TTaskActorImpl; - - static Y_POD_THREAD(TTaskActorImpl*) TlsCurrentTaskActor{nullptr}; - - struct TCurrentTaskActorGuard { - TCurrentTaskActorGuard(TTaskActorImpl* current) noexcept { - Y_ABORT_UNLESS(TlsCurrentTaskActor == nullptr); - TlsCurrentTaskActor = current; - } - - ~TCurrentTaskActorGuard() noexcept { - TlsCurrentTaskActor = nullptr; - } - }; - - enum : ui32 { - EvResumeTask = EventSpaceBegin(TEvents::ES_SYSTEM) + 256, - }; - - struct TEvResumeTask : public TEventLocal<TEvResumeTask, EvResumeTask> { - std::coroutine_handle<> Handle; - TTaskResult<void>* Result; - - explicit TEvResumeTask(std::coroutine_handle<> handle, TTaskResult<void>* result) noexcept - : Handle(handle) - , Result(result) - {} - - ~TEvResumeTask() noexcept { - if (Handle) { - Result->SetException(std::make_exception_ptr(TTaskCancelled())); - Handle.resume(); - } - } - }; - - class TTaskActorResult final : public TAtomicRefCount<TTaskActorResult> { - public: - bool Finished = false; - }; - - class TTaskActorImpl : public TActor<TTaskActorImpl> { - friend class TTaskActor; - friend class TAfterAwaiter; - friend class TBindAwaiter; - - public: - TTaskActorImpl(TTask<void>&& task) - : TActor(&TThis::StateBoot) - , Task(std::move(task)) - { - Y_ABORT_UNLESS(Task); - } - - ~TTaskActorImpl() { - Stopped = true; - while (EventAwaiter) { - // Unblock event awaiter until task stops trying - TCurrentTaskActorGuard guard(this); - std::exchange(EventAwaiter, {}).resume(); - } - } - - void Registered(TActorSystem* sys, const TActorId& parent) override { - ParentId = parent; - sys->Send(new IEventHandle(TEvents::TSystem::Bootstrap, 0, SelfId(), SelfId(), {}, 0)); - } - - STATEFN(StateBoot) { - Y_ABORT_UNLESS(ev->GetTypeRewrite() == TEvents::TSystem::Bootstrap, "Expected bootstrap event"); - TCurrentTaskActorGuard guard(this); - Become(&TThis::StateWork); - AwaitThenCallback(std::move(Task).WhenDone(), - [result = Result](TTaskResult<void>&& outcome) noexcept { - result->Finished = true; - try { - outcome.Value(); - } catch (TTaskCancelled&) { - // ignore - } - }); - Check(); - } - - STATEFN(StateWork) { - TCurrentTaskActorGuard guard(this); - switch (ev->GetTypeRewrite()) { - hFunc(TEvResumeTask, Handle); - default: - Y_ABORT_UNLESS(EventAwaiter); - Event.reset(ev.Release()); - std::exchange(EventAwaiter, {}).resume(); - } - Check(); - } - - void Handle(TEvResumeTask::TPtr& ev) { - auto* msg = ev->Get(); - msg->Result->SetValue(); - std::exchange(msg->Handle, {}).resume(); - } - - bool Check() { - if (Result->Finished) { - Y_ABORT_UNLESS(!EventAwaiter, "Task terminated while waiting for the next event"); - PassAway(); - return false; - } - - Y_ABORT_UNLESS(EventAwaiter, "Task suspended without waiting for the next event"); - return true; - } - - void WaitForEvent(std::coroutine_handle<> h) noexcept { - Y_ABORT_UNLESS(!EventAwaiter, "Task cannot have multiple awaiters for the next event"); - EventAwaiter = h; - } - - std::unique_ptr<IEventHandle> FinishWaitForEvent() { - if (Stopped) { - throw TTaskCancelled(); - } - Y_ABORT_UNLESS(Event, "Task does not have current event"); - return std::move(Event); - } - - private: - TIntrusivePtr<TTaskActorResult> Result = MakeIntrusive<TTaskActorResult>(); - TTask<void> Task; - TActorId ParentId; - std::coroutine_handle<> EventAwaiter; - std::unique_ptr<IEventHandle> Event; - bool Stopped = false; - }; - - void TTaskActorNextEvent::await_suspend(std::coroutine_handle<> h) noexcept { - Y_ABORT_UNLESS(TlsCurrentTaskActor, "Not in a task actor context"); - TlsCurrentTaskActor->WaitForEvent(h); - } - - std::unique_ptr<IEventHandle> TTaskActorNextEvent::await_resume() { - Y_ABORT_UNLESS(TlsCurrentTaskActor, "Not in a task actor context"); - return TlsCurrentTaskActor->FinishWaitForEvent(); - } - - IActor* TTaskActor::Create(TTask<void>&& task) { - return new TTaskActorImpl(std::move(task)); - } - - TActorIdentity TTaskActor::SelfId() noexcept { - Y_ABORT_UNLESS(TlsCurrentTaskActor, "Not in a task actor context"); - return TlsCurrentTaskActor->SelfId(); - } - - TActorId TTaskActor::ParentId() noexcept { - Y_ABORT_UNLESS(TlsCurrentTaskActor, "Not in a task actor context"); - return TlsCurrentTaskActor->ParentId; - } - - void TAfterAwaiter::await_suspend(std::coroutine_handle<> h) noexcept { - Y_ABORT_UNLESS(TlsCurrentTaskActor, "Not in a task actor context"); - TlsCurrentTaskActor->Schedule(Duration, new TEvResumeTask(h, &Result)); - } - - bool TBindAwaiter::await_ready() noexcept { - if (TlsCurrentTaskActor && TlsCurrentTaskActor->SelfId() == ActorId) { - return true; - } - return false; - } - - void TBindAwaiter::await_suspend(std::coroutine_handle<> h) noexcept { - Sys->Send(new IEventHandle(ActorId, ActorId, new TEvResumeTask(h, &Result))); - } - -} // namespace NActors diff --git a/library/cpp/actors/cppcoro/task_actor.h b/library/cpp/actors/cppcoro/task_actor.h deleted file mode 100644 index 75d498a04e..0000000000 --- a/library/cpp/actors/cppcoro/task_actor.h +++ /dev/null @@ -1,107 +0,0 @@ -#include <library/cpp/actors/core/actor.h> -#include "task.h" - -namespace NActors { - - struct TTaskActorNextEvent { - static constexpr bool await_ready() noexcept { return false; } - - static void await_suspend(std::coroutine_handle<> h) noexcept; - - static std::unique_ptr<IEventHandle> await_resume(); - }; - - class TAfterAwaiter { - public: - TAfterAwaiter(TDuration duration) - : Duration(duration) - {} - - static constexpr bool await_ready() noexcept { return false; } - - void await_suspend(std::coroutine_handle<> h) noexcept; - - void await_resume() { - Result.Value(); - } - - private: - TDuration Duration; - TTaskResult<void> Result; - }; - - class TBindAwaiter { - public: - TBindAwaiter(TActorSystem* sys, const TActorId& actorId) - : Sys(sys) - , ActorId(actorId) - {} - - bool await_ready() noexcept; - - void await_suspend(std::coroutine_handle<> h) noexcept; - - void await_resume() { - Result.Value(); - } - - private: - TActorSystem* Sys; - TActorId ActorId; - TTaskResult<void> Result; - }; - - class TTaskActor { - public: - /** - * Creates a new actor that will run the specified task. - */ - static IActor* Create(TTask<void>&& task); - - /** - * Returns the next actor event when awaited - */ - static constexpr TTaskActorNextEvent NextEvent{}; - - /** - * Returns the identity of current task actor. - */ - static TActorIdentity SelfId() noexcept; - - /** - * Returns an actor id of the actor that registered current task actor. - */ - static TActorId ParentId() noexcept; - - /** - * Returns awaiter that completes after the specified timeout. - */ - static TAfterAwaiter After(TDuration duration) noexcept { - return TAfterAwaiter{ duration }; - } - - /** - * Returns awaiter that completes on actor thread when awaited. - */ - static TBindAwaiter Bind() noexcept { - TActorId actorId = SelfId(); - TActorSystem* sys = TActivationContext::ActorSystem(); - return TBindAwaiter{ sys, actorId }; - } - - /** - * Returns a task that runs the specified task, but binds the result - * back to the actor thread. Useful when the specified task may be - * working with non-actor coroutines. - */ - template<class T> - static TTask<T> Bind(TTask<T>&& task) { - return [](TTask<T> task, TBindAwaiter bindTask) -> TTask<T> { - auto result = co_await std::move(task).WhenDone(); - co_await bindTask; - co_return std::move(result).Value(); - }(std::move(task), Bind()); - } - }; - -} // namespace NActors diff --git a/library/cpp/actors/cppcoro/task_actor_ut.cpp b/library/cpp/actors/cppcoro/task_actor_ut.cpp deleted file mode 100644 index 43186bfc55..0000000000 --- a/library/cpp/actors/cppcoro/task_actor_ut.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "task_actor.h" -#include <library/cpp/actors/core/executor_pool_basic.h> -#include <library/cpp/actors/core/scheduler_basic.h> - -#include <library/cpp/testing/unittest/registar.h> - -Y_UNIT_TEST_SUITE(TaskActor) { - - using namespace NActors; - - enum : ui32 { - EvBegin = EventSpaceBegin(TEvents::ES_USERSPACE), - EvRequest, - EvResponse, - EvStop, - }; - - struct TEvRequest: public TEventLocal<TEvRequest, EvRequest> { - }; - - struct TEvResponse: public TEventLocal<TEvResponse, EvResponse> { - }; - - struct TEvStop: public TEventLocal<TEvStop, EvStop> { - }; - - TTask<void> SimpleResponder() { - for (;;) { - auto ev = co_await TTaskActor::NextEvent; - Y_ABORT_UNLESS(ev->GetTypeRewrite() == TEvRequest::EventType); - auto* msg = ev->Get<TEvRequest>(); - Y_UNUSED(msg); - TTaskActor::SelfId().Send(ev->Sender, new TEvResponse); - } - } - - TTask<void> SimpleRequester(TActorId responder, TManualEvent& doneEvent, std::atomic<int>& itemsProcessed) { - // Note: it's ok to use lambda capture because captures outlive this coroutine - auto singleRequest = [&]() -> TTask<bool> { - TTaskActor::SelfId().Send(responder, new TEvRequest); - auto ev = co_await TTaskActor::NextEvent; - switch (ev->GetTypeRewrite()) { - case TEvResponse::EventType: - co_return true; - case TEvStop::EventType: - co_return false; - default: - Y_ABORT("Unexpected event"); - } - }; - while (co_await singleRequest()) { - ++itemsProcessed; - } - doneEvent.Signal(); - } - - void Check(TDuration duration, std::unique_ptr<IEventBase> stopEvent) { - THolder<TActorSystemSetup> setup = MakeHolder<TActorSystemSetup>(); - setup->NodeId = 0; - setup->ExecutorsCount = 1; - setup->Executors.Reset(new TAutoPtr<IExecutorPool>[setup->ExecutorsCount]); - for (ui32 i = 0; i < setup->ExecutorsCount; ++i) { - setup->Executors[i] = new TBasicExecutorPool(i, 5, 10, "basic"); - } - setup->Scheduler = new TBasicSchedulerThread; - - TActorSystem actorSystem(setup); - - actorSystem.Start(); - - TManualEvent doneEvent; - std::atomic<int> itemsProcessed{0}; - - auto responder = actorSystem.Register(TTaskActor::Create(SimpleResponder())); - auto requester = actorSystem.Register(TTaskActor::Create(SimpleRequester(responder, doneEvent, itemsProcessed))); - auto deadline = TMonotonic::Now() + duration; - while (itemsProcessed.load() < 10) { - UNIT_ASSERT_C(TMonotonic::Now() < deadline, "cannot observe 10 responses in " << duration); - Sleep(TDuration::MilliSeconds(100)); - } - actorSystem.Send(requester, stopEvent.release()); - doneEvent.WaitI(); - - UNIT_ASSERT_GE(itemsProcessed.load(), 10); - - actorSystem.Stop(); - } - - Y_UNIT_TEST(Basic) { - Check(TDuration::Seconds(10), std::make_unique<TEvStop>()); - } - -} // Y_UNIT_TEST_SUITE(TaskActor) diff --git a/library/cpp/actors/cppcoro/task_group.cpp b/library/cpp/actors/cppcoro/task_group.cpp deleted file mode 100644 index 9ddd30d707..0000000000 --- a/library/cpp/actors/cppcoro/task_group.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "task_group.h" diff --git a/library/cpp/actors/cppcoro/task_group.h b/library/cpp/actors/cppcoro/task_group.h deleted file mode 100644 index 1de0cf5c1e..0000000000 --- a/library/cpp/actors/cppcoro/task_group.h +++ /dev/null @@ -1,302 +0,0 @@ -#pragma once -#include "task_result.h" -#include <util/generic/ptr.h> -#include <util/system/compiler.h> -#include <util/system/yassert.h> -#include <coroutine> -#include <atomic> -#include <memory> - -namespace NActors { - - namespace NDetail { - - template<class T> - struct TTaskGroupResult final : public TTaskResult<T> { - TTaskGroupResult* Next; - }; - - template<class T> - struct TTaskGroupSink final - : public TAtomicRefCount<TTaskGroupSink<T>> - { - std::atomic<void*> LastReady{ nullptr }; - TTaskGroupResult<T>* ReadyQueue = nullptr; - std::coroutine_handle<> Continuation; - - static constexpr uintptr_t MarkerAwaiting = 1; - static constexpr uintptr_t MarkerDetached = 2; - - ~TTaskGroupSink() noexcept { - if (!IsDetached()) { - Detach(); - } - } - - std::coroutine_handle<> Push(std::unique_ptr<TTaskGroupResult<T>>&& result) noexcept { - void* currentValue = LastReady.load(std::memory_order_acquire); - for (;;) { - if (currentValue == (void*)MarkerAwaiting) { - if (Y_UNLIKELY(!LastReady.compare_exchange_weak(currentValue, nullptr, std::memory_order_acquire))) { - continue; - } - // We consume the awaiter - Y_DEBUG_ABORT_UNLESS(ReadyQueue == nullptr, "TaskGroup is awaiting with non-empty ready queue"); - result->Next = ReadyQueue; - ReadyQueue = result.release(); - return std::exchange(Continuation, {}); - } - if (currentValue == (void*)MarkerDetached) { - // Task group is detached, discard the result - return std::noop_coroutine(); - } - TTaskGroupResult<T>* current = reinterpret_cast<TTaskGroupResult<T>*>(currentValue); - result->Next = current; - void* nextValue = result.get(); - if (Y_LIKELY(LastReady.compare_exchange_weak(currentValue, nextValue, std::memory_order_acq_rel))) { - // Result successfully added - result.release(); - return std::noop_coroutine(); - } - } - } - - bool Ready() const noexcept { - return ReadyQueue != nullptr || LastReady.load(std::memory_order_acquire) != nullptr; - } - - Y_NO_INLINE std::coroutine_handle<> Suspend(std::coroutine_handle<> h) noexcept { - Y_DEBUG_ABORT_UNLESS(ReadyQueue == nullptr, "Caller suspending with non-empty ready queue"); - Continuation = h; - void* currentValue = LastReady.load(std::memory_order_acquire); - for (;;) { - if (currentValue == nullptr) { - if (Y_UNLIKELY(!LastReady.compare_exchange_weak(currentValue, (void*)MarkerAwaiting, std::memory_order_release))) { - continue; - } - // Continuation may wake up on another thread - return std::noop_coroutine(); - } - Y_ABORT_UNLESS(currentValue != (void*)MarkerAwaiting, "TaskGroup is suspending with an awaiting marker"); - Y_ABORT_UNLESS(currentValue != (void*)MarkerDetached, "TaskGroup is suspending with a detached marker"); - // Race: ready queue is not actually empty - Continuation = {}; - return h; - } - } - - std::unique_ptr<TTaskGroupResult<T>> Resume() noexcept { - std::unique_ptr<TTaskGroupResult<T>> result; - if (ReadyQueue == nullptr) { - void* headValue = LastReady.exchange(nullptr, std::memory_order_acq_rel); - Y_ABORT_UNLESS(headValue != (void*)MarkerAwaiting, "TaskGroup is resuming with an awaiting marker"); - Y_ABORT_UNLESS(headValue != (void*)MarkerDetached, "TaskGroup is resuming with a detached marker"); - Y_ABORT_UNLESS(headValue, "TaskGroup is resuming with an empty queue"); - TTaskGroupResult<T>* head = reinterpret_cast<TTaskGroupResult<T>*>(headValue); - while (head) { - auto* next = std::exchange(head->Next, nullptr); - head->Next = ReadyQueue; - ReadyQueue = head; - head = next; - } - } - Y_ABORT_UNLESS(ReadyQueue != nullptr); - result.reset(ReadyQueue); - ReadyQueue = std::exchange(result->Next, nullptr); - return result; - } - - static void Dispose(TTaskGroupResult<T>* head) noexcept { - while (head) { - auto* next = std::exchange(head->Next, nullptr); - std::unique_ptr<TTaskGroupResult<T>> ptr(head); - head = next; - } - } - - bool IsDetached() const noexcept { - void* headValue = LastReady.load(std::memory_order_acquire); - return headValue == (void*)MarkerDetached; - } - - void Detach() noexcept { - // After this exchange all new results will be discarded - void* headValue = LastReady.exchange((void*)MarkerDetached, std::memory_order_acq_rel); - Y_ABORT_UNLESS(headValue != (void*)MarkerAwaiting, "TaskGroup is detaching with an awaiting marker"); - Y_ABORT_UNLESS(headValue != (void*)MarkerDetached, "TaskGroup is detaching with a detached marker"); - if (headValue) { - Dispose(reinterpret_cast<TTaskGroupResult<T>*>(headValue)); - } - if (ReadyQueue) { - Dispose(std::exchange(ReadyQueue, nullptr)); - } - } - }; - - template<class T> - class TTaskGroupResultHandler { - public: - void unhandled_exception() noexcept { - Result->SetException(std::current_exception()); - } - - template<class TResult> - void return_value(TResult&& result) { - Result->SetValue(std::forward<TResult>(result)); - } - - protected: - std::unique_ptr<TTaskGroupResult<T>> Result = std::make_unique<TTaskGroupResult<T>>(); - }; - - template<> - class TTaskGroupResultHandler<void> { - public: - void unhandled_exception() noexcept { - Result->SetException(std::current_exception()); - } - - void return_void() noexcept { - Result->SetValue(); - } - - protected: - std::unique_ptr<TTaskGroupResult<void>> Result = std::make_unique<TTaskGroupResult<void>>(); - }; - - template<class T> - class TTaskGroupPromise final : public TTaskGroupResultHandler<T> { - public: - using THandle = std::coroutine_handle<TTaskGroupPromise<T>>; - - THandle get_return_object() noexcept { - return THandle::from_promise(*this); - } - - static auto initial_suspend() noexcept { return std::suspend_always{}; } - - struct TFinalSuspend { - static bool await_ready() noexcept { return false; } - static void await_resume() noexcept { Y_ABORT("unexpected coroutine resume"); } - - Y_NO_INLINE - static std::coroutine_handle<> await_suspend(std::coroutine_handle<TTaskGroupPromise<T>> h) noexcept { - auto& promise = h.promise(); - auto sink = std::move(promise.Sink); - auto next = sink->Push(std::move(promise.Result)); - h.destroy(); - return next; - } - }; - - static auto final_suspend() noexcept { return TFinalSuspend{}; } - - void SetSink(const TIntrusivePtr<TTaskGroupSink<T>>& sink) { - Sink = sink; - } - - private: - TIntrusivePtr<TTaskGroupSink<T>> Sink; - }; - - template<class T> - class TTaskGroupTask final { - public: - using THandle = std::coroutine_handle<TTaskGroupPromise<T>>; - using promise_type = TTaskGroupPromise<T>; - using value_type = T; - - public: - TTaskGroupTask(THandle handle) - : Handle(handle) - {} - - void Start(const TIntrusivePtr<TTaskGroupSink<T>>& sink) { - Handle.promise().SetSink(sink); - Handle.resume(); - } - - private: - THandle Handle; - }; - - template<class T, class TAwaitable> - TTaskGroupTask<T> CreateTaskGroupTask(TAwaitable awaitable) { - co_return co_await std::move(awaitable); - } - - } // namespace NDetail - - /** - * A task group allows starting multiple subtasks of the same result type - * and awaiting them in a structured way. When task group is destroyed - * all subtasks are detached in a thread-safe way. - */ - template<class T> - class TTaskGroup { - public: - TTaskGroup() = default; - - TTaskGroup(const TTaskGroup&) = delete; - TTaskGroup(TTaskGroup&&) = delete; - TTaskGroup& operator=(const TTaskGroup&) = delete; - TTaskGroup& operator=(TTaskGroup&&) = delete; - - ~TTaskGroup() { - Sink_->Detach(); - } - - /** - * Add task to the group that will await the result of awaitable - */ - template<class TAwaitable> - void AddTask(TAwaitable&& awaitable) { - auto task = NDetail::CreateTaskGroupTask<T>(std::forward<TAwaitable>(awaitable)); - task.Start(Sink_); - ++TaskCount_; - } - - /** - * Returns the number of tasks left unawaited - */ - size_t TaskCount() const { - return TaskCount_; - } - - class TAwaiter { - public: - explicit TAwaiter(TTaskGroup& taskGroup) noexcept - : TaskGroup_(taskGroup) - {} - - bool await_ready() const noexcept { - Y_ABORT_UNLESS(TaskGroup_.TaskCount_ > 0, "Not enough tasks to await"); - --TaskGroup_.TaskCount_; - return TaskGroup_.Sink_->Ready(); - } - - std::coroutine_handle<> await_suspend(std::coroutine_handle<> h) noexcept { - return TaskGroup_.Sink_->Suspend(h); - } - - T await_resume() { - return std::move(*TaskGroup_.Sink_->Resume()).Value(); - } - - private: - TTaskGroup& TaskGroup_; - }; - - /** - * Await result of the next task in the task group - */ - TAwaiter operator co_await() noexcept { - return TAwaiter(*this); - } - - private: - TIntrusivePtr<NDetail::TTaskGroupSink<T>> Sink_ = MakeIntrusive<NDetail::TTaskGroupSink<T>>(); - size_t TaskCount_ = 0; - }; - -} // namespace NActors diff --git a/library/cpp/actors/cppcoro/task_result.cpp b/library/cpp/actors/cppcoro/task_result.cpp deleted file mode 100644 index bb1a1dc5ca..0000000000 --- a/library/cpp/actors/cppcoro/task_result.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "task_result.h" diff --git a/library/cpp/actors/cppcoro/task_result.h b/library/cpp/actors/cppcoro/task_result.h deleted file mode 100644 index da78c53b7a..0000000000 --- a/library/cpp/actors/cppcoro/task_result.h +++ /dev/null @@ -1,113 +0,0 @@ -#pragma once -#include <util/system/yassert.h> -#include <exception> -#include <variant> - -namespace NActors { - - namespace NDetail { - - struct TVoid {}; - - template<class T> - struct TReplaceVoid { - using TType = T; - }; - - template<> - struct TReplaceVoid<void> { - using TType = TVoid; - }; - - template<class T> - struct TLValue { - using TType = T&; - }; - - template<> - struct TLValue<void> { - using TType = void; - }; - - template<class T> - struct TRValue { - using TType = T&&; - }; - - template<> - struct TRValue<void> { - using TType = void; - }; - - } // namespace NDetail - - /** - * Wrapper for the task result - */ - template<class T> - class TTaskResult { - public: - void SetValue() - requires (std::same_as<T, void>) - { - Result.template emplace<1>(); - } - - template<class TResult> - void SetValue(TResult&& result) - requires (!std::same_as<T, void>) - { - Result.template emplace<1>(std::forward<TResult>(result)); - } - - void SetException(std::exception_ptr&& e) noexcept { - Result.template emplace<2>(std::move(e)); - } - - typename NDetail::TLValue<T>::TType Value() & { - switch (Result.index()) { - case 0: { - Y_ABORT("Task result has no value"); - } - case 1: { - if constexpr (std::same_as<T, void>) { - return; - } else { - return std::get<1>(Result); - } - } - case 2: { - std::exception_ptr& e = std::get<2>(Result); - Y_DEBUG_ABORT_UNLESS(e, "Task exception missing"); - std::rethrow_exception(e); - } - } - Y_ABORT("Task result has an invalid state"); - } - - typename NDetail::TRValue<T>::TType Value() && { - switch (Result.index()) { - case 0: { - Y_ABORT("Task result has no value"); - } - case 1: { - if constexpr (std::same_as<T, void>) { - return; - } else { - return std::get<1>(std::move(Result)); - } - } - case 2: { - std::exception_ptr& e = std::get<2>(Result); - Y_DEBUG_ABORT_UNLESS(e, "Task exception missing"); - std::rethrow_exception(std::move(e)); - } - } - Y_ABORT("Task result has an invalid state"); - } - - private: - std::variant<std::monostate, typename NDetail::TReplaceVoid<T>::TType, std::exception_ptr> Result; - }; - -} // namespace NActors diff --git a/library/cpp/actors/cppcoro/task_ut.cpp b/library/cpp/actors/cppcoro/task_ut.cpp deleted file mode 100644 index a1ed5426fc..0000000000 --- a/library/cpp/actors/cppcoro/task_ut.cpp +++ /dev/null @@ -1,263 +0,0 @@ -#include "task.h" -#include "task_group.h" -#include "await_callback.h" -#include <library/cpp/testing/unittest/registar.h> - -using namespace NActors; - -Y_UNIT_TEST_SUITE(Task) { - - TTask<void> SimpleReturnVoid() { - co_return; - } - - TTask<int> SimpleReturn42() { - co_return 42; - } - - Y_UNIT_TEST(SimpleVoidCoroutine) { - bool finished = false; - AwaitThenCallback(SimpleReturnVoid(), [&]() { - finished = true; - }); - UNIT_ASSERT(finished); - } - - Y_UNIT_TEST(SimpleIntCoroutine) { - std::optional<int> result; - AwaitThenCallback(SimpleReturn42(), [&](int value) { - result = value; - }); - UNIT_ASSERT(result); - UNIT_ASSERT_VALUES_EQUAL(*result, 42); - } - - Y_UNIT_TEST(SimpleVoidWhenDone) { - std::optional<TTaskResult<void>> result; - AwaitThenCallback(SimpleReturnVoid().WhenDone(), [&](auto value) { - result = std::move(value); - }); - UNIT_ASSERT(result); - result->Value(); - } - - Y_UNIT_TEST(SimpleIntWhenDone) { - std::optional<TTaskResult<int>> result; - AwaitThenCallback(SimpleReturn42().WhenDone(), [&](auto value) { - result = std::move(value); - }); - UNIT_ASSERT(result); - UNIT_ASSERT_VALUES_EQUAL(result->Value(), 42); - } - - template<class TCallback> - TTask<int> CallTwice(TCallback callback) { - int a = co_await callback(); - int b = co_await callback(); - co_return a + b; - } - - Y_UNIT_TEST(NestedAwait) { - auto task = CallTwice([]{ - return SimpleReturn42(); - }); - UNIT_ASSERT(task); - std::optional<int> result; - AwaitThenCallback(std::move(task), [&](int value) { - result = value; - }); - UNIT_ASSERT(result); - UNIT_ASSERT_VALUES_EQUAL(*result, 84); - } - - template<class T> - struct TPauseState { - std::coroutine_handle<> Next; - std::optional<T> NextResult; - - ~TPauseState() { - while (Next) { - NextResult.reset(); - std::exchange(Next, {}).resume(); - } - } - - struct TAwaiter { - TPauseState* State; - - bool await_ready() const noexcept { return false; } - void await_suspend(std::coroutine_handle<> c) const noexcept { - State->Next = c; - } - T await_resume() const { - if (!State->NextResult) { - throw TTaskCancelled(); - } else { - T result = std::move(*State->NextResult); - State->NextResult.reset(); - return result; - } - } - }; - - auto Wait() { - return TAwaiter{ this }; - } - - explicit operator bool() const { - return bool(Next); - } - - void Resume(T result) { - Y_ABORT_UNLESS(Next && !Next.done()); - NextResult = result; - std::exchange(Next, {}).resume(); - } - - void Cancel() { - Y_ABORT_UNLESS(Next && !Next.done()); - NextResult.reset(); - std::exchange(Next, {}).resume(); - } - }; - - Y_UNIT_TEST(PauseResume) { - TPauseState<int> state; - auto task = CallTwice([&]{ - return state.Wait(); - }); - std::optional<int> result; - AwaitThenCallback(std::move(task), [&](int value) { - result = value; - }); - UNIT_ASSERT(!result); - UNIT_ASSERT(state); - state.Resume(11); - UNIT_ASSERT(!result); - UNIT_ASSERT(state); - state.Resume(22); - UNIT_ASSERT(result); - UNIT_ASSERT_VALUES_EQUAL(*result, 33); - } - - Y_UNIT_TEST(PauseCancel) { - TPauseState<int> state; - auto task = CallTwice([&]{ - return state.Wait(); - }); - std::optional<int> result; - AwaitThenCallback(std::move(task).WhenDone(), [&](TTaskResult<int>&& value) { - try { - result = value.Value(); - } catch (TTaskCancelled&) { - // nothing - } - }); - UNIT_ASSERT(!result); - UNIT_ASSERT(state); - state.Resume(11); - UNIT_ASSERT(!result); - UNIT_ASSERT(state); - state.Cancel(); - UNIT_ASSERT(!result); - } - - Y_UNIT_TEST(GroupWithTwoSubTasks) { - TPauseState<int> state1; - TPauseState<int> state2; - - std::vector<int> results; - auto task = [](auto& state1, auto& state2, auto& results) -> TTask<int> { - TTaskGroup<int> group; - group.AddTask(state1.Wait()); - group.AddTask(state2.Wait()); - int a = co_await group; - results.push_back(a); - int b = co_await group; - results.push_back(b); - co_return a + b; - }(state1, state2, results); - - std::optional<int> result; - AwaitThenCallback(std::move(task), [&](int value) { - result = value; - }); - - // We must be waiting for both states - UNIT_ASSERT(state1); - UNIT_ASSERT(state2); - state2.Resume(22); - UNIT_ASSERT_VALUES_EQUAL(results.size(), 1u); - UNIT_ASSERT_VALUES_EQUAL(results.at(0), 22); - UNIT_ASSERT(!result); - state1.Resume(11); - UNIT_ASSERT_VALUES_EQUAL(results.size(), 2u); - UNIT_ASSERT_VALUES_EQUAL(results.at(1), 11); - UNIT_ASSERT(result); - UNIT_ASSERT_VALUES_EQUAL(*result, 33); - } - - Y_UNIT_TEST(GroupWithTwoSubTasksDetached) { - TPauseState<int> state1; - TPauseState<int> state2; - - std::vector<int> results; - auto task = [](auto& state1, auto& state2, auto& results) -> TTask<int> { - TTaskGroup<int> group; - group.AddTask(state1.Wait()); - group.AddTask(state2.Wait()); - int a = co_await group; - results.push_back(a); - co_return a; - }(state1, state2, results); - - std::optional<int> result; - AwaitThenCallback(std::move(task), [&](int value) { - result = value; - }); - - // We must be waiting for both states - UNIT_ASSERT(state1); - UNIT_ASSERT(state2); - state2.Resume(22); - UNIT_ASSERT_VALUES_EQUAL(results.size(), 1u); - UNIT_ASSERT_VALUES_EQUAL(results.at(0), 22); - UNIT_ASSERT(result); - UNIT_ASSERT_VALUES_EQUAL(*result, 22); - } - - Y_UNIT_TEST(GroupWithTwoSubTasksOneCancelled) { - TPauseState<int> state1; - TPauseState<int> state2; - std::vector<int> results; - auto task = [](auto& state1, auto& state2, auto& results) -> TTask<void> { - TTaskGroup<int> group; - group.AddTask(state1.Wait()); - group.AddTask(state2.Wait()); - for (int i = 0; i < 2; ++i) { - try { - results.push_back(co_await group); - } catch (TTaskCancelled&) { - results.push_back(-1); - } - } - }(state1, state2, results); - - bool finished = false; - AwaitThenCallback(std::move(task), [&]() { - finished = true; - }); - - UNIT_ASSERT(state1); - UNIT_ASSERT(state2); - state2.Cancel(); - UNIT_ASSERT_VALUES_EQUAL(results.size(), 1u); - UNIT_ASSERT_VALUES_EQUAL(results.at(0), -1); - UNIT_ASSERT(!finished); - state1.Resume(11); - UNIT_ASSERT_VALUES_EQUAL(results.size(), 2u); - UNIT_ASSERT_VALUES_EQUAL(results.at(1), 11); - UNIT_ASSERT(finished); - } - -} // Y_UNIT_TEST_SUITE(Task) diff --git a/library/cpp/actors/cppcoro/ut/CMakeLists.darwin-arm64.txt b/library/cpp/actors/cppcoro/ut/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 5ec40dbae9..0000000000 --- a/library/cpp/actors/cppcoro/ut/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,68 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-cppcoro-ut) -target_include_directories(library-cpp-actors-cppcoro-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro -) -target_link_libraries(library-cpp-actors-cppcoro-ut PUBLIC - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-cppcoro - cpp-actors-testlib -) -target_link_options(library-cpp-actors-cppcoro-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-cppcoro-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_actor_ut.cpp -) -set_property( - TARGET - library-cpp-actors-cppcoro-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-cppcoro-ut - TEST_TARGET - library-cpp-actors-cppcoro-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-cppcoro-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-cppcoro-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-cppcoro-ut - system_allocator -) -vcs_info(library-cpp-actors-cppcoro-ut) diff --git a/library/cpp/actors/cppcoro/ut/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/cppcoro/ut/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 7cebff01de..0000000000 --- a/library/cpp/actors/cppcoro/ut/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,69 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-cppcoro-ut) -target_include_directories(library-cpp-actors-cppcoro-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro -) -target_link_libraries(library-cpp-actors-cppcoro-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-cppcoro - cpp-actors-testlib -) -target_link_options(library-cpp-actors-cppcoro-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-cppcoro-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_actor_ut.cpp -) -set_property( - TARGET - library-cpp-actors-cppcoro-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-cppcoro-ut - TEST_TARGET - library-cpp-actors-cppcoro-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-cppcoro-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-cppcoro-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-cppcoro-ut - system_allocator -) -vcs_info(library-cpp-actors-cppcoro-ut) diff --git a/library/cpp/actors/cppcoro/ut/CMakeLists.linux-aarch64.txt b/library/cpp/actors/cppcoro/ut/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 4a11af3456..0000000000 --- a/library/cpp/actors/cppcoro/ut/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,72 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-cppcoro-ut) -target_include_directories(library-cpp-actors-cppcoro-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro -) -target_link_libraries(library-cpp-actors-cppcoro-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-cppcoro - cpp-actors-testlib -) -target_link_options(library-cpp-actors-cppcoro-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-cppcoro-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_actor_ut.cpp -) -set_property( - TARGET - library-cpp-actors-cppcoro-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-cppcoro-ut - TEST_TARGET - library-cpp-actors-cppcoro-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-cppcoro-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-cppcoro-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-cppcoro-ut - cpp-malloc-jemalloc -) -vcs_info(library-cpp-actors-cppcoro-ut) diff --git a/library/cpp/actors/cppcoro/ut/CMakeLists.linux-x86_64.txt b/library/cpp/actors/cppcoro/ut/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 2e2412f989..0000000000 --- a/library/cpp/actors/cppcoro/ut/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,74 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-cppcoro-ut) -target_include_directories(library-cpp-actors-cppcoro-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro -) -target_link_libraries(library-cpp-actors-cppcoro-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-cppcoro - cpp-actors-testlib -) -target_link_options(library-cpp-actors-cppcoro-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-cppcoro-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_actor_ut.cpp -) -set_property( - TARGET - library-cpp-actors-cppcoro-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-cppcoro-ut - TEST_TARGET - library-cpp-actors-cppcoro-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-cppcoro-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-cppcoro-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-cppcoro-ut - cpp-malloc-tcmalloc - libs-tcmalloc-no_percpu_cache -) -vcs_info(library-cpp-actors-cppcoro-ut) diff --git a/library/cpp/actors/cppcoro/ut/CMakeLists.txt b/library/cpp/actors/cppcoro/ut/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/cppcoro/ut/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/cppcoro/ut/CMakeLists.windows-x86_64.txt b/library/cpp/actors/cppcoro/ut/CMakeLists.windows-x86_64.txt deleted file mode 100644 index e3b8b019c8..0000000000 --- a/library/cpp/actors/cppcoro/ut/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,62 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-cppcoro-ut) -target_include_directories(library-cpp-actors-cppcoro-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro -) -target_link_libraries(library-cpp-actors-cppcoro-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-cppcoro - cpp-actors-testlib -) -target_sources(library-cpp-actors-cppcoro-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/cppcoro/task_actor_ut.cpp -) -set_property( - TARGET - library-cpp-actors-cppcoro-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-cppcoro-ut - TEST_TARGET - library-cpp-actors-cppcoro-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-cppcoro-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-cppcoro-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-cppcoro-ut - system_allocator -) -vcs_info(library-cpp-actors-cppcoro-ut) diff --git a/library/cpp/actors/cppcoro/ut/ya.make b/library/cpp/actors/cppcoro/ut/ya.make deleted file mode 100644 index 24a9c73613..0000000000 --- a/library/cpp/actors/cppcoro/ut/ya.make +++ /dev/null @@ -1,12 +0,0 @@ -UNITTEST_FOR(library/cpp/actors/cppcoro) - -PEERDIR( - library/cpp/actors/testlib -) - -SRCS( - task_ut.cpp - task_actor_ut.cpp -) - -END() diff --git a/library/cpp/actors/cppcoro/ya.make b/library/cpp/actors/cppcoro/ya.make deleted file mode 100644 index 4df4f05302..0000000000 --- a/library/cpp/actors/cppcoro/ya.make +++ /dev/null @@ -1,25 +0,0 @@ -LIBRARY() - -PEERDIR( - library/cpp/actors/core -) - -SRCS( - await_callback.cpp - await_callback.h - task_actor.cpp - task_actor.h - task_group.cpp - task_group.h - task_result.cpp - task_result.h - task.cpp - task.h -) - -END() - -RECURSE_FOR_TESTS( - corobenchmark - ut -) diff --git a/library/cpp/actors/dnscachelib/CMakeLists.darwin-arm64.txt b/library/cpp/actors/dnscachelib/CMakeLists.darwin-arm64.txt deleted file mode 100644 index b769b26408..0000000000 --- a/library/cpp/actors/dnscachelib/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,21 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(cpp-actors-dnscachelib) -target_link_libraries(cpp-actors-dnscachelib PUBLIC - contrib-libs-cxxsupp - yutil - contrib-libs-c-ares - library-cpp-lwtrace - cpp-deprecated-atomic -) -target_sources(cpp-actors-dnscachelib PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnscachelib/dnscache.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnscachelib/probes.cpp -) diff --git a/library/cpp/actors/dnscachelib/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/dnscachelib/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index b769b26408..0000000000 --- a/library/cpp/actors/dnscachelib/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,21 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(cpp-actors-dnscachelib) -target_link_libraries(cpp-actors-dnscachelib PUBLIC - contrib-libs-cxxsupp - yutil - contrib-libs-c-ares - library-cpp-lwtrace - cpp-deprecated-atomic -) -target_sources(cpp-actors-dnscachelib PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnscachelib/dnscache.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnscachelib/probes.cpp -) diff --git a/library/cpp/actors/dnscachelib/CMakeLists.linux-aarch64.txt b/library/cpp/actors/dnscachelib/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 60de9ca5ab..0000000000 --- a/library/cpp/actors/dnscachelib/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,22 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(cpp-actors-dnscachelib) -target_link_libraries(cpp-actors-dnscachelib PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - contrib-libs-c-ares - library-cpp-lwtrace - cpp-deprecated-atomic -) -target_sources(cpp-actors-dnscachelib PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnscachelib/dnscache.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnscachelib/probes.cpp -) diff --git a/library/cpp/actors/dnscachelib/CMakeLists.linux-x86_64.txt b/library/cpp/actors/dnscachelib/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 60de9ca5ab..0000000000 --- a/library/cpp/actors/dnscachelib/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,22 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(cpp-actors-dnscachelib) -target_link_libraries(cpp-actors-dnscachelib PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - contrib-libs-c-ares - library-cpp-lwtrace - cpp-deprecated-atomic -) -target_sources(cpp-actors-dnscachelib PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnscachelib/dnscache.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnscachelib/probes.cpp -) diff --git a/library/cpp/actors/dnscachelib/CMakeLists.txt b/library/cpp/actors/dnscachelib/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/dnscachelib/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/dnscachelib/CMakeLists.windows-x86_64.txt b/library/cpp/actors/dnscachelib/CMakeLists.windows-x86_64.txt deleted file mode 100644 index b769b26408..0000000000 --- a/library/cpp/actors/dnscachelib/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,21 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(cpp-actors-dnscachelib) -target_link_libraries(cpp-actors-dnscachelib PUBLIC - contrib-libs-cxxsupp - yutil - contrib-libs-c-ares - library-cpp-lwtrace - cpp-deprecated-atomic -) -target_sources(cpp-actors-dnscachelib PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnscachelib/dnscache.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnscachelib/probes.cpp -) diff --git a/library/cpp/actors/dnscachelib/dnscache.cpp b/library/cpp/actors/dnscachelib/dnscache.cpp deleted file mode 100644 index 91ed284c12..0000000000 --- a/library/cpp/actors/dnscachelib/dnscache.cpp +++ /dev/null @@ -1,458 +0,0 @@ -#include "dnscache.h" -#include "probes.h" -#include "timekeeper.h" - -#include <ares.h> -#include <util/system/guard.h> -#include <util/datetime/systime.h> - -const TDnsCache::THost TDnsCache::NullHost; - -LWTRACE_USING(DNSCACHELIB_PROVIDER); - -static_assert(sizeof(ares_channel) == sizeof(void*), "expect sizeof(ares_channel) == sizeof(void *)"); - -TDnsCache::TDnsCache(bool allowIpv4, bool allowIpv6, time_t lifetime, time_t neg, ui32 timeout) - : EntryLifetime(lifetime) - , NegativeLifetime(neg) - , Timeout(TDuration::MicroSeconds(timeout)) - , AllowIpV4(allowIpv4) - , AllowIpV6(allowIpv6) - , ACacheHits(0) - , ACacheMisses(0) - , PtrCacheHits(0) - , PtrCacheMisses(0) -{ -#ifdef _win_ - if (ares_library_init(ARES_LIB_INIT_WIN32) != ARES_SUCCESS) { - LWPROBE(AresInitFailed); - ythrow yexception() << "ares_init() failed"; - } -#endif - - ares_channel chan; - - if (ares_init(&chan) != ARES_SUCCESS) { - LWPROBE(AresInitFailed); - ythrow yexception() << "ares_init() failed"; - } - Channel = chan; - LWPROBE(Created); -} - -TDnsCache::~TDnsCache(void) { - ares_channel chan = static_cast<ares_channel>(Channel); - - ares_cancel(chan); - ares_destroy(chan); - LWPROBE(Destroyed); - -#ifdef _win_ - ares_library_cleanup(); -#endif -} - -TString TDnsCache::GetHostByAddr(const NAddr::IRemoteAddr& addr) { - in6_addr key; - - if (addr.Addr()->sa_family == AF_INET6) { - const struct sockaddr_in6* s6 = (const struct sockaddr_in6*)(addr.Addr()); - memcpy(&key, &s6->sin6_addr, sizeof(s6->sin6_addr)); - } else if (addr.Addr()->sa_family == AF_INET) { - const struct sockaddr_in* s4 = (const struct sockaddr_in*)(addr.Addr()); - memset(&key, 0, sizeof(key)); - memcpy(&key, &s4->sin_addr, sizeof(s4->sin_addr)); - } else { - return ""; - } - const TAddr& host = ResolveAddr(key, addr.Addr()->sa_family); - - return host.Hostname; -} - -TIpHost TDnsCache::Get(const TString& hostname) { - if (!AllowIpV4) - return TIpHost(-1); - - const THost& addr = Resolve(hostname, AF_INET); - - TGuard<TMutex> lock(CacheMtx); - if (addr.AddrsV4.empty()) { - return TIpHost(-1); - } - return addr.AddrsV4.front(); -} - -NAddr::IRemoteAddrPtr TDnsCache::GetAddr( - const TString& hostname, - int family, - TIpPort port, - bool cacheOnly) { - if (family != AF_INET && AllowIpV6) { - const THost& addr = Resolve(hostname, AF_INET6, cacheOnly); - - TGuard<TMutex> lock(CacheMtx); - if (!addr.AddrsV6.empty()) { - struct sockaddr_in6 sin6; - Zero(sin6); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = addr.AddrsV6.front(); - sin6.sin6_port = HostToInet(port); - - return MakeHolder<NAddr::TIPv6Addr>(sin6); - } - } - - if (family != AF_INET6 && AllowIpV4) { - const THost& addr = Resolve(hostname, AF_INET, cacheOnly); - - TGuard<TMutex> lock(CacheMtx); - if (!addr.AddrsV4.empty()) { - return MakeHolder<NAddr::TIPv4Addr>(TIpAddress(addr.AddrsV4.front(), port)); - } - } - - LWPROBE(FamilyMismatch, family, AllowIpV4, AllowIpV6); - return nullptr; -} - -void TDnsCache::GetAllAddresses( - const TString& hostname, - TVector<NAddr::IRemoteAddrPtr>& addrs) { - if (AllowIpV4) { - const THost& addr4 = Resolve(hostname, AF_INET); - - TGuard<TMutex> lock(CacheMtx); - for (size_t i = 0; i < addr4.AddrsV4.size(); i++) { - addrs.push_back(MakeHolder<NAddr::TIPv4Addr>(TIpAddress(addr4.AddrsV4[i], 0))); - } - } - - if (AllowIpV6) { - const THost& addr6 = Resolve(hostname, AF_INET6); - - struct sockaddr_in6 sin6; - Zero(sin6); - sin6.sin6_family = AF_INET6; - - TGuard<TMutex> lock(CacheMtx); - for (size_t i = 0; i < addr6.AddrsV6.size(); i++) { - sin6.sin6_addr = addr6.AddrsV6[i]; - - addrs.push_back(MakeHolder<NAddr::TIPv6Addr>(sin6)); - } - } -} - -void TDnsCache::GetStats(ui64& a_cache_hits, ui64& a_cache_misses, - ui64& ptr_cache_hits, ui64& ptr_cache_misses) { - TGuard<TMutex> lock(CacheMtx); - - a_cache_hits = ACacheHits; - a_cache_misses = ACacheMisses; - ptr_cache_hits = PtrCacheHits; - ptr_cache_misses = PtrCacheMisses; -} - -bool TDnsCache::THost::IsStale(int family, const TDnsCache* ctx) const noexcept { - time_t resolved = family == AF_INET ? ResolvedV4 : ResolvedV6; - time_t notfound = family == AF_INET ? NotFoundV4 : NotFoundV6; - - if (TTimeKeeper::GetTime() - resolved < ctx->EntryLifetime) - return false; - - if (TTimeKeeper::GetTime() - notfound < ctx->NegativeLifetime) - return false; - - return true; -} - -const TDnsCache::THost& -TDnsCache::Resolve(const TString& hostname, int family, bool cacheOnly) { - if (!ValidateHName(hostname)) { - LWPROBE(ResolveNullHost, hostname, family); - return NullHost; - } - - THostCache::iterator p; - - Y_ASSERT(family == AF_INET || family == AF_INET6); - - { - TGuard<TMutex> lock(CacheMtx); - p = HostCache.find(hostname); - if (p != HostCache.end()) { - if (!p->second.IsStale(family, this)) { - /* Recently resolved, just return cached value */ - ACacheHits += 1; - THost& host = p->second; - LWPROBE(ResolveFromCache, hostname, family, host.AddrsV4ToString(), host.AddrsV6ToString(), ACacheHits); - return host; - } else { - LWPROBE(ResolveCacheTimeout, hostname); - } - } else { - /* Never resolved, create cache entry */ - LWPROBE(ResolveCacheNew, hostname); - p = HostCache.insert(std::make_pair(hostname, THost())).first; - } - ACacheMisses += 1; - } - - if (cacheOnly) - return NullHost; - - TAtomic& inprogress = (family == AF_INET ? p->second.InProgressV4 : p->second.InProgressV6); - - { - /* This way only! CacheMtx should always be taken AFTER AresMtx, - * because later in ares_process it can only be done this way. - * Lock order reversal will cause deadlock in unfortunate monents. - */ - TGuard<TMutex> areslock(AresMtx); - TGuard<TMutex> cachelock(CacheMtx); - - if (!inprogress) { - ares_channel chan = static_cast<ares_channel>(Channel); - TGHBNContext* ctx = new TGHBNContext(); - ctx->Owner = this; - ctx->Hostname = hostname; - ctx->Family = family; - - AtomicSet(inprogress, 1); - ares_gethostbyname(chan, hostname.c_str(), family, - &TDnsCache::GHBNCallback, ctx); - } - } - - WaitTask(inprogress); - - LWPROBE(ResolveDone, hostname, family, p->second.AddrsV4ToString(), p->second.AddrsV6ToString()); - return p->second; -} - -bool TDnsCache::ValidateHName(const TString& name) const noexcept { - return name.size() > 0; -} - -const TDnsCache::TAddr& TDnsCache::ResolveAddr(const in6_addr& addr, int family) { - TAddrCache::iterator p; - - { - TGuard<TMutex> lock(CacheMtx); - p = AddrCache.find(addr); - if (p != AddrCache.end()) { - if (TTimeKeeper::GetTime() - p->second.Resolved < EntryLifetime || TTimeKeeper::GetTime() - p->second.NotFound < NegativeLifetime) { - /* Recently resolved, just return cached value */ - PtrCacheHits += 1; - return p->second; - } - } else { - /* Never resolved, create cache entry */ - - p = AddrCache.insert(std::make_pair(addr, TAddr())).first; - } - PtrCacheMisses += 1; - } - - { - /* This way only! CacheMtx should always be taken AFTER AresMtx, - * because later in ares_process it can only be done this way. - * Lock order reversal will cause deadlock in unfortunate monents. - */ - TGuard<TMutex> areslock(AresMtx); - TGuard<TMutex> cachelock(CacheMtx); - - if (!p->second.InProgress) { - ares_channel chan = static_cast<ares_channel>(Channel); - TGHBAContext* ctx = new TGHBAContext(); - ctx->Owner = this; - ctx->Addr = addr; - - AtomicSet(p->second.InProgress, 1); - ares_gethostbyaddr(chan, &addr, - family == AF_INET ? sizeof(in_addr) : sizeof(in6_addr), - family, &TDnsCache::GHBACallback, ctx); - } - } - - WaitTask(p->second.InProgress); - - return p->second; -} - -void TDnsCache::WaitTask(TAtomic& flag) { - const TInstant start = TInstant(TTimeKeeper::GetTimeval()); - - while (AtomicGet(flag)) { - ares_channel chan = static_cast<ares_channel>(Channel); - - struct pollfd pfd[ARES_GETSOCK_MAXNUM]; - int nfds; - ares_socket_t socks[ARES_GETSOCK_MAXNUM]; - int bits; - - { - TGuard<TMutex> lock(AresMtx); - bits = ares_getsock(chan, socks, ARES_GETSOCK_MAXNUM); - if (bits == 0) { - /* other thread did our job */ - continue; - } - } - - for (nfds = 0; nfds < ARES_GETSOCK_MAXNUM; nfds++) { - pfd[nfds].events = 0; - pfd[nfds].revents = 0; - if (ARES_GETSOCK_READABLE(bits, nfds)) { - pfd[nfds].fd = socks[nfds]; - pfd[nfds].events |= POLLRDNORM | POLLIN; - } - if (ARES_GETSOCK_WRITABLE(bits, nfds)) { - pfd[nfds].fd = socks[nfds]; - pfd[nfds].events |= POLLWRNORM | POLLOUT; - } - if (pfd[nfds].events == 0) { - break; - } - } - - Y_ASSERT(nfds != 0); - - const TDuration left = TInstant(TTimeKeeper::GetTimeval()) - start; - const TDuration wait = Max(Timeout - left, TDuration::Zero()); - - int rv = poll(pfd, nfds, wait.MilliSeconds()); - - if (rv == -1) { - if (errno == EINTR) { - continue; - } - /* Unknown error in select, can't recover. Just pretend there was no reply */ - rv = 0; - } - - if (rv == 0) { - /* poll() timed out */ - TGuard<TMutex> lock(AresMtx); - ares_process_fd(chan, ARES_SOCKET_BAD, ARES_SOCKET_BAD); - } else { - for (int i = 0; i < nfds; i++) { - if (pfd[i].revents == 0) { - continue; - } - TGuard<TMutex> lock(AresMtx); - ares_process_fd(chan, - pfd[i].revents & (POLLRDNORM | POLLIN) - ? pfd[i].fd - : ARES_SOCKET_BAD, - pfd[i].revents & (POLLWRNORM | POLLOUT) - ? pfd[i].fd - : ARES_SOCKET_BAD); - } - } - - if (start + Timeout <= TInstant(TTimeKeeper::GetTimeval())) { - break; - } - } -} - -void TDnsCache::GHBNCallback(void* arg, int status, int, struct hostent* info) { - THolder<TGHBNContext> ctx(static_cast<TGHBNContext*>(arg)); - TGuard<TMutex> lock(ctx->Owner->CacheMtx); - THostCache::iterator p = ctx->Owner->HostCache.find(ctx->Hostname); - - Y_ASSERT(p != ctx->Owner->HostCache.end()); - - time_t& resolved = (ctx->Family == AF_INET ? p->second.ResolvedV4 : p->second.ResolvedV6); - time_t& notfound = (ctx->Family == AF_INET ? p->second.NotFoundV4 : p->second.NotFoundV6); - TAtomic& inprogress = (ctx->Family == AF_INET ? p->second.InProgressV4 : p->second.InProgressV6); - - if (status == ARES_SUCCESS) { - if (info->h_addrtype == AF_INET) { - p->second.AddrsV4.clear(); - for (int i = 0; info->h_addr_list[i] != nullptr; i++) { - p->second.AddrsV4.push_back(*(TIpHost*)(info->h_addr_list[i])); - } - /* It is possible to ask ares for IPv6 and have IPv4 addrs instead, - so take care and set V4 timers anyway. - */ - p->second.ResolvedV4 = TTimeKeeper::GetTime(); - p->second.ResolvedV4 = 0; - AtomicSet(p->second.InProgressV4, 0); - } else if (info->h_addrtype == AF_INET6) { - p->second.AddrsV6.clear(); - for (int i = 0; info->h_addr_list[i] != nullptr; i++) { - p->second.AddrsV6.push_back(*(struct in6_addr*)(info->h_addr_list[i])); - } - } else { - Y_ABORT("unknown address type in ares callback"); - } - resolved = TTimeKeeper::GetTime(); - notfound = 0; - } else { - notfound = TTimeKeeper::GetTime(); - resolved = 0; - } - AtomicSet(inprogress, 0); -} - -void TDnsCache::GHBACallback(void* arg, int status, int, struct hostent* info) { - THolder<TGHBAContext> ctx(static_cast<TGHBAContext*>(arg)); - TGuard<TMutex> lock(ctx->Owner->CacheMtx); - TAddrCache::iterator p = ctx->Owner->AddrCache.find(ctx->Addr); - - Y_ASSERT(p != ctx->Owner->AddrCache.end()); - - if (status == ARES_SUCCESS) { - p->second.Hostname = info->h_name; - p->second.Resolved = TTimeKeeper::GetTime(); - p->second.NotFound = 0; - } else { - p->second.NotFound = TTimeKeeper::GetTime(); - p->second.Resolved = 0; - } - AtomicSet(p->second.InProgress, 0); -} - -TString TDnsCache::THost::AddrsV4ToString() const { - TStringStream ss; - bool first = false; - for (TIpHost addr : AddrsV4) { - ss << (first ? "" : " ") << IpToString(addr); - first = false; - } - return ss.Str(); -} - -TString TDnsCache::THost::AddrsV6ToString() const { - TStringStream ss; - bool first = false; - for (in6_addr addr : AddrsV6) { - struct sockaddr_in6 sin6; - Zero(sin6); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = addr; - - NAddr::TIPv6Addr addr6(sin6); - ss << (first ? "" : " ") << NAddr::PrintHost(addr6); - first = false; - } - return ss.Str(); -} - -TDnsCache::TAresLibInit::TAresLibInit() { -#ifdef _win_ - const auto res = ares_library_init(ARES_LIB_INIT_ALL); - Y_ABORT_UNLESS(res == 0); -#endif -} - -TDnsCache::TAresLibInit::~TAresLibInit() { -#ifdef _win_ - ares_library_cleanup(); -#endif -} - -TDnsCache::TAresLibInit TDnsCache::InitAresLib; diff --git a/library/cpp/actors/dnscachelib/dnscache.h b/library/cpp/actors/dnscachelib/dnscache.h deleted file mode 100644 index ac36e6ddc0..0000000000 --- a/library/cpp/actors/dnscachelib/dnscache.h +++ /dev/null @@ -1,139 +0,0 @@ -#pragma once - -#include <library/cpp/deprecated/atomic/atomic.h> - -#include <util/generic/map.h> -#include <util/generic/vector.h> -#include <util/network/address.h> -#include <util/system/mutex.h> -#include <util/datetime/base.h> - -/** Asynchronous DNS resolver. - * - * This is NOT general purpose resolver! It is designed with very specific assumptions: - * 1) there is relatively small and rarely changed set of resolved names (like, server pool in cluster) - * 2) this names supposed to have addresses, absense of A record is equal to DNS error - * 3) most of the time IP addresses do not change - * 4) it's OK to return old IP address when DNS server not responding in time - */ - -class TDnsCache { -public: - TDnsCache(bool allowIpv4 = true, bool allowIpv6 = true, time_t entry_lifetime = 1800, time_t neg_lifetime = 1, ui32 request_timeout = 500000); - ~TDnsCache(); - - TString GetHostByAddr(const NAddr::IRemoteAddr&); - - // ip in network byte order - TIpHost Get(const TString& host); - - /* use with AF_INET, AF_INET6 or AF_UNSPEC */ - NAddr::IRemoteAddrPtr GetAddr(const TString& host, - int family, - TIpPort port = 0, - bool cacheOnly = false); - - void GetAllAddresses(const TString& host, TVector<NAddr::IRemoteAddrPtr>&); - - void GetStats(ui64& a_cache_hits, ui64& a_cache_misses, - ui64& ptr_cache_hits, ui64& ptr_cache_misses); - -protected: - bool ValidateHName(const TString& host) const noexcept; - -private: - struct TGHBNContext { - TDnsCache* Owner; - TString Hostname; - int Family; - }; - - struct TGHBAContext { - TDnsCache* Owner; - in6_addr Addr; - }; - - struct THost { - THost() noexcept { - } - - TVector<TIpHost> AddrsV4; - time_t ResolvedV4 = 0; - time_t NotFoundV4 = 0; - TAtomic InProgressV4 = 0; - - TVector<in6_addr> AddrsV6; - time_t ResolvedV6 = 0; - time_t NotFoundV6 = 0; - TAtomic InProgressV6 = 0; - - TString AddrsV4ToString() const; - TString AddrsV6ToString() const; - - bool IsStale(int family, const TDnsCache* ctx) const noexcept; - }; - - typedef TMap<TString, THost> THostCache; - - struct TAddr { - TString Hostname; - time_t Resolved = 0; - time_t NotFound = 0; - TAtomic InProgress = 0; - }; - /* IRemoteAddr is annoingly hard to use, so I'll use in6_addr as key - * and put v4 addrs in it. - */ - struct TAddrCmp { - bool operator()(const in6_addr& left, const in6_addr& right) const { - for (size_t i = 0; i < sizeof(left); i++) { - if (left.s6_addr[i] < right.s6_addr[i]) { - return true; - } else if (left.s6_addr[i] > right.s6_addr[i]) { - return false; - } - } - // equal - return false; - } - }; - typedef TMap<in6_addr, TAddr, TAddrCmp> TAddrCache; - - const THost& Resolve(const TString&, int family, bool cacheOnly = false); - - const TAddr& ResolveAddr(const in6_addr&, int family); - - void WaitTask(TAtomic&); - - static void GHBNCallback(void* arg, int status, int timeouts, - struct hostent* info); - - static void GHBACallback(void* arg, int status, int timeouts, - struct hostent* info); - - const time_t EntryLifetime; - const time_t NegativeLifetime; - const TDuration Timeout; - const bool AllowIpV4; - const bool AllowIpV6; - - TMutex CacheMtx; - THostCache HostCache; - TAddrCache AddrCache; - ui64 ACacheHits; - ui64 ACacheMisses; - ui64 PtrCacheHits; - ui64 PtrCacheMisses; - - const static THost NullHost; - - TMutex AresMtx; - void* Channel; - - struct TAresLibInit { - TAresLibInit(); - ~TAresLibInit(); - }; - - static TAresLibInit InitAresLib; -}; diff --git a/library/cpp/actors/dnscachelib/probes.cpp b/library/cpp/actors/dnscachelib/probes.cpp deleted file mode 100644 index 07734ab20f..0000000000 --- a/library/cpp/actors/dnscachelib/probes.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "probes.h" - -LWTRACE_DEFINE_PROVIDER(DNSCACHELIB_PROVIDER) diff --git a/library/cpp/actors/dnscachelib/probes.h b/library/cpp/actors/dnscachelib/probes.h deleted file mode 100644 index 313b7b8712..0000000000 --- a/library/cpp/actors/dnscachelib/probes.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include <library/cpp/lwtrace/all.h> - -#define DNSCACHELIB_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ - PROBE(Created, GROUPS(), TYPES(), NAMES()) \ - PROBE(Destroyed, GROUPS(), TYPES(), NAMES()) \ - PROBE(AresInitFailed, GROUPS(), TYPES(), NAMES()) \ - PROBE(FamilyMismatch, \ - GROUPS(), \ - TYPES(int, bool, bool), \ - NAMES("family", "allowIpV4", "allowIpV6")) \ - PROBE(ResolveNullHost, \ - GROUPS(), \ - TYPES(TString, int), \ - NAMES("hostname", "family")) \ - PROBE(ResolveFromCache, \ - GROUPS(), \ - TYPES(TString, int, TString, TString, ui64), \ - NAMES("hostname", "family", "addrsV4", "addrsV6", "aCacheHits")) \ - PROBE(ResolveDone, \ - GROUPS(), \ - TYPES(TString, int, TString, TString), \ - NAMES("hostname", "family", "addrsV4", "addrsV6")) \ - PROBE(ResolveCacheTimeout, \ - GROUPS(), \ - TYPES(TString), \ - NAMES("hostname")) \ - PROBE(ResolveCacheNew, \ - GROUPS(), \ - TYPES(TString), \ - NAMES("hostname")) \ - /**/ - -LWTRACE_DECLARE_PROVIDER(DNSCACHELIB_PROVIDER) diff --git a/library/cpp/actors/dnscachelib/timekeeper.h b/library/cpp/actors/dnscachelib/timekeeper.h deleted file mode 100644 index 0528d8549c..0000000000 --- a/library/cpp/actors/dnscachelib/timekeeper.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include <util/datetime/base.h> -#include <util/generic/singleton.h> -#include <util/string/cast.h> -#include <util/system/thread.h> -#include <util/system/event.h> -#include <util/system/env.h> - -#include <cstdlib> - -/* Keeps current time accurate up to 1/10 second */ - -class TTimeKeeper { -public: - static TInstant GetNow(void) { - return TInstant::MicroSeconds(GetTime()); - } - - static time_t GetTime(void) { - return Singleton<TTimeKeeper>()->CurrentTime.tv_sec; - } - - static const struct timeval& GetTimeval(void) { - return Singleton<TTimeKeeper>()->CurrentTime; - } - - TTimeKeeper() - : Thread(&TTimeKeeper::Worker, this) - { - ConstTime = !!GetEnv("TEST_TIME"); - if (ConstTime) { - try { - CurrentTime.tv_sec = FromString<ui32>(GetEnv("TEST_TIME")); - } catch (TFromStringException exc) { - ConstTime = false; - } - } - if (!ConstTime) { - gettimeofday(&CurrentTime, nullptr); - Thread.Start(); - } - } - - ~TTimeKeeper() { - if (!ConstTime) { - Exit.Signal(); - Thread.Join(); - } - } - -private: - static const ui32 UpdateInterval = 100000; - struct timeval CurrentTime; - bool ConstTime; - TSystemEvent Exit; - TThread Thread; - - static void* Worker(void* arg) { - TTimeKeeper* owner = static_cast<TTimeKeeper*>(arg); - - do { - /* Race condition may occur here but locking looks too expensive */ - - gettimeofday(&owner->CurrentTime, nullptr); - } while (!owner->Exit.WaitT(TDuration::MicroSeconds(UpdateInterval))); - - return nullptr; - } -}; diff --git a/library/cpp/actors/dnscachelib/ya.make b/library/cpp/actors/dnscachelib/ya.make deleted file mode 100644 index 62eaafc8f5..0000000000 --- a/library/cpp/actors/dnscachelib/ya.make +++ /dev/null @@ -1,23 +0,0 @@ -LIBRARY() - -SRCS( - dnscache.cpp - dnscache.h - probes.cpp - probes.h - timekeeper.h -) - -PEERDIR( - contrib/libs/c-ares - library/cpp/lwtrace - library/cpp/deprecated/atomic -) - -IF (NOT EXPORT_CMAKE) - ADDINCL( - contrib/libs/c-ares/include - ) -ENDIF() - -END() diff --git a/library/cpp/actors/dnsresolver/CMakeLists.darwin-arm64.txt b/library/cpp/actors/dnsresolver/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 30d19f1b99..0000000000 --- a/library/cpp/actors/dnsresolver/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,22 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-dnsresolver) -target_link_libraries(cpp-actors-dnsresolver PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core - contrib-libs-c-ares -) -target_sources(cpp-actors-dnsresolver PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_ondemand.cpp -) diff --git a/library/cpp/actors/dnsresolver/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/dnsresolver/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 30d19f1b99..0000000000 --- a/library/cpp/actors/dnsresolver/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,22 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-dnsresolver) -target_link_libraries(cpp-actors-dnsresolver PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core - contrib-libs-c-ares -) -target_sources(cpp-actors-dnsresolver PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_ondemand.cpp -) diff --git a/library/cpp/actors/dnsresolver/CMakeLists.linux-aarch64.txt b/library/cpp/actors/dnsresolver/CMakeLists.linux-aarch64.txt deleted file mode 100644 index f7dbdca2ef..0000000000 --- a/library/cpp/actors/dnsresolver/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,23 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-dnsresolver) -target_link_libraries(cpp-actors-dnsresolver PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-actors-core - contrib-libs-c-ares -) -target_sources(cpp-actors-dnsresolver PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_ondemand.cpp -) diff --git a/library/cpp/actors/dnsresolver/CMakeLists.linux-x86_64.txt b/library/cpp/actors/dnsresolver/CMakeLists.linux-x86_64.txt deleted file mode 100644 index f7dbdca2ef..0000000000 --- a/library/cpp/actors/dnsresolver/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,23 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-dnsresolver) -target_link_libraries(cpp-actors-dnsresolver PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-actors-core - contrib-libs-c-ares -) -target_sources(cpp-actors-dnsresolver PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_ondemand.cpp -) diff --git a/library/cpp/actors/dnsresolver/CMakeLists.txt b/library/cpp/actors/dnsresolver/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/dnsresolver/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/dnsresolver/CMakeLists.windows-x86_64.txt b/library/cpp/actors/dnsresolver/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 30d19f1b99..0000000000 --- a/library/cpp/actors/dnsresolver/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,22 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-dnsresolver) -target_link_libraries(cpp-actors-dnsresolver PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core - contrib-libs-c-ares -) -target_sources(cpp-actors-dnsresolver PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_ondemand.cpp -) diff --git a/library/cpp/actors/dnsresolver/dnsresolver.cpp b/library/cpp/actors/dnsresolver/dnsresolver.cpp deleted file mode 100644 index d7d8c0e3b6..0000000000 --- a/library/cpp/actors/dnsresolver/dnsresolver.cpp +++ /dev/null @@ -1,485 +0,0 @@ -#include "dnsresolver.h" - -#include <library/cpp/actors/core/actorsystem.h> -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/threading/queue/mpsc_htswap.h> -#include <util/network/pair.h> -#include <util/network/socket.h> -#include <util/string/builder.h> -#include <util/system/thread.h> - -#include <ares.h> - -#include <atomic> - -namespace NActors { -namespace NDnsResolver { - - class TAresLibraryInitBase { - protected: - TAresLibraryInitBase() noexcept { - int status = ares_library_init(ARES_LIB_INIT_ALL); - Y_ABORT_UNLESS(status == ARES_SUCCESS, "Unexpected failure to initialize c-ares library"); - } - - ~TAresLibraryInitBase() noexcept { - ares_library_cleanup(); - } - }; - - class TCallbackQueueBase { - protected: - TCallbackQueueBase() noexcept { - int err = SocketPair(Sockets, false, true); - Y_ABORT_UNLESS(err == 0, "Unexpected failure to create a socket pair"); - SetNonBlock(Sockets[0]); - SetNonBlock(Sockets[1]); - } - - ~TCallbackQueueBase() noexcept { - closesocket(Sockets[0]); - closesocket(Sockets[1]); - } - - protected: - using TCallback = std::function<void()>; - using TCallbackQueue = NThreading::THTSwapQueue<TCallback>; - - void PushCallback(TCallback callback) { - Y_ABORT_UNLESS(callback, "Cannot push an empty callback"); - CallbackQueue.Push(std::move(callback)); // this is a lockfree queue - - // Wake up worker thread on the first activation - if (Activations.fetch_add(1, std::memory_order_acq_rel) == 0) { - char ch = 'x'; - ssize_t ret; -#ifdef _win_ - ret = send(SignalSock(), &ch, 1, 0); - if (ret == -1) { - Y_ABORT_UNLESS(WSAGetLastError() == WSAEWOULDBLOCK, "Unexpected send error"); - return; - } -#else - do { - ret = send(SignalSock(), &ch, 1, 0); - } while (ret == -1 && errno == EINTR); - if (ret == -1) { - Y_ABORT_UNLESS(errno == EAGAIN || errno == EWOULDBLOCK, "Unexpected send error"); - return; - } -#endif - Y_ABORT_UNLESS(ret == 1, "Unexpected send result"); - } - } - - void RunCallbacks() noexcept { - char ch[32]; - ssize_t ret; - bool signalled = false; - for (;;) { - ret = recv(WaitSock(), ch, sizeof(ch), 0); - if (ret > 0) { - signalled = true; - } - if (ret == sizeof(ch)) { - continue; - } - if (ret != -1) { - break; - } -#ifdef _win_ - if (WSAGetLastError() == WSAEWOULDBLOCK) { - break; - } - Y_ABORT("Unexpected recv error"); -#else - if (errno == EAGAIN || errno == EWOULDBLOCK) { - break; - } - Y_ABORT_UNLESS(errno == EINTR, "Unexpected recv error"); -#endif - } - - if (signalled) { - // There's exactly one write to SignalSock while Activations != 0 - // It's impossible to get signalled while Activations == 0 - // We must set Activations = 0 to receive new signals - size_t count = Activations.exchange(0, std::memory_order_acq_rel); - Y_ABORT_UNLESS(count != 0); - - // N.B. due to the way HTSwap works we may not be able to pop - // all callbacks on this activation, however we expect a new - // delayed activation to happen at a later time. - while (auto callback = CallbackQueue.Pop()) { - callback(); - } - } - } - - SOCKET SignalSock() { - return Sockets[0]; - } - - SOCKET WaitSock() { - return Sockets[1]; - } - - private: - SOCKET Sockets[2]; - TCallbackQueue CallbackQueue; - std::atomic<size_t> Activations{ 0 }; - }; - - class TSimpleDnsResolver - : public TActor<TSimpleDnsResolver> - , private TAresLibraryInitBase - , private TCallbackQueueBase - { - public: - TSimpleDnsResolver(TSimpleDnsResolverOptions options) noexcept - : TActor(&TThis::StateWork) - , Options(std::move(options)) - , WorkerThread(&TThis::WorkerThreadStart, this) - { - InitAres(); - - WorkerThread.Start(); - } - - ~TSimpleDnsResolver() noexcept override { - if (!Stopped) { - PushCallback([this] { - // Mark as stopped first - Stopped = true; - - // Cancel all current ares requests (will not send replies) - ares_cancel(AresChannel); - }); - - WorkerThread.Join(); - } - - StopAres(); - } - - static constexpr EActivityType ActorActivityType() { - return EActivityType::DNS_RESOLVER; - } - - private: - void InitAres() noexcept { - struct ares_options options; - memset(&options, 0, sizeof(options)); - int optmask = 0; - - options.flags = ARES_FLAG_STAYOPEN; - optmask |= ARES_OPT_FLAGS; - - options.sock_state_cb = &TThis::SockStateCallback; - options.sock_state_cb_data = this; - optmask |= ARES_OPT_SOCK_STATE_CB; - - options.timeout = Options.Timeout.MilliSeconds(); - if (options.timeout > 0) { - optmask |= ARES_OPT_TIMEOUTMS; - } - - options.tries = Options.Attempts; - if (options.tries > 0) { - optmask |= ARES_OPT_TRIES; - } - - int err = ares_init_options(&AresChannel, &options, optmask); - Y_ABORT_UNLESS(err == 0, "Unexpected failure to initialize c-ares channel"); - - if (Options.Servers) { - TStringBuilder csv; - for (const TString& server : Options.Servers) { - if (csv) { - csv << ','; - } - csv << server; - } - err = ares_set_servers_ports_csv(AresChannel, csv.c_str()); - Y_ABORT_UNLESS(err == 0, "Unexpected failure to set a list of dns servers: %s", ares_strerror(err)); - } - } - - void StopAres() noexcept { - // Destroy the ares channel - ares_destroy(AresChannel); - AresChannel = nullptr; - } - - private: - STRICT_STFUNC(StateWork, { - hFunc(TEvents::TEvPoison, Handle); - hFunc(TEvDns::TEvGetHostByName, Handle); - hFunc(TEvDns::TEvGetAddr, Handle); - }) - - void Handle(TEvents::TEvPoison::TPtr&) { - Y_ABORT_UNLESS(!Stopped); - - PushCallback([this] { - // Cancel all current ares requests (will send notifications) - ares_cancel(AresChannel); - - // Mark as stopped last - Stopped = true; - }); - - WorkerThread.Join(); - PassAway(); - } - - private: - enum class ERequestType { - GetHostByName, - GetAddr, - }; - - struct TRequestContext : public TThrRefBase { - using TPtr = TIntrusivePtr<TRequestContext>; - - TThis* Self; - TActorSystem* ActorSystem; - TActorId SelfId; - TActorId Sender; - ui64 Cookie; - ERequestType Type; - - TRequestContext(TThis* self, TActorSystem* as, TActorId selfId, TActorId sender, ui64 cookie, ERequestType type) - : Self(self) - , ActorSystem(as) - , SelfId(selfId) - , Sender(sender) - , Cookie(cookie) - , Type(type) - { } - }; - - private: - void Handle(TEvDns::TEvGetHostByName::TPtr& ev) { - auto* msg = ev->Get(); - auto reqCtx = MakeIntrusive<TRequestContext>( - this, TActivationContext::ActorSystem(), SelfId(), ev->Sender, ev->Cookie, ERequestType::GetHostByName); - PushCallback([this, reqCtx = std::move(reqCtx), name = std::move(msg->Name), family = msg->Family] () mutable { - StartGetAddrInfo(std::move(reqCtx), std::move(name), family); - }); - } - - void Handle(TEvDns::TEvGetAddr::TPtr& ev) { - auto* msg = ev->Get(); - auto reqCtx = MakeIntrusive<TRequestContext>( - this, TActivationContext::ActorSystem(), SelfId(), ev->Sender, ev->Cookie, ERequestType::GetAddr); - PushCallback([this, reqCtx = std::move(reqCtx), name = std::move(msg->Name), family = msg->Family] () mutable { - StartGetAddrInfo(std::move(reqCtx), std::move(name), family); - }); - } - - void StartGetAddrInfo(TRequestContext::TPtr reqCtx, TString name, int family) noexcept { - reqCtx->Ref(); - ares_addrinfo_hints hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_flags = ARES_AI_NOSORT; - hints.ai_family = family; - ares_getaddrinfo(AresChannel, name.c_str(), nullptr, &hints, &TThis::GetAddrInfoAresCallback, reqCtx.Get()); - } - - private: - static void GetAddrInfoAresCallback(void* arg, int status, int timeouts, ares_addrinfo *result) { - struct TDeleter { - void operator ()(ares_addrinfo *ptr) const { - ares_freeaddrinfo(ptr); - } - }; - std::unique_ptr<ares_addrinfo, TDeleter> ptr(result); - - Y_UNUSED(timeouts); - TRequestContext::TPtr reqCtx(static_cast<TRequestContext*>(arg)); - reqCtx->UnRef(); - - if (reqCtx->Self->Stopped) { - // Don't send any replies after destruction - return; - } - - switch (reqCtx->Type) { - case ERequestType::GetHostByName: { - auto result = MakeHolder<TEvDns::TEvGetHostByNameResult>(); - if (status == ARES_SUCCESS) { - for (auto *node = ptr->nodes; node; node = node->ai_next) { - switch (node->ai_family) { - case AF_INET: { - result->AddrsV4.emplace_back(((sockaddr_in*)node->ai_addr)->sin_addr); - break; - } - case AF_INET6: { - result->AddrsV6.emplace_back(((sockaddr_in6*)node->ai_addr)->sin6_addr); - break; - } - default: - Y_ABORT("unknown address family in ares callback"); - } - } - } else { - result->ErrorText = ares_strerror(status); - } - result->Status = status; - - reqCtx->ActorSystem->Send(new IEventHandle(reqCtx->Sender, reqCtx->SelfId, result.Release(), 0, reqCtx->Cookie)); - break; - } - - case ERequestType::GetAddr: { - auto result = MakeHolder<TEvDns::TEvGetAddrResult>(); - if (status == ARES_SUCCESS && Y_UNLIKELY(ptr->nodes == nullptr)) { - status = ARES_ENODATA; - } - if (status == ARES_SUCCESS) { - auto *node = ptr->nodes; - switch (node->ai_family) { - case AF_INET: { - result->Addr = ((sockaddr_in*)node->ai_addr)->sin_addr; - break; - } - case AF_INET6: { - result->Addr = ((sockaddr_in6*)node->ai_addr)->sin6_addr; - break; - } - default: - Y_ABORT("unknown address family in ares callback"); - } - } else { - result->ErrorText = ares_strerror(status); - } - result->Status = status; - - reqCtx->ActorSystem->Send(new IEventHandle(reqCtx->Sender, reqCtx->SelfId, result.Release(), 0, reqCtx->Cookie)); - break; - } - } - } - - private: - static void SockStateCallback(void* data, ares_socket_t socket_fd, int readable, int writable) { - static_cast<TThis*>(data)->DoSockStateCallback(socket_fd, readable, writable); - } - - void DoSockStateCallback(ares_socket_t socket_fd, int readable, int writable) noexcept { - int events = (readable ? (POLLRDNORM | POLLIN) : 0) | (writable ? (POLLWRNORM | POLLOUT) : 0); - if (events == 0) { - AresSockStates.erase(socket_fd); - } else { - AresSockStates[socket_fd].NeededEvents = events; - } - } - - private: - static void* WorkerThreadStart(void* arg) noexcept { - static_cast<TSimpleDnsResolver*>(arg)->WorkerThreadLoop(); - return nullptr; - } - - void WorkerThreadLoop() noexcept { - TThread::SetCurrentThreadName("DnsResolver"); - - TVector<struct pollfd> fds; - while (!Stopped) { - fds.clear(); - fds.reserve(1 + AresSockStates.size()); - { - auto& entry = fds.emplace_back(); - entry.fd = WaitSock(); - entry.events = POLLRDNORM | POLLIN; - } - for (auto& kv : AresSockStates) { - auto& entry = fds.emplace_back(); - entry.fd = kv.first; - entry.events = kv.second.NeededEvents; - } - - int timeout = -1; - struct timeval tv; - if (ares_timeout(AresChannel, nullptr, &tv)) { - timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000; - } - - int ret = poll(fds.data(), fds.size(), timeout); - if (ret == -1) { - if (errno == EINTR) { - continue; - } - // we cannot handle failures, run callbacks and pretend everything is ok - RunCallbacks(); - if (Stopped) { - break; - } - ret = 0; - } - - bool ares_called = false; - if (ret > 0) { - for (size_t i = 0; i < fds.size(); ++i) { - auto& entry = fds[i]; - - // Handle WaitSock activation and run callbacks - if (i == 0) { - if (entry.revents & (POLLRDNORM | POLLIN)) { - RunCallbacks(); - if (Stopped) { - break; - } - } - continue; - } - - // All other sockets belong to ares - if (entry.revents == 0) { - continue; - } - // Previous invocation of aress_process_fd might have removed some sockets - if (Y_UNLIKELY(!AresSockStates.contains(entry.fd))) { - continue; - } - ares_process_fd( - AresChannel, - entry.revents & (POLLRDNORM | POLLIN) ? entry.fd : ARES_SOCKET_BAD, - entry.revents & (POLLWRNORM | POLLOUT) ? entry.fd : ARES_SOCKET_BAD); - ares_called = true; - } - - if (Stopped) { - break; - } - } - - if (!ares_called) { - // Let ares handle timeouts - ares_process_fd(AresChannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); - } - } - } - - private: - struct TSockState { - short NeededEvents = 0; // poll events - }; - - private: - TSimpleDnsResolverOptions Options; - TThread WorkerThread; - - ares_channel AresChannel; - THashMap<SOCKET, TSockState> AresSockStates; - - bool Stopped = false; - }; - - IActor* CreateSimpleDnsResolver(TSimpleDnsResolverOptions options) { - return new TSimpleDnsResolver(std::move(options)); - } - -} // namespace NDnsResolver -} // namespace NActors diff --git a/library/cpp/actors/dnsresolver/dnsresolver.h b/library/cpp/actors/dnsresolver/dnsresolver.h deleted file mode 100644 index 1121c31e51..0000000000 --- a/library/cpp/actors/dnsresolver/dnsresolver.h +++ /dev/null @@ -1,128 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/actor.h> -#include <library/cpp/actors/core/events.h> -#include <library/cpp/actors/core/event_local.h> -#include <library/cpp/monlib/dynamic_counters/counters.h> -#include <util/network/address.h> -#include <variant> - -namespace NActors { -namespace NDnsResolver { - - struct TEvDns { - enum EEv { - EvGetHostByName = EventSpaceBegin(TEvents::ES_DNS), - EvGetHostByNameResult, - EvGetAddr, - EvGetAddrResult, - }; - - /** - * TEvGetHostByName returns the result of ares_gethostbyname - */ - struct TEvGetHostByName : public TEventLocal<TEvGetHostByName, EvGetHostByName> { - TString Name; - int Family; - - explicit TEvGetHostByName(TString name, int family = AF_UNSPEC) - : Name(std::move(name)) - , Family(family) - { } - }; - - struct TEvGetHostByNameResult : public TEventLocal<TEvGetHostByNameResult, EvGetHostByNameResult> { - TVector<struct in_addr> AddrsV4; - TVector<struct in6_addr> AddrsV6; - TString ErrorText; - int Status = 0; - }; - - /** - * TEvGetAddr returns a single address for a given hostname - */ - struct TEvGetAddr : public TEventLocal<TEvGetAddr, EvGetAddr> { - TString Name; - int Family; - - explicit TEvGetAddr(TString name, int family = AF_UNSPEC) - : Name(std::move(name)) - , Family(family) - { } - }; - - struct TEvGetAddrResult : public TEventLocal<TEvGetAddrResult, EvGetAddrResult> { - // N.B. "using" here doesn't work with Visual Studio compiler - typedef struct in6_addr TIPv6Addr; - typedef struct in_addr TIPv4Addr; - - std::variant<std::monostate, TIPv6Addr, TIPv4Addr> Addr; - TString ErrorText; - int Status = 0; - - bool IsV6() const { - return std::holds_alternative<TIPv6Addr>(Addr); - } - - bool IsV4() const { - return std::holds_alternative<TIPv4Addr>(Addr); - } - - const TIPv6Addr& GetAddrV6() const { - const TIPv6Addr* p = std::get_if<TIPv6Addr>(&Addr); - Y_ABORT_UNLESS(p, "Result is not an ipv6 address"); - return *p; - } - - const TIPv4Addr& GetAddrV4() const { - const TIPv4Addr* p = std::get_if<TIPv4Addr>(&Addr); - Y_ABORT_UNLESS(p, "Result is not an ipv4 address"); - return *p; - } - }; - }; - - struct TSimpleDnsResolverOptions { - // Initial per-server timeout, grows exponentially with each retry - TDuration Timeout = TDuration::Seconds(1); - // Number of attempts per-server - int Attempts = 2; - // Optional list of custom dns servers (ip.v4[:port], ip::v6 or [ip::v6]:port format) - TVector<TString> Servers; - }; - - IActor* CreateSimpleDnsResolver(TSimpleDnsResolverOptions options = TSimpleDnsResolverOptions()); - - struct TCachingDnsResolverOptions { - // Soft expire time specifies delay before name is refreshed in background - TDuration SoftNegativeExpireTime = TDuration::Seconds(1); - TDuration SoftPositiveExpireTime = TDuration::Seconds(10); - // Hard expire time specifies delay before the last result is forgotten - TDuration HardNegativeExpireTime = TDuration::Seconds(10); - TDuration HardPositiveExpireTime = TDuration::Hours(2); - // Allow these request families - bool AllowIPv6 = true; - bool AllowIPv4 = true; - // Optional counters - NMonitoring::TDynamicCounterPtr MonCounters = nullptr; - }; - - IActor* CreateCachingDnsResolver(TActorId upstream, TCachingDnsResolverOptions options = TCachingDnsResolverOptions()); - - struct TOnDemandDnsResolverOptions - : public TSimpleDnsResolverOptions - , public TCachingDnsResolverOptions - { - }; - - IActor* CreateOnDemandDnsResolver(TOnDemandDnsResolverOptions options = TOnDemandDnsResolverOptions()); - - /** - * Returns actor id of a globally registered dns resolver - */ - inline TActorId MakeDnsResolverActorId() { - return TActorId(0, TStringBuf("dnsresolver")); - } - -} // namespace NDnsResolver -} // namespace NActors diff --git a/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp b/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp deleted file mode 100644 index 83b1847962..0000000000 --- a/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp +++ /dev/null @@ -1,694 +0,0 @@ -#include "dnsresolver.h" - -#include <library/cpp/actors/core/hfunc.h> -#include <util/generic/intrlist.h> - -#include <ares.h> - -#include <queue> - -namespace NActors { -namespace NDnsResolver { - - class TCachingDnsResolver : public TActor<TCachingDnsResolver> { - public: - struct TMonCounters { - NMonitoring::TDynamicCounters::TCounterPtr OutgoingInFlightV4; - NMonitoring::TDynamicCounters::TCounterPtr OutgoingInFlightV6; - NMonitoring::TDynamicCounters::TCounterPtr OutgoingInFlightUnspec; - NMonitoring::TDynamicCounters::TCounterPtr OutgoingErrorsV4; - NMonitoring::TDynamicCounters::TCounterPtr OutgoingErrorsV6; - NMonitoring::TDynamicCounters::TCounterPtr OutgoingErrorsUnspec; - NMonitoring::TDynamicCounters::TCounterPtr OutgoingTotalV4; - NMonitoring::TDynamicCounters::TCounterPtr OutgoingTotalV6; - NMonitoring::TDynamicCounters::TCounterPtr OutgoingTotalUnspec; - - NMonitoring::TDynamicCounters::TCounterPtr IncomingInFlight; - NMonitoring::TDynamicCounters::TCounterPtr IncomingErrors; - NMonitoring::TDynamicCounters::TCounterPtr IncomingTotal; - - NMonitoring::TDynamicCounters::TCounterPtr CacheSize; - NMonitoring::TDynamicCounters::TCounterPtr CacheHits; - NMonitoring::TDynamicCounters::TCounterPtr CacheMisses; - - TMonCounters(const NMonitoring::TDynamicCounterPtr& counters) - : OutgoingInFlightV4(counters->GetCounter("DnsResolver/Outgoing/InFlight/V4", false)) - , OutgoingInFlightV6(counters->GetCounter("DnsResolver/Outgoing/InFlight/V6", false)) - , OutgoingInFlightUnspec(counters->GetCounter("DnsResolver/Outgoing/InFlight/Unspec", false)) - , OutgoingErrorsV4(counters->GetCounter("DnsResolver/Outgoing/Errors/V4", true)) - , OutgoingErrorsV6(counters->GetCounter("DnsResolver/Outgoing/Errors/V6", true)) - , OutgoingErrorsUnspec(counters->GetCounter("DnsResolver/Outgoing/Errors/Unspec", true)) - , OutgoingTotalV4(counters->GetCounter("DnsResolver/Outgoing/Total/V4", true)) - , OutgoingTotalV6(counters->GetCounter("DnsResolver/Outgoing/Total/V6", true)) - , OutgoingTotalUnspec(counters->GetCounter("DnsResolver/Outgoing/Total/Unspec", true)) - , IncomingInFlight(counters->GetCounter("DnsResolver/Incoming/InFlight", false)) - , IncomingErrors(counters->GetCounter("DnsResolver/Incoming/Errors", true)) - , IncomingTotal(counters->GetCounter("DnsResolver/Incoming/Total", true)) - , CacheSize(counters->GetCounter("DnsResolver/Cache/Size", false)) - , CacheHits(counters->GetCounter("DnsResolver/Cache/Hits", true)) - , CacheMisses(counters->GetCounter("DnsResolver/Cache/Misses", true)) - { } - - const NMonitoring::TDynamicCounters::TCounterPtr& OutgoingInFlightByFamily(int family) const { - switch (family) { - case AF_INET: - return OutgoingInFlightV4; - case AF_INET6: - return OutgoingInFlightV6; - case AF_UNSPEC: - return OutgoingInFlightUnspec; - default: - Y_ABORT("Unexpected family %d", family); - } - } - - const NMonitoring::TDynamicCounters::TCounterPtr& OutgoingErrorsByFamily(int family) const { - switch (family) { - case AF_INET: - return OutgoingErrorsV4; - case AF_INET6: - return OutgoingErrorsV6; - case AF_UNSPEC: - return OutgoingErrorsUnspec; - default: - Y_ABORT("Unexpected family %d", family); - } - } - - const NMonitoring::TDynamicCounters::TCounterPtr& OutgoingTotalByFamily(int family) const { - switch (family) { - case AF_INET: - return OutgoingTotalV4; - case AF_INET6: - return OutgoingTotalV6; - case AF_UNSPEC: - return OutgoingTotalUnspec; - default: - Y_ABORT("Unexpected family %d", family); - } - } - }; - - public: - TCachingDnsResolver(TActorId upstream, TCachingDnsResolverOptions options) - : TActor(&TThis::StateWork) - , Upstream(upstream) - , Options(std::move(options)) - , MonCounters(Options.MonCounters ? new TMonCounters(Options.MonCounters) : nullptr) - { } - - static constexpr EActivityType ActorActivityType() { - return EActivityType::DNS_RESOLVER; - } - - private: - STRICT_STFUNC(StateWork, { - hFunc(TEvents::TEvPoison, Handle); - hFunc(TEvDns::TEvGetHostByName, Handle); - hFunc(TEvDns::TEvGetAddr, Handle); - hFunc(TEvDns::TEvGetHostByNameResult, Handle); - hFunc(TEvents::TEvUndelivered, Handle); - }); - - void Handle(TEvents::TEvPoison::TPtr&) { - DropPending(ARES_ECANCELLED); - PassAway(); - } - - void Handle(TEvDns::TEvGetHostByName::TPtr& ev) { - auto req = MakeHolder<TIncomingRequest>(); - req->Type = EIncomingRequestType::GetHostByName; - req->Sender = ev->Sender; - req->Cookie = ev->Cookie; - req->Name = std::move(ev->Get()->Name); - req->Family = ev->Get()->Family; - EnqueueRequest(std::move(req)); - } - - void Handle(TEvDns::TEvGetAddr::TPtr& ev) { - auto req = MakeHolder<TIncomingRequest>(); - req->Type = EIncomingRequestType::GetAddr; - req->Sender = ev->Sender; - req->Cookie = ev->Cookie; - req->Name = std::move(ev->Get()->Name); - req->Family = ev->Get()->Family; - EnqueueRequest(std::move(req)); - } - - void Handle(TEvDns::TEvGetHostByNameResult::TPtr& ev) { - auto waitingIt = WaitingRequests.find(ev->Cookie); - Y_ABORT_UNLESS(waitingIt != WaitingRequests.end(), "Unexpected reply, reqId=%" PRIu64, ev->Cookie); - auto waitingInfo = waitingIt->second; - WaitingRequests.erase(waitingIt); - - switch (waitingInfo.Family) { - case AF_UNSPEC: - case AF_INET6: - case AF_INET: - if (ev->Get()->Status) { - ProcessError(waitingInfo.Family, waitingInfo.Position, ev->Get()->Status, std::move(ev->Get()->ErrorText)); - } else { - ProcessAddrs(waitingInfo.Family, waitingInfo.Position, std::move(ev->Get()->AddrsV6), std::move(ev->Get()->AddrsV4)); - } - break; - - default: - Y_ABORT("Unexpected request family %d", waitingInfo.Family); - } - } - - void Handle(TEvents::TEvUndelivered::TPtr& ev) { - switch (ev->Get()->SourceType) { - case TEvDns::TEvGetHostByName::EventType: { - auto waitingIt = WaitingRequests.find(ev->Cookie); - Y_ABORT_UNLESS(waitingIt != WaitingRequests.end(), "Unexpected TEvUndelivered, reqId=%" PRIu64, ev->Cookie); - auto waitingInfo = waitingIt->second; - WaitingRequests.erase(waitingIt); - - switch (waitingInfo.Family) { - case AF_UNSPEC: - case AF_INET6: - case AF_INET: - ProcessError(waitingInfo.Family, waitingInfo.Position, ARES_ENOTINITIALIZED, "Caching dns resolver cannot deliver to the underlying resolver"); - break; - - default: - Y_ABORT("Unexpected request family %d", waitingInfo.Family); - } - - break; - } - - default: - Y_ABORT("Unexpected TEvUndelievered, type=%" PRIu32, ev->Get()->SourceType); - } - } - - private: - enum EIncomingRequestType { - GetHostByName, - GetAddr, - }; - - struct TIncomingRequest : public TIntrusiveListItem<TIncomingRequest> { - EIncomingRequestType Type; - TActorId Sender; - ui64 Cookie; - TString Name; - int Family; - }; - - using TIncomingRequestList = TIntrusiveListWithAutoDelete<TIncomingRequest, TDelete>; - - void EnqueueRequest(THolder<TIncomingRequest> req) { - if (MonCounters) { - ++*MonCounters->IncomingTotal; - } - - CleanupExpired(TActivationContext::Now()); - - switch (req->Family) { - case AF_UNSPEC: - if (Options.AllowIPv6 && Options.AllowIPv4) { - EnqueueRequest(AF_UNSPEC, std::move(req)); - return; - } - if (Options.AllowIPv6) { - EnqueueRequest(AF_INET6, std::move(req)); - return; - } - if (Options.AllowIPv4) { - EnqueueRequest(AF_INET, std::move(req)); - return; - } - break; - - case AF_INET6: - if (Options.AllowIPv6) { - EnqueueRequest(AF_INET6, std::move(req)); - return; - } - break; - - case AF_INET: - if (Options.AllowIPv4) { - EnqueueRequest(AF_INET, std::move(req)); - return; - } - break; - } - - ReplyWithError(std::move(req), ARES_EBADFAMILY); - } - - void EnqueueRequest(int family, THolder<TIncomingRequest> req) { - auto now = TActivationContext::Now(); - - auto& fullState = NameToState[req->Name]; - if (MonCounters) { - *MonCounters->CacheSize = NameToState.size(); - } - - auto& state = fullState.StateByFamily(family); - EnsureRequest(state, req->Name, family, now); - - if (state.IsHardExpired(now)) { - Y_ABORT_UNLESS(state.Waiting); - if (MonCounters) { - ++*MonCounters->CacheMisses; - } - state.WaitingRequests.PushBack(req.Release()); - return; - } - - if (MonCounters) { - ++*MonCounters->CacheHits; - } - - if (state.Status != 0) { - ReplyWithError(std::move(req), state.Status, state.ErrorText); - } else { - ReplyWithAddrs(std::move(req), state.AddrsIPv6, state.AddrsIPv4); - } - } - - private: - struct TFamilyState { - TVector<struct in6_addr> AddrsIPv6; - TVector<struct in_addr> AddrsIPv4; - TIncomingRequestList WaitingRequests; - TInstant SoftDeadline; - TInstant HardDeadline; - TInstant NextSoftDeadline; - TInstant NextHardDeadline; - TString ErrorText; - int Status = -1; // never requested before - bool InSoftHeap = false; - bool InHardHeap = false; - bool Waiting = false; - - bool Needed() const { - return InSoftHeap || InHardHeap || Waiting; - } - - bool ServerReplied() const { - return ServerReplied(Status); - } - - bool IsSoftExpired(TInstant now) const { - return !InSoftHeap || NextSoftDeadline < now; - } - - bool IsHardExpired(TInstant now) const { - return !InHardHeap || NextHardDeadline < now; - } - - static bool ServerReplied(int status) { - return ( - status == ARES_SUCCESS || - status == ARES_ENODATA || - status == ARES_ENOTFOUND); - } - }; - - struct TState { - TFamilyState StateUnspec; - TFamilyState StateIPv6; - TFamilyState StateIPv4; - - bool Needed() const { - return StateUnspec.Needed() || StateIPv6.Needed() || StateIPv4.Needed(); - } - - const TFamilyState& StateByFamily(int family) const { - switch (family) { - case AF_UNSPEC: - return StateUnspec; - case AF_INET6: - return StateIPv6; - case AF_INET: - return StateIPv4; - default: - Y_ABORT("Unsupported family %d", family); - } - } - - TFamilyState& StateByFamily(int family) { - switch (family) { - case AF_UNSPEC: - return StateUnspec; - case AF_INET6: - return StateIPv6; - case AF_INET: - return StateIPv4; - default: - Y_ABORT("Unsupported family %d", family); - } - } - }; - - using TNameToState = THashMap<TString, TState>; - - template<const TFamilyState TState::* StateToFamily, - const TInstant TFamilyState::* FamilyToDeadline> - struct THeapCompare { - // returns true when b < a - bool operator()(TNameToState::iterator a, TNameToState::iterator b) const { - const TState& aState = a->second; - const TState& bState = b->second; - const TFamilyState& aFamily = aState.*StateToFamily; - const TFamilyState& bFamily = bState.*StateToFamily; - const TInstant& aDeadline = aFamily.*FamilyToDeadline; - const TInstant& bDeadline = bFamily.*FamilyToDeadline; - return bDeadline < aDeadline; - } - }; - - template<const TFamilyState TState::* StateToFamily, - const TInstant TFamilyState::* FamilyToDeadline> - using TStateHeap = std::priority_queue< - TNameToState::iterator, - std::vector<TNameToState::iterator>, - THeapCompare<StateToFamily, FamilyToDeadline> - >; - - struct TWaitingInfo { - TNameToState::iterator Position; - int Family; - }; - - private: - void EnsureRequest(TFamilyState& state, const TString& name, int family, TInstant now) { - if (state.Waiting) { - return; // request is already pending - } - - if (!state.IsSoftExpired(now) && !state.IsHardExpired(now)) { - return; // response is not expired yet - } - - if (MonCounters) { - ++*MonCounters->OutgoingInFlightByFamily(family); - ++*MonCounters->OutgoingTotalByFamily(family); - } - - ui64 reqId = ++LastRequestId; - auto& req = WaitingRequests[reqId]; - req.Position = NameToState.find(name); - req.Family = family; - Y_ABORT_UNLESS(req.Position != NameToState.end()); - - Send(Upstream, new TEvDns::TEvGetHostByName(name, family), IEventHandle::FlagTrackDelivery, reqId); - state.Waiting = true; - } - - template<TFamilyState TState::* StateToFamily, - TInstant TFamilyState::* FamilyToDeadline, - TInstant TFamilyState::* FamilyToNextDeadline, - bool TFamilyState::* FamilyToFlag, - class THeap> - void PushToHeap(THeap& heap, TNameToState::iterator it, TInstant newDeadline) { - auto& family = it->second.*StateToFamily; - TInstant& deadline = family.*FamilyToDeadline; - TInstant& nextDeadline = family.*FamilyToNextDeadline; - bool& flag = family.*FamilyToFlag; - nextDeadline = newDeadline; - if (!flag) { - deadline = newDeadline; - heap.push(it); - flag = true; - } - } - - void PushSoftUnspec(TNameToState::iterator it, TInstant newDeadline) { - PushToHeap<&TState::StateUnspec, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapUnspec, it, newDeadline); - } - - void PushHardUnspec(TNameToState::iterator it, TInstant newDeadline) { - PushToHeap<&TState::StateUnspec, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapUnspec, it, newDeadline); - } - - void PushSoftV6(TNameToState::iterator it, TInstant newDeadline) { - PushToHeap<&TState::StateIPv6, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv6, it, newDeadline); - } - - void PushHardV6(TNameToState::iterator it, TInstant newDeadline) { - PushToHeap<&TState::StateIPv6, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapIPv6, it, newDeadline); - } - - void PushSoftV4(TNameToState::iterator it, TInstant newDeadline) { - PushToHeap<&TState::StateIPv4, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv4, it, newDeadline); - } - - void PushHardV4(TNameToState::iterator it, TInstant newDeadline) { - PushToHeap<&TState::StateIPv4, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapIPv4, it, newDeadline); - } - - void PushSoft(int family, TNameToState::iterator it, TInstant newDeadline) { - switch (family) { - case AF_UNSPEC: - PushSoftUnspec(it, newDeadline); - break; - case AF_INET6: - PushSoftV6(it, newDeadline); - break; - case AF_INET: - PushSoftV4(it, newDeadline); - break; - default: - Y_ABORT("Unexpected family %d", family); - } - } - - void PushHard(int family, TNameToState::iterator it, TInstant newDeadline) { - switch (family) { - case AF_UNSPEC: - PushHardUnspec(it, newDeadline); - break; - case AF_INET6: - PushHardV6(it, newDeadline); - break; - case AF_INET: - PushHardV4(it, newDeadline); - break; - default: - Y_ABORT("Unexpected family %d", family); - } - } - - void ProcessError(int family, TNameToState::iterator it, int status, TString errorText) { - auto now = TActivationContext::Now(); - if (MonCounters) { - --*MonCounters->OutgoingInFlightByFamily(family); - ++*MonCounters->OutgoingErrorsByFamily(family); - } - - auto& state = it->second.StateByFamily(family); - Y_ABORT_UNLESS(state.Waiting, "Got error for a state we are not waiting"); - state.Waiting = false; - - // When we have a cached positive reply, don't overwrite it with spurious errors - const bool serverReplied = TFamilyState::ServerReplied(status); - if (!serverReplied && state.ServerReplied() && !state.IsHardExpired(now)) { - PushSoft(family, it, now + Options.SoftNegativeExpireTime); - if (state.Status == ARES_SUCCESS) { - SendAddrs(family, it); - } else { - SendErrors(family, it); - } - return; - } - - state.Status = status; - state.ErrorText = std::move(errorText); - PushSoft(family, it, now + Options.SoftNegativeExpireTime); - if (serverReplied) { - // Server actually replied, so keep it cached for longer - PushHard(family, it, now + Options.HardPositiveExpireTime); - } else { - PushHard(family, it, now + Options.HardNegativeExpireTime); - } - - SendErrors(family, it); - } - - void SendErrors(int family, TNameToState::iterator it) { - auto& state = it->second.StateByFamily(family); - while (state.WaitingRequests) { - THolder<TIncomingRequest> req(state.WaitingRequests.PopFront()); - ReplyWithError(std::move(req), state.Status, state.ErrorText); - } - } - - void ProcessAddrs(int family, TNameToState::iterator it, TVector<struct in6_addr> addrs6, TVector<struct in_addr> addrs4) { - if (Y_UNLIKELY(addrs6.empty() && addrs4.empty())) { - // Probably unnecessary: we don't want to deal with empty address lists - return ProcessError(family, it, ARES_ENODATA, ares_strerror(ARES_ENODATA)); - } - - auto now = TActivationContext::Now(); - if (MonCounters) { - --*MonCounters->OutgoingInFlightByFamily(family); - } - - auto& state = it->second.StateByFamily(family); - Y_ABORT_UNLESS(state.Waiting, "Got reply for a state we are not waiting"); - state.Waiting = false; - - state.Status = ARES_SUCCESS; - state.AddrsIPv6 = std::move(addrs6); - state.AddrsIPv4 = std::move(addrs4); - PushSoft(family, it, now + Options.SoftPositiveExpireTime); - PushHard(family, it, now + Options.HardPositiveExpireTime); - - SendAddrs(family, it); - } - - void SendAddrs(int family, TNameToState::iterator it) { - auto& state = it->second.StateByFamily(family); - while (state.WaitingRequests) { - THolder<TIncomingRequest> req(state.WaitingRequests.PopFront()); - ReplyWithAddrs(std::move(req), state.AddrsIPv6, state.AddrsIPv4); - } - } - - private: - template<TFamilyState TState::*StateToFamily, - TInstant TFamilyState::* FamilyToDeadline, - TInstant TFamilyState::* FamilyToNextDeadline, - bool TFamilyState::* FamilyToFlag> - void DoCleanupExpired(TStateHeap<StateToFamily, FamilyToDeadline>& heap, TInstant now) { - while (!heap.empty()) { - auto it = heap.top(); - auto& family = it->second.*StateToFamily; - TInstant& deadline = family.*FamilyToDeadline; - if (now <= deadline) { - break; - } - - bool& flag = family.*FamilyToFlag; - Y_ABORT_UNLESS(flag); - heap.pop(); - flag = false; - - TInstant& nextDeadline = family.*FamilyToNextDeadline; - if (now < nextDeadline) { - deadline = nextDeadline; - heap.push(it); - flag = true; - continue; - } - - // Remove unnecessary items - if (!it->second.Needed()) { - NameToState.erase(it); - if (MonCounters) { - *MonCounters->CacheSize = NameToState.size(); - } - } - } - } - - void CleanupExpired(TInstant now) { - DoCleanupExpired<&TState::StateUnspec, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapUnspec, now); - DoCleanupExpired<&TState::StateUnspec, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapUnspec, now); - DoCleanupExpired<&TState::StateIPv6, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv6, now); - DoCleanupExpired<&TState::StateIPv6, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapIPv6, now); - DoCleanupExpired<&TState::StateIPv4, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv4, now); - DoCleanupExpired<&TState::StateIPv4, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapIPv4, now); - } - - template<class TEvent> - void SendError(TActorId replyTo, ui64 cookie, int status, const TString& errorText) { - auto reply = MakeHolder<TEvent>(); - reply->Status = status; - reply->ErrorText = errorText; - this->Send(replyTo, reply.Release(), 0, cookie); - } - - void ReplyWithError(THolder<TIncomingRequest> req, int status, const TString& errorText) { - if (MonCounters) { - ++*MonCounters->IncomingErrors; - } - switch (req->Type) { - case EIncomingRequestType::GetHostByName: { - SendError<TEvDns::TEvGetHostByNameResult>(req->Sender, req->Cookie, status, errorText); - break; - } - case EIncomingRequestType::GetAddr: { - SendError<TEvDns::TEvGetAddrResult>(req->Sender, req->Cookie, status, errorText); - break; - } - } - } - - void ReplyWithAddrs(THolder<TIncomingRequest> req, const TVector<struct in6_addr>& addrs6, const TVector<struct in_addr>& addrs4) { - switch (req->Type) { - case EIncomingRequestType::GetHostByName: { - auto reply = MakeHolder<TEvDns::TEvGetHostByNameResult>(); - reply->AddrsV6 = addrs6; - reply->AddrsV4 = addrs4; - Send(req->Sender, reply.Release(), 0, req->Cookie); - break; - } - case EIncomingRequestType::GetAddr: { - auto reply = MakeHolder<TEvDns::TEvGetAddrResult>(); - if (!addrs6.empty()) { - reply->Addr = addrs6.front(); - } else if (!addrs4.empty()) { - reply->Addr = addrs4.front(); - } else { - Y_ABORT("Unexpected reply with empty address list"); - } - Send(req->Sender, reply.Release(), 0, req->Cookie); - break; - } - } - } - - void ReplyWithError(THolder<TIncomingRequest> req, int status) { - ReplyWithError(std::move(req), status, ares_strerror(status)); - } - - void DropPending(TIncomingRequestList& list, int status, const TString& errorText) { - while (list) { - THolder<TIncomingRequest> req(list.PopFront()); - ReplyWithError(std::move(req), status, errorText); - } - } - - void DropPending(int status, const TString& errorText) { - for (auto& [name, state] : NameToState) { - DropPending(state.StateUnspec.WaitingRequests, status, errorText); - DropPending(state.StateIPv6.WaitingRequests, status, errorText); - DropPending(state.StateIPv4.WaitingRequests, status, errorText); - } - } - - void DropPending(int status) { - DropPending(status, ares_strerror(status)); - } - - private: - const TActorId Upstream; - const TCachingDnsResolverOptions Options; - const THolder<TMonCounters> MonCounters; - - TNameToState NameToState; - TStateHeap<&TState::StateUnspec, &TFamilyState::SoftDeadline> SoftHeapUnspec; - TStateHeap<&TState::StateUnspec, &TFamilyState::HardDeadline> HardHeapUnspec; - TStateHeap<&TState::StateIPv6, &TFamilyState::SoftDeadline> SoftHeapIPv6; - TStateHeap<&TState::StateIPv6, &TFamilyState::HardDeadline> HardHeapIPv6; - TStateHeap<&TState::StateIPv4, &TFamilyState::SoftDeadline> SoftHeapIPv4; - TStateHeap<&TState::StateIPv4, &TFamilyState::HardDeadline> HardHeapIPv4; - - THashMap<ui64, TWaitingInfo> WaitingRequests; - ui64 LastRequestId = 0; - }; - - IActor* CreateCachingDnsResolver(TActorId upstream, TCachingDnsResolverOptions options) { - return new TCachingDnsResolver(upstream, std::move(options)); - } - -} // namespace NDnsResolver -} // namespace NActors diff --git a/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp b/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp deleted file mode 100644 index 60a45f6fba..0000000000 --- a/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp +++ /dev/null @@ -1,648 +0,0 @@ -#include "dnsresolver.h" - -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/testlib/test_runtime.h> -#include <library/cpp/testing/unittest/registar.h> -#include <util/string/builder.h> - -#include <ares.h> - -using namespace NActors; -using namespace NActors::NDnsResolver; - -// FIXME: use a mock resolver -Y_UNIT_TEST_SUITE(CachingDnsResolver) { - - struct TAddrToString { - TString operator()(const std::monostate&) const { - return "<nothing>"; - } - - TString operator()(const struct in6_addr& addr) const { - char dst[INET6_ADDRSTRLEN]; - auto res = ares_inet_ntop(AF_INET6, &addr, dst, INET6_ADDRSTRLEN); - Y_ABORT_UNLESS(res, "Cannot convert ipv6 address"); - return dst; - } - - TString operator()(const struct in_addr& addr) const { - char dst[INET_ADDRSTRLEN]; - auto res = ares_inet_ntop(AF_INET, &addr, dst, INET_ADDRSTRLEN); - Y_ABORT_UNLESS(res, "Cannot convert ipv4 address"); - return dst; - } - }; - - TString AddrToString(const std::variant<std::monostate, struct in6_addr, struct in_addr>& v) { - return std::visit(TAddrToString(), v); - } - - struct TMockReply { - static constexpr TDuration DefaultDelay = TDuration::MilliSeconds(1); - - int Status = 0; - TDuration Delay; - TVector<struct in6_addr> AddrsV6; - TVector<struct in_addr> AddrsV4; - - static TMockReply Error(int status, TDuration delay = DefaultDelay) { - Y_ABORT_UNLESS(status != 0); - TMockReply reply; - reply.Status = status; - reply.Delay = delay; - return reply; - } - - static TMockReply Empty(TDuration delay = DefaultDelay) { - TMockReply reply; - reply.Delay = delay; - return reply; - } - - static TMockReply ManyV6(const TVector<TString>& addrs, TDuration delay = DefaultDelay) { - TMockReply reply; - reply.Delay = delay; - for (const TString& addr : addrs) { - void* dst = &reply.AddrsV6.emplace_back(); - int status = ares_inet_pton(AF_INET6, addr.c_str(), dst); - Y_ABORT_UNLESS(status == 1, "Invalid ipv6 address: %s", addr.c_str()); - } - return reply; - } - - static TMockReply ManyV4(const TVector<TString>& addrs, TDuration delay = DefaultDelay) { - TMockReply reply; - reply.Delay = delay; - for (const TString& addr : addrs) { - void* dst = &reply.AddrsV4.emplace_back(); - int status = ares_inet_pton(AF_INET, addr.c_str(), dst); - Y_ABORT_UNLESS(status == 1, "Invalid ipv4 address: %s", addr.c_str()); - } - return reply; - } - - static TMockReply SingleV6(const TString& addr, TDuration delay = DefaultDelay) { - return ManyV6({ addr }, delay); - } - - static TMockReply SingleV4(const TString& addr, TDuration delay = DefaultDelay) { - return ManyV4({ addr }, delay); - } - - friend TMockReply operator+(const TMockReply& a, const TMockReply& b) { - Y_ABORT_UNLESS(a.Status == b.Status); - TMockReply result; - result.Status = a.Status; - result.Delay = Max(a.Delay, b.Delay); - result.AddrsV6.insert(result.AddrsV6.end(), a.AddrsV6.begin(), a.AddrsV6.end()); - result.AddrsV6.insert(result.AddrsV6.end(), b.AddrsV6.begin(), b.AddrsV6.end()); - result.AddrsV4.insert(result.AddrsV4.end(), a.AddrsV4.begin(), a.AddrsV4.end()); - result.AddrsV4.insert(result.AddrsV4.end(), b.AddrsV4.begin(), b.AddrsV4.end()); - return result; - } - }; - - using TMockDnsCallback = std::function<TMockReply (const TString&, int)>; - - class TMockDnsResolver : public TActor<TMockDnsResolver> { - public: - TMockDnsResolver(TMockDnsCallback callback) - : TActor(&TThis::StateWork) - , Callback(std::move(callback)) - { } - - private: - struct TEvPrivate { - enum EEv { - EvScheduled = EventSpaceBegin(TEvents::ES_PRIVATE), - }; - - struct TEvScheduled : public TEventLocal<TEvScheduled, EvScheduled> { - TActorId Sender; - ui64 Cookie; - TMockReply Reply; - - TEvScheduled(TActorId sender, ui64 cookie, TMockReply reply) - : Sender(sender) - , Cookie(cookie) - , Reply(std::move(reply)) - { } - }; - }; - - private: - STRICT_STFUNC(StateWork, { - hFunc(TEvents::TEvPoison, Handle); - hFunc(TEvDns::TEvGetHostByName, Handle); - hFunc(TEvPrivate::TEvScheduled, Handle); - }); - - void Handle(TEvents::TEvPoison::TPtr&) { - PassAway(); - } - - void Handle(TEvDns::TEvGetHostByName::TPtr& ev) { - auto reply = Callback(ev->Get()->Name, ev->Get()->Family); - if (reply.Delay) { - Schedule(reply.Delay, new TEvPrivate::TEvScheduled(ev->Sender, ev->Cookie, std::move(reply))); - } else { - SendReply(ev->Sender, ev->Cookie, std::move(reply)); - } - } - - void Handle(TEvPrivate::TEvScheduled::TPtr& ev) { - SendReply(ev->Get()->Sender, ev->Get()->Cookie, std::move(ev->Get()->Reply)); - } - - private: - void SendReply(const TActorId& sender, ui64 cookie, TMockReply&& reply) { - auto res = MakeHolder<TEvDns::TEvGetHostByNameResult>(); - res->Status = reply.Status; - if (res->Status != 0) { - res->ErrorText = ares_strerror(res->Status); - } else { - res->AddrsV6 = std::move(reply.AddrsV6); - res->AddrsV4 = std::move(reply.AddrsV4); - } - Send(sender, res.Release(), 0, cookie); - } - - private: - TMockDnsCallback Callback; - }; - - struct TCachingDnsRuntime : public TTestActorRuntimeBase { - TCachingDnsResolverOptions ResolverOptions; - TActorId MockResolver; - TActorId Resolver; - TActorId Sleeper; - TString Section_; - - NMonitoring::TDynamicCounters::TCounterPtr InFlightUnspec; - NMonitoring::TDynamicCounters::TCounterPtr InFlight6; - NMonitoring::TDynamicCounters::TCounterPtr InFlight4; - NMonitoring::TDynamicCounters::TCounterPtr TotalUnspec; - NMonitoring::TDynamicCounters::TCounterPtr Total6; - NMonitoring::TDynamicCounters::TCounterPtr Total4; - NMonitoring::TDynamicCounters::TCounterPtr Misses; - NMonitoring::TDynamicCounters::TCounterPtr Hits; - - THashMap<TString, TMockReply> ReplyV6; - THashMap<TString, TMockReply> ReplyV4; - THashMap<TString, TMockReply> ReplyUnspec; - - TCachingDnsRuntime() { - SetScheduledEventFilter([](auto&&, auto&&, auto&&, auto&&) { return false; }); - ResolverOptions.MonCounters = new NMonitoring::TDynamicCounters; - - ReplyV6["localhost"] = TMockReply::SingleV6("::1"); - ReplyV4["localhost"] = TMockReply::SingleV4("127.0.0.1"); - ReplyV6["yandex.ru"] = TMockReply::SingleV6("2a02:6b8:a::a", TDuration::MilliSeconds(500)); - ReplyV4["yandex.ru"] = TMockReply::SingleV4("77.88.55.77", TDuration::MilliSeconds(250)); - ReplyV6["router.asus.com"] = TMockReply::Error(ARES_ENODATA); - ReplyV4["router.asus.com"] = TMockReply::SingleV4("192.168.0.1"); - ReplyUnspec["localhost"] = ReplyV6.at("localhost") + ReplyV4.at("localhost"); - ReplyUnspec["yandex.ru"] = ReplyV6.at("yandex.ru") + ReplyV4.at("yandex.ru"); - ReplyUnspec["router.asus.com"] = ReplyV4.at("router.asus.com"); - } - - void Start(TMockDnsCallback callback) { - MockResolver = Register(new TMockDnsResolver(std::move(callback))); - EnableScheduleForActor(MockResolver); - Resolver = Register(CreateCachingDnsResolver(MockResolver, ResolverOptions)); - Sleeper = AllocateEdgeActor(); - - InFlightUnspec = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/InFlight/Unspec", false); - InFlight6 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/InFlight/V6", false); - InFlight4 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/InFlight/V4", false); - TotalUnspec = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/Total/Unspec", true); - Total6 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/Total/V6", true); - Total4 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/Total/V4", true); - Misses = ResolverOptions.MonCounters->GetCounter("DnsResolver/Cache/Misses", true); - Hits = ResolverOptions.MonCounters->GetCounter("DnsResolver/Cache/Hits", true); - } - - void Start() { - Start([this](const TString& name, int family) { - switch (family) { - case AF_UNSPEC: { - auto it = ReplyUnspec.find(name); - if (it != ReplyUnspec.end()) { - return it->second; - } - break; - } - case AF_INET6: { - auto it = ReplyV6.find(name); - if (it != ReplyV6.end()) { - return it->second; - } - break; - } - case AF_INET: { - auto it = ReplyV4.find(name); - if (it != ReplyV4.end()) { - return it->second; - } - break; - } - } - return TMockReply::Error(ARES_ENOTFOUND); - }); - } - - void Section(const TString& section) { - Section_ = section; - } - - void Sleep(TDuration duration) { - Schedule(new IEventHandle(Sleeper, Sleeper, new TEvents::TEvWakeup), duration); - GrabEdgeEventRethrow<TEvents::TEvWakeup>(Sleeper); - } - - void WaitNoInFlight() { - if (*InFlightUnspec || *InFlight6 || *InFlight4) { - TDispatchOptions options; - options.CustomFinalCondition = [&]() { - return !*InFlightUnspec && !*InFlight6 && !*InFlight4; - }; - DispatchEvents(options); - UNIT_ASSERT_C(!*InFlight6 && !*InFlight4, "Failed to wait for no inflight in " << Section_); - } - } - - void SendGetHostByName(const TActorId& sender, const TString& name, int family = AF_UNSPEC) { - Send(new IEventHandle(Resolver, sender, new TEvDns::TEvGetHostByName(name, family)), 0, true); - } - - void SendGetAddr(const TActorId& sender, const TString& name, int family = AF_UNSPEC) { - Send(new IEventHandle(Resolver, sender, new TEvDns::TEvGetAddr(name, family)), 0, true); - } - - TEvDns::TEvGetHostByNameResult::TPtr WaitGetHostByName(const TActorId& sender) { - return GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender); - } - - TEvDns::TEvGetAddrResult::TPtr WaitGetAddr(const TActorId& sender) { - return GrabEdgeEventRethrow<TEvDns::TEvGetAddrResult>(sender); - } - - void ExpectInFlightUnspec(i64 count) { - UNIT_ASSERT_VALUES_EQUAL_C(InFlightUnspec->Val(), count, Section_); - } - - void ExpectInFlight6(i64 count) { - UNIT_ASSERT_VALUES_EQUAL_C(InFlight6->Val(), count, Section_); - } - - void ExpectInFlight4(i64 count) { - UNIT_ASSERT_VALUES_EQUAL_C(InFlight4->Val(), count, Section_); - } - - void ExpectTotalUnspec(i64 count) { - UNIT_ASSERT_VALUES_EQUAL_C(TotalUnspec->Val(), count, Section_); - } - - void ExpectTotal6(i64 count) { - UNIT_ASSERT_VALUES_EQUAL_C(Total6->Val(), count, Section_); - } - - void ExpectTotal4(i64 count) { - UNIT_ASSERT_VALUES_EQUAL_C(Total4->Val(), count, Section_); - } - - void ExpectUnspec(i64 total, i64 inflight) { - UNIT_ASSERT_C( - TotalUnspec->Val() == total && InFlightUnspec->Val() == inflight, - Section_ << ": Expect6(" << total << ", " << inflight << ") " - << " but got (" << TotalUnspec->Val() << ", " << InFlightUnspec->Val() << ")"); - } - - void Expect6(i64 total, i64 inflight) { - UNIT_ASSERT_C( - Total6->Val() == total && InFlight6->Val() == inflight, - Section_ << ": Expect6(" << total << ", " << inflight << ") " - << " but got (" << Total6->Val() << ", " << InFlight6->Val() << ")"); - } - - void Expect4(i64 total, i64 inflight) { - UNIT_ASSERT_C( - Total4->Val() == total && InFlight4->Val() == inflight, - Section_ << ": Expect4(" << total << ", " << inflight << ") " - << " got (" << Total4->Val() << ", " << InFlight4->Val() << ")"); - } - - void ExpectMisses(i64 count) { - UNIT_ASSERT_VALUES_EQUAL_C(Misses->Val(), count, Section_); - } - - void ExpectHits(i64 count) { - UNIT_ASSERT_VALUES_EQUAL_C(Hits->Val(), count, Section_); - } - - void ExpectGetHostByNameError(const TActorId& sender, int status) { - auto ev = WaitGetHostByName(sender); - UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, status, Section_ << ": " << ev->Get()->ErrorText); - } - - void ExpectGetAddrError(const TActorId& sender, int status) { - auto ev = WaitGetAddr(sender); - UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, status, Section_ << ": " << ev->Get()->ErrorText); - } - - void ExpectGetHostByNameSuccess(const TActorId& sender, const TString& expected) { - auto ev = WaitGetHostByName(sender); - UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, Section_ << ": " << ev->Get()->ErrorText); - TStringBuilder result; - for (const auto& addr : ev->Get()->AddrsV6) { - if (result) { - result << ','; - } - result << TAddrToString()(addr); - } - for (const auto& addr : ev->Get()->AddrsV4) { - if (result) { - result << ','; - } - result << TAddrToString()(addr); - } - UNIT_ASSERT_VALUES_EQUAL_C(TString(result), expected, Section_); - } - - void ExpectGetAddrSuccess(const TActorId& sender, const TString& expected) { - auto ev = WaitGetAddr(sender); - UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, Section_ << ": " << ev->Get()->ErrorText); - TString result = AddrToString(ev->Get()->Addr); - UNIT_ASSERT_VALUES_EQUAL_C(result, expected, Section_); - } - }; - - Y_UNIT_TEST(UnusableResolver) { - TCachingDnsRuntime runtime; - runtime.Initialize(); - runtime.Start(); - - auto sender = runtime.AllocateEdgeActor(); - - runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC); - runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a"); - - runtime.Send(new IEventHandle(runtime.MockResolver, { }, new TEvents::TEvPoison), 0, true); - runtime.SendGetAddr(sender, "foo.ru", AF_UNSPEC); - runtime.ExpectGetAddrError(sender, ARES_ENOTINITIALIZED); - } - - Y_UNIT_TEST(ResolveCaching) { - TCachingDnsRuntime runtime; - runtime.Initialize(); - runtime.Start(); - - auto sender = runtime.AllocateEdgeActor(); - - // First time resolve, we expect AF_UNSPEC result to be cached - runtime.Section("First time resolve"); - runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC); - runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a"); - runtime.ExpectUnspec(1, 0); - runtime.ExpectMisses(1); - runtime.ExpectHits(0); - - // Second resolve, unspec is a cache hit, ipv6 and ipv4 result in cache misses - runtime.Section("Second resolve"); - runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC); - runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a"); - runtime.ExpectUnspec(1, 0); - runtime.ExpectHits(1); - - // Wait until soft expiration and try unspec again - // Will cause a cache hit, but will start a new request in background - runtime.Section("Retry both after soft expiration"); - runtime.Sleep(TDuration::Seconds(15)); - runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC); - runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a"); - runtime.ExpectUnspec(2, 1); - runtime.ExpectMisses(1); - runtime.ExpectHits(2); - runtime.WaitNoInFlight(); - - // Wait until hard expiration and try unspec again - // Will cause a cache miss and new resolve requests - runtime.Section("Retry both after hard expiration"); - runtime.Sleep(TDuration::Hours(2)); - runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC); - runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a"); - runtime.ExpectUnspec(3, 0); - runtime.ExpectMisses(2); - runtime.ExpectHits(2); - - // Wait half the hard expiration time, must always result in a cache hit - runtime.Section("Retry both after half hard expiration"); - for (ui64 i = 1; i <= 4; ++i) { - runtime.Sleep(TDuration::Hours(1)); - runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC); - runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a"); - runtime.ExpectUnspec(3 + i, 1); - runtime.ExpectHits(2 + i); - runtime.WaitNoInFlight(); - } - - // Change unspec result to a timeout, must keep using cached result until hard expiration - runtime.Section("Dns keeps timing out"); - runtime.ReplyUnspec["yandex.ru"] = TMockReply::Error(ARES_ETIMEOUT); - for (ui64 i = 1; i <= 4; ++i) { - runtime.Sleep(TDuration::Seconds(15)); - runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC); - runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a"); - runtime.ExpectUnspec(7 + i, 1); - runtime.ExpectHits(6 + i); - runtime.WaitNoInFlight(); - } - - // Change unspec result to v4, must switch to a v4 result eventually - runtime.Section("Host changes to being ipv4 only"); - runtime.ReplyUnspec["yandex.ru"] = runtime.ReplyV4.at("yandex.ru"); - runtime.Sleep(TDuration::Seconds(2)); - runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC); - runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a"); - runtime.WaitNoInFlight(); - runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC); - runtime.ExpectGetAddrSuccess(sender, "77.88.55.77"); - runtime.ExpectUnspec(12, 0); - runtime.ExpectMisses(2); - - // Change unspec result to nxdomain, must start returning it - runtime.Section("Host is removed from dns"); - runtime.ReplyUnspec["yandex.ru"] = TMockReply::Error(ARES_ENOTFOUND); - runtime.Sleep(TDuration::Seconds(15)); - runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC); - runtime.ExpectGetAddrSuccess(sender, "77.88.55.77"); - runtime.WaitNoInFlight(); - runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC); - runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND); - } - - Y_UNIT_TEST(ResolveCachingV4) { - TCachingDnsRuntime runtime; - runtime.Initialize(); - runtime.Start(); - - auto sender = runtime.AllocateEdgeActor(); - - runtime.Section("First request"); - runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC); - runtime.ExpectGetAddrSuccess(sender, "192.168.0.1"); - runtime.ExpectMisses(1); - - runtime.Section("Second request"); - runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC); - runtime.ExpectGetAddrSuccess(sender, "192.168.0.1"); - runtime.ExpectHits(1); - - runtime.Section("Dns keeps timing out"); - runtime.ReplyUnspec["router.asus.com"] = TMockReply::Error(ARES_ETIMEOUT); - for (ui64 i = 1; i <= 4; ++i) { - runtime.Sleep(TDuration::Seconds(15)); - runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC); - runtime.ExpectGetAddrSuccess(sender, "192.168.0.1"); - runtime.ExpectUnspec(1 + i, 1); - runtime.ExpectHits(1 + i); - runtime.WaitNoInFlight(); - } - - runtime.Section("Host is removed from dns"); - runtime.ReplyUnspec["router.asus.com"] = TMockReply::Error(ARES_ENOTFOUND); - runtime.Sleep(TDuration::Seconds(15)); - runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC); - runtime.ExpectGetAddrSuccess(sender, "192.168.0.1"); - runtime.WaitNoInFlight(); - runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC); - runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND); - } - - Y_UNIT_TEST(EventualTimeout) { - TCachingDnsRuntime runtime; - runtime.Initialize(); - runtime.Start(); - - auto sender = runtime.AllocateEdgeActor(); - - runtime.ReplyUnspec["notfound.ru"] = TMockReply::Error(ARES_ENOTFOUND); - runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC); - runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND); - - runtime.ReplyUnspec["notfound.ru"] = TMockReply::Error(ARES_ETIMEOUT); - runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC); - runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND); - runtime.WaitNoInFlight(); - - bool timeout = false; - for (ui64 i = 1; i <= 8; ++i) { - runtime.Sleep(TDuration::Minutes(30)); - runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC); - auto ev = runtime.WaitGetAddr(sender); - if (ev->Get()->Status == ARES_ETIMEOUT && i > 2) { - timeout = true; - break; - } - UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, ARES_ENOTFOUND, - "Iteration " << i << ": " << ev->Get()->ErrorText); - } - - UNIT_ASSERT_C(timeout, "DnsResolver did not reply with a timeout"); - } - - Y_UNIT_TEST(MultipleRequestsAndHosts) { - TCachingDnsRuntime runtime; - runtime.Initialize(); - runtime.Start(); - - auto sender = runtime.AllocateEdgeActor(); - - runtime.SendGetHostByName(sender, "router.asus.com", AF_UNSPEC); - runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC); - runtime.SendGetHostByName(sender, "yandex.ru", AF_UNSPEC); - runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC); - runtime.ExpectGetHostByNameSuccess(sender, "192.168.0.1"); - runtime.ExpectGetAddrSuccess(sender, "192.168.0.1"); - runtime.ExpectGetHostByNameSuccess(sender, "2a02:6b8:a::a,77.88.55.77"); - runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a"); - - runtime.SendGetHostByName(sender, "notfound.ru", AF_UNSPEC); - runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC); - runtime.ExpectGetHostByNameError(sender, ARES_ENOTFOUND); - runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND); - } - - Y_UNIT_TEST(DisabledIPv6) { - TCachingDnsRuntime runtime; - runtime.ResolverOptions.AllowIPv6 = false; - runtime.Initialize(); - runtime.Start(); - - auto sender = runtime.AllocateEdgeActor(); - - runtime.SendGetHostByName(sender, "yandex.ru", AF_UNSPEC); - runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC); - runtime.ExpectGetHostByNameSuccess(sender, "77.88.55.77"); - runtime.ExpectGetAddrSuccess(sender, "77.88.55.77"); - - runtime.SendGetHostByName(sender, "yandex.ru", AF_INET6); - runtime.SendGetAddr(sender, "yandex.ru", AF_INET6); - runtime.ExpectGetHostByNameError(sender, ARES_EBADFAMILY); - runtime.ExpectGetAddrError(sender, ARES_EBADFAMILY); - - runtime.SendGetHostByName(sender, "yandex.ru", AF_UNSPEC); - runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC); - runtime.ExpectGetHostByNameSuccess(sender, "77.88.55.77"); - runtime.ExpectGetAddrSuccess(sender, "77.88.55.77"); - - runtime.SendGetHostByName(sender, "notfound.ru", AF_UNSPEC); - runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC); - runtime.ExpectGetHostByNameError(sender, ARES_ENOTFOUND); - runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND); - } - - Y_UNIT_TEST(DisabledIPv4) { - TCachingDnsRuntime runtime; - runtime.ResolverOptions.AllowIPv4 = false; - runtime.Initialize(); - runtime.Start(); - - auto sender = runtime.AllocateEdgeActor(); - - runtime.SendGetHostByName(sender, "router.asus.com", AF_UNSPEC); - runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC); - runtime.ExpectGetHostByNameError(sender, ARES_ENODATA); - runtime.ExpectGetAddrError(sender, ARES_ENODATA); - - runtime.SendGetHostByName(sender, "router.asus.com", AF_INET); - runtime.SendGetAddr(sender, "router.asus.com", AF_INET); - runtime.ExpectGetHostByNameError(sender, ARES_EBADFAMILY); - runtime.ExpectGetAddrError(sender, ARES_EBADFAMILY); - - runtime.SendGetHostByName(sender, "router.asus.com", AF_UNSPEC); - runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC); - runtime.ExpectGetHostByNameError(sender, ARES_ENODATA); - runtime.ExpectGetAddrError(sender, ARES_ENODATA); - - runtime.SendGetHostByName(sender, "notfound.ru", AF_UNSPEC); - runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC); - runtime.ExpectGetHostByNameError(sender, ARES_ENOTFOUND); - runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND); - } - - Y_UNIT_TEST(PoisonPill) { - TCachingDnsRuntime runtime; - runtime.Initialize(); - runtime.Start(); - - auto sender = runtime.AllocateEdgeActor(); - - runtime.SendGetHostByName(sender, "yandex.ru", AF_UNSPEC); - runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC); - runtime.Send(new IEventHandle(runtime.Resolver, sender, new TEvents::TEvPoison), 0, true); - runtime.ExpectGetHostByNameError(sender, ARES_ECANCELLED); - runtime.ExpectGetAddrError(sender, ARES_ECANCELLED); - } - -} diff --git a/library/cpp/actors/dnsresolver/dnsresolver_ondemand.cpp b/library/cpp/actors/dnsresolver/dnsresolver_ondemand.cpp deleted file mode 100644 index 8b0ddf5a6d..0000000000 --- a/library/cpp/actors/dnsresolver/dnsresolver_ondemand.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "dnsresolver.h" - -#include <library/cpp/actors/core/hfunc.h> - -namespace NActors { -namespace NDnsResolver { - - class TOnDemandDnsResolver : public TActor<TOnDemandDnsResolver> { - public: - TOnDemandDnsResolver(TOnDemandDnsResolverOptions options) - : TActor(&TThis::StateWork) - , Options(std::move(options)) - { } - - static constexpr EActivityType ActorActivityType() { - return EActivityType::DNS_RESOLVER; - } - - private: - STRICT_STFUNC(StateWork, { - cFunc(TEvents::TEvPoison::EventType, PassAway); - fFunc(TEvDns::TEvGetHostByName::EventType, Forward); - fFunc(TEvDns::TEvGetAddr::EventType, Forward); - }); - - void Forward(STATEFN_SIG) { - ev->Rewrite(ev->GetTypeRewrite(), GetUpstream()); - TActivationContext::Send(ev.Release()); - } - - private: - TActorId GetUpstream() { - if (Y_UNLIKELY(!CachingResolverId)) { - if (Y_LIKELY(!SimpleResolverId)) { - SimpleResolverId = RegisterWithSameMailbox(CreateSimpleDnsResolver(Options)); - } - CachingResolverId = RegisterWithSameMailbox(CreateCachingDnsResolver(SimpleResolverId, Options)); - } - return CachingResolverId; - } - - void PassAway() override { - if (CachingResolverId) { - Send(CachingResolverId, new TEvents::TEvPoison); - CachingResolverId = { }; - } - if (SimpleResolverId) { - Send(SimpleResolverId, new TEvents::TEvPoison); - SimpleResolverId = { }; - } - } - - private: - TOnDemandDnsResolverOptions Options; - TActorId SimpleResolverId; - TActorId CachingResolverId; - }; - - IActor* CreateOnDemandDnsResolver(TOnDemandDnsResolverOptions options) { - return new TOnDemandDnsResolver(std::move(options)); - } - -} // namespace NDnsResolver -} // namespace NActors diff --git a/library/cpp/actors/dnsresolver/dnsresolver_ondemand_ut.cpp b/library/cpp/actors/dnsresolver/dnsresolver_ondemand_ut.cpp deleted file mode 100644 index 2758484552..0000000000 --- a/library/cpp/actors/dnsresolver/dnsresolver_ondemand_ut.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "dnsresolver.h" - -#include <library/cpp/actors/testlib/test_runtime.h> -#include <library/cpp/testing/unittest/registar.h> - -using namespace NActors; -using namespace NActors::NDnsResolver; - -Y_UNIT_TEST_SUITE(OnDemandDnsResolver) { - - Y_UNIT_TEST(ResolveLocalHost) { - TTestActorRuntimeBase runtime; - runtime.Initialize(); - auto sender = runtime.AllocateEdgeActor(); - auto resolver = runtime.Register(CreateOnDemandDnsResolver()); - runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("localhost", AF_UNSPEC)), - 0, true); - auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender); - UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText); - size_t addrs = ev->Get()->AddrsV4.size() + ev->Get()->AddrsV6.size(); - UNIT_ASSERT_C(addrs > 0, "Got " << addrs << " addresses"); - } - -} diff --git a/library/cpp/actors/dnsresolver/dnsresolver_ut.cpp b/library/cpp/actors/dnsresolver/dnsresolver_ut.cpp deleted file mode 100644 index 93c4b832e2..0000000000 --- a/library/cpp/actors/dnsresolver/dnsresolver_ut.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "dnsresolver.h" - -#include <library/cpp/actors/testlib/test_runtime.h> -#include <library/cpp/testing/unittest/registar.h> -#include <util/string/builder.h> - -#include <ares.h> - -using namespace NActors; -using namespace NActors::NDnsResolver; - -Y_UNIT_TEST_SUITE(DnsResolver) { - - struct TSilentUdpServer { - TInetDgramSocket Socket; - ui16 Port; - - TSilentUdpServer() { - TSockAddrInet addr("127.0.0.1", 0); - int err = Socket.Bind(&addr); - Y_ABORT_UNLESS(err == 0, "Cannot bind a udp socket"); - Port = addr.GetPort(); - } - }; - - Y_UNIT_TEST(ResolveLocalHost) { - TTestActorRuntimeBase runtime; - runtime.Initialize(); - auto sender = runtime.AllocateEdgeActor(); - auto resolver = runtime.Register(CreateSimpleDnsResolver()); - runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("localhost", AF_UNSPEC)), - 0, true); - auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender); - UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText); - size_t addrs = ev->Get()->AddrsV4.size() + ev->Get()->AddrsV6.size(); - UNIT_ASSERT_C(addrs > 0, "Got " << addrs << " addresses"); - } - - Y_UNIT_TEST(ResolveYandexRu) { - TTestActorRuntimeBase runtime; - runtime.Initialize(); - auto sender = runtime.AllocateEdgeActor(); - auto resolver = runtime.Register(CreateSimpleDnsResolver()); - runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("yandex.ru", AF_UNSPEC)), - 0, true); - auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender); - UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText); - size_t addrs = ev->Get()->AddrsV4.size() + ev->Get()->AddrsV6.size(); - UNIT_ASSERT_C(addrs > 0, "Got " << addrs << " addresses"); - } - - Y_UNIT_TEST(GetAddrYandexRu) { - TTestActorRuntimeBase runtime; - runtime.Initialize(); - auto sender = runtime.AllocateEdgeActor(); - auto resolver = runtime.Register(CreateSimpleDnsResolver()); - - runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetAddr("yandex.ru", AF_UNSPEC)), - 0, true); - auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetAddrResult>(sender); - UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText); - UNIT_ASSERT_C(ev->Get()->IsV4() || ev->Get()->IsV6(), "Expect v4 or v6 address"); - } - - Y_UNIT_TEST(ResolveTimeout) { - TSilentUdpServer server; - TTestActorRuntimeBase runtime; - runtime.Initialize(); - auto sender = runtime.AllocateEdgeActor(); - TSimpleDnsResolverOptions options; - options.Timeout = TDuration::MilliSeconds(250); - options.Attempts = 2; - options.Servers.emplace_back(TStringBuilder() << "127.0.0.1:" << server.Port); - auto resolver = runtime.Register(CreateSimpleDnsResolver(options)); - runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("timeout.yandex.ru", AF_INET)), - 0, true); - auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender); - UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, ARES_ETIMEOUT, ev->Get()->ErrorText); - } - - Y_UNIT_TEST(ResolveGracefulStop) { - TSilentUdpServer server; - TTestActorRuntimeBase runtime; - runtime.Initialize(); - auto sender = runtime.AllocateEdgeActor(); - TSimpleDnsResolverOptions options; - options.Timeout = TDuration::Seconds(5); - options.Attempts = 5; - options.Servers.emplace_back(TStringBuilder() << "127.0.0.1:" << server.Port); - auto resolver = runtime.Register(CreateSimpleDnsResolver(options)); - runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("timeout.yandex.ru", AF_INET)), - 0, true); - runtime.Send(new IEventHandle(resolver, sender, new TEvents::TEvPoison), 0, true); - auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender); - UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, ARES_ECANCELLED, ev->Get()->ErrorText); - } - -} diff --git a/library/cpp/actors/dnsresolver/ut/CMakeLists.darwin-arm64.txt b/library/cpp/actors/dnsresolver/ut/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 8874bee8e5..0000000000 --- a/library/cpp/actors/dnsresolver/ut/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,70 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-dnsresolver-ut) -target_include_directories(library-cpp-actors-dnsresolver-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver - ${CMAKE_SOURCE_DIR}/contrib/libs/c-ares/include -) -target_link_libraries(library-cpp-actors-dnsresolver-ut PUBLIC - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-dnsresolver - cpp-actors-testlib -) -target_link_options(library-cpp-actors-dnsresolver-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-dnsresolver-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_ondemand_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_ut.cpp -) -set_property( - TARGET - library-cpp-actors-dnsresolver-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-dnsresolver-ut - TEST_TARGET - library-cpp-actors-dnsresolver-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-dnsresolver-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-dnsresolver-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-dnsresolver-ut - system_allocator -) -vcs_info(library-cpp-actors-dnsresolver-ut) diff --git a/library/cpp/actors/dnsresolver/ut/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/dnsresolver/ut/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 9e092bba80..0000000000 --- a/library/cpp/actors/dnsresolver/ut/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,71 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-dnsresolver-ut) -target_include_directories(library-cpp-actors-dnsresolver-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver - ${CMAKE_SOURCE_DIR}/contrib/libs/c-ares/include -) -target_link_libraries(library-cpp-actors-dnsresolver-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-dnsresolver - cpp-actors-testlib -) -target_link_options(library-cpp-actors-dnsresolver-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-dnsresolver-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_ondemand_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_ut.cpp -) -set_property( - TARGET - library-cpp-actors-dnsresolver-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-dnsresolver-ut - TEST_TARGET - library-cpp-actors-dnsresolver-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-dnsresolver-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-dnsresolver-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-dnsresolver-ut - system_allocator -) -vcs_info(library-cpp-actors-dnsresolver-ut) diff --git a/library/cpp/actors/dnsresolver/ut/CMakeLists.linux-aarch64.txt b/library/cpp/actors/dnsresolver/ut/CMakeLists.linux-aarch64.txt deleted file mode 100644 index c8eb27acd0..0000000000 --- a/library/cpp/actors/dnsresolver/ut/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,74 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-dnsresolver-ut) -target_include_directories(library-cpp-actors-dnsresolver-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver - ${CMAKE_SOURCE_DIR}/contrib/libs/c-ares/include -) -target_link_libraries(library-cpp-actors-dnsresolver-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-dnsresolver - cpp-actors-testlib -) -target_link_options(library-cpp-actors-dnsresolver-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-dnsresolver-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_ondemand_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_ut.cpp -) -set_property( - TARGET - library-cpp-actors-dnsresolver-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-dnsresolver-ut - TEST_TARGET - library-cpp-actors-dnsresolver-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-dnsresolver-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-dnsresolver-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-dnsresolver-ut - cpp-malloc-jemalloc -) -vcs_info(library-cpp-actors-dnsresolver-ut) diff --git a/library/cpp/actors/dnsresolver/ut/CMakeLists.linux-x86_64.txt b/library/cpp/actors/dnsresolver/ut/CMakeLists.linux-x86_64.txt deleted file mode 100644 index eae7bc85a3..0000000000 --- a/library/cpp/actors/dnsresolver/ut/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,76 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-dnsresolver-ut) -target_include_directories(library-cpp-actors-dnsresolver-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver - ${CMAKE_SOURCE_DIR}/contrib/libs/c-ares/include -) -target_link_libraries(library-cpp-actors-dnsresolver-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-dnsresolver - cpp-actors-testlib -) -target_link_options(library-cpp-actors-dnsresolver-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-dnsresolver-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_ondemand_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_ut.cpp -) -set_property( - TARGET - library-cpp-actors-dnsresolver-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-dnsresolver-ut - TEST_TARGET - library-cpp-actors-dnsresolver-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-dnsresolver-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-dnsresolver-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-dnsresolver-ut - cpp-malloc-tcmalloc - libs-tcmalloc-no_percpu_cache -) -vcs_info(library-cpp-actors-dnsresolver-ut) diff --git a/library/cpp/actors/dnsresolver/ut/CMakeLists.txt b/library/cpp/actors/dnsresolver/ut/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/dnsresolver/ut/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/dnsresolver/ut/CMakeLists.windows-x86_64.txt b/library/cpp/actors/dnsresolver/ut/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 7705d206a3..0000000000 --- a/library/cpp/actors/dnsresolver/ut/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,64 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-dnsresolver-ut) -target_include_directories(library-cpp-actors-dnsresolver-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver - ${CMAKE_SOURCE_DIR}/contrib/libs/c-ares/include -) -target_link_libraries(library-cpp-actors-dnsresolver-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-dnsresolver - cpp-actors-testlib -) -target_sources(library-cpp-actors-dnsresolver-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_ondemand_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/dnsresolver/dnsresolver_ut.cpp -) -set_property( - TARGET - library-cpp-actors-dnsresolver-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-dnsresolver-ut - TEST_TARGET - library-cpp-actors-dnsresolver-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-dnsresolver-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-dnsresolver-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-dnsresolver-ut - system_allocator -) -vcs_info(library-cpp-actors-dnsresolver-ut) diff --git a/library/cpp/actors/dnsresolver/ut/ya.make b/library/cpp/actors/dnsresolver/ut/ya.make deleted file mode 100644 index ec4b117bf7..0000000000 --- a/library/cpp/actors/dnsresolver/ut/ya.make +++ /dev/null @@ -1,18 +0,0 @@ -UNITTEST_FOR(library/cpp/actors/dnsresolver) - -PEERDIR( - library/cpp/actors/testlib -) - -SRCS( - dnsresolver_caching_ut.cpp - dnsresolver_ondemand_ut.cpp - dnsresolver_ut.cpp -) - -ADDINCL(contrib/libs/c-ares/include) - -TAG(ya:external) -REQUIREMENTS(network:full) - -END() diff --git a/library/cpp/actors/dnsresolver/ya.make b/library/cpp/actors/dnsresolver/ya.make deleted file mode 100644 index 6d9318a254..0000000000 --- a/library/cpp/actors/dnsresolver/ya.make +++ /dev/null @@ -1,18 +0,0 @@ -LIBRARY() - -SRCS( - dnsresolver.cpp - dnsresolver_caching.cpp - dnsresolver_ondemand.cpp -) - -PEERDIR( - library/cpp/actors/core - contrib/libs/c-ares -) - -END() - -RECURSE_FOR_TESTS( - ut -) diff --git a/library/cpp/actors/examples/01_ping_pong/CMakeLists.darwin-arm64.txt b/library/cpp/actors/examples/01_ping_pong/CMakeLists.darwin-arm64.txt deleted file mode 100644 index b2acea01a5..0000000000 --- a/library/cpp/actors/examples/01_ping_pong/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,29 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(example_01_ping_pong) -target_link_libraries(example_01_ping_pong PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core -) -target_link_options(example_01_ping_pong PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(example_01_ping_pong PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/01_ping_pong/main.cpp -) -target_allocator(example_01_ping_pong - library-cpp-lfalloc -) -vcs_info(example_01_ping_pong) diff --git a/library/cpp/actors/examples/01_ping_pong/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/examples/01_ping_pong/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 1e053eb6b4..0000000000 --- a/library/cpp/actors/examples/01_ping_pong/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,30 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(example_01_ping_pong) -target_link_libraries(example_01_ping_pong PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-actors-core -) -target_link_options(example_01_ping_pong PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(example_01_ping_pong PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/01_ping_pong/main.cpp -) -target_allocator(example_01_ping_pong - library-cpp-lfalloc -) -vcs_info(example_01_ping_pong) diff --git a/library/cpp/actors/examples/01_ping_pong/CMakeLists.linux-aarch64.txt b/library/cpp/actors/examples/01_ping_pong/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 5884f06261..0000000000 --- a/library/cpp/actors/examples/01_ping_pong/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,33 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(example_01_ping_pong) -target_link_libraries(example_01_ping_pong PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-actors-core -) -target_link_options(example_01_ping_pong PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(example_01_ping_pong PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/01_ping_pong/main.cpp -) -target_allocator(example_01_ping_pong - library-cpp-lfalloc -) -vcs_info(example_01_ping_pong) diff --git a/library/cpp/actors/examples/01_ping_pong/CMakeLists.linux-x86_64.txt b/library/cpp/actors/examples/01_ping_pong/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 7320982029..0000000000 --- a/library/cpp/actors/examples/01_ping_pong/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,34 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(example_01_ping_pong) -target_link_libraries(example_01_ping_pong PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-actors-core -) -target_link_options(example_01_ping_pong PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(example_01_ping_pong PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/01_ping_pong/main.cpp -) -target_allocator(example_01_ping_pong - library-cpp-lfalloc -) -vcs_info(example_01_ping_pong) diff --git a/library/cpp/actors/examples/01_ping_pong/CMakeLists.txt b/library/cpp/actors/examples/01_ping_pong/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/examples/01_ping_pong/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/examples/01_ping_pong/CMakeLists.windows-x86_64.txt b/library/cpp/actors/examples/01_ping_pong/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 22c41768c9..0000000000 --- a/library/cpp/actors/examples/01_ping_pong/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,23 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(example_01_ping_pong) -target_link_libraries(example_01_ping_pong PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-actors-core -) -target_sources(example_01_ping_pong PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/01_ping_pong/main.cpp -) -target_allocator(example_01_ping_pong - library-cpp-lfalloc -) -vcs_info(example_01_ping_pong) diff --git a/library/cpp/actors/examples/01_ping_pong/main.cpp b/library/cpp/actors/examples/01_ping_pong/main.cpp deleted file mode 100644 index 437f06eadd..0000000000 --- a/library/cpp/actors/examples/01_ping_pong/main.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#include <library/cpp/actors/core/actorsystem.h> -#include <library/cpp/actors/core/executor_pool_basic.h> -#include <library/cpp/actors/core/scheduler_basic.h> -#include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/core/actor_bootstrapped.h> -#include <library/cpp/actors/util/should_continue.h> -#include <util/system/sigset.h> -#include <util/generic/xrange.h> - -using namespace NActors; - -static TProgramShouldContinue ShouldContinue; - -void OnTerminate(int) { - ShouldContinue.ShouldStop(); -} - -class TPingActor : public TActorBootstrapped<TPingActor> { - const TActorId Target; - ui64 HandledEvents; - TInstant PeriodStart; - - void Handle(TEvents::TEvPing::TPtr &ev) { - Send(ev->Sender, new TEvents::TEvPong()); - Send(ev->Sender, new TEvents::TEvPing()); - Become(&TThis::StatePing); - } - - void Handle(TEvents::TEvPong::TPtr &ev) { - Y_UNUSED(ev); - Become(&TThis::StateWait); - } - - void PrintStats() { - const i64 ms = (TInstant::Now() - PeriodStart).MilliSeconds(); - Cout << "Handled " << 2 * HandledEvents << " over " << ms << "ms" << Endl; - ScheduleStats(); - } - - void ScheduleStats() { - HandledEvents = 0; - PeriodStart = TInstant::Now(); - Schedule(TDuration::Seconds(1), new TEvents::TEvWakeup()); - } - -public: - TPingActor(TActorId target) - : Target(target) - , HandledEvents(0) - , PeriodStart(TInstant::Now()) - {} - - STFUNC(StateWait) { - switch (ev->GetTypeRewrite()) { - hFunc(TEvents::TEvPing, Handle); - sFunc(TEvents::TEvWakeup, PrintStats); - } - - ++HandledEvents; - } - - STFUNC(StatePing) { - switch (ev->GetTypeRewrite()) { - hFunc(TEvents::TEvPong, Handle); - sFunc(TEvents::TEvWakeup, PrintStats); - } - - ++HandledEvents; - } - - void Bootstrap() { - if (Target) { - Become(&TThis::StatePing); - Send(Target, new TEvents::TEvPing()); - ScheduleStats(); - } - else { - Become(&TThis::StateWait); - }; - } -}; - -THolder<TActorSystemSetup> BuildActorSystemSetup(ui32 threads, ui32 pools) { - Y_ABORT_UNLESS(threads > 0 && threads < 100); - Y_ABORT_UNLESS(pools > 0 && pools < 10); - - auto setup = MakeHolder<TActorSystemSetup>(); - - setup->NodeId = 1; - - setup->ExecutorsCount = pools; - setup->Executors.Reset(new TAutoPtr<IExecutorPool>[pools]); - for (ui32 idx : xrange(pools)) { - setup->Executors[idx] = new TBasicExecutorPool(idx, threads, 50); - } - - setup->Scheduler = new TBasicSchedulerThread(TSchedulerConfig(512, 0)); - - return setup; -} - -int main(int argc, char **argv) { - Y_UNUSED(argc); - Y_UNUSED(argv); - -#ifdef _unix_ - signal(SIGPIPE, SIG_IGN); -#endif - signal(SIGINT, &OnTerminate); - signal(SIGTERM, &OnTerminate); - - THolder<TActorSystemSetup> actorSystemSetup = BuildActorSystemSetup(2, 1); - TActorSystem actorSystem(actorSystemSetup); - - actorSystem.Start(); - - const TActorId a = actorSystem.Register(new TPingActor(TActorId())); - const TActorId b = actorSystem.Register(new TPingActor(a)); - Y_UNUSED(b); - - while (ShouldContinue.PollState() == TProgramShouldContinue::Continue) { - Sleep(TDuration::MilliSeconds(200)); - } - - actorSystem.Stop(); - actorSystem.Cleanup(); - - return ShouldContinue.GetReturnCode(); -} diff --git a/library/cpp/actors/examples/01_ping_pong/ya.make b/library/cpp/actors/examples/01_ping_pong/ya.make deleted file mode 100644 index d33cfd3456..0000000000 --- a/library/cpp/actors/examples/01_ping_pong/ya.make +++ /dev/null @@ -1,13 +0,0 @@ -PROGRAM(example_01_ping_pong) - -ALLOCATOR(LF) - -SRCS( - main.cpp -) - -PEERDIR( - library/cpp/actors/core -) - -END() diff --git a/library/cpp/actors/examples/02_discovery/CMakeLists.darwin-arm64.txt b/library/cpp/actors/examples/02_discovery/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 5e379dc7ca..0000000000 --- a/library/cpp/actors/examples/02_discovery/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,66 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) - -add_executable(example_02_discovery) -target_link_libraries(example_02_discovery PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core - cpp-actors-dnsresolver - cpp-actors-interconnect - cpp-actors-http - contrib-libs-protobuf -) -target_link_options(example_02_discovery PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_proto_messages(example_02_discovery PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/protocol.proto -) -target_sources(example_02_discovery PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/endpoint.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/lookup.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/main.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/publish.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/replica.cpp -) -target_allocator(example_02_discovery - library-cpp-lfalloc -) -target_proto_addincls(example_02_discovery - ./ - ${CMAKE_SOURCE_DIR}/ - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src - ${CMAKE_SOURCE_DIR}/contrib/libs/opentelemetry-proto - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src -) -target_proto_outs(example_02_discovery - --cpp_out=${CMAKE_BINARY_DIR}/ - --cpp_styleguide_out=${CMAKE_BINARY_DIR}/ -) -vcs_info(example_02_discovery) diff --git a/library/cpp/actors/examples/02_discovery/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/examples/02_discovery/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 1003ca94c5..0000000000 --- a/library/cpp/actors/examples/02_discovery/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,67 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) - -add_executable(example_02_discovery) -target_link_libraries(example_02_discovery PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-actors-core - cpp-actors-dnsresolver - cpp-actors-interconnect - cpp-actors-http - contrib-libs-protobuf -) -target_link_options(example_02_discovery PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_proto_messages(example_02_discovery PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/protocol.proto -) -target_sources(example_02_discovery PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/endpoint.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/lookup.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/main.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/publish.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/replica.cpp -) -target_allocator(example_02_discovery - library-cpp-lfalloc -) -target_proto_addincls(example_02_discovery - ./ - ${CMAKE_SOURCE_DIR}/ - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src - ${CMAKE_SOURCE_DIR}/contrib/libs/opentelemetry-proto - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src -) -target_proto_outs(example_02_discovery - --cpp_out=${CMAKE_BINARY_DIR}/ - --cpp_styleguide_out=${CMAKE_BINARY_DIR}/ -) -vcs_info(example_02_discovery) diff --git a/library/cpp/actors/examples/02_discovery/CMakeLists.linux-aarch64.txt b/library/cpp/actors/examples/02_discovery/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 564892d9f7..0000000000 --- a/library/cpp/actors/examples/02_discovery/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,70 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) - -add_executable(example_02_discovery) -target_link_libraries(example_02_discovery PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-actors-core - cpp-actors-dnsresolver - cpp-actors-interconnect - cpp-actors-http - contrib-libs-protobuf -) -target_link_options(example_02_discovery PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_proto_messages(example_02_discovery PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/protocol.proto -) -target_sources(example_02_discovery PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/endpoint.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/lookup.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/main.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/publish.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/replica.cpp -) -target_allocator(example_02_discovery - library-cpp-lfalloc -) -target_proto_addincls(example_02_discovery - ./ - ${CMAKE_SOURCE_DIR}/ - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src - ${CMAKE_SOURCE_DIR}/contrib/libs/opentelemetry-proto - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src -) -target_proto_outs(example_02_discovery - --cpp_out=${CMAKE_BINARY_DIR}/ - --cpp_styleguide_out=${CMAKE_BINARY_DIR}/ -) -vcs_info(example_02_discovery) diff --git a/library/cpp/actors/examples/02_discovery/CMakeLists.linux-x86_64.txt b/library/cpp/actors/examples/02_discovery/CMakeLists.linux-x86_64.txt deleted file mode 100644 index aed3404cb8..0000000000 --- a/library/cpp/actors/examples/02_discovery/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,71 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) - -add_executable(example_02_discovery) -target_link_libraries(example_02_discovery PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-actors-core - cpp-actors-dnsresolver - cpp-actors-interconnect - cpp-actors-http - contrib-libs-protobuf -) -target_link_options(example_02_discovery PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_proto_messages(example_02_discovery PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/protocol.proto -) -target_sources(example_02_discovery PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/endpoint.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/lookup.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/main.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/publish.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/replica.cpp -) -target_allocator(example_02_discovery - library-cpp-lfalloc -) -target_proto_addincls(example_02_discovery - ./ - ${CMAKE_SOURCE_DIR}/ - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src - ${CMAKE_SOURCE_DIR}/contrib/libs/opentelemetry-proto - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src -) -target_proto_outs(example_02_discovery - --cpp_out=${CMAKE_BINARY_DIR}/ - --cpp_styleguide_out=${CMAKE_BINARY_DIR}/ -) -vcs_info(example_02_discovery) diff --git a/library/cpp/actors/examples/02_discovery/CMakeLists.txt b/library/cpp/actors/examples/02_discovery/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/examples/02_discovery/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/examples/02_discovery/CMakeLists.windows-x86_64.txt b/library/cpp/actors/examples/02_discovery/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 6bf59ae8c9..0000000000 --- a/library/cpp/actors/examples/02_discovery/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,60 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) - -add_executable(example_02_discovery) -target_link_libraries(example_02_discovery PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-actors-core - cpp-actors-dnsresolver - cpp-actors-interconnect - cpp-actors-http - contrib-libs-protobuf -) -target_proto_messages(example_02_discovery PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/protocol.proto -) -target_sources(example_02_discovery PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/endpoint.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/lookup.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/main.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/publish.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/examples/02_discovery/replica.cpp -) -target_allocator(example_02_discovery - library-cpp-lfalloc -) -target_proto_addincls(example_02_discovery - ./ - ${CMAKE_SOURCE_DIR}/ - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src - ${CMAKE_SOURCE_DIR}/contrib/libs/opentelemetry-proto - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src -) -target_proto_outs(example_02_discovery - --cpp_out=${CMAKE_BINARY_DIR}/ - --cpp_styleguide_out=${CMAKE_BINARY_DIR}/ -) -vcs_info(example_02_discovery) diff --git a/library/cpp/actors/examples/02_discovery/endpoint.cpp b/library/cpp/actors/examples/02_discovery/endpoint.cpp deleted file mode 100644 index 38c068ca8f..0000000000 --- a/library/cpp/actors/examples/02_discovery/endpoint.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "services.h" - -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/core/actor_bootstrapped.h> -#include <library/cpp/actors/protos/services_common.pb.h> - -#include <library/cpp/actors/http/http.h> -#include <library/cpp/actors/http/http_proxy.h> - -#include <util/system/hostname.h> -#include <util/string/builder.h> - -class TExampleHttpRequest : public TActor<TExampleHttpRequest> { - TIntrusivePtr<TExampleStorageConfig> Config; - const TString PublishKey; - - TActorId HttpProxy; - NHttp::THttpIncomingRequestPtr Request; - - void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr &ev) { - Request = std::move(ev->Get()->Request); - HttpProxy = ev->Sender; - - Register(CreateLookupActor(Config.Get(), PublishKey, SelfId())); - } - - void Handle(TEvExample::TEvInfo::TPtr &ev) { - auto *msg = ev->Get(); - - TStringBuilder body; - for (const auto &x : msg->Payloads) - body << x << Endl; - - auto response = Request->CreateResponseOK(body, "application/text; charset=utf-8"); - Send(HttpProxy, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response)); - - PassAway(); - } -public: - static constexpr IActor::EActivityType ActorActivityType() { - // define app-specific activity tag to track elapsed cpu | handled events | actor count in Solomon - return EActorActivity::ACTORLIB_COMMON; - } - - TExampleHttpRequest(TExampleStorageConfig *config, const TString &publishKey) - : TActor(&TThis::StateWork) - , Config(config) - , PublishKey(publishKey) - {} - - STFUNC(StateWork) { - switch (ev->GetTypeRewrite()) { - hFunc(NHttp::TEvHttpProxy::TEvHttpIncomingRequest, Handle); - hFunc(TEvExample::TEvInfo, Handle); - } - } -}; - -class TExampleHttpEndpoint : public TActorBootstrapped<TExampleHttpEndpoint> { - TIntrusivePtr<TExampleStorageConfig> Config; - const TString PublishKey; - const ui16 HttpPort; - - TActorId PublishActor; - TActorId HttpProxy; - - std::shared_ptr<NMonitoring::TMetricRegistry> SensorsRegistry = std::make_shared<NMonitoring::TMetricRegistry>(); - - void PassAway() override { - Send(PublishActor, new TEvents::TEvPoison()); - Send(HttpProxy, new TEvents::TEvPoison()); - - return TActor::PassAway(); - } - - void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr &ev) { - const TActorId reqActor = Register(new TExampleHttpRequest(Config.Get(), PublishKey)); - TlsActivationContext->Send(ev->Forward(reqActor)); - } - -public: - static constexpr IActor::EActivityType ActorActivityType() { - // define app-specific activity tag to track elapsed cpu | handled events | actor count in Solomon - return EActorActivity::ACTORLIB_COMMON; - } - - TExampleHttpEndpoint(TExampleStorageConfig *config, const TString &publishKey, ui16 port) - : Config(config) - , PublishKey(publishKey) - , HttpPort(port) - { - } - - void Bootstrap() { - const TString publishPayload = ToString(HttpPort); - PublishActor = Register(CreatePublishActor(Config.Get(), PublishKey, publishPayload)); - HttpProxy = Register(NHttp::CreateHttpProxy(SensorsRegistry)); - - Send(HttpProxy, new NHttp::TEvHttpProxy::TEvAddListeningPort(HttpPort, FQDNHostName())); - Send(HttpProxy, new NHttp::TEvHttpProxy::TEvRegisterHandler("/list", SelfId())); - - Become(&TThis::StateWork); - } - - STFUNC(StateWork) { - switch (ev->GetTypeRewrite()) { - hFunc(NHttp::TEvHttpProxy::TEvHttpIncomingRequest, Handle); - default: - break; - } - } -}; - -IActor* CreateEndpointActor(TExampleStorageConfig *config, const TString &publishKey, ui16 port) { - return new TExampleHttpEndpoint(config, publishKey, port); -} diff --git a/library/cpp/actors/examples/02_discovery/lookup.cpp b/library/cpp/actors/examples/02_discovery/lookup.cpp deleted file mode 100644 index fb136a431c..0000000000 --- a/library/cpp/actors/examples/02_discovery/lookup.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include "services.h" - -#include <library/cpp/actors/core/actorsystem.h> -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/core/interconnect.h> -#include <library/cpp/actors/core/actor_bootstrapped.h> -#include <util/generic/set.h> -#include <util/generic/vector.h> - -class TExampleLookupRequestActor : public TActor<TExampleLookupRequestActor> { - const TActorId Owner; - const TActorId Replica; - const TString Key; - - void Registered(TActorSystem* sys, const TActorId&) override { - const auto flags = IEventHandle::FlagTrackDelivery | IEventHandle::FlagSubscribeOnSession; - sys->Send(new IEventHandle(Replica, SelfId(), new TEvExample::TEvReplicaLookup(Key), flags)); - } - - void PassAway() override { - const ui32 replicaNode = Replica.NodeId(); - if (replicaNode != SelfId().NodeId()) { - const TActorId &interconnectProxy = TlsActivationContext->ExecutorThread.ActorSystem->InterconnectProxy(Replica.NodeId()); - Send(interconnectProxy, new TEvents::TEvUnsubscribe()); - } - return IActor::PassAway(); - } - - void Handle(TEvExample::TEvReplicaInfo::TPtr &ev) { - Send(Owner, ev->Release().Release()); - return PassAway(); - } - - void HandleUndelivered() { - Send(Owner, new TEvExample::TEvReplicaInfo(Key)); - return PassAway(); - } -public: - static constexpr IActor::EActivityType ActorActivityType() { - // define app-specific activity tag to track elapsed cpu | handled events | actor count in Solomon - return EActorActivity::ACTORLIB_COMMON; - } - - TExampleLookupRequestActor(TActorId owner, TActorId replica, const TString &key) - : TActor(&TThis::StateWork) - , Owner(owner) - , Replica(replica) - , Key(key) - {} - - STFUNC(StateWork) { - switch (ev->GetTypeRewrite()) { - hFunc(TEvExample::TEvReplicaInfo, Handle); - sFunc(TEvents::TEvUndelivered, HandleUndelivered); - sFunc(TEvInterconnect::TEvNodeDisconnected, HandleUndelivered); - default: - break; - } - } -}; - -class TExampleLookupActor : public TActorBootstrapped<TExampleLookupActor> { - TIntrusiveConstPtr<TExampleStorageConfig> Config; - const TString Key; - const TActorId ReplyTo; - TVector<TActorId> RequestActors; - - ui32 TotalReplicas = 0; - ui32 RepliedSuccess = 0; - ui32 RepliedError = 0; - - TSet<TString> Payloads; - - void Handle(TEvExample::TEvReplicaInfo::TPtr &ev) { - NActorsExample::TEvReplicaInfo &record = ev->Get()->Record; - if (record.PayloadSize()) { - ++RepliedSuccess; - for (const TString &payload : record.GetPayload()) { - Payloads.insert(payload); - } - } - else { - ++RepliedError; - } - - const ui32 majority = (TotalReplicas / 2 + 1); - if (RepliedSuccess == majority || (RepliedSuccess + RepliedError == TotalReplicas)) - return ReplyAndDie(); - } - - void ReplyAndDie() { - TVector<TString> replyPayloads(Payloads.begin(), Payloads.end()); - Send(ReplyTo, new TEvExample::TEvInfo(Key, std::move(replyPayloads))); - return PassAway(); - } -public: - static constexpr IActor::EActivityType ActorActivityType() { - // define app-specific activity tag to track elapsed cpu | handled events | actor count in Solomon - return EActorActivity::ACTORLIB_COMMON; - } - - TExampleLookupActor(TExampleStorageConfig *config, const TString &key, TActorId replyTo) - : Config(config) - , Key(key) - , ReplyTo(replyTo) - {} - - void Bootstrap() { - Y_ABORT_UNLESS(Config->Replicas.size() > 0); - - TotalReplicas = Config->Replicas.size(); - RequestActors.reserve(TotalReplicas); - for (const auto &replica : Config->Replicas) { - const TActorId requestActor = Register(new TExampleLookupRequestActor(SelfId(), replica, Key)); - RequestActors.emplace_back(requestActor); - } - - Become(&TThis::StateWork); - } - - STFUNC(StateWork) { - switch (ev->GetTypeRewrite()) { - hFunc(TEvExample::TEvReplicaInfo, Handle); - default: - break; - } - } -}; - -IActor* CreateLookupActor(TExampleStorageConfig *config, const TString &key, TActorId replyTo) { - return new TExampleLookupActor(config, key, replyTo); -} diff --git a/library/cpp/actors/examples/02_discovery/main.cpp b/library/cpp/actors/examples/02_discovery/main.cpp deleted file mode 100644 index 9dec850c77..0000000000 --- a/library/cpp/actors/examples/02_discovery/main.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "services.h" - -#include <library/cpp/actors/core/actorsystem.h> -#include <library/cpp/actors/core/executor_pool_basic.h> -#include <library/cpp/actors/core/scheduler_basic.h> -#include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/dnsresolver/dnsresolver.h> -#include <library/cpp/actors/interconnect/interconnect.h> -#include <library/cpp/actors/interconnect/interconnect_common.h> -#include <library/cpp/actors/interconnect/interconnect_tcp_proxy.h> -#include <library/cpp/actors/interconnect/interconnect_tcp_server.h> -#include <library/cpp/actors/interconnect/poller_actor.h> -#include <library/cpp/actors/interconnect/poller_tcp.h> -#include <library/cpp/actors/util/should_continue.h> - -#include <util/system/sigset.h> -#include <util/generic/xrange.h> - -using namespace NActors; -using namespace NActors::NDnsResolver; - -static const ui32 CfgTotalReplicaNodes = 5; -static const ui16 CfgBasePort = 13300; -static const ui16 CfgHttpPort = 8881; -static const TString PublishKey = "endpoint"; - -static TProgramShouldContinue ShouldContinue; - -void OnTerminate(int) { - ShouldContinue.ShouldStop(); -} - -THolder<TActorSystemSetup> BuildActorSystemSetup(ui32 nodeId, ui32 threads, NMonitoring::TDynamicCounters &counters) { - Y_ABORT_UNLESS(threads > 0 && threads < 100); - - auto setup = MakeHolder<TActorSystemSetup>(); - - setup->NodeId = nodeId; - - setup->ExecutorsCount = 1; - setup->Executors.Reset(new TAutoPtr<IExecutorPool>[1]); - setup->Executors[0] = new TBasicExecutorPool(0, threads, 50); - setup->Scheduler = new TBasicSchedulerThread(TSchedulerConfig(512, 0)); - - setup->LocalServices.emplace_back(MakePollerActorId(), TActorSetupCmd(CreatePollerActor(), TMailboxType::ReadAsFilled, 0)); - - TIntrusivePtr<TTableNameserverSetup> nameserverTable = new TTableNameserverSetup(); - for (ui32 xnode : xrange<ui32>(1, CfgTotalReplicaNodes + 1)) { - nameserverTable->StaticNodeTable[xnode] = std::make_pair("127.0.0.1", CfgBasePort + xnode); - } - - setup->LocalServices.emplace_back( - MakeDnsResolverActorId(), - TActorSetupCmd(CreateOnDemandDnsResolver(), TMailboxType::ReadAsFilled, 0) - ); - - setup->LocalServices.emplace_back( - GetNameserviceActorId(), - TActorSetupCmd(CreateNameserverTable(nameserverTable), TMailboxType::ReadAsFilled, 0) - ); - - TIntrusivePtr<TInterconnectProxyCommon> icCommon = new TInterconnectProxyCommon(); - icCommon->NameserviceId = GetNameserviceActorId(); - icCommon->MonCounters = counters.GetSubgroup("counters", "interconnect"); - icCommon->TechnicalSelfHostName = "127.0.0.1"; - - setup->Interconnect.ProxyActors.resize(CfgTotalReplicaNodes + 1); - for (ui32 xnode : xrange<ui32>(1, CfgTotalReplicaNodes + 1)) { - if (xnode != nodeId) { - IActor *actor = new TInterconnectProxyTCP(xnode, icCommon); - setup->Interconnect.ProxyActors[xnode] = TActorSetupCmd(actor, TMailboxType::ReadAsFilled, 0); - } - else { - IActor *listener = new TInterconnectListenerTCP("127.0.0.1", CfgBasePort + xnode, icCommon); - setup->LocalServices.emplace_back( - MakeInterconnectListenerActorId(false), - TActorSetupCmd(listener, TMailboxType::ReadAsFilled, 0) - ); - } - } - - return setup; -} - -int main(int argc, char **argv) { - Y_UNUSED(argc); - Y_UNUSED(argv); - -#ifdef _unix_ - signal(SIGPIPE, SIG_IGN); -#endif - signal(SIGINT, &OnTerminate); - signal(SIGTERM, &OnTerminate); - - TIntrusivePtr<TExampleStorageConfig> config = new TExampleStorageConfig(); - for (ui32 nodeid : xrange<ui32>(1, CfgTotalReplicaNodes + 1)) { - config->Replicas.push_back(MakeReplicaId(nodeid)); - } - - TVector<THolder<TActorSystem>> actorSystemHolder; - TVector<TIntrusivePtr<NMonitoring::TDynamicCounters>> countersHolder; - for (ui32 nodeid : xrange<ui32>(1, CfgTotalReplicaNodes + 1)) { - countersHolder.emplace_back(new NMonitoring::TDynamicCounters()); - THolder<TActorSystemSetup> actorSystemSetup = BuildActorSystemSetup(nodeid, 2, *countersHolder.back()); - actorSystemSetup->LocalServices.emplace_back( - TActorId(), - TActorSetupCmd(CreateEndpointActor(config.Get(), PublishKey, CfgHttpPort + nodeid), TMailboxType::HTSwap, 0) - ); - - actorSystemSetup->LocalServices.emplace_back( - MakeReplicaId(nodeid), - TActorSetupCmd(CreateReplica(), TMailboxType::ReadAsFilled, 0) - ); - - actorSystemHolder.emplace_back(new TActorSystem(actorSystemSetup)); - } - - for (auto &xh : actorSystemHolder) - xh->Start(); - - while (ShouldContinue.PollState() == TProgramShouldContinue::Continue) { - Sleep(TDuration::MilliSeconds(200)); - } - - // stop actorsystem to not generate new reqeusts for external services - // no events would be processed anymore - for (auto &xh : actorSystemHolder) - xh->Stop(); - - // and then cleanup actorsystem - // from this moment working with actorsystem prohibited - for (auto &xh : actorSystemHolder) - xh->Cleanup(); - - return ShouldContinue.GetReturnCode(); -} diff --git a/library/cpp/actors/examples/02_discovery/protocol.proto b/library/cpp/actors/examples/02_discovery/protocol.proto deleted file mode 100644 index 41cc2cc9c8..0000000000 --- a/library/cpp/actors/examples/02_discovery/protocol.proto +++ /dev/null @@ -1,19 +0,0 @@ -package NActorsExample; - -message TEvReplicaInfo { - optional string Key = 1; - repeated string Payload = 2; -}; - -message TEvReplicaPublishAck { - optional string Key = 1; -}; - -message TEvReplicaPublish { - optional string Key = 1; - optional string Payload = 2; -}; - -message TEvReplicaLookup { - optional string Key = 1; -}; diff --git a/library/cpp/actors/examples/02_discovery/publish.cpp b/library/cpp/actors/examples/02_discovery/publish.cpp deleted file mode 100644 index d923283e6b..0000000000 --- a/library/cpp/actors/examples/02_discovery/publish.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "services.h" - -#include <library/cpp/actors/core/actorsystem.h> -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/core/interconnect.h> -#include <library/cpp/actors/core/actor_bootstrapped.h> -#include <util/generic/set.h> -#include <util/generic/vector.h> - -class TExamplePublishReplicaActor : public TActorBootstrapped<TExamplePublishReplicaActor> { - const TActorId Owner; - const TActorId Replica; - const TString Key; - const TString Payload; - - void PassAway() override { - const ui32 replicaNode = Replica.NodeId(); - if (replicaNode != SelfId().NodeId()) { - const TActorId &interconnectProxy = TlsActivationContext->ExecutorThread.ActorSystem->InterconnectProxy(Replica.NodeId()); - Send(interconnectProxy, new TEvents::TEvUnsubscribe()); - } - return IActor::PassAway(); - } - - void SomeSleep() { - Become(&TThis::StateSleep, TDuration::MilliSeconds(250), new TEvents::TEvWakeup()); - } -public: - static constexpr IActor::EActivityType ActorActivityType() { - // define app-specific activity tag to track elapsed cpu | handled events | actor count in Solomon - return EActorActivity::ACTORLIB_COMMON; - } - - TExamplePublishReplicaActor(TActorId owner, TActorId replica, const TString &key, const TString &payload) - : Owner(owner) - , Replica(replica) - , Key(key) - , Payload(payload) - {} - - void Bootstrap() { - const ui32 flags = IEventHandle::FlagTrackDelivery | IEventHandle::FlagSubscribeOnSession; - Send(Replica, new TEvExample::TEvReplicaPublish(Key, Payload), flags); - Become(&TThis::StatePublish); - } - - STFUNC(StatePublish) { - switch (ev->GetTypeRewrite()) { - sFunc(TEvents::TEvPoison, PassAway); - sFunc(TEvents::TEvUndelivered, SomeSleep); - sFunc(TEvInterconnect::TEvNodeDisconnected, SomeSleep); - default: - break; - } - } - - STFUNC(StateSleep) { - switch (ev->GetTypeRewrite()) { - sFunc(TEvents::TEvPoison, PassAway); - sFunc(TEvents::TEvWakeup, Bootstrap); - default: - break; - } - } -}; - -class TExamplePublishActor : public TActorBootstrapped<TExamplePublishActor> { - TIntrusiveConstPtr<TExampleStorageConfig> Config; - const TString Key; - const TString Payload; - TVector<TActorId> PublishActors; - - void PassAway() override { - for (const auto &x : PublishActors) - Send(x, new TEvents::TEvPoison()); - return IActor::PassAway(); - } -public: - static constexpr IActor::EActivityType ActorActivityType() { - // define app-specific activity tag to track elapsed cpu | handled events | actor count in Solomon - return EActorActivity::ACTORLIB_COMMON; - } - - TExamplePublishActor(TExampleStorageConfig *config, const TString &key, const TString &what) - : Config(config) - , Key(key) - , Payload(what) - {} - - void Bootstrap() { - for (auto &replica : Config->Replicas) { - const TActorId x = Register(new TExamplePublishReplicaActor(SelfId(), replica, Key, Payload)); - PublishActors.emplace_back(x); - } - - Become(&TThis::StateWork); - } - - STFUNC(StateWork) { - switch (ev->GetTypeRewrite()) { - sFunc(TEvents::TEvPoison, PassAway); - default: - break; - } - } -}; - -IActor* CreatePublishActor(TExampleStorageConfig *config, const TString &key, const TString &what) { - return new TExamplePublishActor(config, key, what); -} diff --git a/library/cpp/actors/examples/02_discovery/replica.cpp b/library/cpp/actors/examples/02_discovery/replica.cpp deleted file mode 100644 index 96a6f5f475..0000000000 --- a/library/cpp/actors/examples/02_discovery/replica.cpp +++ /dev/null @@ -1,181 +0,0 @@ -#include "services.h" -#include <library/cpp/actors/core/actorsystem.h> -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/core/interconnect.h> -#include <util/generic/set.h> -#include <util/generic/hash_set.h> -#include <util/generic/vector.h> - -class TExampleReplicaActor : public TActor<TExampleReplicaActor> { - using TOwnerIndex = TMap<TActorId, ui32, TActorId::TOrderedCmp>; - using TKeyIndex = THashMap<TString, TSet<ui32>>; - - struct TEntry { - TString Payload; - TActorId Owner; - TOwnerIndex::iterator OwnerIt; - TKeyIndex::iterator KeyIt; - }; - - TVector<TEntry> Entries; - TVector<ui32> AvailableEntries; - - TOwnerIndex IndexOwner; - TKeyIndex IndexKey; - - ui32 AllocateEntry() { - ui32 ret; - if (AvailableEntries) { - ret = AvailableEntries.back(); - AvailableEntries.pop_back(); - } - else { - ret = Entries.size(); - Entries.emplace_back(); - } - - return ret; - } - - bool IsLastEntryOnNode(TOwnerIndex::iterator ownerIt) { - const ui32 ownerNodeId = ownerIt->first.NodeId(); - if (ownerIt != IndexOwner.begin()) { - auto x = ownerIt; - --x; - if (x->first.NodeId() == ownerNodeId) - return false; - } - - ++ownerIt; - if (ownerIt != IndexOwner.end()) { - if (ownerIt->first.NodeId() == ownerNodeId) - return false; - } - - return true; - } - - void CleanupEntry(ui32 entryIndex) { - TEntry &entry = Entries[entryIndex]; - entry.KeyIt->second.erase(entryIndex); - if (entry.KeyIt->second.empty()) - IndexKey.erase(entry.KeyIt); - - if (IsLastEntryOnNode(entry.OwnerIt)) - Send(TlsActivationContext->ExecutorThread.ActorSystem->InterconnectProxy(entry.OwnerIt->first.NodeId()), new TEvents::TEvUnsubscribe()); - - IndexOwner.erase(entry.OwnerIt); - - TString().swap(entry.Payload); - entry.Owner = TActorId(); - entry.KeyIt = IndexKey.end(); - entry.OwnerIt = IndexOwner.end(); - - AvailableEntries.emplace_back(entryIndex); - } - - void Handle(TEvExample::TEvReplicaLookup::TPtr &ev) { - auto &record = ev->Get()->Record; - const auto &key = record.GetKey(); - - auto keyIt = IndexKey.find(key); - if (keyIt == IndexKey.end()) { - Send(ev->Sender, new TEvExample::TEvReplicaInfo(key), 0, ev->Cookie); - return; - } - - auto reply = MakeHolder<TEvExample::TEvReplicaInfo>(key); - reply->Record.MutablePayload()->Reserve(keyIt->second.size()); - for (ui32 entryIndex : keyIt->second) { - const TEntry &entry = Entries[entryIndex]; - reply->Record.AddPayload(entry.Payload); - } - - Send(ev->Sender, std::move(reply), 0, ev->Cookie); - } - - void Handle(TEvExample::TEvReplicaPublish::TPtr &ev) { - auto &record = ev->Get()->Record; - const TString &key = record.GetKey(); - const TString &payload = record.GetPayload(); - const TActorId &owner = ev->Sender; - - auto ownerIt = IndexOwner.find(owner); - if (ownerIt != IndexOwner.end()) { - const ui32 entryIndex = ownerIt->second; - TEntry &entry = Entries[entryIndex]; - if (entry.KeyIt->first != key) { - // reply nothing, request suspicious - return; - } - - entry.Payload = payload; - } - else { - const ui32 entryIndex = AllocateEntry(); - TEntry &entry = Entries[entryIndex]; - - entry.Payload = payload; - entry.Owner = owner; - - entry.OwnerIt = IndexOwner.emplace(owner, entryIndex).first; - entry.KeyIt = IndexKey.emplace(std::make_pair(key, TSet<ui32>())).first; - entry.KeyIt->second.emplace(entryIndex); - - Send(owner, new TEvExample::TEvReplicaPublishAck(), IEventHandle::FlagTrackDelivery | IEventHandle::FlagSubscribeOnSession, ev->Cookie); - } - } - - void Handle(TEvents::TEvUndelivered::TPtr &ev) { - auto ownerIt = IndexOwner.find(ev->Sender); - if (ownerIt == IndexOwner.end()) - return; - - CleanupEntry(ownerIt->second); - } - - void Handle(TEvInterconnect::TEvNodeDisconnected::TPtr &ev) { - auto *msg = ev->Get(); - const ui32 nodeId = msg->NodeId; - auto ownerIt = IndexOwner.lower_bound(TActorId(nodeId, 0, 0, 0)); - while (ownerIt != IndexOwner.end() && ownerIt->first.NodeId() == nodeId) { - const ui32 idx = ownerIt->second; - ++ownerIt; - CleanupEntry(idx); - } - } - -public: - static constexpr IActor::EActivityType ActorActivityType() { - // define app-specific activity tag to track elapsed cpu | handled events | actor count in Solomon - return EActorActivity::ACTORLIB_COMMON; - } - - TExampleReplicaActor() - : TActor(&TThis::StateWork) - {} - - STFUNC(StateWork) { - switch (ev->GetTypeRewrite()) { - hFunc(TEvExample::TEvReplicaLookup, Handle); - hFunc(TEvExample::TEvReplicaPublish, Handle); - hFunc(TEvents::TEvUndelivered, Handle); - hFunc(TEvInterconnect::TEvNodeDisconnected, Handle); - - IgnoreFunc(TEvInterconnect::TEvNodeConnected); - default: - // here is place to spam some log message on unknown events - break; - } - } -}; - -IActor* CreateReplica() { - return new TExampleReplicaActor(); -} - -TActorId MakeReplicaId(ui32 nodeid) { - char x[12] = { 'r', 'p', 'l' }; - memcpy(x + 5, &nodeid, sizeof(ui32)); - return TActorId(nodeid, TStringBuf(x, 12)); -} diff --git a/library/cpp/actors/examples/02_discovery/services.h b/library/cpp/actors/examples/02_discovery/services.h deleted file mode 100644 index 266517c577..0000000000 --- a/library/cpp/actors/examples/02_discovery/services.h +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once -#include <library/cpp/actors/examples/02_discovery/protocol.pb.h> - -#include <library/cpp/actors/core/actor.h> -#include <library/cpp/actors/core/events.h> -#include <library/cpp/actors/core/event_pb.h> -#include <library/cpp/actors/core/event_local.h> - -#include <util/generic/vector.h> - -using namespace NActors; - -struct TExampleStorageConfig : public TThrRefBase { - TVector<TActorId> Replicas; -}; - -struct TEvExample { - enum EEv { - EvReplicaLookup = EventSpaceBegin(TEvents::ES_USERSPACE + 1), - EvReplicaPublish, - - EvReplicaInfo = EventSpaceBegin(TEvents::ES_USERSPACE + 2), - EvReplicaPublishAck, - - EvInfo = EventSpaceBegin(TEvents::ES_USERSPACE + 3), - }; - - struct TEvReplicaLookup : public TEventPB<TEvReplicaLookup, NActorsExample::TEvReplicaLookup, EvReplicaLookup> { - TEvReplicaLookup() - {} - - TEvReplicaLookup(const TString &key) - { - Record.SetKey(key); - } - }; - - struct TEvReplicaPublish : public TEventPB<TEvReplicaPublish, NActorsExample::TEvReplicaPublish, EvReplicaPublish> { - TEvReplicaPublish() - {} - - TEvReplicaPublish(const TString &key, const TString &payload) - { - Record.SetKey(key); - Record.SetPayload(payload); - } - }; - - struct TEvReplicaInfo : public TEventPB<TEvReplicaInfo, NActorsExample::TEvReplicaInfo, EvReplicaInfo> { - TEvReplicaInfo() - {} - - TEvReplicaInfo(const TString &key) - { - Record.SetKey(key); - } - }; - - struct TEvReplicaPublishAck : public TEventPB<TEvReplicaPublishAck, NActorsExample::TEvReplicaPublishAck, EvReplicaPublishAck> { - TEvReplicaPublishAck() - {} - - TEvReplicaPublishAck(const TString &key) - { - Record.SetKey(key); - } - }; - - struct TEvInfo : public TEventLocal<TEvInfo, EvInfo> { - const TString Key; - const TVector<TString> Payloads; - - TEvInfo(const TString &key, TVector<TString> &&payloads) - : Key(key) - , Payloads(payloads) - {} - }; -}; - -IActor* CreateReplica(); -IActor* CreatePublishActor(TExampleStorageConfig *config, const TString &key, const TString &what); -IActor* CreateLookupActor(TExampleStorageConfig *config, const TString &key, TActorId replyTo); -IActor* CreateEndpointActor(TExampleStorageConfig *config, const TString &publishKey, ui16 httpPort); - -TActorId MakeReplicaId(ui32 nodeid); diff --git a/library/cpp/actors/examples/02_discovery/ya.make b/library/cpp/actors/examples/02_discovery/ya.make deleted file mode 100644 index 953c13259c..0000000000 --- a/library/cpp/actors/examples/02_discovery/ya.make +++ /dev/null @@ -1,25 +0,0 @@ -PROGRAM(example_02_discovery) - -ALLOCATOR(LF) - -SRCS( - endpoint.cpp - lookup.cpp - main.cpp - publish.cpp - replica.cpp - services.h -) - -SRCS( - protocol.proto -) - -PEERDIR( - library/cpp/actors/core - library/cpp/actors/dnsresolver - library/cpp/actors/interconnect - library/cpp/actors/http -) - -END() diff --git a/library/cpp/actors/examples/CMakeLists.txt b/library/cpp/actors/examples/CMakeLists.txt deleted file mode 100644 index bcda1cfeef..0000000000 --- a/library/cpp/actors/examples/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(01_ping_pong) -add_subdirectory(02_discovery) diff --git a/library/cpp/actors/examples/ya.make b/library/cpp/actors/examples/ya.make deleted file mode 100644 index 0a98074b47..0000000000 --- a/library/cpp/actors/examples/ya.make +++ /dev/null @@ -1,4 +0,0 @@ -RECURSE( - 01_ping_pong - 02_discovery -) diff --git a/library/cpp/actors/helpers/CMakeLists.darwin-arm64.txt b/library/cpp/actors/helpers/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 7367c0b925..0000000000 --- a/library/cpp/actors/helpers/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,22 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-helpers) -target_link_libraries(cpp-actors-helpers PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core - cpp-monlib-dynamic_counters -) -target_sources(cpp-actors-helpers PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/activeactors.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/flow_controlled_queue.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/selfping_actor.cpp -) diff --git a/library/cpp/actors/helpers/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/helpers/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 7367c0b925..0000000000 --- a/library/cpp/actors/helpers/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,22 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-helpers) -target_link_libraries(cpp-actors-helpers PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core - cpp-monlib-dynamic_counters -) -target_sources(cpp-actors-helpers PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/activeactors.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/flow_controlled_queue.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/selfping_actor.cpp -) diff --git a/library/cpp/actors/helpers/CMakeLists.linux-aarch64.txt b/library/cpp/actors/helpers/CMakeLists.linux-aarch64.txt deleted file mode 100644 index da8ce6e8e6..0000000000 --- a/library/cpp/actors/helpers/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,23 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-helpers) -target_link_libraries(cpp-actors-helpers PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-actors-core - cpp-monlib-dynamic_counters -) -target_sources(cpp-actors-helpers PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/activeactors.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/flow_controlled_queue.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/selfping_actor.cpp -) diff --git a/library/cpp/actors/helpers/CMakeLists.linux-x86_64.txt b/library/cpp/actors/helpers/CMakeLists.linux-x86_64.txt deleted file mode 100644 index da8ce6e8e6..0000000000 --- a/library/cpp/actors/helpers/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,23 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-helpers) -target_link_libraries(cpp-actors-helpers PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-actors-core - cpp-monlib-dynamic_counters -) -target_sources(cpp-actors-helpers PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/activeactors.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/flow_controlled_queue.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/selfping_actor.cpp -) diff --git a/library/cpp/actors/helpers/CMakeLists.txt b/library/cpp/actors/helpers/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/helpers/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/helpers/CMakeLists.windows-x86_64.txt b/library/cpp/actors/helpers/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 7367c0b925..0000000000 --- a/library/cpp/actors/helpers/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,22 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-helpers) -target_link_libraries(cpp-actors-helpers PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core - cpp-monlib-dynamic_counters -) -target_sources(cpp-actors-helpers PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/activeactors.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/flow_controlled_queue.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/selfping_actor.cpp -) diff --git a/library/cpp/actors/helpers/activeactors.cpp b/library/cpp/actors/helpers/activeactors.cpp deleted file mode 100644 index 145e97dc57..0000000000 --- a/library/cpp/actors/helpers/activeactors.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "activeactors.h" - diff --git a/library/cpp/actors/helpers/activeactors.h b/library/cpp/actors/helpers/activeactors.h deleted file mode 100644 index ec482e93c8..0000000000 --- a/library/cpp/actors/helpers/activeactors.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/actor.h> -#include <library/cpp/actors/core/events.h> -#include <util/generic/hash_set.h> - -namespace NActors { - - //////////////////////////////////////////////////////////////////////////// - // TActiveActors - // This class helps manage created actors and kill them all on PoisonPill. - //////////////////////////////////////////////////////////////////////////// - class TActiveActors : public THashSet<TActorId> { - public: - void Insert(const TActorId &aid) { - bool inserted = insert(aid).second; - Y_ABORT_UNLESS(inserted); - } - - void Insert(const TActiveActors &moreActors) { - for (const auto &aid : moreActors) { - Insert(aid); - } - } - - void Erase(const TActorId &aid) { - auto num = erase(aid); - Y_ABORT_UNLESS(num == 1); - } - - size_t KillAndClear(const TActorContext &ctx) { - size_t s = size(); // number of actors managed - for (const auto &x: *this) { - ctx.Send(x, new TEvents::TEvPoisonPill()); - } - clear(); - return s; // how many actors we killed - } - }; - -} // NKikimr - diff --git a/library/cpp/actors/helpers/flow_controlled_queue.cpp b/library/cpp/actors/helpers/flow_controlled_queue.cpp deleted file mode 100644 index 49ed7c79f0..0000000000 --- a/library/cpp/actors/helpers/flow_controlled_queue.cpp +++ /dev/null @@ -1,215 +0,0 @@ -#include "flow_controlled_queue.h" - -#include <library/cpp/actors/core/interconnect.h> -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/util/datetime.h> - -#include <util/generic/deque.h> -#include <util/datetime/cputimer.h> -#include <util/generic/algorithm.h> - -namespace NActors { - -class TFlowControlledRequestQueue; - -class TFlowControlledRequestActor : public IActorCallback { - TFlowControlledRequestQueue * const QueueActor; - - void HandleReply(TAutoPtr<IEventHandle> &ev); - void HandleUndelivered(TEvents::TEvUndelivered::TPtr &ev); -public: - const TActorId Source; - const ui64 Cookie; - const ui32 Flags; - const ui64 StartCounter; - - TFlowControlledRequestActor(ui32 activity, TFlowControlledRequestQueue *queue, TActorId source, ui64 cookie, ui32 flags) - : IActorCallback(static_cast<TReceiveFunc>(&TFlowControlledRequestActor::StateWait), activity) - , QueueActor(queue) - , Source(source) - , Cookie(cookie) - , Flags(flags) - , StartCounter(GetCycleCountFast()) - {} - - STATEFN(StateWait) { - switch (ev->GetTypeRewrite()) { - hFunc(TEvents::TEvUndelivered, HandleUndelivered); - default: - HandleReply(ev); - } - } - - TDuration AccumulatedLatency() const { - const ui64 cc = GetCycleCountFast() - StartCounter; - return CyclesToDuration(cc); - } - - using IActor::PassAway; -}; - -class TFlowControlledRequestQueue : public IActorCallback { - const TActorId Target; - const TFlowControlledQueueConfig Config; - - TDeque<THolder<IEventHandle>> UnhandledRequests; - TDeque<TFlowControlledRequestActor *> RegisteredRequests; - - bool Subscribed = false; - - TDuration MinimalSeenLatency; - - bool CanRegister() { - const ui64 inFly = RegisteredRequests.size(); - if (inFly <= Config.MinAllowedInFly) // <= for handling minAllowed == 0 - return true; - - if (inFly >= Config.MaxAllowedInFly) - return false; - - if (Config.TargetDynamicRate) { - if (const ui64 dynMax = MinimalSeenLatency.MicroSeconds() * Config.TargetDynamicRate / 1000000) { - if (inFly >= dynMax) - return false; - } - } - - const TDuration currentLatency = RegisteredRequests.front()->AccumulatedLatency(); - if (currentLatency <= Config.MinTrackedLatency) - return true; - - if (currentLatency <= MinimalSeenLatency * Config.LatencyFactor) - return true; - - return false; - } - - void HandleForwardedEvent(TAutoPtr<IEventHandle> &ev) { - if (CanRegister()) { - RegisterReqActor(ev); - } else { - UnhandledRequests.emplace_back(ev.Release()); - } - } - - void RegisterReqActor(THolder<IEventHandle> ev) { - TFlowControlledRequestActor *reqActor = new TFlowControlledRequestActor(ActivityType, this, ev->Sender, ev->Cookie, ev->Flags); - const TActorId reqActorId = RegisterWithSameMailbox(reqActor); - RegisteredRequests.emplace_back(reqActor); - - if (!Subscribed && (Target.NodeId() != SelfId().NodeId())) { - Send(TActivationContext::InterconnectProxy(Target.NodeId()), new TEvents::TEvSubscribe(), IEventHandle::FlagTrackDelivery); - Subscribed = true; - } - - TActivationContext::Send(new IEventHandle(Target, reqActorId, ev.Get()->ReleaseBase().Release(), IEventHandle::FlagTrackDelivery, ev->Cookie)); - } - - void PumpQueue() { - while (RegisteredRequests && RegisteredRequests.front() == nullptr) - RegisteredRequests.pop_front(); - - while (UnhandledRequests && CanRegister()) { - RegisterReqActor(std::move(UnhandledRequests.front())); - UnhandledRequests.pop_front(); - } - } - - void HandleDisconnected() { - Subscribed = false; - - const ui32 nodeid = Target.NodeId(); - for (TFlowControlledRequestActor *reqActor : RegisteredRequests) { - if (reqActor) { - if (reqActor->Flags & IEventHandle::FlagSubscribeOnSession) { - TActivationContext::Send( - new IEventHandle(reqActor->Source, TActorId(), new TEvInterconnect::TEvNodeDisconnected(nodeid), 0, reqActor->Cookie) - ); - } - reqActor->PassAway(); - } - } - - RegisteredRequests.clear(); - - for (auto &ev : UnhandledRequests) { - const auto reason = TEvents::TEvUndelivered::Disconnected; - if (ev->Flags & IEventHandle::FlagTrackDelivery) { - TActivationContext::Send( - new IEventHandle(ev->Sender, ev->Recipient, new TEvents::TEvUndelivered(ev->GetTypeRewrite(), reason), 0, ev->Cookie) - ); - } - } - - UnhandledRequests.clear(); - } - - void HandlePoison() { - HandleDisconnected(); - - if (SelfId().NodeId() != Target.NodeId()) - Send(TActivationContext::InterconnectProxy(Target.NodeId()), new TEvents::TEvUnsubscribe()); - - PassAway(); - } -public: - template <class TEnum> - TFlowControlledRequestQueue(TActorId target, const TEnum activity, const TFlowControlledQueueConfig &config) - : IActorCallback(static_cast<TReceiveFunc>(&TFlowControlledRequestQueue::StateWork), activity) - , Target(target) - , Config(config) - , MinimalSeenLatency(TDuration::Seconds(1)) - {} - - STATEFN(StateWork) { - switch (ev->GetTypeRewrite()) { - cFunc(TEvInterconnect::TEvNodeDisconnected::EventType, HandleDisconnected); - IgnoreFunc(TEvInterconnect::TEvNodeConnected); - cFunc(TEvents::TEvUndelivered::EventType, HandleDisconnected); - cFunc(TEvents::TEvPoison::EventType, HandlePoison); - default: - HandleForwardedEvent(ev); - } - } - - void HandleRequestReply(TAutoPtr<IEventHandle> &ev, TFlowControlledRequestActor *reqActor) { - auto it = Find(RegisteredRequests, reqActor); - if (it == RegisteredRequests.end()) - return; - TActivationContext::Send(ev->Forward(reqActor->Source).Release()); - const TDuration reqLatency = reqActor->AccumulatedLatency(); - if (reqLatency < MinimalSeenLatency) - MinimalSeenLatency = reqLatency; - - *it = nullptr; - PumpQueue(); - } - - void HandleRequestUndelivered(TEvents::TEvUndelivered::TPtr &ev, TFlowControlledRequestActor *reqActor) { - auto it = Find(RegisteredRequests, reqActor); - if (it == RegisteredRequests.end()) - return; - - TActivationContext::Send(ev->Forward(reqActor->Source).Release()); - - *it = nullptr; - PumpQueue(); - } -}; - -void TFlowControlledRequestActor::HandleReply(TAutoPtr<IEventHandle> &ev) { - QueueActor->HandleRequestReply(ev, this); - PassAway(); -} - -void TFlowControlledRequestActor::HandleUndelivered(TEvents::TEvUndelivered::TPtr &ev) { - QueueActor->HandleRequestUndelivered(ev, this); - PassAway(); -} - -template <class TEnum> -IActor* CreateFlowControlledRequestQueue(TActorId targetId, const TEnum activity, const TFlowControlledQueueConfig &config) { - return new TFlowControlledRequestQueue(targetId, activity, config); -} - -} diff --git a/library/cpp/actors/helpers/flow_controlled_queue.h b/library/cpp/actors/helpers/flow_controlled_queue.h deleted file mode 100644 index bbfffa18d7..0000000000 --- a/library/cpp/actors/helpers/flow_controlled_queue.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/actor.h> - -namespace NActors { - - struct TFlowControlledQueueConfig { - ui32 MinAllowedInFly = 20; - ui32 MaxAllowedInFly = 100; - ui32 TargetDynamicRate = 0; - - TDuration MinTrackedLatency = TDuration::MilliSeconds(20); - ui32 LatencyFactor = 4; - }; - - template <class TEnum = IActor::EActivityType> - IActor* CreateFlowControlledRequestQueue(TActorId targetId, const TEnum activity = IActor::EActivityType::ACTORLIB_COMMON, const TFlowControlledQueueConfig &config = TFlowControlledQueueConfig()); - -} diff --git a/library/cpp/actors/helpers/future_callback.h b/library/cpp/actors/helpers/future_callback.h deleted file mode 100644 index 6626dd439d..0000000000 --- a/library/cpp/actors/helpers/future_callback.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/actor.h> -#include <library/cpp/actors/core/hfunc.h> - -namespace NActors { - -template <typename EventType> -struct TActorFutureCallback : TActor<TActorFutureCallback<EventType>> { - using TCallback = std::function<void(TAutoPtr<TEventHandle<EventType>>&)>; - using TBase = TActor<TActorFutureCallback<EventType>>; - TCallback Callback; - - static constexpr IActor::EActivityType ActorActivityType() { - return IActor::EActivityType::ACTOR_FUTURE_CALLBACK; - } - - TActorFutureCallback(TCallback&& callback) - : TBase(&TActorFutureCallback::StateWaitForEvent) - , Callback(std::move(callback)) - {} - - STRICT_STFUNC(StateWaitForEvent, - HFunc(EventType, Handle) - ) - - void Handle(typename EventType::TPtr ev, const TActorContext& ctx) { - Callback(ev); - TBase::Die(ctx); - } -}; - -} // NActors diff --git a/library/cpp/actors/helpers/mon_histogram_helper.h b/library/cpp/actors/helpers/mon_histogram_helper.h deleted file mode 100644 index 2c5ef0bbee..0000000000 --- a/library/cpp/actors/helpers/mon_histogram_helper.h +++ /dev/null @@ -1,86 +0,0 @@ -#pragma once - -#include <library/cpp/monlib/dynamic_counters/counters.h> - -#include <util/string/cast.h> - -namespace NActors { - namespace NMon { - class THistogramCounterHelper { - public: - THistogramCounterHelper() - : FirstBucketVal(0) - , BucketCount(0) - { - } - - THistogramCounterHelper(const THistogramCounterHelper&) = default; - - void Init(NMonitoring::TDynamicCounters* group, const TString& baseName, const TString& unit, - ui64 firstBucket, ui64 bucketCnt, bool useSensorLabelName = true) - { - Y_ASSERT(FirstBucketVal == 0); - Y_ASSERT(BucketCount == 0); - - FirstBucketVal = firstBucket; - BucketCount = bucketCnt; - BucketsHolder.reserve(BucketCount); - Buckets.reserve(BucketCount); - for (size_t i = 0; i < BucketCount; ++i) { - TString bucketName = GetBucketName(i) + " " + unit; - auto labelName = useSensorLabelName ? "sensor" : "name"; - BucketsHolder.push_back(group->GetSubgroup(labelName, baseName)->GetNamedCounter("range", bucketName, true)); - Buckets.push_back(BucketsHolder.back().Get()); - } - } - - void Add(ui64 val) { - Y_ASSERT(FirstBucketVal != 0); - Y_ASSERT(BucketCount != 0); - Y_ABORT_UNLESS(val <= (1ULL << 63ULL)); - size_t ind = 0; - if (val > FirstBucketVal) { - ind = GetValueBitCount((2 * val - 1) / FirstBucketVal) - 1; - if (ind >= BucketCount) { - ind = BucketCount - 1; - } - } - Buckets[ind]->Inc(); - } - - ui64 GetBucketCount() const { - return BucketCount; - } - - ui64 GetBucketValue(size_t index) const { - Y_ASSERT(index < BucketCount); - return Buckets[index]->Val(); - } - - void SetBucketValue(ui64 index, ui64 value) { - Y_ASSERT(index < BucketCount); - *Buckets[index] = value; - } - - private: - TString GetBucketName(size_t ind) const { - Y_ASSERT(FirstBucketVal != 0); - Y_ASSERT(BucketCount != 0); - Y_ASSERT(ind < BucketCount); - if (ind + 1 < BucketCount) { - return ToString<ui64>(FirstBucketVal << ind); - } else { - // Last slot is up to +INF - return "INF"; - } - } - - private: - ui64 FirstBucketVal; - ui64 BucketCount; - TVector<NMonitoring::TDynamicCounters::TCounterPtr> BucketsHolder; - TVector<NMonitoring::TDeprecatedCounter*> Buckets; - }; - - } -} diff --git a/library/cpp/actors/helpers/selfping_actor.cpp b/library/cpp/actors/helpers/selfping_actor.cpp deleted file mode 100644 index f9f7c297fc..0000000000 --- a/library/cpp/actors/helpers/selfping_actor.cpp +++ /dev/null @@ -1,208 +0,0 @@ -#include "selfping_actor.h" - -#include <library/cpp/actors/core/actor_bootstrapped.h> -#include <library/cpp/actors/core/hfunc.h> - -#include <library/cpp/containers/stack_vector/stack_vec.h> -#include <library/cpp/sliding_window/sliding_window.h> - -namespace NActors { - -ui64 MeasureTaskDurationNs() { - // Prepare worm test data - // 11 * 11 * 3 * 8 = 2904 bytes, fits in L1 cache - constexpr ui64 Size = 11; - // Align the data to reduce random alignment effects - alignas(64) TStackVec<ui64, Size * Size * 3> data; - ui64 s = 0; - NHPTimer::STime beginTime; - NHPTimer::STime endTime; - // Prepare the data - data.resize(Size * Size * 3); - for (ui64 matrixIdx = 0; matrixIdx < 3; ++matrixIdx) { - for (ui64 y = 0; y < Size; ++y) { - for (ui64 x = 0; x < Size; ++x) { - data[matrixIdx * (Size * Size) + y * Size + x] = y * Size + x; - } - } - } - // Warm-up the cache - NHPTimer::GetTime(&beginTime); - for (ui64 idx = 0; idx < data.size(); ++idx) { - s += data[idx]; - } - NHPTimer::GetTime(&endTime); - s += (ui64)(1000000.0 * NHPTimer::GetSeconds(endTime - beginTime)); - - // Measure the CPU performance - // C = A * B with injected dependency to s - NHPTimer::GetTime(&beginTime); - for (ui64 y = 0; y < Size; ++y) { - for (ui64 x = 0; x < Size; ++x) { - for (ui64 i = 0; i < Size; ++i) { - s += data[y * Size + i] * data[Size * Size + i * Size + x]; - } - data[2 * Size * Size + y * Size + x] = s; - s = 0; - } - } - for (ui64 idx = 0; idx < data.size(); ++idx) { - s += data[idx]; - } - NHPTimer::GetTime(&endTime); - // Prepare the result - double d = 1000000000.0 * (NHPTimer::GetSeconds(endTime - beginTime) + 0.000000001 * (s & 1)); - return (ui64)d; -} - -namespace { - -struct TEvPing: public TEventLocal<TEvPing, TEvents::THelloWorld::Ping> { - TEvPing(double timeStart) - : TimeStart(timeStart) - {} - - const double TimeStart; -}; - -template <class TValueType_> -struct TAvgOperation { - struct TValueType { - ui64 Count = 0; - TValueType_ Sum = TValueType_(); - }; - using TValueVector = TVector<TValueType>; - - static constexpr TValueType InitialValue() { - return TValueType(); // zero - } - - // Updates value in current bucket and returns window value - static TValueType UpdateBucket(TValueType windowValue, TValueVector& buckets, size_t index, TValueType newVal) { - Y_ASSERT(index < buckets.size()); - buckets[index].Sum += newVal.Sum; - buckets[index].Count += newVal.Count; - windowValue.Sum += newVal.Sum; - windowValue.Count += newVal.Count; - return windowValue; - } - - static TValueType ClearBuckets(TValueType windowValue, TValueVector& buckets, size_t firstElemIndex, size_t bucketsToClear) { - Y_ASSERT(!buckets.empty()); - Y_ASSERT(firstElemIndex < buckets.size()); - Y_ASSERT(bucketsToClear <= buckets.size()); - - const size_t arraySize = buckets.size(); - for (size_t i = 0; i < bucketsToClear; ++i) { - TValueType& curVal = buckets[firstElemIndex]; - windowValue.Sum -= curVal.Sum; - windowValue.Count -= curVal.Count; - curVal = InitialValue(); - firstElemIndex = (firstElemIndex + 1) % arraySize; - } - return windowValue; - } - -}; - -class TSelfPingActor : public TActorBootstrapped<TSelfPingActor> { -private: - const TDuration SendInterval; - const NMonitoring::TDynamicCounters::TCounterPtr MaxPingCounter; - const NMonitoring::TDynamicCounters::TCounterPtr AvgPingCounter; - const NMonitoring::TDynamicCounters::TCounterPtr AvgPingCounterWithSmallWindow; - const NMonitoring::TDynamicCounters::TCounterPtr CalculationTimeCounter; - - NSlidingWindow::TSlidingWindow<NSlidingWindow::TMaxOperation<ui64>> MaxPingSlidingWindow; - NSlidingWindow::TSlidingWindow<TAvgOperation<ui64>> AvgPingSlidingWindow; - NSlidingWindow::TSlidingWindow<TAvgOperation<ui64>> AvgPingSmallSlidingWindow; - NSlidingWindow::TSlidingWindow<TAvgOperation<ui64>> CalculationSlidingWindow; - - THPTimer Timer; - -public: - static constexpr auto ActorActivityType() { - return EActivityType::SELF_PING_ACTOR; - } - - TSelfPingActor(TDuration sendInterval, - const NMonitoring::TDynamicCounters::TCounterPtr& maxPingCounter, - const NMonitoring::TDynamicCounters::TCounterPtr& avgPingCounter, - const NMonitoring::TDynamicCounters::TCounterPtr& avgPingSmallWindowCounter, - const NMonitoring::TDynamicCounters::TCounterPtr& calculationTimeCounter) - : SendInterval(sendInterval) - , MaxPingCounter(maxPingCounter) - , AvgPingCounter(avgPingCounter) - , AvgPingCounterWithSmallWindow(avgPingSmallWindowCounter) - , CalculationTimeCounter(calculationTimeCounter) - , MaxPingSlidingWindow(TDuration::Seconds(15), 100) - , AvgPingSlidingWindow(TDuration::Seconds(15), 100) - , AvgPingSmallSlidingWindow(TDuration::Seconds(1), 100) - , CalculationSlidingWindow(TDuration::Seconds(15), 100) - { - } - - void Bootstrap(const TActorContext& ctx) - { - Become(&TSelfPingActor::RunningState); - SchedulePing(ctx, Timer.Passed()); - } - - STFUNC(RunningState) - { - switch (ev->GetTypeRewrite()) { - HFunc(TEvPing, HandlePing); - default: - Y_ABORT("TSelfPingActor::RunningState: unexpected event 0x%08" PRIx32, ev->GetTypeRewrite()); - } - } - - void HandlePing(TEvPing::TPtr &ev, const TActorContext &ctx) - { - const auto now = ctx.Now(); - const double hpNow = Timer.Passed(); - const auto& e = *ev->Get(); - const double passedTime = hpNow - e.TimeStart; - const ui64 delayUs = passedTime > 0.0 ? static_cast<ui64>(passedTime * 1e6) : 0; - - if (MaxPingCounter) { - *MaxPingCounter = MaxPingSlidingWindow.Update(delayUs, now); - } - if (AvgPingCounter) { - auto res = AvgPingSlidingWindow.Update({1, delayUs}, now); - *AvgPingCounter = double(res.Sum) / double(res.Count + 1); - } - if (AvgPingCounterWithSmallWindow) { - auto res = AvgPingSmallSlidingWindow.Update({1, delayUs}, now); - *AvgPingCounterWithSmallWindow = double(res.Sum) / double(res.Count + 1); - } - - if (CalculationTimeCounter) { - ui64 d = MeasureTaskDurationNs(); - auto res = CalculationSlidingWindow.Update({1, d}, now); - *CalculationTimeCounter = double(res.Sum) / double(res.Count + 1); - } - - SchedulePing(ctx, hpNow); - } - -private: - void SchedulePing(const TActorContext &ctx, double hpNow) const - { - ctx.Schedule(SendInterval, new TEvPing(hpNow)); - } -}; - -} // namespace - -IActor* CreateSelfPingActor( - TDuration sendInterval, - const NMonitoring::TDynamicCounters::TCounterPtr& maxPingCounter, - const NMonitoring::TDynamicCounters::TCounterPtr& avgPingCounter, - const NMonitoring::TDynamicCounters::TCounterPtr& avgPingSmallWindowCounter, - const NMonitoring::TDynamicCounters::TCounterPtr& calculationTimeCounter) -{ - return new TSelfPingActor(sendInterval, maxPingCounter, avgPingCounter, avgPingSmallWindowCounter, calculationTimeCounter); -} - -} // NActors diff --git a/library/cpp/actors/helpers/selfping_actor.h b/library/cpp/actors/helpers/selfping_actor.h deleted file mode 100644 index a06bfe8292..0000000000 --- a/library/cpp/actors/helpers/selfping_actor.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/actor.h> -#include <library/cpp/monlib/dynamic_counters/counters.h> - -namespace NActors { - -ui64 MeasureTaskDurationNs(); -NActors::IActor* CreateSelfPingActor( - TDuration sendInterval, - const NMonitoring::TDynamicCounters::TCounterPtr& maxPingCounter, - const NMonitoring::TDynamicCounters::TCounterPtr& avgPingCounter, - const NMonitoring::TDynamicCounters::TCounterPtr& avgPingSmallWindowCounter, - const NMonitoring::TDynamicCounters::TCounterPtr& calculationTimeCounter); - -} // NActors diff --git a/library/cpp/actors/helpers/selfping_actor_ut.cpp b/library/cpp/actors/helpers/selfping_actor_ut.cpp deleted file mode 100644 index 542f817755..0000000000 --- a/library/cpp/actors/helpers/selfping_actor_ut.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "selfping_actor.h" - -#include <library/cpp/testing/unittest/registar.h> -#include <library/cpp/actors/testlib/test_runtime.h> - -namespace NActors { -namespace Tests { - -THolder<TTestActorRuntimeBase> CreateRuntime() { - auto runtime = MakeHolder<TTestActorRuntimeBase>(); - runtime->SetScheduledEventFilter([](auto&&, auto&&, auto&&, auto&&) { return false; }); - runtime->Initialize(); - return runtime; -} - -Y_UNIT_TEST_SUITE(TSelfPingTest) { - Y_UNIT_TEST(Basic) - { - auto runtime = CreateRuntime(); - - //const TActorId sender = runtime.AllocateEdgeActor(); - - NMonitoring::TDynamicCounters::TCounterPtr counter(new NMonitoring::TCounterForPtr()); - NMonitoring::TDynamicCounters::TCounterPtr counter2(new NMonitoring::TCounterForPtr()); - NMonitoring::TDynamicCounters::TCounterPtr counter3(new NMonitoring::TCounterForPtr()); - NMonitoring::TDynamicCounters::TCounterPtr counter4(new NMonitoring::TCounterForPtr()); - - auto actor = CreateSelfPingActor( - TDuration::MilliSeconds(100), // sendInterval (unused in test) - counter, counter2, counter3, counter4); - - UNIT_ASSERT_VALUES_EQUAL(counter->Val(), 0); - UNIT_ASSERT_VALUES_EQUAL(counter2->Val(), 0); - UNIT_ASSERT_VALUES_EQUAL(counter3->Val(), 0); - UNIT_ASSERT_VALUES_EQUAL(counter4->Val(), 0); - - const TActorId actorId = runtime->Register(actor); - Y_UNUSED(actorId); - - //runtime.Send(new IEventHandle(actorId, sender, new TEvSelfPing::TEvPing(0.0))); - - // TODO check after events are handled - //Sleep(TDuration::Seconds(1)); - //UNIT_ASSERT((intmax_t)counter->Val() >= (intmax_t)Delay.MicroSeconds()); - } -} - -} // namespace Tests -} // namespace NActors diff --git a/library/cpp/actors/helpers/ut/CMakeLists.darwin-arm64.txt b/library/cpp/actors/helpers/ut/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 0112181222..0000000000 --- a/library/cpp/actors/helpers/ut/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,76 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-helpers-ut) -target_include_directories(library-cpp-actors-helpers-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers -) -target_link_libraries(library-cpp-actors-helpers-ut PUBLIC - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-helpers - cpp-actors-interconnect - cpp-actors-testlib - cpp-actors-core -) -target_link_options(library-cpp-actors-helpers-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-helpers-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/selfping_actor_ut.cpp -) -set_property( - TARGET - library-cpp-actors-helpers-ut - PROPERTY - SPLIT_FACTOR - 10 -) -add_yunittest( - NAME - library-cpp-actors-helpers-ut - TEST_TARGET - library-cpp-actors-helpers-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-helpers-ut - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-helpers-ut - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-helpers-ut - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-helpers-ut - system_allocator -) -vcs_info(library-cpp-actors-helpers-ut) diff --git a/library/cpp/actors/helpers/ut/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/helpers/ut/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 126b29e574..0000000000 --- a/library/cpp/actors/helpers/ut/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,77 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-helpers-ut) -target_include_directories(library-cpp-actors-helpers-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers -) -target_link_libraries(library-cpp-actors-helpers-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-helpers - cpp-actors-interconnect - cpp-actors-testlib - cpp-actors-core -) -target_link_options(library-cpp-actors-helpers-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-helpers-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/selfping_actor_ut.cpp -) -set_property( - TARGET - library-cpp-actors-helpers-ut - PROPERTY - SPLIT_FACTOR - 10 -) -add_yunittest( - NAME - library-cpp-actors-helpers-ut - TEST_TARGET - library-cpp-actors-helpers-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-helpers-ut - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-helpers-ut - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-helpers-ut - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-helpers-ut - system_allocator -) -vcs_info(library-cpp-actors-helpers-ut) diff --git a/library/cpp/actors/helpers/ut/CMakeLists.linux-aarch64.txt b/library/cpp/actors/helpers/ut/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 24da0dacd6..0000000000 --- a/library/cpp/actors/helpers/ut/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,80 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-helpers-ut) -target_include_directories(library-cpp-actors-helpers-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers -) -target_link_libraries(library-cpp-actors-helpers-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-helpers - cpp-actors-interconnect - cpp-actors-testlib - cpp-actors-core -) -target_link_options(library-cpp-actors-helpers-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-helpers-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/selfping_actor_ut.cpp -) -set_property( - TARGET - library-cpp-actors-helpers-ut - PROPERTY - SPLIT_FACTOR - 10 -) -add_yunittest( - NAME - library-cpp-actors-helpers-ut - TEST_TARGET - library-cpp-actors-helpers-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-helpers-ut - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-helpers-ut - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-helpers-ut - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-helpers-ut - cpp-malloc-jemalloc -) -vcs_info(library-cpp-actors-helpers-ut) diff --git a/library/cpp/actors/helpers/ut/CMakeLists.linux-x86_64.txt b/library/cpp/actors/helpers/ut/CMakeLists.linux-x86_64.txt deleted file mode 100644 index db118dc91e..0000000000 --- a/library/cpp/actors/helpers/ut/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,82 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-helpers-ut) -target_include_directories(library-cpp-actors-helpers-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers -) -target_link_libraries(library-cpp-actors-helpers-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-helpers - cpp-actors-interconnect - cpp-actors-testlib - cpp-actors-core -) -target_link_options(library-cpp-actors-helpers-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-helpers-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/selfping_actor_ut.cpp -) -set_property( - TARGET - library-cpp-actors-helpers-ut - PROPERTY - SPLIT_FACTOR - 10 -) -add_yunittest( - NAME - library-cpp-actors-helpers-ut - TEST_TARGET - library-cpp-actors-helpers-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-helpers-ut - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-helpers-ut - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-helpers-ut - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-helpers-ut - cpp-malloc-tcmalloc - libs-tcmalloc-no_percpu_cache -) -vcs_info(library-cpp-actors-helpers-ut) diff --git a/library/cpp/actors/helpers/ut/CMakeLists.txt b/library/cpp/actors/helpers/ut/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/helpers/ut/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/helpers/ut/CMakeLists.windows-x86_64.txt b/library/cpp/actors/helpers/ut/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 7e68870a0e..0000000000 --- a/library/cpp/actors/helpers/ut/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,70 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-helpers-ut) -target_include_directories(library-cpp-actors-helpers-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers -) -target_link_libraries(library-cpp-actors-helpers-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-helpers - cpp-actors-interconnect - cpp-actors-testlib - cpp-actors-core -) -target_sources(library-cpp-actors-helpers-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/helpers/selfping_actor_ut.cpp -) -set_property( - TARGET - library-cpp-actors-helpers-ut - PROPERTY - SPLIT_FACTOR - 10 -) -add_yunittest( - NAME - library-cpp-actors-helpers-ut - TEST_TARGET - library-cpp-actors-helpers-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-helpers-ut - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-helpers-ut - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-helpers-ut - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-helpers-ut - system_allocator -) -vcs_info(library-cpp-actors-helpers-ut) diff --git a/library/cpp/actors/helpers/ut/ya.make b/library/cpp/actors/helpers/ut/ya.make deleted file mode 100644 index 10b298bb72..0000000000 --- a/library/cpp/actors/helpers/ut/ya.make +++ /dev/null @@ -1,31 +0,0 @@ -UNITTEST_FOR(library/cpp/actors/helpers) - -FORK_SUBTESTS() -IF (SANITIZER_TYPE) - SIZE(LARGE) - TIMEOUT(1200) - TAG(ya:fat) - SPLIT_FACTOR(20) - REQUIREMENTS( - ram:32 - ) -ELSE() - SIZE(MEDIUM) - TIMEOUT(600) - REQUIREMENTS( - ram:16 - ) -ENDIF() - - -PEERDIR( - library/cpp/actors/interconnect - library/cpp/actors/testlib - library/cpp/actors/core -) - -SRCS( - selfping_actor_ut.cpp -) - -END() diff --git a/library/cpp/actors/helpers/ya.make b/library/cpp/actors/helpers/ya.make deleted file mode 100644 index 94acdca726..0000000000 --- a/library/cpp/actors/helpers/ya.make +++ /dev/null @@ -1,23 +0,0 @@ -LIBRARY() - -SRCS( - activeactors.cpp - activeactors.h - flow_controlled_queue.cpp - flow_controlled_queue.h - future_callback.h - mon_histogram_helper.h - selfping_actor.cpp -) - -PEERDIR( - library/cpp/actors/core - library/cpp/monlib/dynamic_counters -) - -END() - -RECURSE_FOR_TESTS( - ut -) - diff --git a/library/cpp/actors/http/CMakeLists.darwin-arm64.txt b/library/cpp/actors/http/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 1947b6fa39..0000000000 --- a/library/cpp/actors/http/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,32 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-http) -target_link_libraries(cpp-actors-http PUBLIC - contrib-libs-cxxsupp - yutil - contrib-libs-openssl - contrib-libs-zlib - cpp-actors-core - cpp-actors-interconnect - library-cpp-dns - cpp-monlib-metrics - cpp-string_utils-quote -) -target_sources(cpp-actors-http PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_cache.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_compress.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy_acceptor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy_incoming.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy_outgoing.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_static.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http.cpp -) diff --git a/library/cpp/actors/http/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/http/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 1947b6fa39..0000000000 --- a/library/cpp/actors/http/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,32 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-http) -target_link_libraries(cpp-actors-http PUBLIC - contrib-libs-cxxsupp - yutil - contrib-libs-openssl - contrib-libs-zlib - cpp-actors-core - cpp-actors-interconnect - library-cpp-dns - cpp-monlib-metrics - cpp-string_utils-quote -) -target_sources(cpp-actors-http PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_cache.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_compress.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy_acceptor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy_incoming.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy_outgoing.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_static.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http.cpp -) diff --git a/library/cpp/actors/http/CMakeLists.linux-aarch64.txt b/library/cpp/actors/http/CMakeLists.linux-aarch64.txt deleted file mode 100644 index a0e186fa07..0000000000 --- a/library/cpp/actors/http/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,33 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-http) -target_link_libraries(cpp-actors-http PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - contrib-libs-openssl - contrib-libs-zlib - cpp-actors-core - cpp-actors-interconnect - library-cpp-dns - cpp-monlib-metrics - cpp-string_utils-quote -) -target_sources(cpp-actors-http PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_cache.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_compress.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy_acceptor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy_incoming.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy_outgoing.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_static.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http.cpp -) diff --git a/library/cpp/actors/http/CMakeLists.linux-x86_64.txt b/library/cpp/actors/http/CMakeLists.linux-x86_64.txt deleted file mode 100644 index a0e186fa07..0000000000 --- a/library/cpp/actors/http/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,33 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-http) -target_link_libraries(cpp-actors-http PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - contrib-libs-openssl - contrib-libs-zlib - cpp-actors-core - cpp-actors-interconnect - library-cpp-dns - cpp-monlib-metrics - cpp-string_utils-quote -) -target_sources(cpp-actors-http PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_cache.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_compress.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy_acceptor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy_incoming.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy_outgoing.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_static.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http.cpp -) diff --git a/library/cpp/actors/http/CMakeLists.txt b/library/cpp/actors/http/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/http/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/http/CMakeLists.windows-x86_64.txt b/library/cpp/actors/http/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 1947b6fa39..0000000000 --- a/library/cpp/actors/http/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,32 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-http) -target_link_libraries(cpp-actors-http PUBLIC - contrib-libs-cxxsupp - yutil - contrib-libs-openssl - contrib-libs-zlib - cpp-actors-core - cpp-actors-interconnect - library-cpp-dns - cpp-monlib-metrics - cpp-string_utils-quote -) -target_sources(cpp-actors-http PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_cache.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_compress.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy_acceptor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy_incoming.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy_outgoing.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_proxy.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_static.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http.cpp -) diff --git a/library/cpp/actors/http/http.cpp b/library/cpp/actors/http/http.cpp deleted file mode 100644 index 9da46e412b..0000000000 --- a/library/cpp/actors/http/http.cpp +++ /dev/null @@ -1,823 +0,0 @@ -#include "http.h" -#include <library/cpp/string_utils/quote/quote.h> - -inline TStringBuf operator +(TStringBuf l, TStringBuf r) { - if (l.empty()) { - return r; - } - if (r.empty()) { - return l; - } - if (l.end() == r.begin()) { - return TStringBuf(l.data(), l.size() + r.size()); - } - if (r.end() == l.begin()) { - return TStringBuf(r.data(), l.size() + r.size()); - } - Y_ABORT("oops"); - return TStringBuf(); -} - -inline TStringBuf operator +=(TStringBuf& l, TStringBuf r) { - return l = l + r; -} - -static bool is_not_number(TStringBuf v) { - return v.empty() || std::find_if_not(v.begin(), v.end(), [](unsigned char c) { return std::isdigit(c); }) != v.end(); -} - -namespace NHttp { - -template <> TStringBuf THttpRequest::GetName<&THttpRequest::Host>() { return "Host"; } -template <> TStringBuf THttpRequest::GetName<&THttpRequest::Accept>() { return "Accept"; } -template <> TStringBuf THttpRequest::GetName<&THttpRequest::Connection>() { return "Connection"; } -template <> TStringBuf THttpRequest::GetName<&THttpRequest::ContentType>() { return "Content-Type"; } -template <> TStringBuf THttpRequest::GetName<&THttpRequest::ContentLength>() { return "Content-Length"; } -template <> TStringBuf THttpRequest::GetName<&THttpRequest::TransferEncoding>() { return "Transfer-Encoding"; } -template <> TStringBuf THttpRequest::GetName<&THttpRequest::AcceptEncoding>() { return "Accept-Encoding"; } - -const TMap<TStringBuf, TStringBuf THttpRequest::*, TLessNoCase> THttpRequest::HeadersLocation = { - { THttpRequest::GetName<&THttpRequest::Host>(), &THttpRequest::Host }, - { THttpRequest::GetName<&THttpRequest::Accept>(), &THttpRequest::Accept }, - { THttpRequest::GetName<&THttpRequest::Connection>(), &THttpRequest::Connection }, - { THttpRequest::GetName<&THttpRequest::ContentType>(), &THttpRequest::ContentType }, - { THttpRequest::GetName<&THttpRequest::ContentLength>(), &THttpRequest::ContentLength }, - { THttpRequest::GetName<&THttpRequest::TransferEncoding>(), &THttpRequest::TransferEncoding }, - { THttpRequest::GetName<&THttpRequest::AcceptEncoding>(), &THttpRequest::AcceptEncoding }, -}; - -template <> TStringBuf THttpResponse::GetName<&THttpResponse::Connection>() { return "Connection"; } -template <> TStringBuf THttpResponse::GetName<&THttpResponse::ContentType>() { return "Content-Type"; } -template <> TStringBuf THttpResponse::GetName<&THttpResponse::ContentLength>() { return "Content-Length"; } -template <> TStringBuf THttpResponse::GetName<&THttpResponse::TransferEncoding>() { return "Transfer-Encoding"; } -template <> TStringBuf THttpResponse::GetName<&THttpResponse::LastModified>() { return "Last-Modified"; } -template <> TStringBuf THttpResponse::GetName<&THttpResponse::ContentEncoding>() { return "Content-Encoding"; } - -const TMap<TStringBuf, TStringBuf THttpResponse::*, TLessNoCase> THttpResponse::HeadersLocation = { - { THttpResponse::GetName<&THttpResponse::Connection>(), &THttpResponse::Connection }, - { THttpResponse::GetName<&THttpResponse::ContentType>(), &THttpResponse::ContentType }, - { THttpResponse::GetName<&THttpResponse::ContentLength>(), &THttpResponse::ContentLength }, - { THttpResponse::GetName<&THttpResponse::TransferEncoding>(), &THttpResponse::TransferEncoding }, - { THttpResponse::GetName<&THttpResponse::LastModified>(), &THttpResponse::LastModified }, - { THttpResponse::GetName<&THttpResponse::ContentEncoding>(), &THttpResponse::ContentEncoding } -}; - -void THttpRequest::Clear() { - // a dirty little trick - this->~THttpRequest(); // basically, do nothing - new (this) THttpRequest(); // reset all fields -} - -template <> -bool THttpParser<THttpRequest, TSocketBuffer>::HaveBody() const { - if (!Body.empty()) { - return true; - } - return !ContentLength.empty() || !TransferEncoding.empty(); -} - -template <> -void THttpParser<THttpRequest, TSocketBuffer>::Advance(size_t len) { - TStringBuf data(Pos(), len); - while (!data.empty()) { - if (Stage != EParseStage::Error) { - LastSuccessStage = Stage; - } - switch (Stage) { - case EParseStage::Method: { - if (ProcessData(Method, data, ' ', MaxMethodSize)) { - Stage = EParseStage::URL; - } - break; - } - case EParseStage::URL: { - if (ProcessData(URL, data, ' ', MaxURLSize)) { - Stage = EParseStage::Protocol; - } - break; - } - case EParseStage::Protocol: { - if (ProcessData(Protocol, data, '/', MaxProtocolSize)) { - Stage = EParseStage::Version; - } - break; - } - case EParseStage::Version: { - if (ProcessData(Version, data, "\r\n", MaxVersionSize)) { - Stage = EParseStage::Header; - Headers = data; - } - break; - } - case EParseStage::Header: { - if (ProcessData(Header, data, "\r\n", MaxHeaderSize)) { - if (Header.empty()) { - if (HaveBody() && (ContentLength.empty() || ContentLength != "0")) { - Stage = EParseStage::Body; - } else if (TotalSize.has_value() && !data.empty()) { - Stage = EParseStage::Body; - } else { - Stage = EParseStage::Done; - } - } else { - ProcessHeader(Header); - } - Headers = TStringBuf(Headers.data(), data.data() - Headers.data()); - } - if (Stage != EParseStage::Body) { - break; - } - [[fallthrough]]; - } - case EParseStage::Body: { - if (TEqNoCase()(TransferEncoding, "chunked")) { - Stage = EParseStage::ChunkLength; - } else if (!ContentLength.empty()) { - if (is_not_number(ContentLength)) { - // Invalid content length - Stage = EParseStage::Error; - } else if (ProcessData(Content, data, FromStringWithDefault(ContentLength, 0))) { - Body = Content; - Stage = EParseStage::Done; - } - } else if (TotalSize.has_value()) { - if (ProcessData(Content, data, GetBodySizeFromTotalSize())) { - Body = Content; - Stage = EParseStage::Done; - } - } else { - // Invalid body encoding - Stage = EParseStage::Error; - } - break; - } - case EParseStage::ChunkLength: { - if (ProcessData(Line, data, "\r\n", MaxChunkLengthSize)) { - if (!Line.empty()) { - ChunkLength = ParseHex(Line); - if (ChunkLength <= MaxChunkSize) { - ContentSize = Content.size() + ChunkLength; - if (ContentSize <= MaxChunkContentSize) { - Stage = EParseStage::ChunkData; - Line.Clear(); - } else { - // Invalid chunk content length - Stage = EParseStage::Error; - } - } else { - // Invalid chunk length - Stage = EParseStage::Error; - } - } else { - // Invalid body encoding - Stage = EParseStage::Error; - } - } - break; - } - case EParseStage::ChunkData: { - if (!IsError()) { - if (ProcessData(Content, data, ContentSize)) { - if (ProcessData(Line, data, 2)) { - if (Line == "\r\n") { - if (ChunkLength == 0) { - Body = Content; - Stage = EParseStage::Done; - } else { - Stage = EParseStage::ChunkLength; - } - Line.Clear(); - } else { - // Invalid body encoding - Stage = EParseStage::Error; - } - } - } - } - break; - } - - case EParseStage::Done: - case EParseStage::Error: { - data.Clear(); - break; - } - default: - Y_ABORT("Invalid processing sequence"); - break; - } - } - TSocketBuffer::Advance(len); -} - -template <> -THttpParser<THttpRequest, TSocketBuffer>::EParseStage THttpParser<THttpRequest, TSocketBuffer>::GetInitialStage() { - return EParseStage::Method; -} - -template <> -bool THttpParser<THttpResponse, TSocketBuffer>::HaveBody() const { - if (!Body.empty()) { - return true; - } - return (!Status.starts_with("1") && Status != "204" && Status != "304") - && (!ContentType.empty() || !ContentLength.empty() || !TransferEncoding.empty()); -} - -template <> -THttpParser<THttpResponse, TSocketBuffer>::EParseStage THttpParser<THttpResponse, TSocketBuffer>::GetInitialStage() { - return EParseStage::Protocol; -} - -void THttpResponse::Clear() { - // a dirty little trick - this->~THttpResponse(); // basically, do nothing - new (this) THttpResponse(); // reset all fields -} - -template <> -void THttpParser<THttpResponse, TSocketBuffer>::Advance(size_t len) { - TStringBuf data(Pos(), len); - while (!data.empty()) { - if (Stage != EParseStage::Error) { - LastSuccessStage = Stage; - } - switch (Stage) { - case EParseStage::Protocol: { - if (ProcessData(Protocol, data, '/', MaxProtocolSize)) { - Stage = EParseStage::Version; - } - break; - } - case EParseStage::Version: { - if (ProcessData(Version, data, ' ', MaxVersionSize)) { - Stage = EParseStage::Status; - } - break; - } - case EParseStage::Status: { - if (ProcessData(Status, data, ' ', MaxStatusSize)) { - Stage = EParseStage::Message; - } - break; - } - case EParseStage::Message: { - if (ProcessData(Message, data, "\r\n", MaxMessageSize)) { - Stage = EParseStage::Header; - Headers = TStringBuf(data.data(), size_t(0)); - } - break; - } - case EParseStage::Header: { - if (ProcessData(Header, data, "\r\n", MaxHeaderSize)) { - if (Header.empty()) { - if (HaveBody() && (ContentLength.empty() || ContentLength != "0")) { - Stage = EParseStage::Body; - } else if (TotalSize.has_value() && !data.empty()) { - Stage = EParseStage::Body; - } else { - Stage = EParseStage::Done; - } - } else { - ProcessHeader(Header); - } - Headers = TStringBuf(Headers.data(), data.data() - Headers.data()); - } - if (Stage != EParseStage::Body) { - break; - } - [[fallthrough]]; - } - case EParseStage::Body: { - if (TEqNoCase()(TransferEncoding, "chunked")) { - Stage = EParseStage::ChunkLength; - } else if (!ContentLength.empty()) { - if (is_not_number(ContentLength)) { - // Invalid content length - Stage = EParseStage::Error; - } else if (ProcessData(Body, data, FromStringWithDefault(ContentLength, 0))) { - Stage = EParseStage::Done; - if (Body && ContentEncoding == "deflate") { - Content = DecompressDeflate(Body); - Body = Content; - } - } - } else if (TotalSize.has_value()) { - if (ProcessData(Content, data, GetBodySizeFromTotalSize())) { - Body = Content; - Stage = EParseStage::Done; - if (Body && ContentEncoding == "deflate") { - Content = DecompressDeflate(Body); - Body = Content; - } - } - } else { - // Invalid body encoding - Stage = EParseStage::Error; - } - break; - } - case EParseStage::ChunkLength: { - if (ProcessData(Line, data, "\r\n", MaxChunkLengthSize)) { - if (!Line.empty()) { - ChunkLength = ParseHex(Line); - if (ChunkLength <= MaxChunkSize) { - ContentSize = Content.size() + ChunkLength; - if (ContentSize <= MaxChunkContentSize) { - Stage = EParseStage::ChunkData; - Line.Clear(); - } else { - // Invalid chunk content length - Stage = EParseStage::Error; - } - } else { - // Invalid chunk length - Stage = EParseStage::Error; - } - } else { - // Invalid body encoding - Stage = EParseStage::Error; - } - } - break; - } - case EParseStage::ChunkData: { - if (!IsError()) { - if (ProcessData(Content, data, ContentSize)) { - if (ProcessData(Line, data, 2)) { - if (Line == "\r\n") { - if (ChunkLength == 0) { - Body = Content; - Stage = EParseStage::Done; - if (Body && ContentEncoding == "deflate") { - Content = DecompressDeflate(Body); - Body = Content; - } - } else { - Stage = EParseStage::ChunkLength; - } - Line.Clear(); - } else { - // Invalid body encoding - Stage = EParseStage::Error; - } - } - } - } - break; - } - case EParseStage::Done: - case EParseStage::Error: - data.Clear(); - break; - default: - // Invalid processing sequence - Stage = EParseStage::Error; - break; - } - } - TSocketBuffer::Advance(len); -} - -template <> -void THttpParser<THttpResponse, TSocketBuffer>::ConnectionClosed() { - if (Stage == EParseStage::Done) { - return; - } - if (Stage == EParseStage::Body) { - // ? - Stage = EParseStage::Done; - } else { - LastSuccessStage = Stage; - Stage = EParseStage::Error; - } -} - -THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseString(TStringBuf data) { - THttpParser<THttpResponse, TSocketBuffer> parser(data); - THeadersBuilder headers(parser.Headers); - if (!Endpoint->WorkerName.empty()) { - headers.Set("X-Worker-Name", Endpoint->WorkerName); - } - THttpOutgoingResponsePtr response = new THttpOutgoingResponse(this); - response->InitResponse(parser.Protocol, parser.Version, parser.Status, parser.Message); - if (parser.HaveBody()) { - if (parser.ContentType && !Endpoint->CompressContentTypes.empty()) { - TStringBuf contentType = parser.ContentType.Before(';'); - Trim(contentType, ' '); - if (Count(Endpoint->CompressContentTypes, contentType) != 0) { - if (response->EnableCompression()) { - headers.Erase("Content-Length"); // we will need new length after compression - } - } - } - headers.Erase("Transfer-Encoding"); // we erase transfer-encoding because we convert body to content-length - response->Set(headers); - response->SetBody(parser.Body); - } else { - headers.Erase("Transfer-Encoding"); // we erase transfer-encoding because we convert body to content-length - response->Set(headers); - if (!response->ContentLength) { - response->Set<&THttpResponse::ContentLength>("0"); - } - } - return response; -} - -THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseOK(TStringBuf body, TStringBuf contentType, TInstant lastModified) { - return CreateResponse("200", "OK", contentType, body, lastModified); -} - -THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseBadRequest(TStringBuf html, TStringBuf contentType) { - if (html.empty() && IsError()) { - contentType = "text/plain"; - html = GetErrorText(); - } - return CreateResponse("400", "Bad Request", contentType, html); -} - -THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseNotFound(TStringBuf html, TStringBuf contentType) { - return CreateResponse("404", "Not Found", contentType, html); -} - -THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseServiceUnavailable(TStringBuf html, TStringBuf contentType) { - return CreateResponse("503", "Service Unavailable", contentType, html); -} - -THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseGatewayTimeout(TStringBuf html, TStringBuf contentType) { - return CreateResponse("504", "Gateway Timeout", contentType, html); -} - -THttpIncomingResponse::THttpIncomingResponse(THttpOutgoingRequestPtr request) - : Request(request) -{} - -THttpOutgoingResponsePtr THttpIncomingRequest::ConstructResponse(TStringBuf status, TStringBuf message) { - TStringBuf version = Version; - if (version != "1.0" && version != "1.1") { - version = "1.1"; - } - THttpOutgoingResponsePtr response = new THttpOutgoingResponse(this, "HTTP", version, status, message); - return response; -} - -THttpOutgoingResponsePtr THttpIncomingRequest::CreateIncompleteResponse(TStringBuf status, TStringBuf message, const THeaders& headers) { - THttpOutgoingResponsePtr response = ConstructResponse(status, message); - if (!headers.Has("Connection")) { - response->Set<&THttpResponse::Connection>(GetConnection()); - } - if (!headers.Has("X-Worker-Name")) { - if (!Endpoint->WorkerName.empty()) { - response->Set("X-Worker-Name", Endpoint->WorkerName); - } - } - response->Set(headers); - return response; -} - -THttpOutgoingResponsePtr THttpIncomingRequest::CreateIncompleteResponse(TStringBuf status, TStringBuf message, const THeaders& headers, TStringBuf body) { - THttpOutgoingResponsePtr response = CreateIncompleteResponse(status, message, headers); - if (!response->ContentType.empty() && !body.empty()) { - if (!Endpoint->CompressContentTypes.empty()) { - TStringBuf contentType = response->ContentType.Before(';'); - Trim(contentType, ' '); - if (Count(Endpoint->CompressContentTypes, contentType) != 0) { - response->EnableCompression(); - } - } - } - return response; -} - -void THttpIncomingRequest::FinishResponse(THttpOutgoingResponsePtr& response, TStringBuf body) { - if (response->IsNeedBody() || !body.empty()) { - if (Method == "HEAD") { - response->Set<&THttpResponse::ContentLength>(ToString(body.size())); - } else { - response->SetBody(body); - } - } -} - -THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponse(TStringBuf status, TStringBuf message) { - THttpOutgoingResponsePtr response = CreateIncompleteResponse(status, message); - FinishResponse(response); - return response; -} - -THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponse(TStringBuf status, TStringBuf message, const THeaders& headers) { - THttpOutgoingResponsePtr response = CreateIncompleteResponse(status, message, headers); - FinishResponse(response); - return response; -} - -THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponse(TStringBuf status, TStringBuf message, const THeaders& headers, TStringBuf body) { - THttpOutgoingResponsePtr response = CreateIncompleteResponse(status, message, headers, body); - FinishResponse(response, body); - return response; -} - -THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponse(TStringBuf status, TStringBuf message, TStringBuf contentType, TStringBuf body, TInstant lastModified) { - NHttp::THeadersBuilder headers; - if (!contentType.empty() && !body.empty()) { - headers.Set("Content-Type", contentType); - } - if (lastModified) { - headers.Set("Last-Modified", lastModified.FormatGmTime("%a, %d %b %Y %H:%M:%S GMT")); - } - return CreateResponse(status, message, headers, body); -} - -THttpIncomingRequestPtr THttpIncomingRequest::Duplicate() { - THttpIncomingRequestPtr request = new THttpIncomingRequest(*this); - request->Reparse(); - request->Timer.Reset(); - return request; -} - -THttpIncomingResponsePtr THttpIncomingResponse::Duplicate(THttpOutgoingRequestPtr request) { - THttpIncomingResponsePtr response = new THttpIncomingResponse(*this); - response->Reparse(); - response->Request = request; - return response; -} - -THttpOutgoingResponsePtr THttpOutgoingResponse::Duplicate(THttpIncomingRequestPtr request) { - THeadersBuilder headers(Headers); - if (!request->Endpoint->WorkerName.empty()) { - headers.Set("X-Worker-Name", request->Endpoint->WorkerName); - } - THttpOutgoingResponsePtr response = new THttpOutgoingResponse(request); - response->InitResponse(Protocol, Version, Status, Message); - if (Body) { - if (ContentType && !request->Endpoint->CompressContentTypes.empty()) { - TStringBuf contentType = ContentType.Before(';'); - Trim(contentType, ' '); - if (Count(request->Endpoint->CompressContentTypes, contentType) != 0) { - if (response->EnableCompression()) { - headers.Erase("Content-Length"); // we will need new length after compression - } - } - } - response->Set(headers); - response->SetBody(Body); - } else { - response->Set(headers); - if (!response->ContentLength) { - response->Set<&THttpResponse::ContentLength>("0"); - } - } - return response; -} - - -THttpOutgoingResponsePtr THttpIncomingResponse::Reverse(THttpIncomingRequestPtr request) { - THttpOutgoingResponsePtr response = new THttpOutgoingResponse(request); - response->Assign(Data(), Size()); - response->Reparse(); - return response; -} - -THttpOutgoingRequest::THttpOutgoingRequest(TStringBuf method, TStringBuf scheme, TStringBuf host, TStringBuf uri, TStringBuf protocol, TStringBuf version) { - Secure = (scheme == "https"); - TString urie = UrlEscapeRet(uri); - InitRequest(method, urie, protocol, version); - if (host) { - Set<&THttpRequest::Host>(host); - } -} - -THttpOutgoingRequest::THttpOutgoingRequest(TStringBuf method, TStringBuf url, TStringBuf protocol, TStringBuf version) { - TStringBuf scheme, host, uri; - if (!CrackURL(url, scheme, host, uri)) { - Y_ABORT("Invalid URL specified"); - } - if (!scheme.empty() && scheme != "http" && scheme != "https") { - Y_ABORT("Invalid URL specified"); - } - Secure = (scheme == "https"); - TString urie = UrlEscapeRet(uri); - InitRequest(method, urie, protocol, version); - if (host) { - Set<&THttpRequest::Host>(host); - } -} - -THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestString(const TString& data) { - THttpOutgoingRequestPtr request = new THttpOutgoingRequest(); - request->Assign(data.data(), data.size()); - request->Reparse(); - return request; -} - -THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestGet(TStringBuf url) { - return CreateRequest("GET", url); -} - -THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestGet(TStringBuf host, TStringBuf uri) { - return CreateHttpRequest("GET", host, uri); -} - -THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestPost(TStringBuf url, TStringBuf contentType, TStringBuf body) { - return CreateRequest("POST", url, contentType, body); -} - -THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestPost(TStringBuf host, TStringBuf uri, TStringBuf contentType, TStringBuf body) { - return CreateHttpRequest("POST", host, uri, contentType, body); -} - -THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequest(TStringBuf method, TStringBuf url, TStringBuf contentType, TStringBuf body) { - THttpOutgoingRequestPtr request = new THttpOutgoingRequest(method, url, "HTTP", "1.1"); - request->Set<&THttpRequest::Accept>("*/*"); - if (!contentType.empty()) { - request->Set<&THttpRequest::ContentType>(contentType); - request->Set<&THttpRequest::Body>(body); - } - return request; -} - -THttpOutgoingRequestPtr THttpOutgoingRequest::CreateHttpRequest(TStringBuf method, TStringBuf host, TStringBuf uri, TStringBuf contentType, TStringBuf body) { - THttpOutgoingRequestPtr request = new THttpOutgoingRequest(method, "http", host, uri, "HTTP", "1.1"); - request->Set<&THttpRequest::Accept>("*/*"); - if (!contentType.empty()) { - request->Set<&THttpRequest::ContentType>(contentType); - request->Set<&THttpRequest::Body>(body); - } - return request; -} - -THttpOutgoingRequestPtr THttpOutgoingRequest::Duplicate() { - THttpOutgoingRequestPtr request = new THttpOutgoingRequest(*this); - request->Reparse(); - return request; -} - -THttpOutgoingResponse::THttpOutgoingResponse(THttpIncomingRequestPtr request) - : Request(request) -{} - -THttpOutgoingResponse::THttpOutgoingResponse(THttpIncomingRequestPtr request, TStringBuf protocol, TStringBuf version, TStringBuf status, TStringBuf message) - : Request(request) -{ - InitResponse(protocol, version, status, message); -} - -const size_t THttpConfig::BUFFER_MIN_STEP; -const TDuration THttpConfig::CONNECTION_TIMEOUT; - -TUrlParameters::TUrlParameters(TStringBuf url) { - TStringBuf base; - TStringBuf params; - if (url.TrySplit('?', base, params)) { - for (TStringBuf param = params.NextTok('&'); !param.empty(); param = params.NextTok('&')) { - TStringBuf name = param.NextTok('='); - Parameters[name] = param; - } - } -} - -TString TUrlParameters::operator [](TStringBuf name) const { - TString value(Get(name)); - CGIUnescape(value); - return value; -} - -bool TUrlParameters::Has(TStringBuf name) const { - return Parameters.count(name) != 0; -} - -TStringBuf TUrlParameters::Get(TStringBuf name) const { - auto it = Parameters.find(name); - if (it != Parameters.end()) { - return it->second; - } - return TStringBuf(); -} - -TString TUrlParameters::Render() const { - TStringBuilder parameters; - for (const std::pair<TStringBuf, TStringBuf> parameter : Parameters) { - if (parameters.empty()) { - parameters << '?'; - } else { - parameters << '&'; - } - parameters << parameter.first; - parameters << '='; - parameters << parameter.second; - } - return parameters; -} - -TCookies::TCookies(TStringBuf cookie) { - for (TStringBuf param = cookie.NextTok(';'); !param.empty(); param = cookie.NextTok(';')) { - param.SkipPrefix(" "); - TStringBuf name = param.NextTok('='); - Cookies[name] = param; - } -} - -TStringBuf TCookies::operator [](TStringBuf name) const { - return Get(name); -} - -bool TCookies::Has(TStringBuf name) const { - return Cookies.count(name) != 0; -} - -TStringBuf TCookies::Get(TStringBuf name) const { - auto it = Cookies.find(name); - if (it != Cookies.end()) { - return it->second; - } - return TStringBuf(); -} - -TString TCookies::Render() const { - TStringBuilder cookies; - for (const std::pair<TStringBuf, TStringBuf> cookie : Cookies) { - if (!cookies.empty()) { - cookies << ' '; - } - cookies << cookie.first; - cookies << '='; - cookies << cookie.second; - cookies << ';'; - } - return cookies; -} - -TCookiesBuilder::TCookiesBuilder() - :TCookies(TStringBuf()) -{} - -void TCookiesBuilder::Set(TStringBuf name, TStringBuf data) { - Data.emplace_back(name, data); - Cookies[Data.back().first] = Data.back().second; -} - -THeaders::THeaders(TStringBuf headers) { - Parse(headers); -} - -size_t THeaders::Parse(TStringBuf headers) { - auto start = headers.begin(); - for (TStringBuf param = headers.NextTok("\r\n"); !param.empty(); param = headers.NextTok("\r\n")) { - TStringBuf name = param.NextTok(":"); - param.SkipPrefix(" "); - Headers[name] = param; - } - return headers.begin() - start; -} - -const TStringBuf THeaders::operator [](TStringBuf name) const { - return Get(name); -} - -bool THeaders::Has(TStringBuf name) const { - return Headers.count(name) != 0; -} - -TStringBuf THeaders::Get(TStringBuf name) const { - auto it = Headers.find(name); - if (it != Headers.end()) { - return it->second; - } - return TStringBuf(); -} - -TString THeaders::Render() const { - TStringBuilder headers; - for (const std::pair<TStringBuf, TStringBuf> header : Headers) { - headers << header.first; - headers << ": "; - headers << header.second; - headers << "\r\n"; - } - return headers; -} - -THeadersBuilder::THeadersBuilder() - : THeaders(TStringBuf()) -{} - -THeadersBuilder::THeadersBuilder(TStringBuf headers) - : THeaders(headers) -{} - -THeadersBuilder::THeadersBuilder(const THeadersBuilder& builder) { - for (const auto& pr : builder.Headers) { - Set(pr.first, pr.second); - } -} - -void THeadersBuilder::Set(TStringBuf name, TStringBuf data) { - Data.emplace_back(name, data); - Headers[Data.back().first] = Data.back().second; -} - -void THeadersBuilder::Erase(TStringBuf name) { - Headers.erase(name); -} - -} diff --git a/library/cpp/actors/http/http.h b/library/cpp/actors/http/http.h deleted file mode 100644 index d96ab062e8..0000000000 --- a/library/cpp/actors/http/http.h +++ /dev/null @@ -1,877 +0,0 @@ -#pragma once -#include <util/datetime/base.h> -#include <util/string/builder.h> -#include <util/system/thread.h> -#include <util/system/hp_timer.h> -#include <util/generic/hash_set.h> -#include <util/generic/buffer.h> -#include <util/generic/intrlist.h> -#include "http_config.h" - -// TODO(xenoxeno): hide in implementation -template <typename Type> -struct THash<TIntrusivePtr<Type>> { - size_t operator ()(const TIntrusivePtr<Type>& ptr) const { return reinterpret_cast<size_t>(ptr.Get()); } -}; - -template<> -inline void Out<NHttp::THttpConfig::SocketAddressType>(IOutputStream& o, const NHttp::THttpConfig::SocketAddressType& x) { - o << x->ToString(); -} - -namespace NHttp { - -bool IsIPv6(const TString& host); -bool IsIPv4(const TString& host); -bool CrackURL(TStringBuf url, TStringBuf& scheme, TStringBuf& host, TStringBuf& uri); -void CrackAddress(const TString& address, TString& hostname, TIpPort& port); -void TrimBegin(TStringBuf& target, char delim); -void TrimEnd(TStringBuf& target, char delim); -void Trim(TStringBuf& target, char delim); -void TrimEnd(TString& target, char delim); -TString CompressDeflate(TStringBuf source); -TString DecompressDeflate(TStringBuf source); - -struct TLessNoCase { - bool operator()(TStringBuf l, TStringBuf r) const { - auto ll = l.length(); - auto rl = r.length(); - if (ll != rl) { - return ll < rl; - } - return strnicmp(l.data(), r.data(), ll) < 0; - } -}; - -struct TEqNoCase { - bool operator()(TStringBuf l, TStringBuf r) const { - auto ll = l.length(); - auto rl = r.length(); - if (ll != rl) { - return false; - } - return strnicmp(l.data(), r.data(), ll) == 0; - } -}; - -struct TSensors { - TString Direction; - TString Host; - TString Url; - TString Status; - TDuration Time; - - TSensors( - TStringBuf direction, - TStringBuf host, - TStringBuf url, - TStringBuf status, - TDuration time) - : Direction(direction) - , Host(host) - , Url(url) - , Status(status) - , Time(time) - {} -}; - -struct TUrlParameters { - THashMap<TStringBuf, TStringBuf> Parameters; - - TUrlParameters(TStringBuf url); - TString operator [](TStringBuf name) const; - bool Has(TStringBuf name) const; - TStringBuf Get(TStringBuf name) const; // raw - TString Render() const; -}; - -struct TCookies { - THashMap<TStringBuf, TStringBuf> Cookies; - - TCookies(TStringBuf cookie); - TCookies(const TCookies&) = delete; - TStringBuf operator [](TStringBuf name) const; - bool Has(TStringBuf name) const; - TStringBuf Get(TStringBuf name) const; // raw - TString Render() const; -}; - -struct TCookiesBuilder : TCookies { - TDeque<std::pair<TString, TString>> Data; - - TCookiesBuilder(); - void Set(TStringBuf name, TStringBuf data); -}; - -struct THeaders { - TMap<TStringBuf, TStringBuf, TLessNoCase> Headers; - - THeaders() = default; - THeaders(TStringBuf headers); - THeaders(const THeaders&) = delete; - const TStringBuf operator [](TStringBuf name) const; - bool Has(TStringBuf name) const; - TStringBuf Get(TStringBuf name) const; // raw - size_t Parse(TStringBuf headers); - TString Render() const; -}; - -struct THeadersBuilder : THeaders { - TDeque<std::pair<TString, TString>> Data; - - THeadersBuilder(); - THeadersBuilder(TStringBuf headers); - THeadersBuilder(const THeadersBuilder& builder); - void Set(TStringBuf name, TStringBuf data); - void Erase(TStringBuf name); -}; - -class TSocketBuffer : public TBuffer, public THttpConfig { -public: - TSocketBuffer() - : TBuffer(BUFFER_SIZE) - {} - - bool EnsureEnoughSpaceAvailable(size_t need) { - size_t avail = Avail(); - if (avail < need) { - Reserve(Capacity() + std::max(need, BUFFER_MIN_STEP)); - return false; - } - return true; - } - - // non-destructive variant of AsString - TString AsString() const { - return TString(Data(), Size()); - } -}; - -class THttpRequest { -public: - TStringBuf Method; - TStringBuf URL; - TStringBuf Protocol; - TStringBuf Version; - TStringBuf Headers; - - TStringBuf Host; - TStringBuf Accept; - TStringBuf Connection; - TStringBuf ContentType; - TStringBuf ContentLength; - TStringBuf AcceptEncoding; - TStringBuf TransferEncoding; - - TStringBuf Body; - - static const TMap<TStringBuf, TStringBuf THttpRequest::*, TLessNoCase> HeadersLocation; - - template <TStringBuf THttpRequest::* Header> - static TStringBuf GetName(); - void Clear(); -}; - -class THttpResponse { -public: - TStringBuf Protocol; - TStringBuf Version; - TStringBuf Status; - TStringBuf Message; - TStringBuf Headers; - - TStringBuf Connection; - TStringBuf ContentType; - TStringBuf ContentLength; - TStringBuf TransferEncoding; - TStringBuf LastModified; - TStringBuf ContentEncoding; - - TStringBuf Body; - - static const TMap<TStringBuf, TStringBuf THttpResponse::*, TLessNoCase> HeadersLocation; - - template <TStringBuf THttpResponse::* Header> - static TStringBuf GetName(); - void Clear(); -}; - -template <typename HeaderType, typename BufferType> -class THttpParser : public HeaderType, public BufferType { -public: - enum class EParseStage : ui8 { - Method, - URL, - Protocol, - Version, - Status, - Message, - Header, - Body, - ChunkLength, - ChunkData, - Done, - Error, - }; - - static constexpr size_t MaxMethodSize = 8; - static constexpr size_t MaxURLSize = 2048; - static constexpr size_t MaxProtocolSize = 4; - static constexpr size_t MaxVersionSize = 4; - static constexpr size_t MaxStatusSize = 3; - static constexpr size_t MaxMessageSize = 1024; - static constexpr size_t MaxHeaderSize = 8192; - static constexpr size_t MaxChunkLengthSize = 8; - static constexpr size_t MaxChunkSize = 256 * 1024 * 1024; - static constexpr size_t MaxChunkContentSize = 1 * 1024 * 1024 * 1024; - - EParseStage Stage; - EParseStage LastSuccessStage; - TStringBuf Line; - TStringBuf& Header = Line; - size_t ChunkLength = 0; - size_t ContentSize = 0; - TString Content; // body storage - std::optional<size_t> TotalSize; - - THttpParser(const THttpParser& src) - : HeaderType(src) - , BufferType(src) - , Stage(src.Stage) - , LastSuccessStage(src.LastSuccessStage) - , Line() - , Header(Line) - , ChunkLength(src.ChunkLength) - , ContentSize(src.ContentSize) - , Content(src.Content) - {} - - template <typename StringType> - bool ProcessData(StringType& target, TStringBuf& source, char delim, size_t maxLen) { - TStringBuf maxSource(source.substr(0, maxLen + 1 - target.size())); - size_t pos = maxSource.find(delim); - target += maxSource.substr(0, pos); - source.Skip(pos); - if (target.size() > maxLen) { - Stage = EParseStage::Error; - return false; - } - if (!source.empty() && *source.begin() == delim) { - source.Skip(1); - } - return pos != TStringBuf::npos; - } - - template <typename StringType> - bool ProcessData(StringType& target, TStringBuf& source, TStringBuf delim, size_t maxLen) { - if (delim.empty()) { - return false; - } - if (delim.size() == 1) { - return ProcessData(target, source, delim[0], maxLen); - } - if (ProcessData(target, source, delim.back(), maxLen + 1)) { - for (signed i = delim.size() - 2; i >= 0; --i) { - TrimEnd(target, delim[i]); - } - return true; - } - return false; - } - - template <typename StringType> - bool ProcessData(StringType& target, TStringBuf& source, size_t size) { - TStringBuf maxSource(source.substr(0, size - target.size())); - target += maxSource; - source.Skip(maxSource.size()); - if (target.size() > size && !source.empty()) { - Stage = EParseStage::Error; - return false; - } - return target.size() == size; - } - - void ProcessHeader(TStringBuf& header) { - TStringBuf name = header.NextTok(':'); - TrimBegin(name, ' '); - TStringBuf value = header; - Trim(value, ' '); - auto cit = HeaderType::HeadersLocation.find(name); - if (cit != HeaderType::HeadersLocation.end()) { - this->*cit->second = value; - } - header.Clear(); - } - - size_t ParseHex(TStringBuf value) { - size_t result = 0; - for (char ch : value) { - if (ch >= '0' && ch <= '9') { - result *= 16; - result += ch - '0'; - } else if (ch >= 'a' && ch <= 'f') { - result *= 16; - result += 10 + ch - 'a'; - } else if (ch >= 'A' && ch <= 'F') { - result *= 16; - result += 10 + ch - 'A'; - } else if (ch == ';') { - break; - } else if (isspace(ch)) { - continue; - } else { - Stage = EParseStage::Error; - return 0; - } - } - return result; - } - - void Advance(size_t len); - void ConnectionClosed(); - - size_t GetBodySizeFromTotalSize() const { - return TotalSize.value() - (HeaderType::Headers.end() - BufferType::Data()); - } - - void Clear() { - BufferType::Clear(); - HeaderType::Clear(); - Stage = GetInitialStage(); - Line.Clear(); - Content.clear(); - } - - bool IsReady() const { - return Stage == EParseStage::Done; - } - - bool IsError() const { - return Stage == EParseStage::Error; - } - - TStringBuf GetErrorText() const { - switch (LastSuccessStage) { - case EParseStage::Method: - return "Invalid http method"; - case EParseStage::URL: - return "Invalid url"; - case EParseStage::Protocol: - return "Invalid http protocol"; - case EParseStage::Version: - return "Invalid http version"; - case EParseStage::Status: - return "Invalid http status"; - case EParseStage::Message: - return "Invalid http message"; - case EParseStage::Header: - return "Invalid http header"; - case EParseStage::Body: - return "Invalid content body"; - case EParseStage::ChunkLength: - case EParseStage::ChunkData: - return "Broken chunked data"; - case EParseStage::Done: - return "Everything is fine"; - case EParseStage::Error: - return "Error on error"; // wat? ...because we don't want to include default label here - } - } - - bool IsDone() const { - return IsReady() || IsError(); - } - - bool HaveBody() const; - - bool EnsureEnoughSpaceAvailable(size_t need = BufferType::BUFFER_MIN_STEP) { - bool result = BufferType::EnsureEnoughSpaceAvailable(need); - if (!result && !BufferType::Empty()) { - Reparse(); - } - return true; - } - - void Reparse() { - size_t size = BufferType::Size(); - Clear(); - Advance(size); - } - - TStringBuf GetRawData() const { - return TStringBuf(BufferType::Data(), BufferType::Size()); - } - - TString GetObfuscatedData() const { - THeaders headers(HeaderType::Headers); - TStringBuf authorization(headers["Authorization"]); - TStringBuf cookie(headers["Cookie"]); - TStringBuf x_ydb_auth_ticket(headers["x-ydb-auth-ticket"]); - TStringBuf x_yacloud_subjecttoken(headers["x-yacloud-subjecttoken"]); - TString data(GetRawData()); - if (!authorization.empty()) { - auto pos = data.find(authorization); - if (pos != TString::npos) { - data.replace(pos, authorization.size(), TString("<obfuscated>")); - } - } - if (!cookie.empty()) { - auto pos = data.find(cookie); - if (pos != TString::npos) { - data.replace(pos, cookie.size(), TString("<obfuscated>")); - } - } - if (!x_ydb_auth_ticket.empty()) { - auto pos = data.find(x_ydb_auth_ticket); - if (pos != TString::npos) { - data.replace(pos, x_ydb_auth_ticket.size(), TString("<obfuscated>")); - } - } - if (!x_yacloud_subjecttoken.empty()) { - auto pos = data.find(x_yacloud_subjecttoken); - if (pos != TString::npos) { - data.replace(pos, x_yacloud_subjecttoken.size(), TString("<obfuscated>")); - } - } - return data; - } - - static EParseStage GetInitialStage(); - - THttpParser() - : Stage(GetInitialStage()) - , LastSuccessStage(Stage) - {} - - THttpParser(TStringBuf data) - : Stage(GetInitialStage()) - , LastSuccessStage(Stage) - { - BufferType::Assign(data.data(), data.size()); - BufferType::Clear(); // reset position to 0 - TotalSize = data.size(); - Advance(data.size()); - } -}; - -template <typename HeaderType, typename BufferType> -class THttpRenderer : public HeaderType, public BufferType { -public: - enum class ERenderStage { - Init, - Header, - Body, - Done, - Error, - }; - - ERenderStage Stage = ERenderStage::Init; - TString Content; // body storage - - //THttpRenderer(TStringBuf method, TStringBuf url, TStringBuf protocol, TStringBuf version); // request - void InitRequest(TStringBuf method, TStringBuf url, TStringBuf protocol, TStringBuf version) { - Y_DEBUG_ABORT_UNLESS(Stage == ERenderStage::Init); - AppendParsedValue<&THttpRequest::Method>(method); - Append(' '); - AppendParsedValue<&THttpRequest::URL>(url); - Append(' '); - AppendParsedValue<&THttpRequest::Protocol>(protocol); - Append('/'); - AppendParsedValue<&THttpRequest::Version>(version); - Append("\r\n"); - Stage = ERenderStage::Header; - HeaderType::Headers = TStringBuf(BufferType::Pos(), size_t(0)); - } - - //THttpRenderer(TStringBuf protocol, TStringBuf version, TStringBuf status, TStringBuf message); // response - void InitResponse(TStringBuf protocol, TStringBuf version, TStringBuf status, TStringBuf message) { - Y_DEBUG_ABORT_UNLESS(Stage == ERenderStage::Init); - AppendParsedValue<&THttpResponse::Protocol>(protocol); - Append('/'); - AppendParsedValue<&THttpResponse::Version>(version); - Append(' '); - AppendParsedValue<&THttpResponse::Status>(status); - Append(' '); - AppendParsedValue<&THttpResponse::Message>(message); - Append("\r\n"); - Stage = ERenderStage::Header; - HeaderType::Headers = TStringBuf(BufferType::Pos(), size_t(0)); - } - - void Append(TStringBuf text) { - EnsureEnoughSpaceAvailable(text.size()); - BufferType::Append(text.data(), text.size()); - } - - void Append(char c) { - EnsureEnoughSpaceAvailable(sizeof(c)); - BufferType::Append(c); - } - - template <TStringBuf HeaderType::* string> - void AppendParsedValue(TStringBuf value) { - Append(value); - static_cast<HeaderType*>(this)->*string = TStringBuf(BufferType::Pos() - value.size(), value.size()); - } - - template <TStringBuf HeaderType::* name> - void Set(TStringBuf value) { - Y_DEBUG_ABORT_UNLESS(Stage == ERenderStage::Header); - Append(HeaderType::template GetName<name>()); - Append(": "); - AppendParsedValue<name>(value); - Append("\r\n"); - HeaderType::Headers = TStringBuf(HeaderType::Headers.Data(), BufferType::Pos() - HeaderType::Headers.Data()); - } - - void Set(TStringBuf name, TStringBuf value) { - Y_DEBUG_ABORT_UNLESS(Stage == ERenderStage::Header); - Append(name); - Append(": "); - auto data = BufferType::Pos(); - Append(value); - auto cit = HeaderType::HeadersLocation.find(name); - if (cit != HeaderType::HeadersLocation.end()) { - (this->*cit->second) = TStringBuf(data, BufferType::Pos()); - } - Append("\r\n"); - HeaderType::Headers = TStringBuf(HeaderType::Headers.Data(), BufferType::Pos() - HeaderType::Headers.Data()); - } - - void Set(const THeaders& headers) { - Y_DEBUG_ABORT_UNLESS(Stage == ERenderStage::Header); - for (const auto& [name, value] : headers.Headers) { - Set(name, value); - } - HeaderType::Headers = TStringBuf(HeaderType::Headers.Data(), BufferType::Pos() - HeaderType::Headers.Data()); - } - - static constexpr TStringBuf ALLOWED_CONTENT_ENCODINGS[] = {"deflate"}; - - void SetContentEncoding(TStringBuf contentEncoding) { - Y_DEBUG_ABORT_UNLESS(Stage == ERenderStage::Header); - if (Count(ALLOWED_CONTENT_ENCODINGS, contentEncoding) != 0) { - Set("Content-Encoding", contentEncoding); - } - } - - void FinishHeader() { - Append("\r\n"); - HeaderType::Headers = TStringBuf(HeaderType::Headers.Data(), BufferType::Pos() - HeaderType::Headers.Data()); - Stage = ERenderStage::Body; - } - - void SetBody(TStringBuf body) { - Y_DEBUG_ABORT_UNLESS(Stage == ERenderStage::Header); - if (HeaderType::ContentLength.empty()) { - Set<&HeaderType::ContentLength>(ToString(body.size())); - } - FinishHeader(); - AppendParsedValue<&HeaderType::Body>(body); - Stage = ERenderStage::Done; - } - - void FinishBody() { - Stage = ERenderStage::Done; - } - - bool IsDone() const { - return Stage == ERenderStage::Done; - } - - void Finish() { - switch (Stage) { - case ERenderStage::Header: - FinishHeader(); - FinishBody(); - break; - case ERenderStage::Body: - FinishBody(); - break; - default: - break; - } - } - - bool EnsureEnoughSpaceAvailable(size_t need = BufferType::BUFFER_MIN_STEP) { - bool result = BufferType::EnsureEnoughSpaceAvailable(need); - if (!result && !BufferType::Empty()) { - Reparse(); - } - return true; - } - - void Clear() { - BufferType::Clear(); - HeaderType::Clear(); - } - - void Reparse() { - // move-magic - size_t size = BufferType::Size(); - THttpParser<HeaderType, BufferType> parser; - // move the buffer to parser - static_cast<BufferType&>(parser) = std::move(static_cast<BufferType&>(*this)); - // reparse - parser.Clear(); - parser.Advance(size); - // move buffer and result back - bool needReassignBody = (parser.Body.data() == parser.Content.data()); - static_cast<HeaderType&>(*this) = std::move(static_cast<HeaderType&>(parser)); - static_cast<BufferType&>(*this) = std::move(static_cast<BufferType&>(parser)); - if (needReassignBody) { - Content = std::move(parser.Content); - HeaderType::Body = Content; - } - switch (parser.Stage) { - case THttpParser<HeaderType, BufferType>::EParseStage::Method: - case THttpParser<HeaderType, BufferType>::EParseStage::URL: - case THttpParser<HeaderType, BufferType>::EParseStage::Protocol: - case THttpParser<HeaderType, BufferType>::EParseStage::Version: - case THttpParser<HeaderType, BufferType>::EParseStage::Status: - case THttpParser<HeaderType, BufferType>::EParseStage::Message: - Stage = ERenderStage::Init; - break; - case THttpParser<HeaderType, BufferType>::EParseStage::Header: - Stage = ERenderStage::Header; - break; - case THttpParser<HeaderType, BufferType>::EParseStage::Body: - case THttpParser<HeaderType, BufferType>::EParseStage::ChunkLength: - case THttpParser<HeaderType, BufferType>::EParseStage::ChunkData: - Stage = ERenderStage::Body; - break; - case THttpParser<HeaderType, BufferType>::EParseStage::Done: - Stage = ERenderStage::Done; - break; - case THttpParser<HeaderType, BufferType>::EParseStage::Error: - Stage = ERenderStage::Error; - break; - } - Y_ABORT_UNLESS(size == BufferType::Size()); - } - - TStringBuf GetRawData() const { - return TStringBuf(BufferType::Data(), BufferType::Size()); - } -}; - -template <> -template <> -inline void THttpRenderer<THttpResponse, TSocketBuffer>::Set<&THttpResponse::Body>(TStringBuf value) { - SetBody(value); -} - -template <> -template <> -inline void THttpRenderer<THttpRequest, TSocketBuffer>::Set<&THttpRequest::Body>(TStringBuf value) { - SetBody(value); -} - -template <> -template <> -inline void THttpRenderer<THttpResponse, TSocketBuffer>::Set<&THttpResponse::ContentEncoding>(TStringBuf value) { - SetContentEncoding(value); -} - -struct THttpEndpointInfo { - TString WorkerName; - bool Secure = false; - const std::vector<TString> CompressContentTypes; // content types, which will be automatically compressed on response - - THttpEndpointInfo() = default; - -protected: - THttpEndpointInfo(std::vector<TString> compressContentTypes) - : CompressContentTypes(std::move(compressContentTypes)) - {} -}; - -class THttpIncomingRequest; -using THttpIncomingRequestPtr = TIntrusivePtr<THttpIncomingRequest>; - -class THttpOutgoingResponse; -using THttpOutgoingResponsePtr = TIntrusivePtr<THttpOutgoingResponse>; - -class THttpIncomingRequest : - public THttpParser<THttpRequest, TSocketBuffer>, - public TRefCounted<THttpIncomingRequest, TAtomicCounter> { -public: - std::shared_ptr<THttpEndpointInfo> Endpoint; - THttpConfig::SocketAddressType Address; - THPTimer Timer; - - THttpIncomingRequest() - : Endpoint(std::make_shared<THttpEndpointInfo>()) - {} - - THttpIncomingRequest(std::shared_ptr<THttpEndpointInfo> endpoint, const THttpConfig::SocketAddressType& address) - : Endpoint(std::move(endpoint)) - , Address(address) - {} - - THttpIncomingRequest(TStringBuf content, std::shared_ptr<THttpEndpointInfo> endpoint, const THttpConfig::SocketAddressType& address) - : THttpParser(content) - , Endpoint(std::move(endpoint)) - , Address(address) - {} - - bool IsConnectionClose() const { - if (Connection.empty()) { - return Version == "1.0"; - } else { - return TEqNoCase()(Connection, "close"); - } - } - - TStringBuf GetConnection() const { - if (!Connection.empty()) { - if (TEqNoCase()(Connection, "keep-alive")) { - return "keep-alive"; - } - if (TEqNoCase()(Connection, "close")) { - return "close"; - } - } - return Version == "1.0" ? "close" : "keep-alive"; - } - - THttpOutgoingResponsePtr CreateResponseOK(TStringBuf body, TStringBuf contentType = "text/html", TInstant lastModified = TInstant()); - THttpOutgoingResponsePtr CreateResponseString(TStringBuf data); - THttpOutgoingResponsePtr CreateResponseBadRequest(TStringBuf html = TStringBuf(), TStringBuf contentType = "text/html"); // 400 - THttpOutgoingResponsePtr CreateResponseNotFound(TStringBuf html = TStringBuf(), TStringBuf contentType = "text/html"); // 404 - THttpOutgoingResponsePtr CreateResponseServiceUnavailable(TStringBuf html = TStringBuf(), TStringBuf contentType = "text/html"); // 503 - THttpOutgoingResponsePtr CreateResponseGatewayTimeout(TStringBuf html = TStringBuf(), TStringBuf contentType = "text/html"); // 504 - THttpOutgoingResponsePtr CreateResponse(TStringBuf status, TStringBuf message); - THttpOutgoingResponsePtr CreateResponse(TStringBuf status, TStringBuf message, const THeaders& headers); - THttpOutgoingResponsePtr CreateResponse(TStringBuf status, TStringBuf message, const THeaders& headers, TStringBuf body); - THttpOutgoingResponsePtr CreateResponse( - TStringBuf status, - TStringBuf message, - TStringBuf contentType, - TStringBuf body = TStringBuf(), - TInstant lastModified = TInstant()); - - THttpOutgoingResponsePtr CreateIncompleteResponse(TStringBuf status, TStringBuf message, const THeaders& headers = {}); - THttpOutgoingResponsePtr CreateIncompleteResponse(TStringBuf status, TStringBuf message, const THeaders& headers, TStringBuf body); - - THttpIncomingRequestPtr Duplicate(); - -private: - THttpOutgoingResponsePtr ConstructResponse(TStringBuf status, TStringBuf message); - void FinishResponse(THttpOutgoingResponsePtr& response, TStringBuf body = TStringBuf()); -}; - -class THttpIncomingResponse; -using THttpIncomingResponsePtr = TIntrusivePtr<THttpIncomingResponse>; - -class THttpOutgoingRequest; -using THttpOutgoingRequestPtr = TIntrusivePtr<THttpOutgoingRequest>; - -class THttpIncomingResponse : - public THttpParser<THttpResponse, TSocketBuffer>, - public TRefCounted<THttpIncomingResponse, TAtomicCounter> { -public: - THttpIncomingResponse(THttpOutgoingRequestPtr request); - - THttpOutgoingRequestPtr GetRequest() const { - return Request; - } - - THttpIncomingResponsePtr Duplicate(THttpOutgoingRequestPtr request); - THttpOutgoingResponsePtr Reverse(THttpIncomingRequestPtr request); - -protected: - THttpOutgoingRequestPtr Request; -}; - -class THttpOutgoingRequest : - public THttpRenderer<THttpRequest, TSocketBuffer>, - public TRefCounted<THttpOutgoingRequest, TAtomicCounter> { -public: - THPTimer Timer; - bool Secure = false; - - THttpOutgoingRequest() = default; - THttpOutgoingRequest(TStringBuf method, TStringBuf url, TStringBuf protocol, TStringBuf version); - THttpOutgoingRequest(TStringBuf method, TStringBuf scheme, TStringBuf host, TStringBuf uri, TStringBuf protocol, TStringBuf version); - static THttpOutgoingRequestPtr CreateRequestString(TStringBuf data); - static THttpOutgoingRequestPtr CreateRequestString(const TString& data); - static THttpOutgoingRequestPtr CreateRequestGet(TStringBuf url); - static THttpOutgoingRequestPtr CreateRequestGet(TStringBuf host, TStringBuf uri); // http only - static THttpOutgoingRequestPtr CreateRequestPost(TStringBuf url, TStringBuf contentType = {}, TStringBuf body = {}); - static THttpOutgoingRequestPtr CreateRequestPost(TStringBuf host, TStringBuf uri, TStringBuf contentType, TStringBuf body); // http only - static THttpOutgoingRequestPtr CreateRequest(TStringBuf method, TStringBuf url, TStringBuf contentType = TStringBuf(), TStringBuf body = TStringBuf()); - static THttpOutgoingRequestPtr CreateHttpRequest(TStringBuf method, TStringBuf host, TStringBuf uri, TStringBuf contentType = TStringBuf(), TStringBuf body = TStringBuf()); - THttpOutgoingRequestPtr Duplicate(); -}; - -class THttpOutgoingResponse : - public THttpRenderer<THttpResponse, TSocketBuffer>, - public TRefCounted<THttpOutgoingResponse, TAtomicCounter> { -public: - THttpOutgoingResponse(THttpIncomingRequestPtr request); - THttpOutgoingResponse(THttpIncomingRequestPtr request, TStringBuf protocol, TStringBuf version, TStringBuf status, TStringBuf message); - - bool IsConnectionClose() const { - if (!Connection.empty()) { - return TEqNoCase()(Connection, "close"); - } else { - return Request->IsConnectionClose(); - } - } - - bool IsNeedBody() const { - return GetRequest()->Method != "HEAD" && Status != "204"; - } - - bool EnableCompression() { - TStringBuf acceptEncoding = Request->AcceptEncoding; - std::vector<TStringBuf> encodings; - TStringBuf encoding; - while (acceptEncoding.NextTok(',', encoding)) { - Trim(encoding, ' '); - if (Count(ALLOWED_CONTENT_ENCODINGS, encoding) != 0) { - encodings.push_back(encoding); - } - } - if (!encodings.empty()) { - // TODO: prioritize encodings - SetContentEncoding(encodings.front()); - return true; - } - return false; - } - - void SetBody(TStringBuf body) { - if (ContentEncoding == "deflate") { - TString compressedBody = CompressDeflate(body); - THttpRenderer<THttpResponse, TSocketBuffer>::SetBody(compressedBody); - Body = Content = body; - } else { - THttpRenderer<THttpResponse, TSocketBuffer>::SetBody(body); - } - } - - void SetBody(const TString& body) { - if (ContentEncoding == "deflate") { - TString compressedBody = CompressDeflate(body); - THttpRenderer<THttpResponse, TSocketBuffer>::SetBody(compressedBody); - Body = Content = body; - } else { - THttpRenderer<THttpResponse, TSocketBuffer>::SetBody(body); - } - } - - THttpIncomingRequestPtr GetRequest() const { - return Request; - } - - THttpOutgoingResponsePtr Duplicate(THttpIncomingRequestPtr request); - -// it's temporary accessible for cleanup -//protected: - THttpIncomingRequestPtr Request; - std::unique_ptr<TSensors> Sensors; -}; - -} diff --git a/library/cpp/actors/http/http_cache.cpp b/library/cpp/actors/http/http_cache.cpp deleted file mode 100644 index d2856f70c2..0000000000 --- a/library/cpp/actors/http/http_cache.cpp +++ /dev/null @@ -1,608 +0,0 @@ -#include "http.h" -#include "http_proxy.h" -#include "http_cache.h" -#include <library/cpp/actors/core/actor_bootstrapped.h> -#include <library/cpp/actors/core/executor_pool_basic.h> -#include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/core/scheduler_basic.h> -#include <library/cpp/actors/http/http.h> -#include <library/cpp/digest/md5/md5.h> -#include <util/digest/multi.h> -#include <util/generic/queue.h> -#include <util/string/cast.h> - -namespace NHttp { - -static bool StatusSuccess(const TStringBuf& status) { - return status.StartsWith("2"); -} - -class THttpOutgoingCacheActor : public NActors::TActorBootstrapped<THttpOutgoingCacheActor>, THttpConfig { -public: - using TBase = NActors::TActorBootstrapped<THttpOutgoingCacheActor>; - NActors::TActorId HttpProxyId; - TGetCachePolicy GetCachePolicy; - static constexpr TDuration RefreshTimeout = TDuration::Seconds(1); - - struct TCacheKey { - TString Host; - TString URL; - TString Headers; - - operator size_t() const { - return MultiHash(Host, URL, Headers); - } - - TString GetId() const { - return MD5::Calc(Host + ':' + URL + ':' + Headers); - } - }; - - struct TCacheRecord { - TInstant RefreshTime; - TInstant DeathTime; - TCachePolicy CachePolicy; - NHttp::THttpOutgoingRequestPtr Request; - NHttp::THttpOutgoingRequestPtr OutgoingRequest; - TDuration Timeout; - NHttp::THttpIncomingResponsePtr Response; - TString Error; - TVector<NHttp::TEvHttpProxy::TEvHttpOutgoingRequest::TPtr> Waiters; - - TCacheRecord(const TCachePolicy cachePolicy) - : CachePolicy(cachePolicy) - {} - - bool IsValid() const { - return Response != nullptr || !Error.empty(); - } - - void UpdateResponse(NHttp::THttpIncomingResponsePtr response, const TString& error, TInstant now) { - if (error.empty() || Response == nullptr || !CachePolicy.KeepOnError) { - Response = response; - Error = error; - } - RefreshTime = now + CachePolicy.TimeToRefresh; - if (CachePolicy.PaceToRefresh) { - RefreshTime += TDuration::MilliSeconds(RandomNumber<ui64>() % CachePolicy.PaceToRefresh.MilliSeconds()); - } - } - - TString GetName() const { - return TStringBuilder() << (Request->Secure ? "https://" : "http://") << Request->Host << Request->URL; - } - }; - - struct TRefreshRecord { - TCacheKey Key; - TInstant RefreshTime; - - bool operator <(const TRefreshRecord& b) const { - return RefreshTime > b.RefreshTime; - } - }; - - THashMap<TCacheKey, TCacheRecord> Cache; - TPriorityQueue<TRefreshRecord> RefreshQueue; - THashMap<THttpOutgoingRequest*, TCacheKey> OutgoingRequests; - - THttpOutgoingCacheActor(const NActors::TActorId& httpProxyId, TGetCachePolicy getCachePolicy) - : HttpProxyId(httpProxyId) - , GetCachePolicy(std::move(getCachePolicy)) - {} - - static constexpr char ActorName[] = "HTTP_OUT_CACHE_ACTOR"; - - void Bootstrap(const NActors::TActorContext&) { - // - Become(&THttpOutgoingCacheActor::StateWork, RefreshTimeout, new NActors::TEvents::TEvWakeup()); - } - - static TString GetCacheHeadersKey(const NHttp::THttpOutgoingRequest* request, const TCachePolicy& policy) { - TStringBuilder key; - if (!policy.HeadersToCacheKey.empty()) { - NHttp::THeaders headers(request->Headers); - for (const TString& header : policy.HeadersToCacheKey) { - key << headers[header]; - } - } - return key; - } - - static TCacheKey GetCacheKey(const NHttp::THttpOutgoingRequest* request, const TCachePolicy& policy) { - return { ToString(request->Host), ToString(request->URL), GetCacheHeadersKey(request, policy) }; - } - - void Handle(NHttp::TEvHttpProxy::TEvHttpOutgoingResponse::TPtr event, const NActors::TActorContext& ctx) { - ctx.Send(event->Forward(HttpProxyId)); - } - - void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) { - ctx.Send(event->Forward(HttpProxyId)); - } - - void Handle(NHttp::TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) { - ctx.Send(event->Forward(HttpProxyId)); - } - - void Handle(NHttp::TEvHttpProxy::TEvRegisterHandler::TPtr event, const NActors::TActorContext& ctx) { - ctx.Send(event->Forward(HttpProxyId)); - } - - void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingResponse::TPtr event, const NActors::TActorContext& ctx) { - NHttp::THttpOutgoingRequestPtr request(event->Get()->Request); - NHttp::THttpIncomingResponsePtr response(event->Get()->Response); - auto itRequests = OutgoingRequests.find(request.Get()); - if (itRequests == OutgoingRequests.end()) { - LOG_ERROR_S(ctx, HttpLog, "Cache received response to unknown request " << request->Host << request->URL); - return; - } - auto key = itRequests->second; - OutgoingRequests.erase(itRequests); - auto it = Cache.find(key); - if (it == Cache.end()) { - LOG_ERROR_S(ctx, HttpLog, "Cache received response to unknown cache key " << request->Host << request->URL); - return; - } - TCacheRecord& cacheRecord = it->second; - cacheRecord.OutgoingRequest.Reset(); - for (auto& waiter : cacheRecord.Waiters) { - NHttp::THttpIncomingResponsePtr response2; - TString error2; - if (response != nullptr) { - response2 = response->Duplicate(waiter->Get()->Request); - } - if (!event->Get()->Error.empty()) { - error2 = event->Get()->Error; - } - ctx.Send(waiter->Sender, new NHttp::TEvHttpProxy::TEvHttpIncomingResponse(waiter->Get()->Request, response2, error2)); - } - cacheRecord.Waiters.clear(); - TString error; - if (event->Get()->Error.empty()) { - if (event->Get()->Response != nullptr && !StatusSuccess(event->Get()->Response->Status)) { - error = event->Get()->Response->Message; - } - } else { - error = event->Get()->Error; - } - if (!error.empty()) { - LOG_WARN_S(ctx, HttpLog, "Error from " << cacheRecord.GetName() << ": " << error); - } - LOG_DEBUG_S(ctx, HttpLog, "OutgoingUpdate " << cacheRecord.GetName()); - cacheRecord.UpdateResponse(response, event->Get()->Error, ctx.Now()); - RefreshQueue.push({it->first, it->second.RefreshTime}); - LOG_DEBUG_S(ctx, HttpLog, "OutgoingSchedule " << cacheRecord.GetName() << " at " << cacheRecord.RefreshTime << " until " << cacheRecord.DeathTime); - } - - void Handle(NHttp::TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) { - const NHttp::THttpOutgoingRequest* request = event->Get()->Request.Get(); - auto policy = GetCachePolicy(request); - if (policy.TimeToExpire == TDuration()) { - ctx.Send(event->Forward(HttpProxyId)); - return; - } - auto key = GetCacheKey(request, policy); - auto it = Cache.find(key); - if (it != Cache.end()) { - if (it->second.IsValid()) { - LOG_DEBUG_S(ctx, HttpLog, "OutgoingRespond " - << it->second.GetName() - << " (" - << ((it->second.Response != nullptr) ? ToString(it->second.Response->Size()) : TString("error")) - << ")"); - NHttp::THttpIncomingResponsePtr response = it->second.Response; - if (response != nullptr) { - response = response->Duplicate(event->Get()->Request); - } - ctx.Send(event->Sender, - new NHttp::TEvHttpProxy::TEvHttpIncomingResponse(event->Get()->Request, - response, - it->second.Error)); - it->second.DeathTime = ctx.Now() + it->second.CachePolicy.TimeToExpire; // prolong active cache items - return; - } - } else { - it = Cache.emplace(key, policy).first; - it->second.Request = event->Get()->Request; - it->second.Timeout = event->Get()->Timeout; - it->second.OutgoingRequest = it->second.Request->Duplicate(); - OutgoingRequests[it->second.OutgoingRequest.Get()] = key; - LOG_DEBUG_S(ctx, HttpLog, "OutgoingInitiate " << it->second.GetName()); - ctx.Send(HttpProxyId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(it->second.OutgoingRequest, it->second.Timeout)); - } - it->second.DeathTime = ctx.Now() + it->second.CachePolicy.TimeToExpire; - it->second.Waiters.emplace_back(std::move(event)); - } - - void HandleRefresh(const NActors::TActorContext& ctx) { - while (!RefreshQueue.empty() && RefreshQueue.top().RefreshTime <= ctx.Now()) { - TRefreshRecord rrec = RefreshQueue.top(); - RefreshQueue.pop(); - auto it = Cache.find(rrec.Key); - if (it != Cache.end()) { - if (it->second.DeathTime > ctx.Now()) { - LOG_DEBUG_S(ctx, HttpLog, "OutgoingRefresh " << it->second.GetName()); - it->second.OutgoingRequest = it->second.Request->Duplicate(); - OutgoingRequests[it->second.OutgoingRequest.Get()] = it->first; - ctx.Send(HttpProxyId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(it->second.OutgoingRequest, it->second.Timeout)); - } else { - LOG_DEBUG_S(ctx, HttpLog, "OutgoingForget " << it->second.GetName()); - if (it->second.OutgoingRequest) { - OutgoingRequests.erase(it->second.OutgoingRequest.Get()); - } - Cache.erase(it); - } - } - } - ctx.Schedule(RefreshTimeout, new NActors::TEvents::TEvWakeup()); - } - - STFUNC(StateWork) { - switch (ev->GetTypeRewrite()) { - HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingResponse, Handle); - HFunc(NHttp::TEvHttpProxy::TEvHttpOutgoingRequest, Handle); - HFunc(NHttp::TEvHttpProxy::TEvAddListeningPort, Handle); - HFunc(NHttp::TEvHttpProxy::TEvRegisterHandler, Handle); - HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingRequest, Handle); - HFunc(NHttp::TEvHttpProxy::TEvHttpOutgoingResponse, Handle); - CFunc(NActors::TEvents::TSystem::Wakeup, HandleRefresh); - } - } -}; - -const TDuration THttpOutgoingCacheActor::RefreshTimeout; - -class THttpIncomingCacheActor : public NActors::TActorBootstrapped<THttpIncomingCacheActor>, THttpConfig { -public: - using TBase = NActors::TActorBootstrapped<THttpIncomingCacheActor>; - NActors::TActorId HttpProxyId; - TGetCachePolicy GetCachePolicy; - static constexpr TDuration RefreshTimeout = TDuration::Seconds(1); - THashMap<TString, TActorId> Handlers; - - struct TCacheKey { - TString Host; - TString URL; - TString Headers; - - operator size_t() const { - return MultiHash(Host, URL, Headers); - } - - TString GetId() const { - return MD5::Calc(Host + ':' + URL + ':' + Headers); - } - }; - - struct TCacheRecord { - TInstant RefreshTime; - TInstant DeathTime; - TCachePolicy CachePolicy; - TString CacheId; - NHttp::THttpIncomingRequestPtr Request; - TDuration Timeout; - NHttp::THttpOutgoingResponsePtr Response; - TVector<NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr> Waiters; - ui32 Retries = 0; - bool Enqueued = false; - - TCacheRecord(const TCachePolicy cachePolicy) - : CachePolicy(cachePolicy) - {} - - bool IsValid() const { - return Response != nullptr; - } - - void InitRequest(NHttp::THttpIncomingRequestPtr request) { - Request = request; - if (CachePolicy.TimeToExpire) { - DeathTime = NActors::TlsActivationContext->Now() + CachePolicy.TimeToExpire; - } - } - - void UpdateResponse(NHttp::THttpOutgoingResponsePtr response, const TString& error, TInstant now) { - if (error.empty() || !CachePolicy.KeepOnError) { - Response = response; - } - Retries = 0; - if (CachePolicy.TimeToRefresh) { - RefreshTime = now + CachePolicy.TimeToRefresh; - if (CachePolicy.PaceToRefresh) { - RefreshTime += TDuration::MilliSeconds(RandomNumber<ui64>() % CachePolicy.PaceToRefresh.MilliSeconds()); - } - } - } - - void UpdateExpireTime() { - if (CachePolicy.TimeToExpire) { - DeathTime = NActors::TlsActivationContext->Now() + CachePolicy.TimeToExpire; - } - } - - TString GetName() const { - return TStringBuilder() << (Request->Endpoint->Secure ? "https://" : "http://") << Request->Host << Request->URL - << " (" << CacheId << ")"; - } - }; - - struct TRefreshRecord { - TCacheKey Key; - TInstant RefreshTime; - - bool operator <(const TRefreshRecord& b) const { - return RefreshTime > b.RefreshTime; - } - }; - - THashMap<TCacheKey, TCacheRecord> Cache; - TPriorityQueue<TRefreshRecord> RefreshQueue; - THashMap<THttpIncomingRequest*, TCacheKey> IncomingRequests; - - THttpIncomingCacheActor(const NActors::TActorId& httpProxyId, TGetCachePolicy getCachePolicy) - : HttpProxyId(httpProxyId) - , GetCachePolicy(std::move(getCachePolicy)) - {} - - static constexpr char ActorName[] = "HTTP_IN_CACHE_ACTOR"; - - void Bootstrap(const NActors::TActorContext&) { - // - Become(&THttpIncomingCacheActor::StateWork, RefreshTimeout, new NActors::TEvents::TEvWakeup()); - } - - static TString GetCacheHeadersKey(const NHttp::THttpIncomingRequest* request, const TCachePolicy& policy) { - TStringBuilder key; - if (!policy.HeadersToCacheKey.empty()) { - NHttp::THeaders headers(request->Headers); - for (const TString& header : policy.HeadersToCacheKey) { - key << headers[header]; - } - } - return key; - } - - static TCacheKey GetCacheKey(const NHttp::THttpIncomingRequest* request, const TCachePolicy& policy) { - return { ToString(request->Host), ToString(request->URL), GetCacheHeadersKey(request, policy) }; - } - - TActorId GetRequestHandler(NHttp::THttpIncomingRequestPtr request) { - TStringBuf url = request->URL.Before('?'); - THashMap<TString, TActorId>::iterator it; - while (!url.empty()) { - it = Handlers.find(url); - if (it != Handlers.end()) { - return it->second; - } else { - if (url.EndsWith('/')) { - url.Trunc(url.size() - 1); - } - size_t pos = url.rfind('/'); - if (pos == TStringBuf::npos) { - break; - } else { - url = url.substr(0, pos + 1); - } - } - } - return {}; - } - - void SendCacheRequest(const TCacheKey& cacheKey, TCacheRecord& cacheRecord, const NActors::TActorContext& ctx) { - cacheRecord.Request = cacheRecord.Request->Duplicate(); - cacheRecord.Request->AcceptEncoding.Clear(); // disable compression - IncomingRequests[cacheRecord.Request.Get()] = cacheKey; - TActorId handler = GetRequestHandler(cacheRecord.Request); - if (handler) { - Send(handler, new NHttp::TEvHttpProxy::TEvHttpIncomingRequest(cacheRecord.Request)); - } else { - LOG_ERROR_S(ctx, HttpLog, "Can't find cache handler for " << cacheRecord.GetName()); - } - } - - void DropCacheRecord(THashMap<TCacheKey, TCacheRecord>::iterator it) { - if (it->second.Request) { - IncomingRequests.erase(it->second.Request.Get()); - } - for (auto& waiter : it->second.Waiters) { - NHttp::THttpOutgoingResponsePtr response; - response = waiter->Get()->Request->CreateResponseGatewayTimeout("Timeout", "text/plain"); - Send(waiter->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response)); - } - Cache.erase(it); - } - - void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingResponse::TPtr event, const NActors::TActorContext& ctx) { - ctx.Send(event->Forward(HttpProxyId)); - } - - void Handle(NHttp::TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) { - ctx.Send(event->Forward(HttpProxyId)); - } - - void Handle(NHttp::TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) { - ctx.Send(event->Forward(HttpProxyId)); - } - - void Handle(NHttp::TEvHttpProxy::TEvRegisterHandler::TPtr event, const NActors::TActorContext& ctx) { - Handlers[event->Get()->Path] = event->Get()->Handler; - ctx.Send(HttpProxyId, new NHttp::TEvHttpProxy::TEvRegisterHandler(event->Get()->Path, ctx.SelfID)); - } - - void Handle(NHttp::TEvHttpProxy::TEvHttpOutgoingResponse::TPtr event, const NActors::TActorContext& ctx) { - NHttp::THttpIncomingRequestPtr request(event->Get()->Response->GetRequest()); - NHttp::THttpOutgoingResponsePtr response(event->Get()->Response); - auto itRequests = IncomingRequests.find(request.Get()); - if (itRequests == IncomingRequests.end()) { - LOG_ERROR_S(ctx, HttpLog, "Cache received response to unknown request " << request->Host << request->URL); - return; - } - - TCacheKey key = itRequests->second; - auto it = Cache.find(key); - if (it == Cache.end()) { - LOG_ERROR_S(ctx, HttpLog, "Cache received response to unknown cache key " << request->Host << request->URL); - return; - } - - IncomingRequests.erase(itRequests); - TCacheRecord& cacheRecord = it->second; - TStringBuf status; - TString error; - - if (event->Get()->Response != nullptr) { - status = event->Get()->Response->Status; - if (!StatusSuccess(status)) { - error = event->Get()->Response->Message; - } - } - if (cacheRecord.CachePolicy.RetriesCount > 0) { - auto itStatusToRetry = std::find(cacheRecord.CachePolicy.StatusesToRetry.begin(), cacheRecord.CachePolicy.StatusesToRetry.end(), status); - if (itStatusToRetry != cacheRecord.CachePolicy.StatusesToRetry.end()) { - if (cacheRecord.Retries < cacheRecord.CachePolicy.RetriesCount) { - ++cacheRecord.Retries; - LOG_WARN_S(ctx, HttpLog, "IncomingRetry " << cacheRecord.GetName() << ": " << status << " " << error); - SendCacheRequest(key, cacheRecord, ctx); - return; - } - } - } - for (auto& waiter : cacheRecord.Waiters) { - NHttp::THttpOutgoingResponsePtr response2; - response2 = response->Duplicate(waiter->Get()->Request); - ctx.Send(waiter->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response2)); - } - cacheRecord.Waiters.clear(); - if (!error.empty()) { - LOG_WARN_S(ctx, HttpLog, "Error from " << cacheRecord.GetName() << ": " << error); - if (!cacheRecord.Response) { - LOG_DEBUG_S(ctx, HttpLog, "IncomingDiscard " << cacheRecord.GetName()); - DropCacheRecord(it); - return; - } - } - if (cacheRecord.CachePolicy.TimeToRefresh) { - LOG_DEBUG_S(ctx, HttpLog, "IncomingUpdate " << cacheRecord.GetName()); - cacheRecord.UpdateResponse(response, error, ctx.Now()); - if (!cacheRecord.Enqueued) { - RefreshQueue.push({it->first, it->second.RefreshTime}); - cacheRecord.Enqueued = true; - } - LOG_DEBUG_S(ctx, HttpLog, "IncomingSchedule " << cacheRecord.GetName() << " at " << cacheRecord.RefreshTime << " until " << cacheRecord.DeathTime); - } else { - LOG_DEBUG_S(ctx, HttpLog, "IncomingDrop " << cacheRecord.GetName()); - DropCacheRecord(it); - } - } - - void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) { - const NHttp::THttpIncomingRequest* request = event->Get()->Request.Get(); - TCachePolicy policy = GetCachePolicy(request); - if (policy.TimeToExpire == TDuration() && policy.RetriesCount == 0) { - TActorId handler = GetRequestHandler(event->Get()->Request); - if (handler) { - ctx.Send(event->Forward(handler)); - } - return; - } - auto key = GetCacheKey(request, policy); - auto it = Cache.find(key); - if (it != Cache.end() && !policy.DiscardCache) { - it->second.UpdateExpireTime(); - if (it->second.IsValid()) { - LOG_DEBUG_S(ctx, HttpLog, "IncomingRespond " - << it->second.GetName() - << " (" - << ((it->second.Response != nullptr) ? ToString(it->second.Response->Size()) : TString("error")) - << ")"); - NHttp::THttpOutgoingResponsePtr response = it->second.Response; - if (response != nullptr) { - response = response->Duplicate(event->Get()->Request); - } - ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response)); - return; - } - } else { - it = Cache.emplace(key, policy).first; - it->second.CacheId = key.GetId(); // for debugging - it->second.InitRequest(event->Get()->Request); - if (policy.DiscardCache) { - LOG_DEBUG_S(ctx, HttpLog, "IncomingDiscardCache " << it->second.GetName()); - } - LOG_DEBUG_S(ctx, HttpLog, "IncomingInitiate " << it->second.GetName()); - SendCacheRequest(key, it->second, ctx); - } - it->second.Waiters.emplace_back(std::move(event)); - } - - void HandleRefresh(const NActors::TActorContext& ctx) { - while (!RefreshQueue.empty() && RefreshQueue.top().RefreshTime <= ctx.Now()) { - TRefreshRecord rrec = RefreshQueue.top(); - RefreshQueue.pop(); - auto it = Cache.find(rrec.Key); - if (it != Cache.end()) { - it->second.Enqueued = false; - if (it->second.DeathTime > ctx.Now()) { - LOG_DEBUG_S(ctx, HttpLog, "IncomingRefresh " << it->second.GetName()); - SendCacheRequest(it->first, it->second, ctx); - } else { - LOG_DEBUG_S(ctx, HttpLog, "IncomingForget " << it->second.GetName()); - DropCacheRecord(it); - } - } - } - ctx.Schedule(RefreshTimeout, new NActors::TEvents::TEvWakeup()); - } - - STFUNC(StateWork) { - switch (ev->GetTypeRewrite()) { - HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingResponse, Handle); - HFunc(NHttp::TEvHttpProxy::TEvHttpOutgoingRequest, Handle); - HFunc(NHttp::TEvHttpProxy::TEvAddListeningPort, Handle); - HFunc(NHttp::TEvHttpProxy::TEvRegisterHandler, Handle); - HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingRequest, Handle); - HFunc(NHttp::TEvHttpProxy::TEvHttpOutgoingResponse, Handle); - CFunc(NActors::TEvents::TSystem::Wakeup, HandleRefresh); - } - } -}; - -TCachePolicy GetDefaultCachePolicy(const THttpRequest* request, const TCachePolicy& defaultPolicy) { - TCachePolicy policy = defaultPolicy; - THeaders headers(request->Headers); - TStringBuf cacheControl(headers["Cache-Control"]); - while (TStringBuf cacheItem = cacheControl.NextTok(',')) { - Trim(cacheItem, ' '); - if (cacheItem == "no-store" || cacheItem == "no-cache") { - policy.DiscardCache = true; - } - TStringBuf itemName = cacheItem.NextTok('='); - TrimEnd(itemName, ' '); - TrimBegin(cacheItem, ' '); - if (itemName == "max-age") { - policy.TimeToRefresh = policy.TimeToExpire = TDuration::Seconds(FromString(cacheItem)); - } - if (itemName == "min-fresh") { - policy.TimeToRefresh = policy.TimeToExpire = TDuration::Seconds(FromString(cacheItem)); - } - if (itemName == "stale-if-error") { - policy.KeepOnError = true; - } - } - return policy; -} - -NActors::IActor* CreateHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy) { - return new THttpOutgoingCacheActor(httpProxyId, std::move(cachePolicy)); -} - -NActors::IActor* CreateOutgoingHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy) { - return new THttpOutgoingCacheActor(httpProxyId, std::move(cachePolicy)); -} - -NActors::IActor* CreateIncomingHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy) { - return new THttpIncomingCacheActor(httpProxyId, std::move(cachePolicy)); -} - -} diff --git a/library/cpp/actors/http/http_cache.h b/library/cpp/actors/http/http_cache.h deleted file mode 100644 index ac38bdcac8..0000000000 --- a/library/cpp/actors/http/http_cache.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include <library/cpp/actors/core/actor.h> -#include "http.h" - -namespace NHttp { - -struct TCachePolicy { - TDuration TimeToExpire; - TDuration TimeToRefresh; - TDuration PaceToRefresh; - bool KeepOnError = false; - bool DiscardCache = false; - TArrayRef<TString> HeadersToCacheKey; - TArrayRef<TString> StatusesToRetry; - ui32 RetriesCount = 0; - - TCachePolicy() = default; -}; - -using TGetCachePolicy = std::function<TCachePolicy(const THttpRequest*)>; - -NActors::IActor* CreateHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy); -NActors::IActor* CreateOutgoingHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy); -NActors::IActor* CreateIncomingHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy); -TCachePolicy GetDefaultCachePolicy(const THttpRequest* request, const TCachePolicy& policy = TCachePolicy()); - -} diff --git a/library/cpp/actors/http/http_compress.cpp b/library/cpp/actors/http/http_compress.cpp deleted file mode 100644 index b6593fe99d..0000000000 --- a/library/cpp/actors/http/http_compress.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "http.h" - -#include <zlib.h> - -namespace NHttp { - -TString CompressDeflate(TStringBuf source) { - int compressionlevel = Z_BEST_COMPRESSION; - z_stream zs = {}; - - if (deflateInit(&zs, compressionlevel) != Z_OK) { - throw yexception() << "deflateInit failed while compressing"; - } - - zs.next_in = (Bytef*)source.data(); - zs.avail_in = source.size(); - - int ret; - char outbuffer[32768]; - TString result; - - // retrieve the compressed bytes blockwise - do { - zs.next_out = reinterpret_cast<Bytef*>(outbuffer); - zs.avail_out = sizeof(outbuffer); - - ret = deflate(&zs, Z_FINISH); - - if (result.size() < zs.total_out) { - result.append(outbuffer, zs.total_out - result.size()); - } - } while (ret == Z_OK); - - deflateEnd(&zs); - - if (ret != Z_STREAM_END) { - throw yexception() << "Exception during zlib compression: (" << ret << ") " << zs.msg; - } - return result; -} - -TString DecompressDeflate(TStringBuf source) { - z_stream zs = {}; - - if (inflateInit(&zs) != Z_OK) { - throw yexception() << "inflateInit failed while decompressing"; - } - - zs.next_in = (Bytef*)source.data(); - zs.avail_in = source.size(); - - int ret; - char outbuffer[32768]; - TString result; - - // retrieve the decompressed bytes blockwise - do { - zs.next_out = reinterpret_cast<Bytef*>(outbuffer); - zs.avail_out = sizeof(outbuffer); - - ret = inflate(&zs, Z_NO_FLUSH); - - if (result.size() < zs.total_out) { - result.append(outbuffer, zs.total_out - result.size()); - } - } while (ret == Z_OK); - - inflateEnd(&zs); - - if (ret != Z_STREAM_END) { - throw yexception() << "Exception during zlib decompression: (" << ret << ") " << zs.msg; - } - return result; -} - -} diff --git a/library/cpp/actors/http/http_config.h b/library/cpp/actors/http/http_config.h deleted file mode 100644 index 1a2f8646a3..0000000000 --- a/library/cpp/actors/http/http_config.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include <util/network/sock.h> -#include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/protos/services_common.pb.h> - -class TInet64StreamSocket; - -namespace NHttp { - -struct THttpConfig { - static constexpr NActors::NLog::EComponent HttpLog = NActorsServices::EServiceCommon::HTTP; - static constexpr size_t BUFFER_SIZE = 64 * 1024; - static constexpr size_t BUFFER_MIN_STEP = 10 * 1024; - static constexpr int LISTEN_QUEUE = 10; - static constexpr TDuration SOCKET_TIMEOUT = TDuration::MilliSeconds(60000); - static constexpr TDuration CONNECTION_TIMEOUT = TDuration::MilliSeconds(60000); - using SocketType = TInet64StreamSocket; - using SocketAddressType = std::shared_ptr<ISockAddr>; -}; - -} diff --git a/library/cpp/actors/http/http_proxy.cpp b/library/cpp/actors/http/http_proxy.cpp deleted file mode 100644 index 74bf497632..0000000000 --- a/library/cpp/actors/http/http_proxy.cpp +++ /dev/null @@ -1,364 +0,0 @@ -#include <library/cpp/actors/core/events.h> -#include <library/cpp/monlib/metrics/metric_registry.h> -#include "http_proxy.h" - -namespace NHttp { - -class THttpProxy : public NActors::TActorBootstrapped<THttpProxy>, public THttpConfig { -public: - IActor* AddListeningPort(TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) { - IActor* listeningSocket = CreateHttpAcceptorActor(ctx.SelfID, Poller); - TActorId acceptorId = ctx.Register(listeningSocket); - ctx.Send(event->Forward(acceptorId)); - Acceptors.emplace_back(acceptorId); - return listeningSocket; - } - - IActor* AddOutgoingConnection(bool secure, const NActors::TActorContext& ctx) { - IActor* connectionSocket = CreateOutgoingConnectionActor(ctx.SelfID, secure, Poller); - TActorId connectionId = ctx.Register(connectionSocket); - Connections.emplace(connectionId); - return connectionSocket; - } - - void Bootstrap(const NActors::TActorContext& ctx) { - Poller = ctx.Register(NActors::CreatePollerActor()); - Become(&THttpProxy::StateWork); - } - - THttpProxy(std::weak_ptr<NMonitoring::TMetricRegistry> registry) - : Registry(std::move(registry)) - {} - - static constexpr char ActorName[] = "HTTP_PROXY_ACTOR"; - -protected: - STFUNC(StateWork) { - switch (ev->GetTypeRewrite()) { - HFunc(TEvHttpProxy::TEvAddListeningPort, Handle); - HFunc(TEvHttpProxy::TEvRegisterHandler, Handle); - HFunc(TEvHttpProxy::TEvHttpIncomingRequest, Handle); - HFunc(TEvHttpProxy::TEvHttpOutgoingRequest, Handle); - HFunc(TEvHttpProxy::TEvHttpIncomingResponse, Handle); - HFunc(TEvHttpProxy::TEvHttpOutgoingResponse, Handle); - HFunc(TEvHttpProxy::TEvHttpAcceptorClosed, Handle); - HFunc(TEvHttpProxy::TEvHttpConnectionClosed, Handle); - HFunc(TEvHttpProxy::TEvResolveHostRequest, Handle); - HFunc(TEvHttpProxy::TEvReportSensors, Handle); - HFunc(NActors::TEvents::TEvPoison, Handle); - } - } - - void PassAway() override { - Send(Poller, new NActors::TEvents::TEvPoisonPill()); - for (const NActors::TActorId& connection : Connections) { - Send(connection, new NActors::TEvents::TEvPoisonPill()); - } - for (const NActors::TActorId& acceptor : Acceptors) { - Send(acceptor, new NActors::TEvents::TEvPoisonPill()); - } - NActors::TActorBootstrapped<THttpProxy>::PassAway(); - } - - void Handle(TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) { - TStringBuf url = event->Get()->Request->URL.Before('?'); - THashMap<TString, TActorId>::iterator it; - while (!url.empty()) { - it = Handlers.find(url); - if (it != Handlers.end()) { - ctx.Send(event->Forward(it->second)); - return; - } else { - if (url.EndsWith('/')) { - url.Chop(1); - } else { - size_t pos = url.rfind('/'); - if (pos == TStringBuf::npos) { - break; - } else { - url = url.substr(0, pos + 1); - } - } - } - } - ctx.Send(event->Sender, new TEvHttpProxy::TEvHttpOutgoingResponse(event->Get()->Request->CreateResponseNotFound())); - } - - void Handle(TEvHttpProxy::TEvHttpIncomingResponse::TPtr event, const NActors::TActorContext& ctx) { - Y_UNUSED(event); - Y_UNUSED(ctx); - Y_ABORT("This event shouldn't be there, it should go to the http connection owner directly"); - } - - void Handle(TEvHttpProxy::TEvHttpOutgoingResponse::TPtr event, const NActors::TActorContext& ctx) { - Y_UNUSED(event); - Y_UNUSED(ctx); - Y_ABORT("This event shouldn't be there, it should go to the http connection directly"); - } - - void Handle(TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) { - bool secure(event->Get()->Request->Secure); - NActors::IActor* actor = AddOutgoingConnection(secure, ctx); - ctx.Send(event->Forward(actor->SelfId())); - } - - void Handle(TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) { - AddListeningPort(event, ctx); - } - - void Handle(TEvHttpProxy::TEvHttpAcceptorClosed::TPtr event, const NActors::TActorContext&) { - for (auto it = Acceptors.begin(); it != Acceptors.end(); ++it) { - if (*it == event->Get()->ConnectionID) { - Acceptors.erase(it); - break; - } - } - } - - void Handle(TEvHttpProxy::TEvHttpConnectionClosed::TPtr event, const NActors::TActorContext&) { - Connections.erase(event->Get()->ConnectionID); - } - - void Handle(TEvHttpProxy::TEvRegisterHandler::TPtr event, const NActors::TActorContext& ctx) { - LOG_TRACE_S(ctx, HttpLog, "Register handler " << event->Get()->Path << " to " << event->Get()->Handler); - Handlers[event->Get()->Path] = event->Get()->Handler; - } - - void Handle(TEvHttpProxy::TEvResolveHostRequest::TPtr event, const NActors::TActorContext& ctx) { - const TString& host(event->Get()->Host); - auto it = Hosts.find(host); - if (it == Hosts.end() || it->second.DeadlineTime > ctx.Now()) { - TString addressPart; - TIpPort portPart = 0; - CrackAddress(host, addressPart, portPart); - if (IsIPv6(addressPart)) { - if (it == Hosts.end()) { - it = Hosts.emplace(host, THostEntry()).first; - } - it->second.Address = std::make_shared<TSockAddrInet6>(addressPart.data(), portPart); - it->second.DeadlineTime = ctx.Now() + HostsTimeToLive; - } else if (IsIPv4(addressPart)) { - if (it == Hosts.end()) { - it = Hosts.emplace(host, THostEntry()).first; - } - it->second.Address = std::make_shared<TSockAddrInet>(addressPart.data(), portPart); - it->second.DeadlineTime = ctx.Now() + HostsTimeToLive; - } else { - // TODO(xenoxeno): move to another, possible blocking actor - try { - const NDns::TResolvedHost* result = NDns::CachedResolve(NDns::TResolveInfo(addressPart, portPart)); - if (result != nullptr) { - auto pAddr = result->Addr.Begin(); - while (pAddr != result->Addr.End() && pAddr->ai_family != AF_INET && pAddr->ai_family != AF_INET6) { - ++pAddr; - } - if (pAddr == result->Addr.End()) { - ctx.Send(event->Sender, new TEvHttpProxy::TEvResolveHostResponse("Invalid address family resolved")); - return; - } - THttpConfig::SocketAddressType address; - switch (pAddr->ai_family) { - case AF_INET: - address = std::make_shared<TSockAddrInet>(); - break; - case AF_INET6: - address = std::make_shared<TSockAddrInet6>(); - break; - } - if (address) { - memcpy(address->SockAddr(), pAddr->ai_addr, pAddr->ai_addrlen); - LOG_DEBUG_S(ctx, HttpLog, "Host " << host << " resolved to " << address->ToString()); - if (it == Hosts.end()) { - it = Hosts.emplace(host, THostEntry()).first; - } - it->second.Address = address; - it->second.DeadlineTime = ctx.Now() + HostsTimeToLive; - } - } else { - ctx.Send(event->Sender, new TEvHttpProxy::TEvResolveHostResponse("Error resolving host")); - return; - } - } - catch (const yexception& e) { - ctx.Send(event->Sender, new TEvHttpProxy::TEvResolveHostResponse(e.what())); - return; - } - } - } - ctx.Send(event->Sender, new TEvHttpProxy::TEvResolveHostResponse(it->first, it->second.Address)); - } - - void Handle(TEvHttpProxy::TEvReportSensors::TPtr event, const NActors::TActorContext&) { - const TEvHttpProxy::TEvReportSensors& sensors(*event->Get()); - const static TString urlNotFound = "not-found"; - const TString& url = (sensors.Status == "404" ? urlNotFound : sensors.Url); - - std::shared_ptr<NMonitoring::TMetricRegistry> registry = Registry.lock(); - if (registry) { - registry->Rate( - { - {"sensor", "count"}, - {"direction", sensors.Direction}, - {"peer", sensors.Host}, - {"url", url}, - {"status", sensors.Status} - })->Inc(); - registry->HistogramRate( - { - {"sensor", "time_us"}, - {"direction", sensors.Direction}, - {"peer", sensors.Host}, - {"url", url}, - {"status", sensors.Status} - }, - NMonitoring::ExplicitHistogram({1, 5, 10, 50, 100, 500, 1000, 5000, 10000, 30000, 60000}))->Record(sensors.Time.MicroSeconds()); - registry->HistogramRate( - { - {"sensor", "time_ms"}, - {"direction", sensors.Direction}, - {"peer", sensors.Host}, - {"url", url}, - {"status", sensors.Status} - }, - NMonitoring::ExplicitHistogram({1, 5, 10, 50, 100, 500, 1000, 5000, 10000, 30000, 60000}))->Record(sensors.Time.MilliSeconds()); - } - } - - void Handle(NActors::TEvents::TEvPoison::TPtr, const NActors::TActorContext&) { - for (const TActorId& acceptor : Acceptors) { - Send(acceptor, new NActors::TEvents::TEvPoisonPill()); - } - for (const TActorId& connection : Connections) { - Send(connection, new NActors::TEvents::TEvPoisonPill()); - } - PassAway(); - } - - NActors::TActorId Poller; - TVector<TActorId> Acceptors; - - struct THostEntry { - THttpConfig::SocketAddressType Address; - TInstant DeadlineTime; - }; - - static constexpr TDuration HostsTimeToLive = TDuration::Seconds(60); - - THashMap<TString, THostEntry> Hosts; - THashMap<TString, TActorId> Handlers; - THashSet<TActorId> Connections; // outgoing - std::weak_ptr<NMonitoring::TMetricRegistry> Registry; -}; - -TEvHttpProxy::TEvReportSensors* BuildOutgoingRequestSensors(const THttpOutgoingRequestPtr& request, const THttpIncomingResponsePtr& response) { - return new TEvHttpProxy::TEvReportSensors( - "out", - request->Host, - request->URL.Before('?'), - response ? response->Status : "504", - TDuration::Seconds(std::abs(request->Timer.Passed())) - ); -} - -TEvHttpProxy::TEvReportSensors* BuildIncomingRequestSensors(const THttpIncomingRequestPtr& request, const THttpOutgoingResponsePtr& response) { - const auto& sensors = response->Sensors; - if (sensors) { - return new TEvHttpProxy::TEvReportSensors(*sensors); - } - return new TEvHttpProxy::TEvReportSensors( - "in", - request->Host, - request->URL.Before('?'), - response->Status, - TDuration::Seconds(std::abs(request->Timer.Passed())) - ); -} - -NActors::IActor* CreateHttpProxy(std::weak_ptr<NMonitoring::TMetricRegistry> registry) { - return new THttpProxy(std::move(registry)); -} - -bool IsIPv6(const TString& host) { - if (host.find_first_not_of(":0123456789abcdef") != TString::npos) { - return false; - } - if (std::count(host.begin(), host.end(), ':') < 2) { - return false; - } - return true; -} - -bool IsIPv4(const TString& host) { - if (host.find_first_not_of(".0123456789") != TString::npos) { - return false; - } - if (std::count(host.begin(), host.end(), '.') != 3) { - return false; - } - return true; -} - -bool CrackURL(TStringBuf url, TStringBuf& scheme, TStringBuf& host, TStringBuf& uri) { - url.TrySplit("://", scheme, url); - auto pos = url.find('/'); - if (pos == TStringBuf::npos) { - host = url; - } else { - host = url.substr(0, pos); - uri = url.substr(pos); - } - return true; -} - -void CrackAddress(const TString& address, TString& hostname, TIpPort& port) { - size_t first_colon_pos = address.find(':'); - if (first_colon_pos != TString::npos) { - size_t last_colon_pos = address.rfind(':'); - if (last_colon_pos == first_colon_pos) { - // only one colon, simple case - port = FromStringWithDefault<TIpPort>(address.substr(first_colon_pos + 1), 0); - hostname = address.substr(0, first_colon_pos); - } else { - // ipv6? - size_t closing_bracket_pos = address.rfind(']'); - if (closing_bracket_pos == TString::npos || closing_bracket_pos > last_colon_pos) { - // whole address is ipv6 host - hostname = address; - } else { - port = FromStringWithDefault<TIpPort>(address.substr(last_colon_pos + 1), 0); - hostname = address.substr(0, last_colon_pos); - } - if (hostname.StartsWith('[') && hostname.EndsWith(']')) { - hostname = hostname.substr(1, hostname.size() - 2); - } - } - } else { - hostname = address; - } -} - - -void TrimBegin(TStringBuf& target, char delim) { - while (!target.empty() && *target.begin() == delim) { - target.Skip(1); - } -} - -void TrimEnd(TStringBuf& target, char delim) { - while (!target.empty() && target.back() == delim) { - target.Trunc(target.size() - 1); - } -} - -void Trim(TStringBuf& target, char delim) { - TrimBegin(target, delim); - TrimEnd(target, delim); -} - -void TrimEnd(TString& target, char delim) { - while (!target.empty() && target.back() == delim) { - target.resize(target.size() - 1); - } -} - -} diff --git a/library/cpp/actors/http/http_proxy.h b/library/cpp/actors/http/http_proxy.h deleted file mode 100644 index d9a2c6a71c..0000000000 --- a/library/cpp/actors/http/http_proxy.h +++ /dev/null @@ -1,246 +0,0 @@ -#pragma once -#include <library/cpp/actors/core/actorsystem.h> -#include <library/cpp/actors/core/actor.h> -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/core/events.h> -#include <library/cpp/actors/core/event_local.h> -#include <library/cpp/actors/core/actor_bootstrapped.h> -#include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/interconnect/poller_actor.h> -#include <library/cpp/dns/cache.h> -#include <library/cpp/monlib/metrics/metric_registry.h> -#include <util/generic/variant.h> -#include "http.h" -#include "http_proxy_sock64.h" -#include "http_proxy_ssl.h" - -namespace NHttp { - -struct TSocketDescriptor : NActors::TSharedDescriptor, THttpConfig { - SocketType Socket; - - TSocketDescriptor() = default; - - TSocketDescriptor(int af) - : Socket(af) - { - } - - TSocketDescriptor(SocketType&& s) - : Socket(std::move(s)) - {} - - int GetDescriptor() override { - return static_cast<SOCKET>(Socket); - } -}; - -struct TEvHttpProxy { - enum EEv { - EvAddListeningPort = EventSpaceBegin(NActors::TEvents::ES_HTTP), - EvConfirmListen, - EvRegisterHandler, - EvHttpIncomingRequest, - EvHttpOutgoingRequest, - EvHttpIncomingResponse, - EvHttpOutgoingResponse, - EvHttpConnectionOpened, - EvHttpConnectionClosed, - EvHttpAcceptorClosed, - EvResolveHostRequest, - EvResolveHostResponse, - EvReportSensors, - EvEnd - }; - - static_assert(EvEnd < EventSpaceEnd(NActors::TEvents::ES_HTTP), "ES_HTTP event space is too small."); - - struct TEvAddListeningPort : NActors::TEventLocal<TEvAddListeningPort, EvAddListeningPort> { - TString Address; - TIpPort Port; - TString WorkerName; - bool Secure = false; - TString CertificateFile; - TString PrivateKeyFile; - TString SslCertificatePem; - std::vector<TString> CompressContentTypes; - - TEvAddListeningPort() = default; - - TEvAddListeningPort(TIpPort port) - : Port(port) - {} - - TEvAddListeningPort(TIpPort port, const TString& workerName) - : Port(port) - , WorkerName(workerName) - {} - }; - - struct TEvConfirmListen : NActors::TEventLocal<TEvConfirmListen, EvConfirmListen> { - THttpConfig::SocketAddressType Address; - std::shared_ptr<THttpEndpointInfo> Endpoint; - - TEvConfirmListen(const THttpConfig::SocketAddressType& address, std::shared_ptr<THttpEndpointInfo> endpoint) - : Address(address) - , Endpoint(std::move(endpoint)) - {} - }; - - struct TEvRegisterHandler : NActors::TEventLocal<TEvRegisterHandler, EvRegisterHandler> { - TString Path; - TActorId Handler; - - TEvRegisterHandler(const TString& path, const TActorId& handler) - : Path(path) - , Handler(handler) - {} - }; - - struct TEvHttpIncomingRequest : NActors::TEventLocal<TEvHttpIncomingRequest, EvHttpIncomingRequest> { - THttpIncomingRequestPtr Request; - - TEvHttpIncomingRequest(THttpIncomingRequestPtr request) - : Request(std::move(request)) - {} - }; - - struct TEvHttpOutgoingRequest : NActors::TEventLocal<TEvHttpOutgoingRequest, EvHttpOutgoingRequest> { - THttpOutgoingRequestPtr Request; - TDuration Timeout; - - TEvHttpOutgoingRequest(THttpOutgoingRequestPtr request) - : Request(std::move(request)) - {} - - TEvHttpOutgoingRequest(THttpOutgoingRequestPtr request, TDuration timeout) - : Request(std::move(request)) - , Timeout(timeout) - {} - }; - - struct TEvHttpIncomingResponse : NActors::TEventLocal<TEvHttpIncomingResponse, EvHttpIncomingResponse> { - THttpOutgoingRequestPtr Request; - THttpIncomingResponsePtr Response; - TString Error; - - TEvHttpIncomingResponse(THttpOutgoingRequestPtr request, THttpIncomingResponsePtr response, const TString& error) - : Request(std::move(request)) - , Response(std::move(response)) - , Error(error) - {} - - TEvHttpIncomingResponse(THttpOutgoingRequestPtr request, THttpIncomingResponsePtr response) - : Request(std::move(request)) - , Response(std::move(response)) - {} - - TString GetError() const { - TStringBuilder error; - if (Response != nullptr && !Response->Status.StartsWith('2')) { - error << Response->Status << ' ' << Response->Message; - } - if (!Error.empty()) { - if (!error.empty()) { - error << ';'; - } - error << Error; - } - return error; - } - }; - - struct TEvHttpOutgoingResponse : NActors::TEventLocal<TEvHttpOutgoingResponse, EvHttpOutgoingResponse> { - THttpOutgoingResponsePtr Response; - - TEvHttpOutgoingResponse(THttpOutgoingResponsePtr response) - : Response(std::move(response)) - {} - }; - - struct TEvHttpConnectionOpened : NActors::TEventLocal<TEvHttpConnectionOpened, EvHttpConnectionOpened> { - TString PeerAddress; - TActorId ConnectionID; - - TEvHttpConnectionOpened(const TString& peerAddress, const TActorId& connectionID) - : PeerAddress(peerAddress) - , ConnectionID(connectionID) - {} - }; - - struct TEvHttpConnectionClosed : NActors::TEventLocal<TEvHttpConnectionClosed, EvHttpConnectionClosed> { - TActorId ConnectionID; - TDeque<THttpIncomingRequestPtr> RecycledRequests; - - TEvHttpConnectionClosed(const TActorId& connectionID) - : ConnectionID(connectionID) - {} - - TEvHttpConnectionClosed(const TActorId& connectionID, TDeque<THttpIncomingRequestPtr> recycledRequests) - : ConnectionID(connectionID) - , RecycledRequests(std::move(recycledRequests)) - {} - }; - - struct TEvHttpAcceptorClosed : NActors::TEventLocal<TEvHttpAcceptorClosed, EvHttpAcceptorClosed> { - TActorId ConnectionID; - - TEvHttpAcceptorClosed(const TActorId& connectionID) - : ConnectionID(connectionID) - {} - }; - - struct TEvResolveHostRequest : NActors::TEventLocal<TEvResolveHostRequest, EvResolveHostRequest> { - TString Host; - - TEvResolveHostRequest(const TString& host) - : Host(host) - {} - }; - - struct TEvResolveHostResponse : NActors::TEventLocal<TEvResolveHostResponse, EvResolveHostResponse> { - TString Host; - THttpConfig::SocketAddressType Address; - TString Error; - - TEvResolveHostResponse(const TString& host, THttpConfig::SocketAddressType address) - : Host(host) - , Address(address) - {} - - TEvResolveHostResponse(const TString& error) - : Error(error) - {} - }; - - struct TEvReportSensors : TSensors, NActors::TEventLocal<TEvReportSensors, EvReportSensors> { - using TSensors::TSensors; - - TEvReportSensors(const TSensors& sensors) - : TSensors(sensors) - {} - }; -}; - -struct TPrivateEndpointInfo : THttpEndpointInfo { - TActorId Proxy; - TActorId Owner; - TSslHelpers::TSslHolder<SSL_CTX> SecureContext; - - TPrivateEndpointInfo(const std::vector<TString>& compressContentTypes) - : THttpEndpointInfo(compressContentTypes) - {} -}; - -NActors::IActor* CreateHttpProxy(std::weak_ptr<NMonitoring::TMetricRegistry> registry = NMonitoring::TMetricRegistry::SharedInstance()); -NActors::IActor* CreateHttpAcceptorActor(const TActorId& owner, const TActorId& poller); -NActors::IActor* CreateOutgoingConnectionActor(const TActorId& owner, bool secure, const TActorId& poller); -NActors::IActor* CreateIncomingConnectionActor( - std::shared_ptr<TPrivateEndpointInfo> endpoint, - TIntrusivePtr<TSocketDescriptor> socket, - THttpConfig::SocketAddressType address, - THttpIncomingRequestPtr recycledRequest = nullptr); -TEvHttpProxy::TEvReportSensors* BuildOutgoingRequestSensors(const THttpOutgoingRequestPtr& request, const THttpIncomingResponsePtr& response); -TEvHttpProxy::TEvReportSensors* BuildIncomingRequestSensors(const THttpIncomingRequestPtr& request, const THttpOutgoingResponsePtr& response); - -} diff --git a/library/cpp/actors/http/http_proxy_acceptor.cpp b/library/cpp/actors/http/http_proxy_acceptor.cpp deleted file mode 100644 index c007f747eb..0000000000 --- a/library/cpp/actors/http/http_proxy_acceptor.cpp +++ /dev/null @@ -1,158 +0,0 @@ -#include <util/network/sock.h> -#include "http_proxy.h" -#include "http_proxy_ssl.h" - -namespace NHttp { - -class TAcceptorActor : public NActors::TActor<TAcceptorActor>, public THttpConfig { -public: - using TBase = NActors::TActor<TAcceptorActor>; - const TActorId Owner; - const TActorId Poller; - TIntrusivePtr<TSocketDescriptor> Socket; - NActors::TPollerToken::TPtr PollerToken; - THashSet<TActorId> Connections; - TDeque<THttpIncomingRequestPtr> RecycledRequests; - std::shared_ptr<TPrivateEndpointInfo> Endpoint; - - TAcceptorActor(const TActorId& owner, const TActorId& poller) - : NActors::TActor<TAcceptorActor>(&TAcceptorActor::StateInit) - , Owner(owner) - , Poller(poller) - { - } - - static constexpr char ActorName[] = "HTTP_ACCEPTOR_ACTOR"; - -protected: - STFUNC(StateListening) { - switch (ev->GetTypeRewrite()) { - HFunc(NActors::TEvPollerRegisterResult, Handle); - HFunc(NActors::TEvPollerReady, Handle); - HFunc(TEvHttpProxy::TEvHttpConnectionClosed, Handle); - HFunc(TEvHttpProxy::TEvReportSensors, Handle); - } - } - - STFUNC(StateInit) { - switch (ev->GetTypeRewrite()) { - HFunc(TEvHttpProxy::TEvAddListeningPort, HandleInit); - } - } - - void HandleInit(TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) { - TString address = event->Get()->Address; - ui16 port = event->Get()->Port; - Socket = new TSocketDescriptor(SocketType::GuessAddressFamily(address)); - // for unit tests :( - SetSockOpt(Socket->Socket, SOL_SOCKET, SO_REUSEADDR, (int)true); -#ifdef SO_REUSEPORT - SetSockOpt(Socket->Socket, SOL_SOCKET, SO_REUSEPORT, (int)true); -#endif - SocketAddressType bindAddress(Socket->Socket.MakeAddress(address, port)); - Endpoint = std::make_shared<TPrivateEndpointInfo>(event->Get()->CompressContentTypes); - Endpoint->Owner = ctx.SelfID; - Endpoint->Proxy = Owner; - Endpoint->WorkerName = event->Get()->WorkerName; - Endpoint->Secure = event->Get()->Secure; - int err = 0; - if (Endpoint->Secure) { - if (!event->Get()->SslCertificatePem.empty()) { - Endpoint->SecureContext = TSslHelpers::CreateServerContext(event->Get()->SslCertificatePem); - } else { - Endpoint->SecureContext = TSslHelpers::CreateServerContext(event->Get()->CertificateFile, event->Get()->PrivateKeyFile); - } - if (Endpoint->SecureContext == nullptr) { - err = -1; - LOG_WARN_S(ctx, HttpLog, "Failed to construct server security context"); - } - } - if (err == 0) { - err = Socket->Socket.Bind(bindAddress.get()); - if (err != 0) { - LOG_WARN_S( - ctx, - HttpLog, - "Failed to bind " << bindAddress->ToString() - << ", code: " << err); - } - } - TStringBuf schema = Endpoint->Secure ? "https://" : "http://"; - if (err == 0) { - err = Socket->Socket.Listen(LISTEN_QUEUE); - if (err == 0) { - LOG_INFO_S(ctx, HttpLog, "Listening on " << schema << bindAddress->ToString()); - SetNonBlock(Socket->Socket); - ctx.Send(Poller, new NActors::TEvPollerRegister(Socket, SelfId(), SelfId())); - TBase::Become(&TAcceptorActor::StateListening); - ctx.Send(event->Sender, new TEvHttpProxy::TEvConfirmListen(bindAddress, Endpoint), 0, event->Cookie); - return; - } else { - LOG_WARN_S( - ctx, - HttpLog, - "Failed to listen on " << schema << bindAddress->ToString() - << ", code: " << err); - } - } - LOG_WARN_S(ctx, HttpLog, "Failed to init - retrying..."); - ctx.ExecutorThread.Schedule(TDuration::Seconds(1), event.Release()); - } - - void Die(const NActors::TActorContext& ctx) override { - ctx.Send(Owner, new TEvHttpProxy::TEvHttpAcceptorClosed(ctx.SelfID)); - for (const NActors::TActorId& connection : Connections) { - ctx.Send(connection, new NActors::TEvents::TEvPoisonPill()); - } - } - - void Handle(NActors::TEvPollerRegisterResult::TPtr ev, const NActors::TActorContext& /*ctx*/) { - PollerToken = std::move(ev->Get()->PollerToken); - PollerToken->Request(true, false); // request read polling - } - - void Handle(NActors::TEvPollerReady::TPtr, const NActors::TActorContext& ctx) { - for (;;) { - SocketAddressType addr; - std::optional<SocketType> s = Socket->Socket.Accept(addr); - if (!s) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - Y_ABORT_UNLESS(PollerToken); - if (PollerToken->RequestReadNotificationAfterWouldBlock()) { - continue; // we can try it again - } - } - break; - } - TIntrusivePtr<TSocketDescriptor> socket = new TSocketDescriptor(std::move(s).value()); - NActors::IActor* connectionSocket = nullptr; - if (RecycledRequests.empty()) { - connectionSocket = CreateIncomingConnectionActor(Endpoint, socket, addr); - } else { - connectionSocket = CreateIncomingConnectionActor(Endpoint, socket, addr, std::move(RecycledRequests.front())); - RecycledRequests.pop_front(); - } - NActors::TActorId connectionId = ctx.Register(connectionSocket); - ctx.Send(Poller, new NActors::TEvPollerRegister(socket, connectionId, connectionId)); - Connections.emplace(connectionId); - } - } - - void Handle(TEvHttpProxy::TEvHttpConnectionClosed::TPtr event, const NActors::TActorContext&) { - Connections.erase(event->Get()->ConnectionID); - for (auto& req : event->Get()->RecycledRequests) { - req->Clear(); - RecycledRequests.push_back(std::move(req)); - } - } - - void Handle(TEvHttpProxy::TEvReportSensors::TPtr event, const NActors::TActorContext& ctx) { - ctx.Send(event->Forward(Owner)); - } -}; - -NActors::IActor* CreateHttpAcceptorActor(const TActorId& owner, const TActorId& poller) { - return new TAcceptorActor(owner, poller); -} - -} diff --git a/library/cpp/actors/http/http_proxy_incoming.cpp b/library/cpp/actors/http/http_proxy_incoming.cpp deleted file mode 100644 index b98b3c09f3..0000000000 --- a/library/cpp/actors/http/http_proxy_incoming.cpp +++ /dev/null @@ -1,310 +0,0 @@ -#include "http_proxy.h" -#include "http_proxy_sock_impl.h" - -namespace NHttp { - -using namespace NActors; - -template <typename TSocketImpl> -class TIncomingConnectionActor : public TActor<TIncomingConnectionActor<TSocketImpl>>, public TSocketImpl, virtual public THttpConfig { -public: - using TBase = TActor<TIncomingConnectionActor<TSocketImpl>>; - static constexpr bool RecycleRequests = true; - - std::shared_ptr<TPrivateEndpointInfo> Endpoint; - SocketAddressType Address; - TList<THttpIncomingRequestPtr> Requests; - THashMap<THttpIncomingRequestPtr, THttpOutgoingResponsePtr> Responses; - THttpIncomingRequestPtr CurrentRequest; - THttpOutgoingResponsePtr CurrentResponse; - TDeque<THttpIncomingRequestPtr> RecycledRequests; - - THPTimer InactivityTimer; - static constexpr TDuration InactivityTimeout = TDuration::Minutes(2); - TEvPollerReady* InactivityEvent = nullptr; - - TPollerToken::TPtr PollerToken; - - TIncomingConnectionActor( - std::shared_ptr<TPrivateEndpointInfo> endpoint, - TIntrusivePtr<TSocketDescriptor> socket, - SocketAddressType address, - THttpIncomingRequestPtr recycledRequest = nullptr) - : TBase(&TIncomingConnectionActor::StateAccepting) - , TSocketImpl(std::move(socket)) - , Endpoint(std::move(endpoint)) - , Address(address) - { - if (recycledRequest != nullptr) { - RecycledRequests.emplace_back(std::move(recycledRequest)); - } - TSocketImpl::SetNonBlock(); - } - - static constexpr char ActorName[] = "IN_CONNECTION_ACTOR"; - - void CleanupRequest(THttpIncomingRequestPtr& request) { - if (RecycleRequests) { - request->Clear(); - RecycledRequests.push_back(std::move(request)); - } else { - request = nullptr; - } - } - - void CleanupResponse(THttpOutgoingResponsePtr& response) { - CleanupRequest(response->Request); - // TODO: maybe recycle too? - response = nullptr; - } - - TAutoPtr<IEventHandle> AfterRegister(const TActorId& self, const TActorId& parent) override { - return new IEventHandle(self, parent, new TEvents::TEvBootstrap()); - } - - void Die(const TActorContext& ctx) override { - ctx.Send(Endpoint->Owner, new TEvHttpProxy::TEvHttpConnectionClosed(ctx.SelfID, std::move(RecycledRequests))); - TSocketImpl::Shutdown(); - TBase::Die(ctx); - } - -protected: - void Bootstrap(const TActorContext& ctx) { - InactivityTimer.Reset(); - ctx.Schedule(InactivityTimeout, InactivityEvent = new TEvPollerReady(nullptr, false, false)); - LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") incoming connection opened"); - OnAccept(ctx); - } - - void OnAccept(const NActors::TActorContext& ctx) { - int res; - bool read = false, write = false; - for (;;) { - if ((res = TSocketImpl::OnAccept(Endpoint, read, write)) != 1) { - if (-res == EAGAIN) { - if (PollerToken && PollerToken->RequestReadNotificationAfterWouldBlock()) { - continue; - } - return; // wait for further notifications - } else { - LOG_ERROR_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed - error in Accept: " << strerror(-res)); - return Die(ctx); - } - } - break; - } - TBase::Become(&TIncomingConnectionActor::StateConnected); - ctx.Send(ctx.SelfID, new TEvPollerReady(nullptr, true, true)); - } - - void HandleAccepting(TEvPollerRegisterResult::TPtr ev, const NActors::TActorContext& ctx) { - PollerToken = std::move(ev->Get()->PollerToken); - OnAccept(ctx); - } - - void HandleAccepting(NActors::TEvPollerReady::TPtr, const NActors::TActorContext& ctx) { - OnAccept(ctx); - } - - void HandleConnected(TEvPollerReady::TPtr event, const TActorContext& ctx) { - if (event->Get()->Read) { - for (;;) { - if (CurrentRequest == nullptr) { - if (RecycleRequests && !RecycledRequests.empty()) { - CurrentRequest = std::move(RecycledRequests.front()); - RecycledRequests.pop_front(); - CurrentRequest->Address = Address; - CurrentRequest->Endpoint = Endpoint; - } else { - CurrentRequest = new THttpIncomingRequest(Endpoint, Address); - } - } - if (!CurrentRequest->EnsureEnoughSpaceAvailable()) { - LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed - not enough space available"); - return Die(ctx); - } - ssize_t need = CurrentRequest->Avail(); - bool read = false, write = false; - ssize_t res = TSocketImpl::Recv(CurrentRequest->Pos(), need, read, write); - if (res > 0) { - InactivityTimer.Reset(); - CurrentRequest->Advance(res); - if (CurrentRequest->IsDone()) { - Requests.emplace_back(CurrentRequest); - CurrentRequest->Timer.Reset(); - if (CurrentRequest->IsReady()) { - LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") -> (" << CurrentRequest->Method << " " << CurrentRequest->URL << ")"); - ctx.Send(Endpoint->Proxy, new TEvHttpProxy::TEvHttpIncomingRequest(CurrentRequest)); - CurrentRequest = nullptr; - } else if (CurrentRequest->IsError()) { - LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") -! (" << CurrentRequest->Method << " " << CurrentRequest->URL << ")"); - bool success = Respond(CurrentRequest->CreateResponseBadRequest(), ctx); - if (!success) { - return; - } - CurrentRequest = nullptr; - } - } - } else if (-res == EAGAIN || -res == EWOULDBLOCK) { - if (PollerToken) { - if (!read && !write) { - read = true; - } - if (PollerToken->RequestNotificationAfterWouldBlock(read, write)) { - continue; - } - } - break; - } else if (-res == EINTR) { - continue; - } else if (!res) { - // connection closed - LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed"); - return Die(ctx); - } else { - LOG_ERROR_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed - error in Receive: " << strerror(-res)); - return Die(ctx); - } - } - } - if (event->Get() == InactivityEvent) { - const TDuration passed = TDuration::Seconds(std::abs(InactivityTimer.Passed())); - if (passed >= InactivityTimeout) { - LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed by inactivity timeout"); - return Die(ctx); // timeout - } else { - ctx.Schedule(InactivityTimeout - passed, InactivityEvent = new TEvPollerReady(nullptr, false, false)); - } - } - if (event->Get()->Write) { - FlushOutput(ctx); - } - } - - void HandleConnected(TEvPollerRegisterResult::TPtr ev, const TActorContext& /*ctx*/) { - PollerToken = std::move(ev->Get()->PollerToken); - PollerToken->Request(true, true); - } - - void HandleConnected(TEvHttpProxy::TEvHttpOutgoingResponse::TPtr event, const TActorContext& ctx) { - Respond(event->Get()->Response, ctx); - } - - bool Respond(THttpOutgoingResponsePtr response, const TActorContext& ctx) { - THttpIncomingRequestPtr request = response->GetRequest(); - response->Finish(); - LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") <- (" << response->Status << " " << response->Message << ")"); - if (!response->Status.StartsWith('2') && response->Status != "404") { - static constexpr size_t MAX_LOGGED_SIZE = 1024; - LOG_DEBUG_S(ctx, HttpLog, - "(#" - << TSocketImpl::GetRawSocket() - << "," - << Address - << ") Request: " - << request->GetObfuscatedData().substr(0, MAX_LOGGED_SIZE)); - LOG_DEBUG_S(ctx, HttpLog, - "(#" - << TSocketImpl::GetRawSocket() - << "," - << Address - << ") Response: " - << TString(response->GetRawData()).substr(0, MAX_LOGGED_SIZE)); - } - THolder<TEvHttpProxy::TEvReportSensors> sensors(BuildIncomingRequestSensors(request, response)); - ctx.Send(Endpoint->Owner, sensors.Release()); - if (request == Requests.front() && CurrentResponse == nullptr) { - CurrentResponse = response; - return FlushOutput(ctx); - } else { - // we are ahead of our pipeline - Responses.emplace(request, response); - return true; - } - } - - bool FlushOutput(const TActorContext& ctx) { - while (CurrentResponse != nullptr) { - size_t size = CurrentResponse->Size(); - if (size == 0) { - Y_ABORT_UNLESS(Requests.front() == CurrentResponse->GetRequest()); - bool close = CurrentResponse->IsConnectionClose(); - Requests.pop_front(); - CleanupResponse(CurrentResponse); - if (!Requests.empty()) { - auto it = Responses.find(Requests.front()); - if (it != Responses.end()) { - CurrentResponse = it->second; - Responses.erase(it); - continue; - } else { - LOG_ERROR_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed - FlushOutput request not found"); - Die(ctx); - return false; - } - } else { - if (close) { - LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed"); - Die(ctx); - return false; - } else { - continue; - } - } - } - bool read = false, write = false; - ssize_t res = TSocketImpl::Send(CurrentResponse->Data(), size, read, write); - if (res > 0) { - CurrentResponse->ChopHead(res); - } else if (-res == EINTR) { - continue; - } else if (-res == EAGAIN || -res == EWOULDBLOCK) { - if (PollerToken) { - if (!read && !write) { - write = true; - } - if (PollerToken->RequestNotificationAfterWouldBlock(read, write)) { - continue; - } - } - break; - } else { - CleanupResponse(CurrentResponse); - LOG_ERROR_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed - error in FlushOutput: " << strerror(-res)); - Die(ctx); - return false; - } - } - return true; - } - - STFUNC(StateAccepting) { - switch (ev->GetTypeRewrite()) { - CFunc(TEvents::TEvBootstrap::EventType, Bootstrap); - HFunc(TEvPollerReady, HandleAccepting); - HFunc(TEvPollerRegisterResult, HandleAccepting); - } - } - - STFUNC(StateConnected) { - switch (ev->GetTypeRewrite()) { - HFunc(TEvPollerReady, HandleConnected); - HFunc(TEvHttpProxy::TEvHttpOutgoingResponse, HandleConnected); - HFunc(TEvPollerRegisterResult, HandleConnected); - } - } -}; - -IActor* CreateIncomingConnectionActor( - std::shared_ptr<TPrivateEndpointInfo> endpoint, - TIntrusivePtr<TSocketDescriptor> socket, - THttpConfig::SocketAddressType address, - THttpIncomingRequestPtr recycledRequest) { - if (endpoint->Secure) { - return new TIncomingConnectionActor<TSecureSocketImpl>(std::move(endpoint), std::move(socket), address, std::move(recycledRequest)); - } else { - return new TIncomingConnectionActor<TPlainSocketImpl>(std::move(endpoint), std::move(socket), address, std::move(recycledRequest)); - } -} - -} diff --git a/library/cpp/actors/http/http_proxy_outgoing.cpp b/library/cpp/actors/http/http_proxy_outgoing.cpp deleted file mode 100644 index b1f27c2c5a..0000000000 --- a/library/cpp/actors/http/http_proxy_outgoing.cpp +++ /dev/null @@ -1,335 +0,0 @@ -#include "http_proxy.h" -#include "http_proxy_sock_impl.h" - -namespace NHttp { - -template <typename TSocketImpl> -class TOutgoingConnectionActor : public NActors::TActor<TOutgoingConnectionActor<TSocketImpl>>, public TSocketImpl, virtual public THttpConfig { -public: - using TBase = NActors::TActor<TOutgoingConnectionActor<TSocketImpl>>; - using TSelf = TOutgoingConnectionActor<TSocketImpl>; - const TActorId Owner; - const TActorId Poller; - SocketAddressType Address; - TActorId RequestOwner; - THttpOutgoingRequestPtr Request; - THttpIncomingResponsePtr Response; - TInstant LastActivity; - TDuration ConnectionTimeout = CONNECTION_TIMEOUT; - NActors::TPollerToken::TPtr PollerToken; - - TOutgoingConnectionActor(const TActorId& owner, const TActorId& poller) - : TBase(&TSelf::StateWaiting) - , Owner(owner) - , Poller(poller) - { - } - - static constexpr char ActorName[] = "OUT_CONNECTION_ACTOR"; - - void Die(const NActors::TActorContext& ctx) override { - ctx.Send(Owner, new TEvHttpProxy::TEvHttpConnectionClosed(ctx.SelfID)); - TSocketImpl::Shutdown(); // to avoid errors when connection already closed - TBase::Die(ctx); - } - - TString GetSocketName() { - TStringBuilder builder; - if (TSocketImpl::Socket) { - builder << "(#" << TSocketImpl::GetRawSocket(); - if (Address && Address->SockAddr()->sa_family) { - builder << "," << Address; - } - builder << ") "; - } - return builder; - } - - void ReplyAndDie(const NActors::TActorContext& ctx) { - LOG_DEBUG_S(ctx, HttpLog, GetSocketName() << "-> (" << Response->Status << " " << Response->Message << ")"); - ctx.Send(RequestOwner, new TEvHttpProxy::TEvHttpIncomingResponse(Request, Response)); - RequestOwner = TActorId(); - THolder<TEvHttpProxy::TEvReportSensors> sensors(BuildOutgoingRequestSensors(Request, Response)); - ctx.Send(Owner, sensors.Release()); - LOG_DEBUG_S(ctx, HttpLog, GetSocketName() << "connection closed"); - Die(ctx); - } - - void ReplyErrorAndDie(const NActors::TActorContext& ctx, const TString& error) { - LOG_ERROR_S(ctx, HttpLog, GetSocketName() << "connection closed with error: " << error); - if (RequestOwner) { - ctx.Send(RequestOwner, new TEvHttpProxy::TEvHttpIncomingResponse(Request, Response, error)); - RequestOwner = TActorId(); - THolder<TEvHttpProxy::TEvReportSensors> sensors(BuildOutgoingRequestSensors(Request, Response)); - ctx.Send(Owner, sensors.Release()); - Die(ctx); - } - } - -protected: - void FailConnection(const NActors::TActorContext& ctx, const TString& error) { - if (Request) { - return ReplyErrorAndDie(ctx, error); - } - return TBase::Become(&TOutgoingConnectionActor::StateFailed); - } - - void Connect(const NActors::TActorContext& ctx) { - LOG_DEBUG_S(ctx, HttpLog, GetSocketName() << "connecting"); - TSocketImpl::Create(Address->SockAddr()->sa_family); - TSocketImpl::SetNonBlock(); - TSocketImpl::SetTimeout(ConnectionTimeout); - int res = TSocketImpl::Connect(Address); - RegisterPoller(ctx); - switch (-res) { - case 0: - return OnConnect(ctx); - case EINPROGRESS: - case EAGAIN: - return TBase::Become(&TOutgoingConnectionActor::StateConnecting); - default: - return ReplyErrorAndDie(ctx, strerror(-res)); - } - } - - void FlushOutput(const NActors::TActorContext& ctx) { - if (Request != nullptr) { - Request->Finish(); - while (auto size = Request->Size()) { - bool read = false, write = false; - ssize_t res = TSocketImpl::Send(Request->Data(), size, read, write); - if (res > 0) { - Request->ChopHead(res); - } else if (-res == EINTR) { - continue; - } else if (-res == EAGAIN || -res == EWOULDBLOCK) { - if (PollerToken) { - if (!read && !write) { - write = true; - } - if (PollerToken->RequestNotificationAfterWouldBlock(read, write)) { - continue; - } - } - break; - } else { - if (!res) { - ReplyAndDie(ctx); - } else { - ReplyErrorAndDie(ctx, strerror(-res)); - } - break; - } - } - } - } - - void PullInput(const NActors::TActorContext& ctx) { - for (;;) { - if (Response == nullptr) { - Response = new THttpIncomingResponse(Request); - } - if (!Response->EnsureEnoughSpaceAvailable()) { - return ReplyErrorAndDie(ctx, "Not enough space in socket buffer"); - } - bool read = false, write = false; - ssize_t res = TSocketImpl::Recv(Response->Pos(), Response->Avail(), read, write); - if (res > 0) { - Response->Advance(res); - if (Response->IsDone() && Response->IsReady()) { - return ReplyAndDie(ctx); - } - } else if (-res == EINTR) { - continue; - } else if (-res == EAGAIN || -res == EWOULDBLOCK) { - if (PollerToken) { - if (!read && !write) { - read = true; - } - if (PollerToken->RequestNotificationAfterWouldBlock(read, write)) { - continue; - } - } - return; - } else { - if (!res) { - Response->ConnectionClosed(); - } - if (Response->IsDone() && Response->IsReady()) { - return ReplyAndDie(ctx); - } - return ReplyErrorAndDie(ctx, strerror(-res)); - } - } - } - - void RegisterPoller(const NActors::TActorContext& ctx) { - ctx.Send(Poller, new NActors::TEvPollerRegister(TSocketImpl::Socket, ctx.SelfID, ctx.SelfID)); - } - - void OnConnect(const NActors::TActorContext& ctx) { - bool read = false, write = false; - if (int res = TSocketImpl::OnConnect(read, write); res != 1) { - if (-res == EAGAIN) { - if (PollerToken) { - PollerToken->Request(read, write); - } - return; - } else { - return ReplyErrorAndDie(ctx, strerror(-res)); - } - } - LOG_DEBUG_S(ctx, HttpLog, GetSocketName() << "outgoing connection opened"); - TBase::Become(&TOutgoingConnectionActor::StateConnected); - LOG_DEBUG_S(ctx, HttpLog, GetSocketName() << "<- (" << Request->Method << " " << Request->URL << ")"); - ctx.Send(ctx.SelfID, new NActors::TEvPollerReady(nullptr, true, true)); - } - - static int GetPort(SocketAddressType address) { - switch (address->SockAddr()->sa_family) { - case AF_INET: - return ntohs(reinterpret_cast<sockaddr_in*>(address->SockAddr())->sin_port); - case AF_INET6: - return ntohs(reinterpret_cast<sockaddr_in6*>(address->SockAddr())->sin6_port); - } - return {}; - } - - static void SetPort(SocketAddressType address, int port) { - switch (address->SockAddr()->sa_family) { - case AF_INET: - reinterpret_cast<sockaddr_in*>(address->SockAddr())->sin_port = htons(port); - break; - case AF_INET6: - reinterpret_cast<sockaddr_in6*>(address->SockAddr())->sin6_port = htons(port); - break; - } - } - - void HandleResolving(TEvHttpProxy::TEvResolveHostResponse::TPtr event, const NActors::TActorContext& ctx) { - LastActivity = ctx.Now(); - if (!event->Get()->Error.empty()) { - return FailConnection(ctx, event->Get()->Error); - } - Address = event->Get()->Address; - if (GetPort(Address) == 0) { - SetPort(Address, Request->Secure ? 443 : 80); - } - Connect(ctx); - } - - void HandleConnecting(NActors::TEvPollerReady::TPtr, const NActors::TActorContext& ctx) { - LastActivity = ctx.Now(); - int res = TSocketImpl::GetError(); - if (res == 0) { - OnConnect(ctx); - } else { - FailConnection(ctx, TStringBuilder() << strerror(res)); - } - } - - void HandleConnecting(NActors::TEvPollerRegisterResult::TPtr ev, const NActors::TActorContext& ctx) { - PollerToken = std::move(ev->Get()->PollerToken); - LastActivity = ctx.Now(); - int res = TSocketImpl::GetError(); - if (res == 0) { - OnConnect(ctx); - } else { - FailConnection(ctx, TStringBuilder() << strerror(res)); - } - } - - void HandleWaiting(TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) { - LastActivity = ctx.Now(); - Request = std::move(event->Get()->Request); - TSocketImpl::SetHost(TString(Request->Host)); - LOG_DEBUG_S(ctx, HttpLog, GetSocketName() << "resolving " << TSocketImpl::Host); - Request->Timer.Reset(); - RequestOwner = event->Sender; - ctx.Send(Owner, new TEvHttpProxy::TEvResolveHostRequest(TSocketImpl::Host)); - if (event->Get()->Timeout) { - ConnectionTimeout = event->Get()->Timeout; - } - ctx.Schedule(ConnectionTimeout, new NActors::TEvents::TEvWakeup()); - LastActivity = ctx.Now(); - TBase::Become(&TOutgoingConnectionActor::StateResolving); - } - - void HandleConnected(NActors::TEvPollerReady::TPtr event, const NActors::TActorContext& ctx) { - LastActivity = ctx.Now(); - if (event->Get()->Write && RequestOwner) { - FlushOutput(ctx); - } - if (event->Get()->Read && RequestOwner) { - PullInput(ctx); - } - } - - void HandleConnected(NActors::TEvPollerRegisterResult::TPtr ev, const NActors::TActorContext& ctx) { - PollerToken = std::move(ev->Get()->PollerToken); - LastActivity = ctx.Now(); - PullInput(ctx); - FlushOutput(ctx); - } - - void HandleFailed(TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) { - Request = std::move(event->Get()->Request); - RequestOwner = event->Sender; - ReplyErrorAndDie(ctx, "Failed"); - } - - void HandleTimeout(const NActors::TActorContext& ctx) { - TDuration inactivityTime = ctx.Now() - LastActivity; - if (inactivityTime >= ConnectionTimeout) { - FailConnection(ctx, "Connection timed out"); - } else { - ctx.Schedule(Min(ConnectionTimeout - inactivityTime, TDuration::MilliSeconds(100)), new NActors::TEvents::TEvWakeup()); - } - } - - STFUNC(StateWaiting) { - switch (ev->GetTypeRewrite()) { - HFunc(TEvHttpProxy::TEvHttpOutgoingRequest, HandleWaiting); - CFunc(NActors::TEvents::TEvWakeup::EventType, HandleTimeout); - } - } - - STFUNC(StateResolving) { - switch (ev->GetTypeRewrite()) { - HFunc(TEvHttpProxy::TEvResolveHostResponse, HandleResolving); - CFunc(NActors::TEvents::TEvWakeup::EventType, HandleTimeout); - } - } - - STFUNC(StateConnecting) { - switch (ev->GetTypeRewrite()) { - HFunc(NActors::TEvPollerReady, HandleConnecting); - CFunc(NActors::TEvents::TEvWakeup::EventType, HandleTimeout); - HFunc(NActors::TEvPollerRegisterResult, HandleConnecting); - } - } - - STFUNC(StateConnected) { - switch (ev->GetTypeRewrite()) { - HFunc(NActors::TEvPollerReady, HandleConnected); - CFunc(NActors::TEvents::TEvWakeup::EventType, HandleTimeout); - HFunc(NActors::TEvPollerRegisterResult, HandleConnected); - } - } - - STFUNC(StateFailed) { - switch (ev->GetTypeRewrite()) { - HFunc(TEvHttpProxy::TEvHttpOutgoingRequest, HandleFailed); - } - } -}; - -NActors::IActor* CreateOutgoingConnectionActor(const TActorId& owner, bool secure, const TActorId& poller) { - if (secure) { - return new TOutgoingConnectionActor<TSecureSocketImpl>(owner, poller); - } else { - return new TOutgoingConnectionActor<TPlainSocketImpl>(owner, poller); - } -} - -} diff --git a/library/cpp/actors/http/http_proxy_sock64.h b/library/cpp/actors/http/http_proxy_sock64.h deleted file mode 100644 index fa6d9a1e56..0000000000 --- a/library/cpp/actors/http/http_proxy_sock64.h +++ /dev/null @@ -1,147 +0,0 @@ -#pragma once -#include <util/network/sock.h> -#include "http.h" - -class TInet64StreamSocket: public TStreamSocket { -protected: - TInet64StreamSocket(const TInet64StreamSocket& parent, SOCKET fd) - : TStreamSocket(fd) - , AF(parent.AF) - { - } - -public: - TInet64StreamSocket(int af = {}) { - CreateSocket(af); - } - - std::shared_ptr<ISockAddr> MakeAddress(const TString& address, int port) { - if (!address) { - if (AF == AF_INET6) { - return std::make_shared<TSockAddrInet6>("::", port); - } else { - return std::make_shared<TSockAddrInet>(INADDR_ANY, port); - } - } - if (NHttp::IsIPv6(address)) { - return std::make_shared<TSockAddrInet6>(address.data(), port); - } else if (NHttp::IsIPv4(address)) { - return std::make_shared<TSockAddrInet>(address.data(), port); - } - struct addrinfo hints = { - .ai_flags = AI_PASSIVE, - .ai_family = AF, - .ai_socktype = SOCK_STREAM, - }; - struct addrinfo* gai_res = nullptr; - int gai_ret = getaddrinfo(address.data(), nullptr, &hints, &gai_res); - std::shared_ptr<ISockAddr> result; - if (gai_ret == 0 && gai_res->ai_addr) { - switch (gai_res->ai_addr->sa_family) { - case AF_INET6: { - std::shared_ptr<TSockAddrInet6> resultIp6 = std::make_shared<TSockAddrInet6>(); - if (resultIp6->Size() >= gai_res->ai_addrlen) { - memcpy(resultIp6->SockAddr(), gai_res->ai_addr, gai_res->ai_addrlen); - resultIp6->SetPort(port); - result = std::move(resultIp6); - } - } - break; - case AF_INET: { - std::shared_ptr<TSockAddrInet> resultIp4 = std::make_shared<TSockAddrInet>(); - if (resultIp4->Size() >= gai_res->ai_addrlen) { - memcpy(resultIp4->SockAddr(), gai_res->ai_addr, gai_res->ai_addrlen); - resultIp4->SetPort(port); - result = std::move(resultIp4); - } - } - break; - } - } - if (gai_res) { - freeaddrinfo(gai_res); - } - if (result) { - return result; - } - throw yexception() << "Unable to resolve address " << address; - } - - static int GuessAddressFamily(const TString& address) { - if (!address) { - return 0; - } - if (NHttp::IsIPv6(address)) { - return AF_INET6; - } else if (NHttp::IsIPv4(address)) { - return AF_INET; - } - struct addrinfo hints = { - .ai_flags = AI_PASSIVE, - .ai_family = 0, - .ai_socktype = SOCK_STREAM, - }; - int result = 0; - struct addrinfo* gai_res = nullptr; - int gai_ret = getaddrinfo(address.data(), nullptr, &hints, &gai_res); - if (gai_ret == 0 && gai_res->ai_addr) { - switch (gai_res->ai_addr->sa_family) { - case AF_INET: - case AF_INET6: - result = gai_res->ai_addr->sa_family; - break; - } - } - if (gai_res) { - freeaddrinfo(gai_res); - } - return result; - } - - static std::shared_ptr<ISockAddr> MakeAddress(const sockaddr_storage& storage) { - std::shared_ptr<ISockAddr> addr; - switch (storage.ss_family) { - case AF_INET: - addr = std::make_shared<TSockAddrInet>(); - break; - case AF_INET6: - addr = std::make_shared<TSockAddrInet6>(); - break; - } - if (addr) { - memcpy(addr->SockAddr(), &storage, addr->Size()); - } - return addr; - } - - std::optional<TInet64StreamSocket> Accept(std::shared_ptr<ISockAddr>& acceptedAddr) { - sockaddr_storage addrStorage = {}; - socklen_t addrLen = sizeof(addrStorage); - SOCKET s = accept((SOCKET)*this, reinterpret_cast<sockaddr*>(&addrStorage), &addrLen); - if (s == INVALID_SOCKET) { - return {}; - } - acceptedAddr = MakeAddress(addrStorage); - return TInet64StreamSocket(*this, s); - } - -protected: - int AF = AF_UNSPEC; - - void CreateSocket(int af) { - SOCKET s; - if (af == 0) { - s = socket(AF = AF_INET6, SOCK_STREAM, 0); - if (s < 0) { - s = socket(AF = AF_INET, SOCK_STREAM, 0); - } - } else { - s = socket(AF = af, SOCK_STREAM, 0); - } - if (AF == AF_INET6) { - SetSockOpt(s, SOL_SOCKET, IPV6_V6ONLY, (int)false); - } - TSocketHolder sock(s); - sock.Swap(*this); - } -}; diff --git a/library/cpp/actors/http/http_proxy_sock_impl.h b/library/cpp/actors/http/http_proxy_sock_impl.h deleted file mode 100644 index 788c99d9b2..0000000000 --- a/library/cpp/actors/http/http_proxy_sock_impl.h +++ /dev/null @@ -1,274 +0,0 @@ -#pragma once - -#include "http.h" -#include "http_proxy.h" - -namespace NHttp { - -struct TPlainSocketImpl : virtual public THttpConfig { - TIntrusivePtr<TSocketDescriptor> Socket; - TString Host; - - TPlainSocketImpl() = default; - - void Create(int af) { - Socket = new TSocketDescriptor(af); - } - - TPlainSocketImpl(TIntrusivePtr<TSocketDescriptor> socket) - : Socket(std::move(socket)) - {} - - SOCKET GetRawSocket() const { - return static_cast<SOCKET>(Socket->Socket); - } - - void SetNonBlock(bool nonBlock = true) noexcept { - try { - ::SetNonBlock(Socket->Socket, nonBlock); - } - catch (const yexception&) { - } - } - - void SetTimeout(TDuration timeout) noexcept { - try { - ::SetSocketTimeout(Socket->Socket, timeout.Seconds(), timeout.MilliSecondsOfSecond()); - } - catch (const yexception&) { - } - } - - void Shutdown() { - //Socket->Socket.ShutDown(SHUT_RDWR); // KIKIMR-3895 - if (Socket) { - ::shutdown(Socket->Socket, SHUT_RDWR); - } - } - - int Connect(SocketAddressType address) { - return Socket->Socket.Connect(address.get()); - } - - static constexpr int OnConnect(bool&, bool&) { - return 1; - } - - static int OnAccept(std::shared_ptr<TPrivateEndpointInfo>, bool&, bool&) { - return 1; - } - - bool IsGood() { - int res; - GetSockOpt(Socket->Socket, SOL_SOCKET, SO_ERROR, res); - return res == 0; - } - - int GetError() { - int res; - GetSockOpt(Socket->Socket, SOL_SOCKET, SO_ERROR, res); - return res; - } - - ssize_t Send(const void* data, size_t size, bool&, bool&) { - return Socket->Socket.Send(data, size); - } - - ssize_t Recv(void* data, size_t size, bool&, bool&) { - return Socket->Socket.Recv(data, size); - } - - void SetHost(const TString& host) { - Host = host; - } -}; - -struct TSecureSocketImpl : TPlainSocketImpl, TSslHelpers { - static TSecureSocketImpl* IO(BIO* bio) noexcept { - return static_cast<TSecureSocketImpl*>(BIO_get_data(bio)); - } - - static int IoWrite(BIO* bio, const char* data, int dlen) noexcept { - BIO_clear_retry_flags(bio); - int res = IO(bio)->Socket->Socket.Send(data, dlen); - if (-res == EAGAIN) { - BIO_set_retry_write(bio); - } - return res; - } - - static int IoRead(BIO* bio, char* data, int dlen) noexcept { - BIO_clear_retry_flags(bio); - int res = IO(bio)->Socket->Socket.Recv(data, dlen); - if (-res == EAGAIN) { - BIO_set_retry_read(bio); - } - return res; - } - - static int IoPuts(BIO* bio, const char* buf) noexcept { - Y_UNUSED(bio); - Y_UNUSED(buf); - return -2; - } - - static int IoGets(BIO* bio, char* buf, int size) noexcept { - Y_UNUSED(bio); - Y_UNUSED(buf); - Y_UNUSED(size); - return -2; - } - - static long IoCtrl(BIO* bio, int cmd, long larg, void* parg) noexcept { - Y_UNUSED(larg); - Y_UNUSED(parg); - - if (cmd == BIO_CTRL_FLUSH) { - IO(bio)->Flush(); - return 1; - } - - return -2; - } - - static int IoCreate(BIO* bio) noexcept { - BIO_set_data(bio, nullptr); - BIO_set_init(bio, 1); - return 1; - } - - static int IoDestroy(BIO* bio) noexcept { - BIO_set_data(bio, nullptr); - BIO_set_init(bio, 0); - return 1; - } - - static BIO_METHOD* CreateIoMethod() { - BIO_METHOD* method = BIO_meth_new(BIO_get_new_index() | BIO_TYPE_SOURCE_SINK, "SecureSocketImpl"); - BIO_meth_set_write(method, IoWrite); - BIO_meth_set_read(method, IoRead); - BIO_meth_set_puts(method, IoPuts); - BIO_meth_set_gets(method, IoGets); - BIO_meth_set_ctrl(method, IoCtrl); - BIO_meth_set_create(method, IoCreate); - BIO_meth_set_destroy(method, IoDestroy); - return method; - } - - static BIO_METHOD* IoMethod() { - static BIO_METHOD* method = CreateIoMethod(); - return method; - } - - TSslHolder<BIO> Bio; - TSslHolder<SSL_CTX> Ctx; - TSslHolder<SSL> Ssl; - - TSecureSocketImpl() = default; - - TSecureSocketImpl(TIntrusivePtr<TSocketDescriptor> socket) - : TPlainSocketImpl(std::move(socket)) - {} - - void InitClientSsl() { - Bio.Reset(BIO_new(IoMethod())); - BIO_set_data(Bio.Get(), this); - BIO_set_nbio(Bio.Get(), 1); - Ctx = CreateClientContext(); - Ssl = ConstructSsl(Ctx.Get(), Bio.Get()); - if (!Host.Empty()) { - SSL_set_tlsext_host_name(Ssl.Get(), Host.c_str()); - } - SSL_set_connect_state(Ssl.Get()); - } - - void InitServerSsl(SSL_CTX* ctx) { - Bio.Reset(BIO_new(IoMethod())); - BIO_set_data(Bio.Get(), this); - BIO_set_nbio(Bio.Get(), 1); - Ssl = ConstructSsl(ctx, Bio.Get()); - SSL_set_accept_state(Ssl.Get()); - } - - void Flush() {} - - ssize_t Send(const void* data, size_t size, bool& read, bool& write) { - ssize_t res = SSL_write(Ssl.Get(), data, size); - if (res < 0) { - res = SSL_get_error(Ssl.Get(), res); - switch(res) { - case SSL_ERROR_WANT_READ: - read = true; - return -EAGAIN; - case SSL_ERROR_WANT_WRITE: - write = true; - return -EAGAIN; - default: - return -EIO; - } - } - return res; - } - - ssize_t Recv(void* data, size_t size, bool& read, bool& write) { - ssize_t res = SSL_read(Ssl.Get(), data, size); - if (res < 0) { - res = SSL_get_error(Ssl.Get(), res); - switch(res) { - case SSL_ERROR_WANT_READ: - read = true; - return -EAGAIN; - case SSL_ERROR_WANT_WRITE: - write = true; - return -EAGAIN; - default: - return -EIO; - } - } - return res; - } - - int OnConnect(bool& read, bool& write) { - if (!Ssl) { - InitClientSsl(); - } - int res = SSL_connect(Ssl.Get()); - if (res <= 0) { - res = SSL_get_error(Ssl.Get(), res); - switch(res) { - case SSL_ERROR_WANT_READ: - read = true; - return -EAGAIN; - case SSL_ERROR_WANT_WRITE: - write = true; - return -EAGAIN; - default: - return -EIO; - } - } - return res; - } - - int OnAccept(std::shared_ptr<TPrivateEndpointInfo> endpoint, bool& read, bool& write) { - if (!Ssl) { - InitServerSsl(endpoint->SecureContext.Get()); - } - int res = SSL_accept(Ssl.Get()); - if (res <= 0) { - res = SSL_get_error(Ssl.Get(), res); - switch(res) { - case SSL_ERROR_WANT_READ: - read = true; - return -EAGAIN; - case SSL_ERROR_WANT_WRITE: - write = true; - return -EAGAIN; - default: - return -EIO; - } - } - return res; - } -}; - -} diff --git a/library/cpp/actors/http/http_proxy_ssl.h b/library/cpp/actors/http/http_proxy_ssl.h deleted file mode 100644 index 9953430b1c..0000000000 --- a/library/cpp/actors/http/http_proxy_ssl.h +++ /dev/null @@ -1,133 +0,0 @@ -#pragma once - -#include <openssl/bio.h> -#include <openssl/ssl.h> -#include <openssl/err.h> -#include <openssl/tls1.h> - -namespace NHttp { - -struct TSslHelpers { - struct TSslDestroy { - static void Destroy(SSL_CTX* ctx) noexcept { - SSL_CTX_free(ctx); - } - - static void Destroy(SSL* ssl) noexcept { - SSL_free(ssl); - } - - static void Destroy(X509* cert) noexcept { - X509_free(cert); - } - - static void Destroy(EVP_PKEY* pkey) noexcept { - EVP_PKEY_free(pkey); - } - - static void Destroy(BIO* bio) noexcept { - BIO_free(bio); - } - }; - - template <typename T> - using TSslHolder = THolder<T, TSslDestroy>; - - static TSslHolder<SSL_CTX> CreateSslCtx(const SSL_METHOD* method) { - TSslHolder<SSL_CTX> ctx(SSL_CTX_new(method)); - - if (ctx) { - SSL_CTX_set_options(ctx.Get(), SSL_OP_NO_SSLv2); - SSL_CTX_set_options(ctx.Get(), SSL_OP_NO_SSLv3); - SSL_CTX_set_options(ctx.Get(), SSL_OP_NO_TLSv1); - SSL_CTX_set_options(ctx.Get(), SSL_OP_NO_TLSv1_1); - SSL_CTX_set_options(ctx.Get(), SSL_OP_MICROSOFT_SESS_ID_BUG); - SSL_CTX_set_options(ctx.Get(), SSL_OP_NETSCAPE_CHALLENGE_BUG); - } - - return ctx; - } - - static TSslHolder<SSL_CTX> CreateClientContext() { - return CreateSslCtx(SSLv23_client_method()); - } - - static TSslHolder<SSL_CTX> CreateServerContext(const TString& certificate, const TString& key) { - TSslHolder<SSL_CTX> ctx = CreateSslCtx(SSLv23_server_method()); - SSL_CTX_set_ecdh_auto(ctx.Get(), 1); - int res; - res = SSL_CTX_use_certificate_chain_file(ctx.Get(), certificate.c_str()); - if (res < 0) { - // TODO(xenoxeno): more diagnostics? - return nullptr; - } - res = SSL_CTX_use_PrivateKey_file(ctx.Get(), key.c_str(), SSL_FILETYPE_PEM); - if (res < 0) { - // TODO(xenoxeno): more diagnostics? - return nullptr; - } - return ctx; - } - - static bool LoadX509Chain(TSslHolder<SSL_CTX>& ctx, const TString& pem) { - TSslHolder<BIO> bio(BIO_new_mem_buf(pem.c_str(), pem.size())); - if (bio == nullptr) { - return false; - } - TSslHolder<X509> cert(PEM_read_bio_X509_AUX(bio.Get(), nullptr, nullptr, nullptr)); - if (cert == nullptr) { - return false; - } - if (SSL_CTX_use_certificate(ctx.Get(), cert.Release()) <= 0) { - return false; - } - SSL_CTX_clear_chain_certs(ctx.Get()); - while (true) { - TSslHolder<X509> ca(PEM_read_bio_X509(bio.Get(), nullptr, nullptr, nullptr)); - if (ca == nullptr) { - break; - } - if (!SSL_CTX_add0_chain_cert(ctx.Get(), ca.Release())) { - return false; - } - } - return true; - } - - static bool LoadPrivateKey(TSslHolder<SSL_CTX>& ctx, const TString& pem) { - TSslHolder<BIO> bio(BIO_new_mem_buf(pem.c_str(), pem.size())); - if (bio == nullptr) { - return false; - } - TSslHolder<EVP_PKEY> pkey(PEM_read_bio_PrivateKey(bio.Get(), nullptr, nullptr, nullptr)); - if (SSL_CTX_use_PrivateKey(ctx.Get(), pkey.Release()) <= 0) { - return false; - } - return true; - } - - static TSslHolder<SSL_CTX> CreateServerContext(const TString& pem) { - TSslHolder<SSL_CTX> ctx = CreateSslCtx(SSLv23_server_method()); - SSL_CTX_set_ecdh_auto(ctx.Get(), 1); - if (!LoadX509Chain(ctx, pem)) { - return nullptr; - } - if (!LoadPrivateKey(ctx, pem)) { - return nullptr; - } - return ctx; - } - - static TSslHolder<SSL> ConstructSsl(SSL_CTX* ctx, BIO* bio) { - TSslHolder<SSL> ssl(SSL_new(ctx)); - - if (ssl) { - BIO_up_ref(bio); // SSL_set_bio consumes only one reference if rbio and wbio are the same - SSL_set_bio(ssl.Get(), bio, bio); - } - - return ssl; - } -}; - -} diff --git a/library/cpp/actors/http/http_static.cpp b/library/cpp/actors/http/http_static.cpp deleted file mode 100644 index ff36f5486d..0000000000 --- a/library/cpp/actors/http/http_static.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include "http_proxy.h" -#include "http_static.h" -#include <library/cpp/actors/core/executor_pool_basic.h> -#include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/core/scheduler_basic.h> -#include <library/cpp/actors/http/http.h> -#include <library/cpp/resource/resource.h> -#include <util/folder/path.h> -#include <util/stream/file.h> - -namespace NHttp { - -class THttpStaticContentHandler : public NActors::TActor<THttpStaticContentHandler> { -public: - using TBase = NActors::TActor<THttpStaticContentHandler>; - const TFsPath URL; - const TFsPath FilePath; - const TFsPath ResourcePath; - const TFsPath Index; - - THttpStaticContentHandler(const TString& url, const TString& filePath, const TString& resourcePath, const TString& index) - : TBase(&THttpStaticContentHandler::StateWork) - , URL(url) - , FilePath(filePath) - , ResourcePath(resourcePath) - , Index(index) - {} - - static constexpr char ActorName[] = "HTTP_STATIC_ACTOR"; - - static TInstant GetCompileTime() { - tm compileTime; - strptime(__DATE__ " " __TIME__, "%B %d %Y %H:%M:%S", &compileTime); - return TInstant::Seconds(mktime(&compileTime)); - } - - void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) { - THttpOutgoingResponsePtr response; - if (event->Get()->Request->Method != "GET") { - response = event->Get()->Request->CreateResponseBadRequest("Wrong request"); - ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response)); - return; - } - TFsPath url(event->Get()->Request->URL.Before('?')); - if (!url.IsAbsolute()) { - response = event->Get()->Request->CreateResponseBadRequest("Completely wrong URL"); - ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response)); - return; - } - if (url.GetPath().EndsWith('/') && Index.IsDefined()) { - url /= Index; - } - url = url.RelativeTo(URL); - try { - // TODO: caching? - TString contentType = mimetypeByExt(url.GetExtension().c_str()); - TString data; - TFileStat filestat; - TFsPath resourcename(ResourcePath / url); - if (NResource::FindExact(resourcename.GetPath(), &data)) { - static TInstant compileTime(GetCompileTime()); - filestat.MTime = compileTime.Seconds(); - } else { - TFsPath filename(FilePath / url); - if (!filename.IsSubpathOf(FilePath) && filename != FilePath) { - response = event->Get()->Request->CreateResponseBadRequest("Wrong URL"); - ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response)); - return; - } - if (filename.Stat(filestat) && filestat.IsFile()) { - data = TUnbufferedFileInput(filename).ReadAll(); - } - } - if (!filestat.IsNull()) { - response = event->Get()->Request->CreateResponseOK(data, contentType, TInstant::Seconds(filestat.MTime)); - } else { - response = event->Get()->Request->CreateResponseNotFound("File not found"); - } - } - catch (const yexception&) { - response = event->Get()->Request->CreateResponseServiceUnavailable("Not available"); - } - ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response)); - } - - STFUNC(StateWork) { - switch (ev->GetTypeRewrite()) { - HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingRequest, Handle); - } - } -}; - -NActors::IActor* CreateHttpStaticContentHandler(const TString& url, const TString& filePath, const TString& resourcePath, const TString& index) { - return new THttpStaticContentHandler(url, filePath, resourcePath, index); -} - -} diff --git a/library/cpp/actors/http/http_static.h b/library/cpp/actors/http/http_static.h deleted file mode 100644 index f91e15dfb1..0000000000 --- a/library/cpp/actors/http/http_static.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include <library/cpp/actors/core/actor.h> -#include "http.h" - -namespace NHttp { - -NActors::IActor* CreateHttpStaticContentHandler(const TString& url, const TString& filePath, const TString& resourcePath, const TString& index = TString()); - -} diff --git a/library/cpp/actors/http/http_ut.cpp b/library/cpp/actors/http/http_ut.cpp deleted file mode 100644 index e06de07867..0000000000 --- a/library/cpp/actors/http/http_ut.cpp +++ /dev/null @@ -1,509 +0,0 @@ -#include <library/cpp/testing/unittest/registar.h> -#include <library/cpp/testing/unittest/tests_data.h> -#include <library/cpp/actors/core/executor_pool_basic.h> -#include <library/cpp/actors/core/scheduler_basic.h> -#include <library/cpp/actors/testlib/test_runtime.h> -#include <util/system/tempfile.h> -#include "http.h" -#include "http_proxy.h" - - - -enum EService : NActors::NLog::EComponent { - MIN, - Logger, - MVP, - MAX -}; - -namespace { - -template <typename HttpType> -void EatWholeString(TIntrusivePtr<HttpType>& request, const TString& data) { - request->EnsureEnoughSpaceAvailable(data.size()); - auto size = std::min(request->Avail(), data.size()); - memcpy(request->Pos(), data.data(), size); - request->Advance(size); -} - -template <typename HttpType> -void EatPartialString(TIntrusivePtr<HttpType>& request, const TString& data) { - for (char c : data) { - request->EnsureEnoughSpaceAvailable(1); - memcpy(request->Pos(), &c, 1); - request->Advance(1); - } -} - -} - -Y_UNIT_TEST_SUITE(HttpProxy) { - Y_UNIT_TEST(BasicParsing) { - NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest(); - EatWholeString(request, "GET /test HTTP/1.1\r\nHost: test\r\nSome-Header: 32344\r\n\r\n"); - UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done); - UNIT_ASSERT_EQUAL(request->Method, "GET"); - UNIT_ASSERT_EQUAL(request->URL, "/test"); - UNIT_ASSERT_EQUAL(request->Protocol, "HTTP"); - UNIT_ASSERT_EQUAL(request->Version, "1.1"); - UNIT_ASSERT_EQUAL(request->Host, "test"); - UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nSome-Header: 32344\r\n\r\n"); - } - - Y_UNIT_TEST(GetWithSpecifiedContentType) { - NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest(); - EatWholeString(request, "GET /test HTTP/1.1\r\nHost: test\r\nContent-Type: application/json\r\nSome-Header: 32344\r\n\r\n"); - UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done); - UNIT_ASSERT_EQUAL(request->Method, "GET"); - UNIT_ASSERT_EQUAL(request->URL, "/test"); - UNIT_ASSERT_EQUAL(request->Protocol, "HTTP"); - UNIT_ASSERT_EQUAL(request->Version, "1.1"); - UNIT_ASSERT_EQUAL(request->Host, "test"); - UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nContent-Type: application/json\r\nSome-Header: 32344\r\n\r\n"); - } - - Y_UNIT_TEST(BasicParsingChunkedBodyRequest) { - NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest(); - EatWholeString(request, "POST /Url HTTP/1.1\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n4\r\nthis\r\n4\r\n is \r\n5\r\ntest.\r\n0\r\n\r\n"); - UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done); - UNIT_ASSERT_EQUAL(request->Method, "POST"); - UNIT_ASSERT_EQUAL(request->URL, "/Url"); - UNIT_ASSERT_EQUAL(request->Connection, "close"); - UNIT_ASSERT_EQUAL(request->Protocol, "HTTP"); - UNIT_ASSERT_EQUAL(request->Version, "1.1"); - UNIT_ASSERT_EQUAL(request->TransferEncoding, "chunked"); - UNIT_ASSERT_EQUAL(request->Body, "this is test."); - } - - Y_UNIT_TEST(BasicPost) { - NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest(); - EatWholeString(request, "POST /Url HTTP/1.1\r\nConnection: close\r\nContent-Length: 13\r\n\r\nthis is test."); - UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done); - UNIT_ASSERT_EQUAL(request->Method, "POST"); - UNIT_ASSERT_EQUAL(request->URL, "/Url"); - UNIT_ASSERT_EQUAL(request->Connection, "close"); - UNIT_ASSERT_EQUAL(request->Protocol, "HTTP"); - UNIT_ASSERT_EQUAL(request->Version, "1.1"); - UNIT_ASSERT_EQUAL(request->TransferEncoding, ""); - UNIT_ASSERT_EQUAL(request->Body, "this is test."); - } - - Y_UNIT_TEST(BasicParsingChunkedBodyResponse) { - NHttp::THttpOutgoingRequestPtr request = nullptr; //new NHttp::THttpOutgoingRequest(); - NHttp::THttpIncomingResponsePtr response = new NHttp::THttpIncomingResponse(request); - EatWholeString(response, "HTTP/1.1 200 OK\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n4\r\nthis\r\n4\r\n is \r\n5\r\ntest.\r\n0\r\n\r\n"); - UNIT_ASSERT_EQUAL(response->Stage, NHttp::THttpIncomingResponse::EParseStage::Done); - UNIT_ASSERT_EQUAL(response->Status, "200"); - UNIT_ASSERT_EQUAL(response->Connection, "close"); - UNIT_ASSERT_EQUAL(response->Protocol, "HTTP"); - UNIT_ASSERT_EQUAL(response->Version, "1.1"); - UNIT_ASSERT_EQUAL(response->TransferEncoding, "chunked"); - UNIT_ASSERT_EQUAL(response->Body, "this is test."); - } - - Y_UNIT_TEST(InvalidParsingChunkedBody) { - NHttp::THttpOutgoingRequestPtr request = nullptr; //new NHttp::THttpOutgoingRequest(); - NHttp::THttpIncomingResponsePtr response = new NHttp::THttpIncomingResponse(request); - EatWholeString(response, "HTTP/1.1 200 OK\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nthis\r\n4\r\n is \r\n5\r\ntest.\r\n0\r\n\r\n"); - UNIT_ASSERT(response->IsError()); - } - - Y_UNIT_TEST(AdvancedParsingChunkedBody) { - NHttp::THttpOutgoingRequestPtr request = nullptr; //new NHttp::THttpOutgoingRequest(); - NHttp::THttpIncomingResponsePtr response = new NHttp::THttpIncomingResponse(request); - EatWholeString(response, "HTTP/1.1 200 OK\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n6\r\nthis\r\n\r\n4\r\n is \r\n5\r\ntest.\r\n0\r\n\r\n"); - UNIT_ASSERT_EQUAL(response->Stage, NHttp::THttpIncomingResponse::EParseStage::Done); - UNIT_ASSERT_EQUAL(response->Status, "200"); - UNIT_ASSERT_EQUAL(response->Connection, "close"); - UNIT_ASSERT_EQUAL(response->Protocol, "HTTP"); - UNIT_ASSERT_EQUAL(response->Version, "1.1"); - UNIT_ASSERT_EQUAL(response->TransferEncoding, "chunked"); - UNIT_ASSERT_EQUAL(response->Body, "this\r\n is test."); - } - - Y_UNIT_TEST(CreateCompressedResponse) { - NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest(); - EatWholeString(request, "GET /Url HTTP/1.1\r\nConnection: close\r\nAccept-Encoding: gzip, deflate\r\n\r\n"); - NHttp::THttpOutgoingResponsePtr response = new NHttp::THttpOutgoingResponse(request, "HTTP", "1.1", "200", "OK"); - TString compressedBody = "something very long to compress with deflate algorithm. something very long to compress with deflate algorithm."; - response->EnableCompression(); - size_t size1 = response->Size(); - response->SetBody(compressedBody); - size_t size2 = response->Size(); - size_t compressedBodySize = size2 - size1; - UNIT_ASSERT_VALUES_EQUAL("deflate", response->ContentEncoding); - UNIT_ASSERT(compressedBodySize < compressedBody.size()); - NHttp::THttpOutgoingResponsePtr response2 = response->Duplicate(request); - UNIT_ASSERT_VALUES_EQUAL(response->Body, response2->Body); - UNIT_ASSERT_VALUES_EQUAL(response->ContentLength, response2->ContentLength); - UNIT_ASSERT_VALUES_EQUAL(response->Size(), response2->Size()); - } - - Y_UNIT_TEST(BasicPartialParsing) { - NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest(); - EatPartialString(request, "GET /test HTTP/1.1\r\nHost: test\r\nSome-Header: 32344\r\n\r\n"); - UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done); - UNIT_ASSERT_EQUAL(request->Method, "GET"); - UNIT_ASSERT_EQUAL(request->URL, "/test"); - UNIT_ASSERT_EQUAL(request->Protocol, "HTTP"); - UNIT_ASSERT_EQUAL(request->Version, "1.1"); - UNIT_ASSERT_EQUAL(request->Host, "test"); - UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nSome-Header: 32344\r\n\r\n"); - } - - Y_UNIT_TEST(BasicPartialParsingChunkedBody) { - NHttp::THttpOutgoingRequestPtr request = nullptr; //new NHttp::THttpOutgoingRequest(); - NHttp::THttpIncomingResponsePtr response = new NHttp::THttpIncomingResponse(request); - EatPartialString(response, "HTTP/1.1 200 OK\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n4\r\nthis\r\n4\r\n is \r\n5\r\ntest.\r\n0\r\n\r\n"); - UNIT_ASSERT_EQUAL(response->Stage, NHttp::THttpIncomingResponse::EParseStage::Done); - UNIT_ASSERT_EQUAL(response->Status, "200"); - UNIT_ASSERT_EQUAL(response->Connection, "close"); - UNIT_ASSERT_EQUAL(response->Protocol, "HTTP"); - UNIT_ASSERT_EQUAL(response->Version, "1.1"); - UNIT_ASSERT_EQUAL(response->TransferEncoding, "chunked"); - UNIT_ASSERT_EQUAL(response->Body, "this is test."); - } - - Y_UNIT_TEST(BasicParsingContentLength0) { - NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest(); - EatPartialString(request, "GET /test HTTP/1.1\r\nHost: test\r\nContent-Length: 0\r\n\r\n"); - UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done); - UNIT_ASSERT_EQUAL(request->Method, "GET"); - UNIT_ASSERT_EQUAL(request->URL, "/test"); - UNIT_ASSERT_EQUAL(request->Protocol, "HTTP"); - UNIT_ASSERT_EQUAL(request->Version, "1.1"); - UNIT_ASSERT_EQUAL(request->Host, "test"); - UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nContent-Length: 0\r\n\r\n"); - } - - Y_UNIT_TEST(AdvancedParsing) { - NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest(); - EatWholeString(request, "GE"); - EatWholeString(request, "T"); - EatWholeString(request, " "); - EatWholeString(request, "/test"); - EatWholeString(request, " HTTP/1.1\r"); - EatWholeString(request, "\nHo"); - EatWholeString(request, "st: test"); - EatWholeString(request, "\r\n"); - EatWholeString(request, "Some-Header: 32344\r\n\r"); - EatWholeString(request, "\n"); - UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done); - UNIT_ASSERT_EQUAL(request->Method, "GET"); - UNIT_ASSERT_EQUAL(request->URL, "/test"); - UNIT_ASSERT_EQUAL(request->Protocol, "HTTP"); - UNIT_ASSERT_EQUAL(request->Version, "1.1"); - UNIT_ASSERT_EQUAL(request->Host, "test"); - UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nSome-Header: 32344\r\n\r\n"); - } - - Y_UNIT_TEST(AdvancedPartialParsing) { - NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest(); - EatPartialString(request, "GE"); - EatPartialString(request, "T"); - EatPartialString(request, " "); - EatPartialString(request, "/test"); - EatPartialString(request, " HTTP/1.1\r"); - EatPartialString(request, "\nHo"); - EatPartialString(request, "st: test"); - EatPartialString(request, "\r\n"); - EatPartialString(request, "Some-Header: 32344\r\n\r"); - EatPartialString(request, "\n"); - UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done); - UNIT_ASSERT_EQUAL(request->Method, "GET"); - UNIT_ASSERT_EQUAL(request->URL, "/test"); - UNIT_ASSERT_EQUAL(request->Protocol, "HTTP"); - UNIT_ASSERT_EQUAL(request->Version, "1.1"); - UNIT_ASSERT_EQUAL(request->Host, "test"); - UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nSome-Header: 32344\r\n\r\n"); - } - - Y_UNIT_TEST(BasicRenderBodyWithHeadersAndCookies) { - NHttp::THttpOutgoingRequestPtr request = NHttp::THttpOutgoingRequest::CreateRequestGet("http://www.yandex.ru/data/url"); - NHttp::THeadersBuilder headers; - NHttp::TCookiesBuilder cookies; - cookies.Set("cookie1", "123456"); - cookies.Set("cookie2", "45678"); - headers.Set("Cookie", cookies.Render()); - request->Set(headers); - TString requestData = request->AsString(); - UNIT_ASSERT_VALUES_EQUAL(requestData, "GET /data/url HTTP/1.1\r\nHost: www.yandex.ru\r\nAccept: */*\r\nCookie: cookie1=123456; cookie2=45678;\r\n"); - } - - Y_UNIT_TEST(BasicRenderOutgoingResponse) { - NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest(); - EatWholeString(request, "GET /test HTTP/1.1\r\nHost: test\r\nSome-Header: 32344\r\n\r\n"); - - NHttp::THttpOutgoingResponsePtr httpResponseOk = request->CreateResponseOK("response ok"); - UNIT_ASSERT_EQUAL(httpResponseOk->Stage, NHttp::THttpOutgoingResponse::ERenderStage::Done); - UNIT_ASSERT_STRINGS_EQUAL(httpResponseOk->Status, "200"); - UNIT_ASSERT_STRINGS_EQUAL(httpResponseOk->Message, "OK"); - UNIT_ASSERT_STRINGS_EQUAL(httpResponseOk->ContentType, "text/html"); - UNIT_ASSERT_STRINGS_EQUAL(httpResponseOk->Body, "response ok"); - - NHttp::THttpOutgoingResponsePtr httpResponseBadRequest = request->CreateResponseBadRequest(); - UNIT_ASSERT_EQUAL(httpResponseBadRequest->Stage, NHttp::THttpOutgoingResponse::ERenderStage::Done); - UNIT_ASSERT_STRINGS_EQUAL(httpResponseBadRequest->Status, "400"); - UNIT_ASSERT_STRINGS_EQUAL(httpResponseBadRequest->Message, "Bad Request"); - UNIT_ASSERT(httpResponseBadRequest->ContentType.empty()); - UNIT_ASSERT(httpResponseBadRequest->Body.empty()); - - NHttp::THttpOutgoingResponsePtr httpResponseNotFound = request->CreateResponseNotFound(); - UNIT_ASSERT_EQUAL(httpResponseNotFound->Stage, NHttp::THttpOutgoingResponse::ERenderStage::Done); - UNIT_ASSERT_STRINGS_EQUAL(httpResponseNotFound->Status, "404"); - UNIT_ASSERT_STRINGS_EQUAL(httpResponseNotFound->Message, "Not Found"); - UNIT_ASSERT(httpResponseNotFound->ContentType.empty()); - UNIT_ASSERT(httpResponseNotFound->Body.empty()); - - NHttp::THttpOutgoingResponsePtr httpResponseServiceUnavailable = request->CreateResponseServiceUnavailable(); - UNIT_ASSERT_EQUAL(httpResponseServiceUnavailable->Stage, NHttp::THttpOutgoingResponse::ERenderStage::Done); - UNIT_ASSERT_STRINGS_EQUAL(httpResponseServiceUnavailable->Status, "503"); - UNIT_ASSERT_STRINGS_EQUAL(httpResponseServiceUnavailable->Message, "Service Unavailable"); - UNIT_ASSERT(httpResponseServiceUnavailable->ContentType.empty()); - UNIT_ASSERT(httpResponseServiceUnavailable->Body.empty()); - - NHttp::THttpOutgoingResponsePtr httpResponseGatewayTimeout = request->CreateResponseGatewayTimeout("gateway timeout body"); - UNIT_ASSERT_EQUAL(httpResponseGatewayTimeout->Stage, NHttp::THttpOutgoingResponse::ERenderStage::Done); - UNIT_ASSERT_STRINGS_EQUAL(httpResponseGatewayTimeout->Status, "504"); - UNIT_ASSERT_STRINGS_EQUAL(httpResponseGatewayTimeout->Message, "Gateway Timeout"); - UNIT_ASSERT_STRINGS_EQUAL(httpResponseGatewayTimeout->ContentType, "text/html"); - UNIT_ASSERT_STRINGS_EQUAL(httpResponseGatewayTimeout->Body, "gateway timeout body"); - - NHttp::THttpOutgoingResponsePtr httpIncompleteResponse = request->CreateIncompleteResponse("401", "Unauthorized"); - UNIT_ASSERT_EQUAL(httpIncompleteResponse->Stage, NHttp::THttpOutgoingResponse::ERenderStage::Header); - UNIT_ASSERT_STRINGS_EQUAL(httpIncompleteResponse->Status, "401"); - UNIT_ASSERT_STRINGS_EQUAL(httpIncompleteResponse->Message, "Unauthorized"); - - NHttp::THttpOutgoingResponsePtr httpResponse = request->CreateResponse("401", "Unauthorized"); - UNIT_ASSERT_EQUAL(httpResponse->Stage, NHttp::THttpOutgoingResponse::ERenderStage::Done); - UNIT_ASSERT_STRINGS_EQUAL(httpResponse->Status, "401"); - UNIT_ASSERT_STRINGS_EQUAL(httpResponse->Message, "Unauthorized"); - - NHttp::THeadersBuilder headers; - NHttp::TCookiesBuilder cookies; - cookies.Set("cookie1", "123456"); - headers.Set("Set-Cookie", cookies.Render()); - headers.Set("Location", "http://www.yandex.ru/data/url"); - - NHttp::THttpOutgoingResponsePtr httpResponseRedirect = request->CreateResponse("302", "Found", headers); - UNIT_ASSERT_EQUAL(httpResponseRedirect->Stage, NHttp::THttpOutgoingResponse::ERenderStage::Done); - UNIT_ASSERT_STRINGS_EQUAL(httpResponseRedirect->Status, "302"); - UNIT_ASSERT_STRINGS_EQUAL(httpResponseRedirect->Message, "Found"); - UNIT_ASSERT_STRING_CONTAINS(httpResponseRedirect->Headers, "Set-Cookie: cookie1=123456;"); - UNIT_ASSERT_STRING_CONTAINS(httpResponseRedirect->Headers, "Location: http://www.yandex.ru/data/url"); - } - - Y_UNIT_TEST(BasicRunning4) { - NActors::TTestActorRuntimeBase actorSystem; - TPortManager portManager; - TIpPort port = portManager.GetTcpPort(); - TAutoPtr<NActors::IEventHandle> handle; - actorSystem.Initialize(); - //actorSystem.SetLogPriority(NActorsServices::HTTP, NActors::NLog::PRI_DEBUG); - - NActors::IActor* proxy = NHttp::CreateHttpProxy(); - NActors::TActorId proxyId = actorSystem.Register(proxy); - actorSystem.Send(new NActors::IEventHandle(proxyId, TActorId(), new NHttp::TEvHttpProxy::TEvAddListeningPort(port)), 0, true); - actorSystem.DispatchEvents(); - - NActors::TActorId serverId = actorSystem.AllocateEdgeActor(); - actorSystem.Send(new NActors::IEventHandle(proxyId, serverId, new NHttp::TEvHttpProxy::TEvRegisterHandler("/test", serverId)), 0, true); - - NActors::TActorId clientId = actorSystem.AllocateEdgeActor(); - NHttp::THttpOutgoingRequestPtr httpRequest = NHttp::THttpOutgoingRequest::CreateRequestGet("http://127.0.0.1:" + ToString(port) + "/test"); - actorSystem.Send(new NActors::IEventHandle(proxyId, clientId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(httpRequest)), 0, true); - - NHttp::TEvHttpProxy::TEvHttpIncomingRequest* request = actorSystem.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvHttpIncomingRequest>(handle); - - UNIT_ASSERT_EQUAL(request->Request->URL, "/test"); - - NHttp::THttpOutgoingResponsePtr httpResponse = request->Request->CreateResponseString("HTTP/1.1 200 Found\r\nConnection: Close\r\nTransfer-Encoding: chunked\r\n\r\n6\r\npassed\r\n0\r\n\r\n"); - actorSystem.Send(new NActors::IEventHandle(handle->Sender, serverId, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(httpResponse)), 0, true); - - NHttp::TEvHttpProxy::TEvHttpIncomingResponse* response = actorSystem.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvHttpIncomingResponse>(handle); - - UNIT_ASSERT_EQUAL(response->Response->Status, "200"); - UNIT_ASSERT_EQUAL(response->Response->Body, "passed"); - } - - Y_UNIT_TEST(BasicRunning6) { - NActors::TTestActorRuntimeBase actorSystem; - TPortManager portManager; - TIpPort port = portManager.GetTcpPort(); - TAutoPtr<NActors::IEventHandle> handle; - actorSystem.Initialize(); - //actorSystem.SetLogPriority(NActorsServices::HTTP, NActors::NLog::PRI_DEBUG); - - NActors::IActor* proxy = NHttp::CreateHttpProxy(); - NActors::TActorId proxyId = actorSystem.Register(proxy); - actorSystem.Send(new NActors::IEventHandle(proxyId, TActorId(), new NHttp::TEvHttpProxy::TEvAddListeningPort(port)), 0, true); - actorSystem.DispatchEvents(); - - NActors::TActorId serverId = actorSystem.AllocateEdgeActor(); - actorSystem.Send(new NActors::IEventHandle(proxyId, serverId, new NHttp::TEvHttpProxy::TEvRegisterHandler("/test", serverId)), 0, true); - - NActors::TActorId clientId = actorSystem.AllocateEdgeActor(); - NHttp::THttpOutgoingRequestPtr httpRequest = NHttp::THttpOutgoingRequest::CreateRequestGet("http://[::1]:" + ToString(port) + "/test"); - actorSystem.Send(new NActors::IEventHandle(proxyId, clientId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(httpRequest)), 0, true); - - NHttp::TEvHttpProxy::TEvHttpIncomingRequest* request = actorSystem.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvHttpIncomingRequest>(handle); - - UNIT_ASSERT_EQUAL(request->Request->URL, "/test"); - - NHttp::THttpOutgoingResponsePtr httpResponse = request->Request->CreateResponseString("HTTP/1.1 200 Found\r\nConnection: Close\r\nTransfer-Encoding: chunked\r\n\r\n6\r\npassed\r\n0\r\n\r\n"); - actorSystem.Send(new NActors::IEventHandle(handle->Sender, serverId, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(httpResponse)), 0, true); - - NHttp::TEvHttpProxy::TEvHttpIncomingResponse* response = actorSystem.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvHttpIncomingResponse>(handle); - - UNIT_ASSERT_EQUAL(response->Response->Status, "200"); - UNIT_ASSERT_EQUAL(response->Response->Body, "passed"); - } - - Y_UNIT_TEST(TlsRunning) { - NActors::TTestActorRuntimeBase actorSystem; - TPortManager portManager; - TIpPort port = portManager.GetTcpPort(); - TAutoPtr<NActors::IEventHandle> handle; - actorSystem.Initialize(); - - TString certificateContent = R"___(-----BEGIN PRIVATE KEY----- -MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCzRZjodO7Aqe1w -RyOj6kG6g2nn8ZGAxfao4mLT0jDTbVksrhV/h2s3uldLkFo5WrNQ8WZe+iIbXeFL -s8tO6hslzreo9sih2IHoRcH5KnS/6YTqVhRTJb1jE2dM8NwYbwTi+T2Pe0FrBPjI -kgVO50gAtYl9C+fc715uZiSKW+rRlP5OoFTwxrOjiU27RPZjFYyWK9wTI1Es9uRr -lbZbLl5cY6dK2J1AViRraaYKCWO26VbOPWLsY4OD3e+ZXIc3OMCz6Yb0wmRPeJ60 -bbbkGfI8O27kDdv69MAWHIm0yYMzKEnom1dce7rNQNDEqJfocsYIsg+EvayT1yQ9 -KTBegw7LAgMBAAECggEBAKaOCrotqYQmXArsjRhFFDwMy+BKdzyEr93INrlFl0dX -WHpCYobRcbOc1G3H94tB0UdqgAnNqtJyLlb+++ydZAuEOu4oGc8EL+10ofq0jzOd -6Xct8kQt0/6wkFDTlii9PHUDy0X65ZRgUiNGRtg/2I2QG+SpowmI+trm2xwQueFs -VaWrjc3cVvXx0b8Lu7hqZUv08kgC38stzuRk/n2T5VWSAr7Z4ZWQbO918Dv35HUw -Wy/0jNUFP9CBCvFJ4l0OoH9nYhWFG+HXWzNdw6/Hca4jciRKo6esCiOZ9uWYv/ec -/NvX9rgFg8G8/SrTisX10+Bbeq+R1RKwq/IG409TH4ECgYEA14L+3QsgNIUMeYAx -jSCyk22R/tOHI1BM+GtKPUhnwHlAssrcPcxXMJovl6WL93VauYjym0wpCz9urSpA -I2CqTsG8GYciA6Dr3mHgD6cK0jj9UPAU6EnZ5S0mjhPqKZqutu9QegzD2uESvuN8 -36xezwQthzAf0nI/P3sJGjVXjikCgYEA1POm5xcV6SmM6HnIdadEebhzZIJ9TXQz -ry3Jj3a7CKyD5C7fAdkHUTCjgT/2ElxPi9ABkZnC+d/cW9GtJFa0II5qO/agm3KQ -ZXYiutu9A7xACHYFXRiJEjVUdGG9dKMVOHUEa8IHEgrrcUVM/suy/GgutywIfaXs -y58IFP24K9MCgYEAk6zjz7wL+XEiNy+sxLQfKf7vB9sSwxQHakK6wHuY/L8Zomp3 -uLEJHfjJm/SIkK0N2g0JkXkCtv5kbKyC/rsCeK0wo52BpVLjzaLr0k34kE0U6B1b -dkEE2pGx1bG3x4KDLj+Wuct9ecK5Aa0IqIyI+vo16GkFpUM8K9e3SQo8UOECgYEA -sCZYAkILYtJ293p9giz5rIISGasDAUXE1vxWBXEeJ3+kneTTnZCrx9Im/ewtnWR0 -fF90XL9HFDDD88POqAd8eo2zfKR2l/89SGBfPBg2EtfuU9FkgGyiPciVcqvC7q9U -B15saMKX3KnhtdGwbfeLt9RqCCTJZT4SUSDcq5hwdvcCgYAxY4Be8mNipj8Cgg22 -mVWSolA0TEzbtUcNk6iGodpi+Z0LKpsPC0YRqPRyh1K+rIltG1BVdmUBHcMlOYxl -lWWvbJH6PkJWy4n2MF7PO45kjN3pPZg4hgH63JjZeAineBwEArUGb9zHnvzcdRvF -wuQ2pZHL/HJ0laUSieHDJ5917w== ------END PRIVATE KEY----- - - ------BEGIN CERTIFICATE----- -MIIDjTCCAnWgAwIBAgIURt5IBx0J3xgEaQvmyrFH2A+NkpMwDQYJKoZIhvcNAQEL -BQAwVjELMAkGA1UEBhMCUlUxDzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9z -Y293MQ8wDQYDVQQKDAZZYW5kZXgxFDASBgNVBAMMC3Rlc3Qtc2VydmVyMB4XDTE5 -MDkyMDE3MTQ0MVoXDTQ3MDIwNDE3MTQ0MVowVjELMAkGA1UEBhMCUlUxDzANBgNV -BAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MQ8wDQYDVQQKDAZZYW5kZXgxFDAS -BgNVBAMMC3Rlc3Qtc2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAs0WY6HTuwKntcEcjo+pBuoNp5/GRgMX2qOJi09Iw021ZLK4Vf4drN7pXS5Ba -OVqzUPFmXvoiG13hS7PLTuobJc63qPbIodiB6EXB+Sp0v+mE6lYUUyW9YxNnTPDc -GG8E4vk9j3tBawT4yJIFTudIALWJfQvn3O9ebmYkilvq0ZT+TqBU8Mazo4lNu0T2 -YxWMlivcEyNRLPbka5W2Wy5eXGOnStidQFYka2mmCgljtulWzj1i7GODg93vmVyH -NzjAs+mG9MJkT3ietG225BnyPDtu5A3b+vTAFhyJtMmDMyhJ6JtXXHu6zUDQxKiX -6HLGCLIPhL2sk9ckPSkwXoMOywIDAQABo1MwUTAdBgNVHQ4EFgQUDv/xuJ4CvCgG -fPrZP3hRAt2+/LwwHwYDVR0jBBgwFoAUDv/xuJ4CvCgGfPrZP3hRAt2+/LwwDwYD -VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAinKpMYaA2tjLpAnPVbjy -/ZxSBhhB26RiQp3Re8XOKyhTWqgYE6kldYT0aXgK9x9mPC5obQannDDYxDc7lX+/ -qP/u1X81ZcDRo/f+qQ3iHfT6Ftt/4O3qLnt45MFM6Q7WabRm82x3KjZTqpF3QUdy -tumWiuAP5DMd1IRDtnKjFHO721OsEsf6NLcqdX89bGeqXDvrkwg3/PNwTyW5E7cj -feY8L2eWtg6AJUnIBu11wvfzkLiH3QKzHvO/SIZTGf5ihDsJ3aKEE9UNauTL3bVc -CRA/5XcX13GJwHHj6LCoc3sL7mt8qV9HKY2AOZ88mpObzISZxgPpdKCfjsrdm63V -6g== ------END CERTIFICATE-----)___"; - - TTempFileHandle certificateFile; - - certificateFile.Write(certificateContent.data(), certificateContent.size()); - - NActors::IActor* proxy = NHttp::CreateHttpProxy(); - NActors::TActorId proxyId = actorSystem.Register(proxy); - - THolder<NHttp::TEvHttpProxy::TEvAddListeningPort> add = MakeHolder<NHttp::TEvHttpProxy::TEvAddListeningPort>(port); - ///////// https configuration - add->Secure = true; - add->CertificateFile = certificateFile.Name(); - add->PrivateKeyFile = certificateFile.Name(); - ///////// - actorSystem.Send(new NActors::IEventHandle(proxyId, TActorId(), add.Release()), 0, true); - actorSystem.DispatchEvents(); - - NActors::TActorId serverId = actorSystem.AllocateEdgeActor(); - actorSystem.Send(new NActors::IEventHandle(proxyId, serverId, new NHttp::TEvHttpProxy::TEvRegisterHandler("/test", serverId)), 0, true); - - NActors::TActorId clientId = actorSystem.AllocateEdgeActor(); - NHttp::THttpOutgoingRequestPtr httpRequest = NHttp::THttpOutgoingRequest::CreateRequestGet("https://[::1]:" + ToString(port) + "/test"); - actorSystem.Send(new NActors::IEventHandle(proxyId, clientId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(httpRequest)), 0, true); - - NHttp::TEvHttpProxy::TEvHttpIncomingRequest* request = actorSystem.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvHttpIncomingRequest>(handle); - - UNIT_ASSERT_EQUAL(request->Request->URL, "/test"); - - NHttp::THttpOutgoingResponsePtr httpResponse = request->Request->CreateResponseString("HTTP/1.1 200 Found\r\nConnection: Close\r\nTransfer-Encoding: chunked\r\n\r\n6\r\npassed\r\n0\r\n\r\n"); - actorSystem.Send(new NActors::IEventHandle(handle->Sender, serverId, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(httpResponse)), 0, true); - - NHttp::TEvHttpProxy::TEvHttpIncomingResponse* response = actorSystem.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvHttpIncomingResponse>(handle); - - UNIT_ASSERT_EQUAL(response->Response->Status, "200"); - UNIT_ASSERT_EQUAL(response->Response->Body, "passed"); - } - - /*Y_UNIT_TEST(AdvancedRunning) { - THolder<NActors::TActorSystemSetup> setup = MakeHolder<NActors::TActorSystemSetup>(); - setup->NodeId = 1; - setup->ExecutorsCount = 1; - setup->Executors = new TAutoPtr<NActors::IExecutorPool>[1]; - setup->Executors[0] = new NActors::TBasicExecutorPool(0, 2, 10); - setup->Scheduler = new NActors::TBasicSchedulerThread(NActors::TSchedulerConfig(512, 100)); - NActors::TActorSystem actorSystem(setup); - actorSystem.Start(); - NHttp::THttpProxy* incomingProxy = new NHttp::THttpProxy(); - NActors::TActorId incomingProxyId = actorSystem.Register(incomingProxy); - actorSystem.Send(incomingProxyId, new NHttp::TEvHttpProxy::TEvAddListeningPort(13337)); - - NHttp::THttpProxy* outgoingProxy = new NHttp::THttpProxy(); - NActors::TActorId outgoingProxyId = actorSystem.Register(outgoingProxy); - - THolder<NHttp::THttpStaticStringRequest> httpRequest = MakeHolder<NHttp::THttpStaticStringRequest>("GET /test HTTP/1.1\r\n\r\n"); - actorSystem.Send(outgoingProxyId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest("[::]:13337", std::move(httpRequest))); - - Sleep(TDuration::Minutes(60)); - }*/ - - Y_UNIT_TEST(TooLongHeader) { - NActors::TTestActorRuntimeBase actorSystem; - actorSystem.SetUseRealInterconnect(); - TPortManager portManager; - TIpPort port = portManager.GetTcpPort(); - TAutoPtr<NActors::IEventHandle> handle; - actorSystem.Initialize(); - - NActors::IActor* proxy = NHttp::CreateHttpProxy(); - NActors::TActorId proxyId = actorSystem.Register(proxy); - actorSystem.Send(new NActors::IEventHandle(proxyId, TActorId(), new NHttp::TEvHttpProxy::TEvAddListeningPort(port)), 0, true); - actorSystem.DispatchEvents(); - - NActors::TActorId serverId = actorSystem.AllocateEdgeActor(); - actorSystem.Send(new NActors::IEventHandle(proxyId, serverId, new NHttp::TEvHttpProxy::TEvRegisterHandler("/test", serverId)), 0, true); - - NActors::TActorId clientId = actorSystem.AllocateEdgeActor(); - NHttp::THttpOutgoingRequestPtr httpRequest = NHttp::THttpOutgoingRequest::CreateRequestGet("http://[::1]:" + ToString(port) + "/test"); - httpRequest->Set("Connection", "close"); - TString longHeader; - longHeader.append(9000, 'X'); - httpRequest->Set(longHeader, "data"); - actorSystem.Send(new NActors::IEventHandle(proxyId, clientId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(httpRequest)), 0, true); - - NHttp::TEvHttpProxy::TEvHttpIncomingResponse* response = actorSystem.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvHttpIncomingResponse>(handle); - - UNIT_ASSERT_EQUAL(response->Response->Status, "400"); - UNIT_ASSERT_EQUAL(response->Response->Body, "Invalid http header"); - } -} diff --git a/library/cpp/actors/http/ut/CMakeLists.darwin-arm64.txt b/library/cpp/actors/http/ut/CMakeLists.darwin-arm64.txt deleted file mode 100644 index f9c9afac61..0000000000 --- a/library/cpp/actors/http/ut/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,67 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-http-ut) -target_include_directories(library-cpp-actors-http-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http -) -target_link_libraries(library-cpp-actors-http-ut PUBLIC - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-http - cpp-actors-testlib -) -target_link_options(library-cpp-actors-http-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-http-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_ut.cpp -) -set_property( - TARGET - library-cpp-actors-http-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-http-ut - TEST_TARGET - library-cpp-actors-http-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-http-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-http-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-http-ut - system_allocator -) -vcs_info(library-cpp-actors-http-ut) diff --git a/library/cpp/actors/http/ut/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/http/ut/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 99677acae5..0000000000 --- a/library/cpp/actors/http/ut/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,68 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-http-ut) -target_include_directories(library-cpp-actors-http-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http -) -target_link_libraries(library-cpp-actors-http-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-http - cpp-actors-testlib -) -target_link_options(library-cpp-actors-http-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-http-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_ut.cpp -) -set_property( - TARGET - library-cpp-actors-http-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-http-ut - TEST_TARGET - library-cpp-actors-http-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-http-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-http-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-http-ut - system_allocator -) -vcs_info(library-cpp-actors-http-ut) diff --git a/library/cpp/actors/http/ut/CMakeLists.linux-aarch64.txt b/library/cpp/actors/http/ut/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 8818e4418f..0000000000 --- a/library/cpp/actors/http/ut/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,71 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-http-ut) -target_include_directories(library-cpp-actors-http-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http -) -target_link_libraries(library-cpp-actors-http-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-http - cpp-actors-testlib -) -target_link_options(library-cpp-actors-http-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-http-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_ut.cpp -) -set_property( - TARGET - library-cpp-actors-http-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-http-ut - TEST_TARGET - library-cpp-actors-http-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-http-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-http-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-http-ut - cpp-malloc-jemalloc -) -vcs_info(library-cpp-actors-http-ut) diff --git a/library/cpp/actors/http/ut/CMakeLists.linux-x86_64.txt b/library/cpp/actors/http/ut/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 620f66ad00..0000000000 --- a/library/cpp/actors/http/ut/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,73 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-http-ut) -target_include_directories(library-cpp-actors-http-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http -) -target_link_libraries(library-cpp-actors-http-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-http - cpp-actors-testlib -) -target_link_options(library-cpp-actors-http-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-http-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http/http_ut.cpp -) -set_property( - TARGET - library-cpp-actors-http-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-http-ut - TEST_TARGET - library-cpp-actors-http-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-http-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-http-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-http-ut - cpp-malloc-tcmalloc - libs-tcmalloc-no_percpu_cache -) -vcs_info(library-cpp-actors-http-ut) diff --git a/library/cpp/actors/http/ut/CMakeLists.txt b/library/cpp/actors/http/ut/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/http/ut/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/http/ut/CMakeLists.windows-x86_64.txt b/library/cpp/actors/http/ut/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 73603d626c..0000000000 --- a/library/cpp/actors/http/ut/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,58 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-http-ut) -target_include_directories(library-cpp-actors-http-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/http -) -target_link_libraries(library-cpp-actors-http-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-http - cpp-actors-testlib -) -set_property( - TARGET - library-cpp-actors-http-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-http-ut - TEST_TARGET - library-cpp-actors-http-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-http-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-http-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-http-ut - system_allocator -) -vcs_info(library-cpp-actors-http-ut) diff --git a/library/cpp/actors/http/ut/ya.make b/library/cpp/actors/http/ut/ya.make deleted file mode 100644 index 8404308053..0000000000 --- a/library/cpp/actors/http/ut/ya.make +++ /dev/null @@ -1,16 +0,0 @@ -UNITTEST_FOR(library/cpp/actors/http) - -SIZE(SMALL) - -PEERDIR( - library/cpp/actors/testlib -) - -IF (NOT OS_WINDOWS) -SRCS( - http_ut.cpp -) -ELSE() -ENDIF() - -END() diff --git a/library/cpp/actors/http/ya.make b/library/cpp/actors/http/ya.make deleted file mode 100644 index 9b66988ea9..0000000000 --- a/library/cpp/actors/http/ya.make +++ /dev/null @@ -1,36 +0,0 @@ -LIBRARY() - -SRCS( - http_cache.cpp - http_cache.h - http_compress.cpp - http_config.h - http_proxy_acceptor.cpp - http_proxy_incoming.cpp - http_proxy_outgoing.cpp - http_proxy_sock_impl.h - http_proxy_sock64.h - http_proxy_ssl.h - http_proxy.cpp - http_proxy.h - http_static.cpp - http_static.h - http.cpp - http.h -) - -PEERDIR( - contrib/libs/openssl - contrib/libs/zlib - library/cpp/actors/core - library/cpp/actors/interconnect - library/cpp/dns - library/cpp/monlib/metrics - library/cpp/string_utils/quote -) - -END() - -RECURSE_FOR_TESTS( - ut -) diff --git a/library/cpp/actors/interconnect/CMakeLists.darwin-arm64.txt b/library/cpp/actors/interconnect/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 92e1fec219..0000000000 --- a/library/cpp/actors/interconnect/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,61 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(mock) -add_subdirectory(ut) -add_subdirectory(ut_fat) -add_subdirectory(ut_huge_cluster) - -add_library(cpp-actors-interconnect) -target_link_libraries(cpp-actors-interconnect PUBLIC - contrib-libs-cxxsupp - yutil - contrib-libs-libc_compat - contrib-libs-openssl - contrib-libs-xxhash - cpp-actors-core - cpp-actors-dnscachelib - cpp-actors-dnsresolver - cpp-actors-helpers - cpp-actors-prof - cpp-actors-protos - cpp-actors-util - cpp-actors-wilson - cpp-digest-crc32c - library-cpp-json - library-cpp-lwtrace - cpp-monlib-dynamic_counters - cpp-monlib-metrics - service-pages-resources - service-pages-tablesorter - cpp-openssl-init - library-cpp-packedtypes -) -target_sources(cpp-actors-interconnect PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_address.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_channel.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_counters.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_handshake.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_mon.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_nameserver_dynamic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_nameserver_table.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_proxy_wrapper.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_resolve.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_stream.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_proxy.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_server.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_session.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/load.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/packet.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_tcp.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_tcp_unit.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_tcp_unit_select.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/types.cpp -) diff --git a/library/cpp/actors/interconnect/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/interconnect/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 92e1fec219..0000000000 --- a/library/cpp/actors/interconnect/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,61 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(mock) -add_subdirectory(ut) -add_subdirectory(ut_fat) -add_subdirectory(ut_huge_cluster) - -add_library(cpp-actors-interconnect) -target_link_libraries(cpp-actors-interconnect PUBLIC - contrib-libs-cxxsupp - yutil - contrib-libs-libc_compat - contrib-libs-openssl - contrib-libs-xxhash - cpp-actors-core - cpp-actors-dnscachelib - cpp-actors-dnsresolver - cpp-actors-helpers - cpp-actors-prof - cpp-actors-protos - cpp-actors-util - cpp-actors-wilson - cpp-digest-crc32c - library-cpp-json - library-cpp-lwtrace - cpp-monlib-dynamic_counters - cpp-monlib-metrics - service-pages-resources - service-pages-tablesorter - cpp-openssl-init - library-cpp-packedtypes -) -target_sources(cpp-actors-interconnect PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_address.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_channel.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_counters.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_handshake.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_mon.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_nameserver_dynamic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_nameserver_table.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_proxy_wrapper.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_resolve.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_stream.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_proxy.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_server.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_session.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/load.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/packet.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_tcp.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_tcp_unit.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_tcp_unit_select.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/types.cpp -) diff --git a/library/cpp/actors/interconnect/CMakeLists.linux-aarch64.txt b/library/cpp/actors/interconnect/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 9fb3219fcf..0000000000 --- a/library/cpp/actors/interconnect/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,63 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(mock) -add_subdirectory(ut) -add_subdirectory(ut_fat) -add_subdirectory(ut_huge_cluster) - -add_library(cpp-actors-interconnect) -target_link_libraries(cpp-actors-interconnect PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - contrib-libs-libc_compat - contrib-libs-openssl - contrib-libs-xxhash - cpp-actors-core - cpp-actors-dnscachelib - cpp-actors-dnsresolver - cpp-actors-helpers - cpp-actors-prof - cpp-actors-protos - cpp-actors-util - cpp-actors-wilson - cpp-digest-crc32c - library-cpp-json - library-cpp-lwtrace - cpp-monlib-dynamic_counters - cpp-monlib-metrics - service-pages-resources - service-pages-tablesorter - cpp-openssl-init - library-cpp-packedtypes -) -target_sources(cpp-actors-interconnect PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_address.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_channel.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_counters.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_handshake.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_mon.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_nameserver_dynamic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_nameserver_table.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_proxy_wrapper.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_resolve.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_stream.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_proxy.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_server.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_session.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/load.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/packet.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_tcp.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_tcp_unit.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_tcp_unit_select.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/types.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_tcp_unit_epoll.cpp -) diff --git a/library/cpp/actors/interconnect/CMakeLists.linux-x86_64.txt b/library/cpp/actors/interconnect/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 9fb3219fcf..0000000000 --- a/library/cpp/actors/interconnect/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,63 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(mock) -add_subdirectory(ut) -add_subdirectory(ut_fat) -add_subdirectory(ut_huge_cluster) - -add_library(cpp-actors-interconnect) -target_link_libraries(cpp-actors-interconnect PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - contrib-libs-libc_compat - contrib-libs-openssl - contrib-libs-xxhash - cpp-actors-core - cpp-actors-dnscachelib - cpp-actors-dnsresolver - cpp-actors-helpers - cpp-actors-prof - cpp-actors-protos - cpp-actors-util - cpp-actors-wilson - cpp-digest-crc32c - library-cpp-json - library-cpp-lwtrace - cpp-monlib-dynamic_counters - cpp-monlib-metrics - service-pages-resources - service-pages-tablesorter - cpp-openssl-init - library-cpp-packedtypes -) -target_sources(cpp-actors-interconnect PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_address.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_channel.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_counters.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_handshake.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_mon.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_nameserver_dynamic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_nameserver_table.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_proxy_wrapper.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_resolve.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_stream.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_proxy.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_server.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_session.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/load.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/packet.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_tcp.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_tcp_unit.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_tcp_unit_select.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/types.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_tcp_unit_epoll.cpp -) diff --git a/library/cpp/actors/interconnect/CMakeLists.txt b/library/cpp/actors/interconnect/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/interconnect/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/interconnect/CMakeLists.windows-x86_64.txt b/library/cpp/actors/interconnect/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 92e1fec219..0000000000 --- a/library/cpp/actors/interconnect/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,61 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(mock) -add_subdirectory(ut) -add_subdirectory(ut_fat) -add_subdirectory(ut_huge_cluster) - -add_library(cpp-actors-interconnect) -target_link_libraries(cpp-actors-interconnect PUBLIC - contrib-libs-cxxsupp - yutil - contrib-libs-libc_compat - contrib-libs-openssl - contrib-libs-xxhash - cpp-actors-core - cpp-actors-dnscachelib - cpp-actors-dnsresolver - cpp-actors-helpers - cpp-actors-prof - cpp-actors-protos - cpp-actors-util - cpp-actors-wilson - cpp-digest-crc32c - library-cpp-json - library-cpp-lwtrace - cpp-monlib-dynamic_counters - cpp-monlib-metrics - service-pages-resources - service-pages-tablesorter - cpp-openssl-init - library-cpp-packedtypes -) -target_sources(cpp-actors-interconnect PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_address.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_channel.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_counters.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_handshake.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_mon.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_nameserver_dynamic.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_nameserver_table.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_proxy_wrapper.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_resolve.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_stream.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_proxy.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_server.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/interconnect_tcp_session.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/load.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/packet.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_actor.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_tcp.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_tcp_unit.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/poller_tcp_unit_select.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/types.cpp -) diff --git a/library/cpp/actors/interconnect/channel_scheduler.h b/library/cpp/actors/interconnect/channel_scheduler.h deleted file mode 100644 index b0eac9debc..0000000000 --- a/library/cpp/actors/interconnect/channel_scheduler.h +++ /dev/null @@ -1,116 +0,0 @@ -#pragma once - -#include "interconnect_channel.h" -#include "event_holder_pool.h" - -#include <memory> - -namespace NActors { - - class TChannelScheduler { - const ui32 PeerNodeId; - std::array<std::optional<TEventOutputChannel>, 16> ChannelArray; - THashMap<ui16, TEventOutputChannel> ChannelMap; - std::shared_ptr<IInterconnectMetrics> Metrics; - TEventHolderPool& Pool; - const ui32 MaxSerializedEventSize; - const TSessionParams Params; - - struct THeapItem { - TEventOutputChannel *Channel; - ui64 WeightConsumed = 0; - - friend bool operator <(const THeapItem& x, const THeapItem& y) { - return x.WeightConsumed > y.WeightConsumed; - } - }; - - std::vector<THeapItem> Heap; - - public: - TChannelScheduler(ui32 peerNodeId, const TChannelsConfig& predefinedChannels, - std::shared_ptr<IInterconnectMetrics> metrics, TEventHolderPool& pool, ui32 maxSerializedEventSize, - TSessionParams params) - : PeerNodeId(peerNodeId) - , Metrics(std::move(metrics)) - , Pool(pool) - , MaxSerializedEventSize(maxSerializedEventSize) - , Params(std::move(params)) - { - for (const auto& item : predefinedChannels) { - GetOutputChannel(item.first); - } - } - - TEventOutputChannel *PickChannelWithLeastConsumedWeight() { - Y_ABORT_UNLESS(!Heap.empty()); - return Heap.front().Channel; - } - - void AddToHeap(TEventOutputChannel& channel, ui64 counter) { - Y_DEBUG_ABORT_UNLESS(channel.IsWorking()); - ui64 weight = channel.WeightConsumedOnPause; - weight -= Min(weight, counter - channel.EqualizeCounterOnPause); - Heap.push_back(THeapItem{&channel, weight}); - std::push_heap(Heap.begin(), Heap.end()); - } - - void FinishPick(ui64 weightConsumed, ui64 counter) { - std::pop_heap(Heap.begin(), Heap.end()); - auto& item = Heap.back(); - item.WeightConsumed += weightConsumed; - if (item.Channel->IsWorking()) { // reschedule - std::push_heap(Heap.begin(), Heap.end()); - } else { // remove from heap - item.Channel->EqualizeCounterOnPause = counter; - item.Channel->WeightConsumedOnPause = item.WeightConsumed; - Heap.pop_back(); - } - } - - TEventOutputChannel& GetOutputChannel(ui16 channel) { - if (channel < ChannelArray.size()) { - auto& res = ChannelArray[channel]; - if (Y_UNLIKELY(!res)) { - res.emplace(Pool, channel, PeerNodeId, MaxSerializedEventSize, Metrics, - Params); - } - return *res; - } else { - auto it = ChannelMap.find(channel); - if (Y_UNLIKELY(it == ChannelMap.end())) { - it = ChannelMap.emplace(std::piecewise_construct, std::forward_as_tuple(channel), - std::forward_as_tuple(Pool, channel, PeerNodeId, MaxSerializedEventSize, - Metrics, Params)).first; - } - return it->second; - } - } - - ui64 Equalize() { - if (Heap.empty()) { - return 0; // nothing to do here -- no working channels - } - - // find the minimum consumed weight among working channels and then adjust weights - const ui64 min = Heap.front().WeightConsumed; - for (THeapItem& item : Heap) { - item.WeightConsumed -= min; - } - return min; - } - - template<typename TCallback> - void ForEach(TCallback&& callback) { - for (auto& channel : ChannelArray) { - if (channel) { - callback(*channel); - } - } - for (auto& [id, channel] : ChannelMap) { - callback(channel); - } - } - }; - -} // NActors diff --git a/library/cpp/actors/interconnect/event_filter.h b/library/cpp/actors/interconnect/event_filter.h deleted file mode 100644 index 47dabf5f16..0000000000 --- a/library/cpp/actors/interconnect/event_filter.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/event.h> - -namespace NActors { - - enum class ENodeClass { - SYSTEM, - LOCAL_TENANT, - PEER_TENANT, - COUNT - }; - - class TEventFilter : TNonCopyable { - using TRouteMask = ui16; - - TVector<TVector<TRouteMask>> ScopeRoutes; - - public: - TEventFilter() - : ScopeRoutes(65536) - {} - - void RegisterEvent(ui32 type, TRouteMask routes) { - auto& evSpaceIndex = ScopeRoutes[type >> 16]; - const ui16 subtype = type & 65535; - size_t size = (subtype + 512) & ~511; - if (evSpaceIndex.size() < size) { - evSpaceIndex.resize(size); - } - evSpaceIndex[subtype] = routes; - } - - bool CheckIncomingEvent(const IEventHandle& ev, const TScopeId& localScopeId) const { - TRouteMask routes = 0; - if (const auto& evSpaceIndex = ScopeRoutes[ev.Type >> 16]) { - const ui16 subtype = ev.Type & 65535; - routes = subtype < evSpaceIndex.size() ? evSpaceIndex[subtype] : 0; - } else { - routes = ~TRouteMask(); // allow unfilled event spaces by default - } - return routes & MakeRouteMask(GetNodeClass(ev.OriginScopeId, localScopeId), GetNodeClass(localScopeId, ev.OriginScopeId)); - } - - static ENodeClass GetNodeClass(const TScopeId& scopeId, const TScopeId& localScopeId) { - if (scopeId.first == 0) { - // system scope, or null scope - return scopeId.second ? ENodeClass::SYSTEM : ENodeClass::COUNT; - } else if (scopeId == localScopeId) { - return ENodeClass::LOCAL_TENANT; - } else { - return ENodeClass::PEER_TENANT; - } - } - - static TRouteMask MakeRouteMask(ENodeClass from, ENodeClass to) { - if (from == ENodeClass::COUNT || to == ENodeClass::COUNT) { - return 0; - } - return 1U << (static_cast<unsigned>(from) * static_cast<unsigned>(ENodeClass::COUNT) + static_cast<unsigned>(to)); - } - - static TRouteMask MakeRouteMask(std::initializer_list<std::pair<ENodeClass, ENodeClass>> items) { - TRouteMask mask = 0; - for (const auto& p : items) { - mask |= MakeRouteMask(p.first, p.second); - } - return mask; - } - }; - -} // NActors diff --git a/library/cpp/actors/interconnect/event_holder_pool.h b/library/cpp/actors/interconnect/event_holder_pool.h deleted file mode 100644 index 0afa1d7a7c..0000000000 --- a/library/cpp/actors/interconnect/event_holder_pool.h +++ /dev/null @@ -1,127 +0,0 @@ -#pragma once - -#include <library/cpp/containers/stack_vector/stack_vec.h> - -#include "packet.h" - -namespace NActors { - struct TEvFreeItems : TEventLocal<TEvFreeItems, EventSpaceBegin(TEvents::ES_PRIVATE)> { - static constexpr size_t MaxEvents = 256; - - std::list<TEventHolder> FreeQueue; - TStackVec<THolder<IEventBase>, MaxEvents> Events; - TStackVec<THolder<TEventSerializedData>, MaxEvents> Buffers; - std::shared_ptr<std::atomic<TAtomicBase>> Counter; - ui64 NumBytes = 0; - - ~TEvFreeItems() { - if (Counter) { - TAtomicBase res = Counter->fetch_sub(NumBytes) - NumBytes; - Y_ABORT_UNLESS(res >= 0); - } - } - - bool GetInLineForDestruction(const TIntrusivePtr<TInterconnectProxyCommon>& common) { - Y_ABORT_UNLESS(!Counter); - const auto& counter = common->DestructorQueueSize; - const auto& max = common->MaxDestructorQueueSize; - if (counter && (TAtomicBase)(counter->fetch_add(NumBytes) + NumBytes) > max) { - counter->fetch_sub(NumBytes); - return false; - } - Counter = counter; - return true; - } - }; - - class TEventHolderPool { - using TDestroyCallback = std::function<void(THolder<IEventBase>)>; - - static constexpr size_t MaxFreeQueueItems = 32; - static constexpr size_t FreeQueueTrimThreshold = MaxFreeQueueItems * 2; - static constexpr ui64 MaxBytesPerMessage = 10 * 1024 * 1024; - - TIntrusivePtr<TInterconnectProxyCommon> Common; - std::list<TEventHolder> Cache; - THolder<TEvFreeItems> PendingFreeEvent; - TDestroyCallback DestroyCallback; - - public: - TEventHolderPool(TIntrusivePtr<TInterconnectProxyCommon> common, - TDestroyCallback destroyCallback) - : Common(std::move(common)) - , DestroyCallback(std::move(destroyCallback)) - {} - - TEventHolder& Allocate(std::list<TEventHolder>& queue) { - if (Cache.empty()) { - queue.emplace_back(); - } else { - queue.splice(queue.end(), Cache, Cache.begin()); - } - return queue.back(); - } - - void Release(std::list<TEventHolder>& queue) { - for (auto it = queue.begin(); it != queue.end(); ) { - Release(queue, it++); - } - } - - void Release(std::list<TEventHolder>& queue, std::list<TEventHolder>::iterator event) { - bool trim = false; - - // release held event, if any - if (THolder<IEventBase> ev = std::move(event->Event)) { - auto p = GetPendingEvent(); - p->NumBytes += event->EventSerializedSize; - auto& events = p->Events; - events.push_back(std::move(ev)); - trim = trim || events.size() >= TEvFreeItems::MaxEvents || p->NumBytes >= MaxBytesPerMessage; - } - - // release buffer, if any - if (event->Buffer && event->Buffer.RefCount() == 1) { - auto p = GetPendingEvent(); - p->NumBytes += event->EventSerializedSize; - auto& buffers = p->Buffers; - buffers.emplace_back(event->Buffer.Release()); - trim = trim || buffers.size() >= TEvFreeItems::MaxEvents || p->NumBytes >= MaxBytesPerMessage; - } - - // free event and trim the cache if its size is exceeded - event->Clear(); - Cache.splice(Cache.end(), queue, event); - if (Cache.size() >= FreeQueueTrimThreshold) { - auto& freeQueue = GetPendingEvent()->FreeQueue; - auto it = Cache.begin(); - std::advance(it, Cache.size() - MaxFreeQueueItems); - freeQueue.splice(freeQueue.end(), Cache, Cache.begin(), it); - trim = true; - } - - // release items if we have hit the limit - if (trim) { - Trim(); - } - } - - void Trim() { - if (auto ev = std::move(PendingFreeEvent); ev && ev->GetInLineForDestruction(Common)) { - DestroyCallback(std::move(ev)); - } - - // ensure it is dropped - PendingFreeEvent.Reset(); - } - - private: - TEvFreeItems* GetPendingEvent() { - if (!PendingFreeEvent) { - PendingFreeEvent.Reset(new TEvFreeItems); - } - return PendingFreeEvent.Get(); - } - }; - -} diff --git a/library/cpp/actors/interconnect/events_local.h b/library/cpp/actors/interconnect/events_local.h deleted file mode 100644 index 465899c335..0000000000 --- a/library/cpp/actors/interconnect/events_local.h +++ /dev/null @@ -1,438 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/events.h> -#include <library/cpp/actors/core/event_local.h> -#include <library/cpp/actors/protos/interconnect.pb.h> -#include <util/generic/deque.h> -#include <util/network/address.h> - -#include "interconnect_stream.h" -#include "types.h" - -namespace NActors { - enum class ENetwork : ui32 { - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // local messages - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - Start = EventSpaceBegin(TEvents::ES_INTERCONNECT_TCP), - - SocketReadyRead = Start, - SocketReadyWrite, - SocketError, - Connect, - Disconnect, - IncomingConnection, - HandshakeAsk, - HandshakeAck, - HandshakeNak, - HandshakeDone, - HandshakeFail, - Kick, - Flush, - NodeInfo, - BunchOfEventsToDestroy, - HandshakeRequest, - HandshakeReplyOK, - HandshakeReplyError, - ResolveAddress, - AddressInfo, - ResolveError, - HTTPStreamStatus, - HTTPSendContent, - ConnectProtocolWakeup, - HTTPProtocolRetry, - EvPollerRegister, - EvPollerRegisterResult, - EvPollerReady, - EvUpdateFromInputSession, - EvConfirmUpdate, - EvSessionBufferSizeRequest, - EvSessionBufferSizeResponse, - EvProcessPingRequest, - EvGetSecureSocket, - EvSecureSocket, - HandshakeBrokerTake, - HandshakeBrokerFree, - HandshakeBrokerPermit, - - // external data channel messages - EvSubscribeForConnection, - EvReportConnection, - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // nonlocal messages; their indices must be preserved in order to work properly while doing rolling update - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - // interconnect load test message - EvLoadMessage = Start + 256, - }; - - struct TEvSocketReadyRead: public TEventLocal<TEvSocketReadyRead, ui32(ENetwork::SocketReadyRead)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvSocketReadyRead, "Network: TEvSocketReadyRead") - }; - - struct TEvSocketReadyWrite: public TEventLocal<TEvSocketReadyWrite, ui32(ENetwork::SocketReadyWrite)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvSocketReadyWrite, "Network: TEvSocketReadyWrite") - }; - - struct TEvSocketError: public TEventLocal<TEvSocketError, ui32(ENetwork::SocketError)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvSocketError, ::strerror(Error)) - TString GetReason() const { - return ::strerror(Error); - } - const int Error; - TIntrusivePtr<NInterconnect::TStreamSocket> Socket; - - TEvSocketError(int error, TIntrusivePtr<NInterconnect::TStreamSocket> sock) - : Error(error) - , Socket(std::move(sock)) - { - } - }; - - struct TEvSocketConnect: public TEventLocal<TEvSocketConnect, ui32(ENetwork::Connect)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvSocketConnect, "Network: TEvSocketConnect") - }; - - struct TEvSocketDisconnect: public TEventLocal<TEvSocketDisconnect, ui32(ENetwork::Disconnect)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvSocketDisconnect, "Network: TEvSocketDisconnect") - TDisconnectReason Reason; - - TEvSocketDisconnect(TDisconnectReason reason) - : Reason(std::move(reason)) - { - } - }; - - struct TEvHandshakeBrokerTake: TEventLocal<TEvHandshakeBrokerTake, ui32(ENetwork::HandshakeBrokerTake)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvHandshakeBrokerTake, "Network: TEvHandshakeBrokerTake") - }; - - struct TEvHandshakeBrokerFree: TEventLocal<TEvHandshakeBrokerFree, ui32(ENetwork::HandshakeBrokerFree)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvHandshakeBrokerFree, "Network: TEvHandshakeBrokerFree") - }; - - struct TEvHandshakeBrokerPermit: TEventLocal<TEvHandshakeBrokerPermit, ui32(ENetwork::HandshakeBrokerPermit)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvHandshakeBrokerPermit, "Network: TEvHandshakeBrokerPermit") - }; - - struct TEvHandshakeAsk: public TEventLocal<TEvHandshakeAsk, ui32(ENetwork::HandshakeAsk)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvHandshakeAsk, "Network: TEvHandshakeAsk") - TEvHandshakeAsk(const TActorId& self, - const TActorId& peer, - ui64 counter) - : Self(self) - , Peer(peer) - , Counter(counter) - { - } - const TActorId Self; - const TActorId Peer; - const ui64 Counter; - }; - - struct TEvHandshakeAck: public TEventLocal<TEvHandshakeAck, ui32(ENetwork::HandshakeAck)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvHandshakeAck, "Network: TEvHandshakeAck") - - TEvHandshakeAck(const TActorId& self, ui64 nextPacket, TSessionParams params) - : Self(self) - , NextPacket(nextPacket) - , Params(std::move(params)) - {} - - const TActorId Self; - const ui64 NextPacket; - const TSessionParams Params; - }; - - struct TEvHandshakeNak : TEventLocal<TEvHandshakeNak, ui32(ENetwork::HandshakeNak)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvSocketReadyRead, "Network: TEvHandshakeNak") - }; - - struct TEvHandshakeRequest - : public TEventLocal<TEvHandshakeRequest, - ui32(ENetwork::HandshakeRequest)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvHandshakeRequest, - "Network: TEvHandshakeRequest") - - NActorsInterconnect::THandshakeRequest Record; - }; - - struct TEvHandshakeReplyOK - : public TEventLocal<TEvHandshakeReplyOK, - ui32(ENetwork::HandshakeReplyOK)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvHandshakeReplyOK, - "Network: TEvHandshakeReplyOK") - - NActorsInterconnect::THandshakeReply Record; - }; - - struct TEvHandshakeReplyError - : public TEventLocal<TEvHandshakeReplyError, - ui32(ENetwork::HandshakeReplyError)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvHandshakeReplyError, - "Network: TEvHandshakeReplyError") - - TEvHandshakeReplyError(TString error) { - Record.SetErrorExplaination(error); - } - - NActorsInterconnect::THandshakeReply Record; - }; - - struct TEvIncomingConnection: public TEventLocal<TEvIncomingConnection, ui32(ENetwork::IncomingConnection)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvIncomingConnection, "Network: TEvIncomingConnection") - TIntrusivePtr<NInterconnect::TStreamSocket> Socket; - NInterconnect::TAddress Address; - - TEvIncomingConnection(TIntrusivePtr<NInterconnect::TStreamSocket> socket, NInterconnect::TAddress address) - : Socket(std::move(socket)) - , Address(std::move(address)) - {} - }; - - struct TEvHandshakeDone: public TEventLocal<TEvHandshakeDone, ui32(ENetwork::HandshakeDone)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvHandshakeDone, "Network: TEvHandshakeDone") - - TEvHandshakeDone( - TIntrusivePtr<NInterconnect::TStreamSocket> socket, - const TActorId& peer, - const TActorId& self, - ui64 nextPacket, - TAutoPtr<TProgramInfo>&& programInfo, - TSessionParams params, - TIntrusivePtr<NInterconnect::TStreamSocket> xdcSocket) - : Socket(std::move(socket)) - , Peer(peer) - , Self(self) - , NextPacket(nextPacket) - , ProgramInfo(std::move(programInfo)) - , Params(std::move(params)) - , XdcSocket(std::move(xdcSocket)) - { - } - - TIntrusivePtr<NInterconnect::TStreamSocket> Socket; - const TActorId Peer; - const TActorId Self; - const ui64 NextPacket; - TAutoPtr<TProgramInfo> ProgramInfo; - const TSessionParams Params; - TIntrusivePtr<NInterconnect::TStreamSocket> XdcSocket; - }; - - struct TEvHandshakeFail: public TEventLocal<TEvHandshakeFail, ui32(ENetwork::HandshakeFail)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvHandshakeFail, "Network: TEvHandshakeFail") - - enum EnumHandshakeFail { - HANDSHAKE_FAIL_TRANSIENT, - HANDSHAKE_FAIL_PERMANENT, - HANDSHAKE_FAIL_SESSION_MISMATCH, - }; - - TEvHandshakeFail(EnumHandshakeFail temporary, TString explanation) - : Temporary(temporary) - , Explanation(std::move(explanation)) - { - } - - const EnumHandshakeFail Temporary; - const TString Explanation; - }; - - struct TEvKick: public TEventLocal<TEvKick, ui32(ENetwork::Kick)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvKick, "Network: TEvKick") - }; - - struct TEvFlush: public TEventLocal<TEvFlush, ui32(ENetwork::Flush)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvFlush, "Network: TEvFlush") - }; - - struct TEvLocalNodeInfo - : public TEventLocal<TEvLocalNodeInfo, ui32(ENetwork::NodeInfo)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvLocalNodeInfo, "Network: TEvLocalNodeInfo") - - ui32 NodeId; - std::vector<NInterconnect::TAddress> Addresses; - }; - - struct TEvBunchOfEventsToDestroy : TEventLocal<TEvBunchOfEventsToDestroy, ui32(ENetwork::BunchOfEventsToDestroy)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvBunchOfEventsToDestroy, - "Network: TEvBunchOfEventsToDestroy") - - TEvBunchOfEventsToDestroy(TDeque<TAutoPtr<IEventBase>> events) - : Events(std::move(events)) - { - } - - TDeque<TAutoPtr<IEventBase>> Events; - }; - - struct TEvResolveAddress - : public TEventLocal<TEvResolveAddress, ui32(ENetwork::ResolveAddress)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvResolveAddress, "Network: TEvResolveAddress") - - TString Address; - ui16 Port; - }; - - struct TEvAddressInfo - : public TEventLocal<TEvAddressInfo, ui32(ENetwork::AddressInfo)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvAddressInfo, "Network: TEvAddressInfo") - - NAddr::IRemoteAddrPtr Address; - }; - - struct TEvResolveError - : public TEventLocal<TEvResolveError, ui32(ENetwork::ResolveError)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvResolveError, "Network: TEvResolveError") - - TString Explain; - TString Host; - }; - - struct TEvHTTPStreamStatus - : public TEventLocal<TEvHTTPStreamStatus, ui32(ENetwork::HTTPStreamStatus)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvHTTPStreamStatus, - "Network: TEvHTTPStreamStatus") - enum EStatus { - READY, - COMPLETE, - ERROR, - }; - - EStatus Status; - TString Error; - TString HttpHeaders; - }; - - struct TEvHTTPSendContent - : public TEventLocal<TEvHTTPSendContent, ui32(ENetwork::HTTPSendContent)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvHTTPSendContent, "Network: TEvHTTPSendContent") - - const char* Data; - size_t Len; - bool Last; - }; - - struct TEvConnectWakeup - : public TEventLocal<TEvConnectWakeup, - ui32(ENetwork::ConnectProtocolWakeup)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvConnectWakeup, "Protocols: TEvConnectWakeup") - }; - - struct TEvHTTPProtocolRetry - : public TEventLocal<TEvHTTPProtocolRetry, - ui32(ENetwork::HTTPProtocolRetry)> { - DEFINE_SIMPLE_LOCAL_EVENT(TEvHTTPProtocolRetry, - "Protocols: TEvHTTPProtocolRetry") - }; - - struct TEvLoadMessage - : TEventPB<TEvLoadMessage, NActorsInterconnect::TEvLoadMessage, static_cast<ui32>(ENetwork::EvLoadMessage)> { - TEvLoadMessage() = default; - - template <typename TContainer> - TEvLoadMessage(const TContainer& route, const TString& id, const TString* payload) { - for (const TActorId& actorId : route) { - auto* hop = Record.AddHops(); - if (actorId) { - ActorIdToProto(actorId, hop->MutableNextHop()); - } - } - Record.SetId(id); - if (payload) { - Record.SetPayload(*payload); - } - } - - template <typename TContainer> - TEvLoadMessage(const TContainer& route, const TString& id, TRope&& payload) { - for (const TActorId& actorId : route) { - auto* hop = Record.AddHops(); - if (actorId) { - ActorIdToProto(actorId, hop->MutableNextHop()); - } - } - Record.SetId(id); - AddPayload(std::move(payload)); - } - }; - - struct TEvUpdateFromInputSession : TEventLocal<TEvUpdateFromInputSession, static_cast<ui32>(ENetwork::EvUpdateFromInputSession)> { - ui64 ConfirmedByInput; // latest Confirm value from processed input packet - ui64 NumDataBytes; - TDuration Ping; - - TEvUpdateFromInputSession(ui64 confirmedByInput, ui64 numDataBytes, TDuration ping) - : ConfirmedByInput(confirmedByInput) - , NumDataBytes(numDataBytes) - , Ping(ping) - { - } - }; - - struct TEvConfirmUpdate : TEventLocal<TEvConfirmUpdate, static_cast<ui32>(ENetwork::EvConfirmUpdate)> - {}; - - struct TEvSessionBufferSizeRequest : TEventLocal<TEvSessionBufferSizeRequest, static_cast<ui32>(ENetwork::EvSessionBufferSizeRequest)> { - //DEFINE_SIMPLE_LOCAL_EVENT(TEvSessionBufferSizeRequest, "Session: TEvSessionBufferSizeRequest") - DEFINE_SIMPLE_LOCAL_EVENT(TEvSessionBufferSizeRequest, "Network: TEvSessionBufferSizeRequest"); - }; - - struct TEvSessionBufferSizeResponse : TEventLocal<TEvSessionBufferSizeResponse, static_cast<ui32>(ENetwork::EvSessionBufferSizeResponse)> { - TEvSessionBufferSizeResponse(const TActorId& sessionId, ui64 outputBufferSize) - : SessionID(sessionId) - , BufferSize(outputBufferSize) - { - } - - TActorId SessionID; - ui64 BufferSize; - }; - - struct TEvProcessPingRequest : TEventLocal<TEvProcessPingRequest, static_cast<ui32>(ENetwork::EvProcessPingRequest)> { - const ui64 Payload; - - TEvProcessPingRequest(ui64 payload) - : Payload(payload) - {} - }; - - struct TEvGetSecureSocket : TEventLocal<TEvGetSecureSocket, (ui32)ENetwork::EvGetSecureSocket> { - TIntrusivePtr<NInterconnect::TStreamSocket> Socket; - - TEvGetSecureSocket(TIntrusivePtr<NInterconnect::TStreamSocket> socket) - : Socket(std::move(socket)) - {} - }; - - struct TEvSecureSocket : TEventLocal<TEvSecureSocket, (ui32)ENetwork::EvSecureSocket> { - TIntrusivePtr<NInterconnect::TSecureSocket> Socket; - - TEvSecureSocket(TIntrusivePtr<NInterconnect::TSecureSocket> socket) - : Socket(std::move(socket)) - {} - }; - - struct TEvSubscribeForConnection : TEventLocal<TEvSubscribeForConnection, (ui32)ENetwork::EvSubscribeForConnection> { - TString HandshakeId; - bool Subscribe; - - TEvSubscribeForConnection(TString handshakeId, bool subscribe) - : HandshakeId(std::move(handshakeId)) - , Subscribe(subscribe) - {} - }; - - struct TEvReportConnection : TEventLocal<TEvReportConnection, (ui32)ENetwork::EvReportConnection> { - TString HandshakeId; - TIntrusivePtr<NInterconnect::TStreamSocket> Socket; - - TEvReportConnection(TString handshakeId, TIntrusivePtr<NInterconnect::TStreamSocket> socket) - : HandshakeId(std::move(handshakeId)) - , Socket(std::move(socket)) - {} - }; -} diff --git a/library/cpp/actors/interconnect/handshake_broker.h b/library/cpp/actors/interconnect/handshake_broker.h deleted file mode 100644 index c850320bd2..0000000000 --- a/library/cpp/actors/interconnect/handshake_broker.h +++ /dev/null @@ -1,156 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/actor.h> -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/interconnect/events_local.h> - -#include <deque> - -namespace NActors { - class TBrokerLeaseHolder { - public: - TBrokerLeaseHolder(TActorId waiterId, TActorId brokerId) - : WaiterId(waiterId) - , BrokerId(brokerId) { - if (TActivationContext::Send(new IEventHandle(BrokerId, WaiterId, new TEvHandshakeBrokerTake()))) { - LeaseRequested = true; - } - } - - ~TBrokerLeaseHolder() { - if (LeaseRequested) { - TActivationContext::Send(new IEventHandle(BrokerId, WaiterId, new TEvHandshakeBrokerFree())); - } - } - - bool IsLeaseRequested() { - return LeaseRequested; - } - - void ForgetLease() { - // only call when TDtorException was caught - LeaseRequested = false; - } - - private: - TActorId WaiterId; - TActorId BrokerId; - bool LeaseRequested = false; - }; - - class THandshakeBroker : public TActor<THandshakeBroker> { - private: - enum class ESelectionStrategy { - FIFO = 0, - LIFO, - Random, - }; - - private: - void PermitNext() { - if (Capacity == 0 && !Waiters.empty()) { - TActorId waiter; - - switch (SelectionStrategy) { - case ESelectionStrategy::FIFO: - waiter = Waiters.front(); - Waiters.pop_front(); - SelectionStrategy = ESelectionStrategy::LIFO; - break; - - case ESelectionStrategy::LIFO: - waiter = Waiters.back(); - Waiters.pop_back(); - SelectionStrategy = ESelectionStrategy::Random; - break; - - case ESelectionStrategy::Random: { - const auto it = WaiterLookup.begin(); - waiter = it->first; - Waiters.erase(it->second); - SelectionStrategy = ESelectionStrategy::FIFO; - break; - } - - default: - Y_ABORT("Unimplimented selection strategy"); - } - - const size_t n = WaiterLookup.erase(waiter); - Y_ABORT_UNLESS(n == 1); - - Send(waiter, new TEvHandshakeBrokerPermit()); - PermittedLeases.insert(waiter); - } else { - Capacity += 1; - } - } - - private: - using TWaiters = std::list<TActorId>; - TWaiters Waiters; - std::unordered_map<TActorId, TWaiters::iterator> WaiterLookup; - std::unordered_set<TActorId> PermittedLeases; - - ESelectionStrategy SelectionStrategy = ESelectionStrategy::FIFO; - - ui32 Capacity; - - void Handle(TEvHandshakeBrokerTake::TPtr &ev) { - const TActorId sender = ev->Sender; - if (Capacity > 0) { - Capacity -= 1; - PermittedLeases.insert(sender); - Send(sender, new TEvHandshakeBrokerPermit()); - } else { - const auto [it, inserted] = WaiterLookup.try_emplace(sender, - Waiters.insert(Waiters.end(), sender)); - Y_ABORT_UNLESS(inserted); - } - } - - void Handle(TEvHandshakeBrokerFree::TPtr& ev) { - const TActorId sender = ev->Sender; - if (!PermittedLeases.erase(sender)) { - // Lease was not permitted yet, remove sender from Waiters queue - const auto it = WaiterLookup.find(sender); - Y_ABORT_UNLESS(it != WaiterLookup.end()); - Waiters.erase(it->second); - WaiterLookup.erase(it); - } - PermitNext(); - } - - public: - THandshakeBroker(ui32 inflightLimit) - : TActor(&TThis::StateFunc) - , Capacity(inflightLimit) - { - } - - static constexpr char ActorName[] = "HANDSHAKE_BROKER_ACTOR"; - - STFUNC(StateFunc) { - switch (ev->GetTypeRewrite()) { - hFunc(TEvHandshakeBrokerTake, Handle); - hFunc(TEvHandshakeBrokerFree, Handle); - - default: - Y_ABORT("unexpected event 0x%08" PRIx32, ev->GetTypeRewrite()); - } - } - - void Bootstrap() { - Become(&TThis::StateFunc); - } - }; - - inline IActor* CreateHandshakeBroker(ui32 maxCapacity) { - return new THandshakeBroker(maxCapacity); - } - - inline TActorId MakeHandshakeBrokerOutId() { - char x[12] = {'I', 'C', 'H', 's', 'h', 'k', 'B', 'r', 'k', 'O', 'u', 't'}; - return TActorId(0, TStringBuf(std::begin(x), std::end(x))); - } -} diff --git a/library/cpp/actors/interconnect/interconnect.h b/library/cpp/actors/interconnect/interconnect.h deleted file mode 100644 index 38d8cd4781..0000000000 --- a/library/cpp/actors/interconnect/interconnect.h +++ /dev/null @@ -1,189 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/actorsystem.h> -#include <library/cpp/actors/core/actor.h> -#include <library/cpp/actors/core/interconnect.h> -#include <util/generic/map.h> -#include <util/network/address.h> - -namespace NActors { - struct TInterconnectGlobalState: public TThrRefBase { - TString SelfAddress; - ui32 SelfPort; - - TVector<TActorId> GlobalNameservers; // todo: add some info about (like expected reply time) - }; - - struct TInterconnectProxySetup: public TThrRefBase { - // synchronous (session -> proxy) - struct IProxy : TNonCopyable { - virtual ~IProxy() { - } - - virtual void ActivateSession(const TActorContext& ctx) = 0; // session activated - virtual void DetachSession(const TActorContext& ctx) = 0; // session is dead - }; - - // synchronous (proxy -> session) - struct ISession : TNonCopyable { - virtual ~ISession() { - } - - virtual void DetachSession(const TActorContext& ownerCtx, const TActorContext& sessionCtx) = 0; // kill yourself - virtual void ForwardPacket(TAutoPtr<IEventHandle>& ev, const TActorContext& ownerCtx, const TActorContext& sessionCtx) = 0; // receive packet for forward - virtual void Connect(const TActorContext& ownerCtx, const TActorContext& sessionCtx) = 0; // begin connection - virtual bool ReceiveIncomingSession(TAutoPtr<IEventHandle>& ev, const TActorContext& ownerCtx, const TActorContext& sessionCtx) = 0; // handle incoming session, if returns true - then session is dead and must be recreated with new one - }; - - ui32 DestinationNode; - - TString StaticAddress; // if set - would be used as main destination address - int StaticPort; - - TIntrusivePtr<TInterconnectGlobalState> GlobalState; - - virtual IActor* CreateSession(const TActorId& ownerId, IProxy* owner) = 0; // returned actor is session and would be attached to same mailbox as proxy to allow sync calls - virtual TActorSetupCmd CreateAcceptor() = 0; - }; - - struct TNameserverSetup { - TActorId ServiceID; - - TIntrusivePtr<TInterconnectGlobalState> GlobalState; - }; - - struct TTableNameserverSetup: public TThrRefBase { - struct TNodeInfo { - TString Address; - TString Host; - TString ResolveHost; - ui16 Port; - TNodeLocation Location; - TString& first; - ui16& second; - - TNodeInfo() - : first(Address) - , second(Port) - { - } - - TNodeInfo(const TNodeInfo&) = default; - - // for testing purposes only - TNodeInfo(const TString& address, const TString& host, ui16 port) - : TNodeInfo() - { - Address = address; - Host = host; - ResolveHost = host; - Port = port; - } - - TNodeInfo(const TString& address, - const TString& host, - const TString& resolveHost, - ui16 port, - const TNodeLocation& location) - : TNodeInfo() - { - Address = address; - Host = host; - ResolveHost = resolveHost; - Port = port; - Location = location; - } - - // for testing purposes only - TNodeInfo& operator=(const std::pair<TString, ui32>& pr) { - Address = pr.first; - Host = pr.first; - ResolveHost = pr.first; - Port = pr.second; - return *this; - } - - TNodeInfo& operator=(const TNodeInfo& ni) { - Address = ni.Address; - Host = ni.Host; - ResolveHost = ni.ResolveHost; - Port = ni.Port; - Location = ni.Location; - return *this; - } - - friend bool operator ==(const TNodeInfo& x, const TNodeInfo& y) { - return x.Address == y.Address && x.Host == y.Host && x.ResolveHost == y.ResolveHost && x.Port == y.Port - && x.Location == y.Location; - } - - friend bool operator !=(const TNodeInfo& x, const TNodeInfo& y) { - return !(x == y); - } - }; - - TMap<ui32, TNodeInfo> StaticNodeTable; - - bool IsEntriesUnique() const; - }; - - struct TNodeRegistrarSetup { - TActorId ServiceID; - - TIntrusivePtr<TInterconnectGlobalState> GlobalState; - }; - - TActorId GetNameserviceActorId(); - - /** - * Const table-lookup based name service - */ - - IActor* CreateNameserverTable( - const TIntrusivePtr<TTableNameserverSetup>& setup, - ui32 poolId = 0); - - /** - * Name service which can be paired with external discovery service. - * Copies information from setup on the start (table may be empty). - * Handles TEvNodesInfo to change list of known nodes. - * - * If PendingPeriod is not zero, wait for unknown nodeId - */ - - IActor* CreateDynamicNameserver( - const TIntrusivePtr<TTableNameserverSetup>& setup, - const TDuration& pendingPeriod = TDuration::Zero(), - ui32 poolId = 0); - - /** - * Creates an actor that resolves host/port and replies with either: - * - * - TEvLocalNodeInfo on success - * - TEvResolveError on errors - * - * Optional defaultAddress may be used as fallback. - */ - IActor* CreateResolveActor( - const TString& host, ui16 port, ui32 nodeId, const TString& defaultAddress, - const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline); - - inline IActor* CreateResolveActor( - ui32 nodeId, const TTableNameserverSetup::TNodeInfo& nodeInfo, - const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline) - { - return CreateResolveActor(nodeInfo.ResolveHost, nodeInfo.Port, nodeId, nodeInfo.Address, - replyTo, replyFrom, deadline); - } - - /** - * Creates an actor that resolves host/port and replies with either: - * - * - TEvAddressInfo on success - * - TEvResolveError on errors - */ - IActor* CreateResolveActor( - const TString& host, ui16 port, - const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline); - -} diff --git a/library/cpp/actors/interconnect/interconnect_address.cpp b/library/cpp/actors/interconnect/interconnect_address.cpp deleted file mode 100644 index 124cd61325..0000000000 --- a/library/cpp/actors/interconnect/interconnect_address.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "interconnect_address.h" - -#include <util/string/cast.h> -#include <util/system/file.h> - -#if defined(_linux_) -#include <sys/un.h> -#include <sys/stat.h> -#endif - -namespace NInterconnect { - TAddress::TAddress() { - memset(&Addr, 0, sizeof(Addr)); - } - - TAddress::TAddress(NAddr::IRemoteAddr& addr) { - socklen_t len = addr.Len(); - Y_ABORT_UNLESS(len <= sizeof(Addr)); - memcpy(&Addr.Generic, addr.Addr(), len); - } - - int TAddress::GetFamily() const { - return Addr.Generic.sa_family; - } - - socklen_t TAddress::Size() const { - switch (Addr.Generic.sa_family) { - case AF_INET6: - return sizeof(sockaddr_in6); - case AF_INET: - return sizeof(sockaddr_in); - default: - return 0; - } - } - - sockaddr* TAddress::SockAddr() { - return &Addr.Generic; - } - - const sockaddr* TAddress::SockAddr() const { - return &Addr.Generic; - } - - ui16 TAddress::GetPort() const { - switch (Addr.Generic.sa_family) { - case AF_INET6: - return ntohs(Addr.Ipv6.sin6_port); - case AF_INET: - return ntohs(Addr.Ipv4.sin_port); - default: - return 0; - } - } - - TString TAddress::ToString() const { - return GetAddress() + ":" + ::ToString(GetPort()); - } - - TAddress::TAddress(const char* addr, ui16 port) { - memset(&Addr, 0, sizeof(Addr)); - if (inet_pton(Addr.Ipv6.sin6_family = AF_INET6, addr, &Addr.Ipv6.sin6_addr) > 0) { - Addr.Ipv6.sin6_port = htons(port); - } else if (inet_pton(Addr.Ipv4.sin_family = AF_INET, addr, &Addr.Ipv4.sin_addr) > 0) { - Addr.Ipv4.sin_port = htons(port); - } - } - - TAddress::TAddress(const TString& addr, ui16 port) - : TAddress(addr.data(), port) - {} - - TAddress::TAddress(in_addr addr, ui16 port) { - Addr.Ipv4.sin_family = AF_INET; - Addr.Ipv4.sin_port = htons(port); - Addr.Ipv4.sin_addr = addr; - } - - TAddress::TAddress(in6_addr addr, ui16 port) { - Addr.Ipv6.sin6_family = AF_INET6; - Addr.Ipv6.sin6_port = htons(port); - Addr.Ipv6.sin6_addr = addr; - } - - TString TAddress::GetAddress() const { - const void *src; - socklen_t size; - - switch (Addr.Generic.sa_family) { - case AF_INET6: - std::tie(src, size) = std::make_tuple(&Addr.Ipv6.sin6_addr, INET6_ADDRSTRLEN); - break; - - case AF_INET: - std::tie(src, size) = std::make_tuple(&Addr.Ipv4.sin_addr, INET_ADDRSTRLEN); - break; - - default: - return TString(); - } - - char *buffer = static_cast<char*>(alloca(size)); - const char *p = inet_ntop(Addr.Generic.sa_family, const_cast<void*>(src), buffer, size); - return p ? TString(p) : TString(); - } -} diff --git a/library/cpp/actors/interconnect/interconnect_address.h b/library/cpp/actors/interconnect/interconnect_address.h deleted file mode 100644 index b19d751806..0000000000 --- a/library/cpp/actors/interconnect/interconnect_address.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include <util/system/defaults.h> -#include <util/network/init.h> -#include <util/network/address.h> -#include <util/generic/string.h> - -namespace NInterconnect { - class TAddress { - union { - sockaddr Generic; - sockaddr_in Ipv4; - sockaddr_in6 Ipv6; - } Addr; - - public: - TAddress(); - TAddress(const char* addr, ui16 port); - TAddress(const TString& addr, ui16 port); - TAddress(in_addr addr, ui16 port); - TAddress(in6_addr addr, ui16 port); - TAddress(NAddr::IRemoteAddr& addr); - int GetFamily() const; - socklen_t Size() const; - ::sockaddr* SockAddr(); - const ::sockaddr* SockAddr() const; - ui16 GetPort() const; - TString GetAddress() const; - TString ToString() const; - - static TAddress AnyIPv4(ui16 port) { - TAddress res; - res.Addr.Ipv4.sin_family = AF_INET; - res.Addr.Ipv4.sin_port = htons(port); - res.Addr.Ipv4.sin_addr.s_addr = htonl(INADDR_ANY); - return res; - } - - static TAddress AnyIPv6(ui16 port) { - TAddress res; - res.Addr.Ipv6.sin6_family = AF_INET6; - res.Addr.Ipv6.sin6_port = htons(port); - res.Addr.Ipv6.sin6_addr = in6addr_any; - return res; - } - }; -} diff --git a/library/cpp/actors/interconnect/interconnect_channel.cpp b/library/cpp/actors/interconnect/interconnect_channel.cpp deleted file mode 100644 index 71f4d6e5c3..0000000000 --- a/library/cpp/actors/interconnect/interconnect_channel.cpp +++ /dev/null @@ -1,360 +0,0 @@ -#include "interconnect_channel.h" - -#include <library/cpp/actors/core/events.h> -#include <library/cpp/actors/core/executor_thread.h> -#include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/core/probes.h> -#include <library/cpp/actors/protos/services_common.pb.h> -#include <library/cpp/actors/prof/tag.h> -#include <library/cpp/digest/crc32c/crc32c.h> - -LWTRACE_USING(ACTORLIB_PROVIDER); - -namespace NActors { - bool TEventOutputChannel::FeedDescriptor(TTcpPacketOutTask& task, TEventHolder& event, ui64 *weightConsumed) { - const size_t amount = sizeof(TChannelPart) + sizeof(TEventDescr2); - if (task.GetInternalFreeAmount() < amount) { - return false; - } - - auto traceId = event.Span.GetTraceId(); - event.Span.EndOk(); - - Y_ABORT_UNLESS(SerializationInfo); - const ui32 flags = (event.Descr.Flags & ~IEventHandle::FlagForwardOnNondelivery) | - (SerializationInfo->IsExtendedFormat ? IEventHandle::FlagExtendedFormat : 0); - - // prepare descriptor record - TEventDescr2 descr{ - event.Descr.Type, - flags, - event.Descr.Recipient, - event.Descr.Sender, - event.Descr.Cookie, - {}, - event.Descr.Checksum, -#if IC_FORCE_HARDENED_PACKET_CHECKS - event.EventSerializedSize -#endif - }; - traceId.Serialize(&descr.TraceId); - - // and channel header before the descriptor - TChannelPart part{ - .ChannelFlags = static_cast<ui16>(ChannelId | TChannelPart::LastPartFlag), - .Size = sizeof(descr) - }; - - // append them to the packet - task.Write<false>(&part, sizeof(part)); - task.Write<false>(&descr, sizeof(descr)); - - *weightConsumed += amount; - OutputQueueSize -= sizeof(TEventDescr2); - Metrics->UpdateOutputChannelEvents(ChannelId); - - return true; - } - - void TEventOutputChannel::DropConfirmed(ui64 confirm) { - LOG_DEBUG_IC_SESSION("ICOCH98", "Dropping confirmed messages"); - for (auto it = NotYetConfirmed.begin(); it != NotYetConfirmed.end() && it->Serial <= confirm; ) { - Pool.Release(NotYetConfirmed, it++); - } - } - - bool TEventOutputChannel::FeedBuf(TTcpPacketOutTask& task, ui64 serial, ui64 *weightConsumed) { - for (;;) { - Y_ABORT_UNLESS(!Queue.empty()); - TEventHolder& event = Queue.front(); - - switch (State) { - case EState::INITIAL: - event.InitChecksum(); - if (event.Buffer) { - State = EState::BODY; - Iter = event.Buffer->GetBeginIter(); - SerializationInfo = &event.Buffer->GetSerializationInfo(); - SectionIndex = 0; - PartLenRemain = 0; - } else if (event.Event) { - State = EState::BODY; - IEventBase *base = event.Event.Get(); - if (event.EventSerializedSize) { - Chunker.SetSerializingEvent(base); - } - SerializationInfoContainer = base->CreateSerializationInfo(); - SerializationInfo = &SerializationInfoContainer; - SectionIndex = 0; - PartLenRemain = 0; - } else { // event without buffer and IEventBase instance - State = EState::DESCRIPTOR; - SerializationInfoContainer = {}; - SerializationInfo = &SerializationInfoContainer; - } - if (!event.EventSerializedSize) { - State = EState::DESCRIPTOR; - } else if (Params.UseExternalDataChannel && !SerializationInfo->Sections.empty()) { - State = EState::SECTIONS; - SectionIndex = 0; - } - break; - - case EState::BODY: - if (FeedPayload(task, event, weightConsumed)) { - State = EState::DESCRIPTOR; - } else { - return false; - } - break; - - case EState::DESCRIPTOR: - if (!FeedDescriptor(task, event, weightConsumed)) { - return false; - } - event.Serial = serial; - NotYetConfirmed.splice(NotYetConfirmed.end(), Queue, Queue.begin()); // move event to not-yet-confirmed queue - SerializationInfoContainer = {}; - SerializationInfo = nullptr; - State = EState::INITIAL; - return true; // we have processed whole event, signal to the caller - - case EState::SECTIONS: { - if (SectionIndex == 0) { - size_t totalSectionSize = 0; - for (const auto& section : SerializationInfo->Sections) { - totalSectionSize += section.Size; - } - Y_ABORT_UNLESS(totalSectionSize == event.EventSerializedSize); - } - - while (SectionIndex != SerializationInfo->Sections.size()) { - char sectionInfo[1 + NInterconnect::NDetail::MaxNumberBytes * 4]; - char *p = sectionInfo; - - const auto& section = SerializationInfo->Sections[SectionIndex]; - char& type = *p++; - type = static_cast<ui8>(EXdcCommand::DECLARE_SECTION); - p += NInterconnect::NDetail::SerializeNumber(section.Headroom, p); - p += NInterconnect::NDetail::SerializeNumber(section.Size, p); - p += NInterconnect::NDetail::SerializeNumber(section.Tailroom, p); - p += NInterconnect::NDetail::SerializeNumber(section.Alignment, p); - if (section.IsInline && Params.UseXdcShuffle) { - type = static_cast<ui8>(EXdcCommand::DECLARE_SECTION_INLINE); - } - Y_ABORT_UNLESS(p <= std::end(sectionInfo)); - - const size_t declareLen = p - sectionInfo; - if (sizeof(TChannelPart) + XdcData.size() + declareLen <= task.GetInternalFreeAmount() && - XdcData.size() + declareLen <= Max<ui16>()) { - XdcData.insert(XdcData.end(), sectionInfo, p); - ++SectionIndex; - } else { - break; - } - } - - if (XdcData.empty()) { - return false; - } - - TChannelPart part{ - .ChannelFlags = static_cast<ui16>(ChannelId | TChannelPart::XdcFlag), - .Size = static_cast<ui16>(XdcData.size()) - }; - task.Write<false>(&part, sizeof(part)); - task.Write<false>(XdcData.data(), XdcData.size()); - XdcData.clear(); - - if (SectionIndex == SerializationInfo->Sections.size()) { - State = EState::BODY; - SectionIndex = 0; - PartLenRemain = 0; - } - - break; - } - } - } - } - - template<bool External> - bool TEventOutputChannel::SerializeEvent(TTcpPacketOutTask& task, TEventHolder& event, size_t *bytesSerialized) { - auto addChunk = [&](const void *data, size_t len, bool allowCopy) { - event.UpdateChecksum(data, len); - if (allowCopy && (reinterpret_cast<uintptr_t>(data) & 63) + len <= 64) { - task.Write<External>(data, len); - } else { - task.Append<External>(data, len); - } - *bytesSerialized += len; - Y_DEBUG_ABORT_UNLESS(len <= PartLenRemain); - PartLenRemain -= len; - - event.EventActuallySerialized += len; - if (event.EventActuallySerialized > MaxSerializedEventSize) { - throw TExSerializedEventTooLarge(event.Descr.Type); - } - }; - - bool complete = false; - if (event.Event) { - while (!complete) { - TMutableContiguousSpan out = task.AcquireSpanForWriting<External>().SubSpan(0, PartLenRemain); - if (!out.size()) { - break; - } - for (const auto& [buffer, size] : Chunker.FeedBuf(out.data(), out.size())) { - addChunk(buffer, size, false); - } - complete = Chunker.IsComplete(); - if (complete) { - Y_ABORT_UNLESS(Chunker.IsSuccessfull()); - } - } - } else if (event.Buffer) { - while (const size_t numb = Min<size_t>(External ? task.GetExternalFreeAmount() : task.GetInternalFreeAmount(), - Iter.ContiguousSize(), PartLenRemain)) { - const char *obuf = Iter.ContiguousData(); - addChunk(obuf, numb, true); - Iter += numb; - } - complete = !Iter.Valid(); - } else { - Y_ABORT(); - } - Y_ABORT_UNLESS(!complete || event.EventActuallySerialized == event.EventSerializedSize, - "EventActuallySerialized# %" PRIu32 " EventSerializedSize# %" PRIu32 " Type# 0x%08" PRIx32, - event.EventActuallySerialized, event.EventSerializedSize, event.Descr.Type); - - return complete; - } - - bool TEventOutputChannel::FeedPayload(TTcpPacketOutTask& task, TEventHolder& event, ui64 *weightConsumed) { - for (;;) { - // calculate inline or external part size (it may cover a few sections, not just single one) - while (!PartLenRemain) { - const auto& sections = SerializationInfo->Sections; - if (!Params.UseExternalDataChannel || sections.empty()) { - // all data goes inline - IsPartInline = true; - PartLenRemain = Max<size_t>(); - } else if (!Params.UseXdcShuffle) { - // when UseXdcShuffle feature is not supported by the remote side, we transfer whole event over XDC - IsPartInline = false; - PartLenRemain = Max<size_t>(); - } else { - Y_ABORT_UNLESS(SectionIndex < sections.size()); - IsPartInline = sections[SectionIndex].IsInline; - while (SectionIndex < sections.size() && IsPartInline == sections[SectionIndex].IsInline) { - PartLenRemain += sections[SectionIndex].Size; - ++SectionIndex; - } - } - } - - // serialize bytes - const auto complete = IsPartInline - ? FeedInlinePayload(task, event, weightConsumed) - : FeedExternalPayload(task, event, weightConsumed); - if (!complete) { // no space to serialize - return false; - } else if (*complete) { // event serialized - return true; - } - } - } - - std::optional<bool> TEventOutputChannel::FeedInlinePayload(TTcpPacketOutTask& task, TEventHolder& event, ui64 *weightConsumed) { - if (task.GetInternalFreeAmount() <= sizeof(TChannelPart)) { - return std::nullopt; - } - - auto partBookmark = task.Bookmark(sizeof(TChannelPart)); - - size_t bytesSerialized = 0; - const bool complete = SerializeEvent<false>(task, event, &bytesSerialized); - - Y_DEBUG_ABORT_UNLESS(bytesSerialized); - Y_ABORT_UNLESS(bytesSerialized <= Max<ui16>()); - - TChannelPart part{ - .ChannelFlags = ChannelId, - .Size = static_cast<ui16>(bytesSerialized) - }; - - task.WriteBookmark(std::move(partBookmark), &part, sizeof(part)); - *weightConsumed += sizeof(TChannelPart) + part.Size; - OutputQueueSize -= part.Size; - - return complete; - } - - std::optional<bool> TEventOutputChannel::FeedExternalPayload(TTcpPacketOutTask& task, TEventHolder& event, ui64 *weightConsumed) { - const size_t partSize = sizeof(TChannelPart) + sizeof(ui8) + sizeof(ui16) + (Params.Encryption ? 0 : sizeof(ui32)); - if (task.GetInternalFreeAmount() < partSize || task.GetExternalFreeAmount() == 0) { - return std::nullopt; - } - - // clear external checksum for this chunk - task.ExternalChecksum = 0; - - auto partBookmark = task.Bookmark(partSize); - - size_t bytesSerialized = 0; - const bool complete = SerializeEvent<true>(task, event, &bytesSerialized); - - Y_ABORT_UNLESS(0 < bytesSerialized && bytesSerialized <= Max<ui16>()); - - char buffer[partSize]; - TChannelPart *part = reinterpret_cast<TChannelPart*>(buffer); - *part = { - .ChannelFlags = static_cast<ui16>(ChannelId | TChannelPart::XdcFlag), - .Size = static_cast<ui16>(partSize - sizeof(TChannelPart)) - }; - char *ptr = reinterpret_cast<char*>(part + 1); - *ptr++ = static_cast<ui8>(EXdcCommand::PUSH_DATA); - *reinterpret_cast<ui16*>(ptr) = bytesSerialized; - ptr += sizeof(ui16); - if (task.ChecksummingXxhash()) { - XXH3_state_t state; - XXH3_64bits_reset(&state); - task.XdcStream.ScanLastBytes(bytesSerialized, [&state](TContiguousSpan span) { - XXH3_64bits_update(&state, span.data(), span.size()); - }); - *reinterpret_cast<ui32*>(ptr) = XXH3_64bits_digest(&state); - } else if (task.ChecksummingCrc32c()) { - *reinterpret_cast<ui32*>(ptr) = task.ExternalChecksum; - } - - task.WriteBookmark(std::move(partBookmark), buffer, partSize); - - *weightConsumed += partSize + bytesSerialized; - OutputQueueSize -= bytesSerialized; - - return complete; - } - - void TEventOutputChannel::NotifyUndelivered() { - LOG_DEBUG_IC_SESSION("ICOCH89", "Notyfying about Undelivered messages! NotYetConfirmed size: %zu, Queue size: %zu", NotYetConfirmed.size(), Queue.size()); - if (State == EState::BODY && Queue.front().Event) { - Y_ABORT_UNLESS(!Chunker.IsComplete()); // chunk must have an event being serialized - Y_ABORT_UNLESS(!Queue.empty()); // this event must be the first event in queue - TEventHolder& event = Queue.front(); - Y_ABORT_UNLESS(Chunker.GetCurrentEvent() == event.Event.Get()); // ensure the event is valid - Chunker.Abort(); // stop serializing current event - Y_ABORT_UNLESS(Chunker.IsComplete()); - } - for (auto& item : NotYetConfirmed) { - if (item.Descr.Flags & IEventHandle::FlagGenerateUnsureUndelivered) { // notify only when unsure flag is set - item.ForwardOnNondelivery(true); - } - } - Pool.Release(NotYetConfirmed); - for (auto& item : Queue) { - item.ForwardOnNondelivery(false); - } - Pool.Release(Queue); - } - -} diff --git a/library/cpp/actors/interconnect/interconnect_channel.h b/library/cpp/actors/interconnect/interconnect_channel.h deleted file mode 100644 index ef2da2fda7..0000000000 --- a/library/cpp/actors/interconnect/interconnect_channel.h +++ /dev/null @@ -1,159 +0,0 @@ -#pragma once - -#include <library/cpp/monlib/dynamic_counters/counters.h> -#include <library/cpp/actors/core/actorsystem.h> -#include <library/cpp/actors/core/event_load.h> -#include <library/cpp/actors/util/rope.h> -#include <util/generic/deque.h> -#include <util/generic/vector.h> -#include <util/generic/map.h> -#include <util/stream/walk.h> -#include <library/cpp/actors/wilson/wilson_span.h> - -#include "interconnect_common.h" -#include "interconnect_counters.h" -#include "packet.h" -#include "event_holder_pool.h" - -namespace NActors { -#pragma pack(push, 1) - - struct TChannelPart { - ui16 ChannelFlags; - ui16 Size; - - static constexpr ui16 LastPartFlag = 0x8000; - static constexpr ui16 XdcFlag = 0x4000; - static constexpr ui16 ChannelMask = (1 << IEventHandle::ChannelBits) - 1; - - static_assert((LastPartFlag & ChannelMask) == 0); - static_assert((XdcFlag & ChannelMask) == 0); - - ui16 GetChannel() const { return ChannelFlags & ChannelMask; } - bool IsLastPart() const { return ChannelFlags & LastPartFlag; } - bool IsXdc() const { return ChannelFlags & XdcFlag; } - - TString ToString() const { - return TStringBuilder() << "{Channel# " << GetChannel() - << " IsLastPart# " << IsLastPart() - << " IsXdc# " << IsXdc() - << " Size# " << Size << "}"; - } - }; - -#pragma pack(pop) - - enum class EXdcCommand : ui8 { - DECLARE_SECTION = 1, - PUSH_DATA, - DECLARE_SECTION_INLINE, - }; - - struct TExSerializedEventTooLarge : std::exception { - const ui32 Type; - - TExSerializedEventTooLarge(ui32 type) - : Type(type) - {} - }; - - class TEventOutputChannel : public TInterconnectLoggingBase { - public: - TEventOutputChannel(TEventHolderPool& pool, ui16 id, ui32 peerNodeId, ui32 maxSerializedEventSize, - std::shared_ptr<IInterconnectMetrics> metrics, TSessionParams params) - : TInterconnectLoggingBase(Sprintf("OutputChannel %" PRIu16 " [node %" PRIu32 "]", id, peerNodeId)) - , Pool(pool) - , PeerNodeId(peerNodeId) - , ChannelId(id) - , Metrics(std::move(metrics)) - , Params(std::move(params)) - , MaxSerializedEventSize(maxSerializedEventSize) - {} - - ~TEventOutputChannel() { - } - - std::pair<ui32, TEventHolder*> Push(IEventHandle& ev) { - TEventHolder& event = Pool.Allocate(Queue); - const ui32 bytes = event.Fill(ev) + sizeof(TEventDescr2); - OutputQueueSize += bytes; - if (event.Span = NWilson::TSpan(15 /*max verbosity*/, NWilson::TTraceId(ev.TraceId), "Interconnect.Queue")) { - event.Span - .Attribute("OutputQueueItems", static_cast<i64>(Queue.size())) - .Attribute("OutputQueueSize", static_cast<i64>(OutputQueueSize)); - } - return std::make_pair(bytes, &event); - } - - void DropConfirmed(ui64 confirm); - - bool FeedBuf(TTcpPacketOutTask& task, ui64 serial, ui64 *weightConsumed); - - bool IsEmpty() const { - return Queue.empty(); - } - - bool IsWorking() const { - return !IsEmpty(); - } - - ui32 GetQueueSize() const { - return (ui32)Queue.size(); - } - - ui64 GetBufferedAmountOfData() const { - return OutputQueueSize; - } - - void NotifyUndelivered(); - - TEventHolderPool& Pool; - const ui32 PeerNodeId; - const ui16 ChannelId; - std::shared_ptr<IInterconnectMetrics> Metrics; - const TSessionParams Params; - const ui32 MaxSerializedEventSize; - ui64 UnaccountedTraffic = 0; - ui64 EqualizeCounterOnPause = 0; - ui64 WeightConsumedOnPause = 0; - - enum class EState { - INITIAL, - BODY, - DESCRIPTOR, - SECTIONS, - }; - EState State = EState::INITIAL; - - protected: - ui64 OutputQueueSize = 0; - - std::list<TEventHolder> Queue; - std::list<TEventHolder> NotYetConfirmed; - TRope::TConstIterator Iter; - TCoroutineChunkSerializer Chunker; - TEventSerializationInfo SerializationInfoContainer; - const TEventSerializationInfo *SerializationInfo = nullptr; - bool IsPartInline = false; - size_t PartLenRemain = 0; - size_t SectionIndex = 0; - std::vector<char> XdcData; - - template<bool External> - bool SerializeEvent(TTcpPacketOutTask& task, TEventHolder& event, size_t *bytesSerialized); - - bool FeedPayload(TTcpPacketOutTask& task, TEventHolder& event, ui64 *weightConsumed); - std::optional<bool> FeedInlinePayload(TTcpPacketOutTask& task, TEventHolder& event, ui64 *weightConsumed); - std::optional<bool> FeedExternalPayload(TTcpPacketOutTask& task, TEventHolder& event, ui64 *weightConsumed); - - bool FeedDescriptor(TTcpPacketOutTask& task, TEventHolder& event, ui64 *weightConsumed); - - void AccountTraffic() { - if (const ui64 amount = std::exchange(UnaccountedTraffic, 0)) { - Metrics->UpdateOutputChannelTraffic(ChannelId, amount); - } - } - - friend class TInterconnectSessionTCP; - }; -} diff --git a/library/cpp/actors/interconnect/interconnect_common.h b/library/cpp/actors/interconnect/interconnect_common.h deleted file mode 100644 index 300153d8de..0000000000 --- a/library/cpp/actors/interconnect/interconnect_common.h +++ /dev/null @@ -1,140 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/actorid.h> -#include <library/cpp/actors/core/actorsystem.h> -#include <library/cpp/actors/util/datetime.h> -#include <library/cpp/monlib/dynamic_counters/counters.h> -#include <library/cpp/monlib/metrics/metric_registry.h> -#include <util/generic/map.h> -#include <util/generic/set.h> -#include <util/system/datetime.h> - -#include "poller_tcp.h" -#include "logging.h" -#include "event_filter.h" - -#include <atomic> - -namespace NActors { - enum class EEncryptionMode { - DISABLED, // no encryption is required at all - OPTIONAL, // encryption is enabled when supported by both peers - REQUIRED, // encryption is mandatory - }; - - struct TInterconnectSettings { - TDuration Handshake; - TDuration DeadPeer; - TDuration CloseOnIdle; - ui32 SendBufferDieLimitInMB = 0; - ui64 OutputBuffersTotalSizeLimitInMB = 0; - ui32 TotalInflightAmountOfData = 0; - bool MergePerPeerCounters = false; - bool MergePerDataCenterCounters = false; - ui32 TCPSocketBufferSize = 0; - TDuration PingPeriod = TDuration::Seconds(3); - TDuration ForceConfirmPeriod = TDuration::Seconds(1); - TDuration LostConnection; - TDuration BatchPeriod; - bool BindOnAllAddresses = true; - EEncryptionMode EncryptionMode = EEncryptionMode::DISABLED; - bool TlsAuthOnly = false; - TString Certificate; // certificate data in PEM format - TString PrivateKey; // private key for the certificate in PEM format - TString CaFilePath; // path to certificate authority file - TString CipherList; // encryption algorithms - TDuration MessagePendingTimeout = TDuration::Seconds(1); // timeout for which messages are queued while in PendingConnection state - ui64 MessagePendingSize = Max<ui64>(); // size of the queue - ui32 MaxSerializedEventSize = NActors::EventMaxByteSize; - ui32 PreallocatedBufferSize = 8 << 10; // 8 KB - ui32 NumPreallocatedBuffers = 16; - bool EnableExternalDataChannel = false; - bool ValidateIncomingPeerViaDirectLookup = false; - ui32 SocketBacklogSize = 0; // SOMAXCONN if zero - - ui32 GetSendBufferSize() const { - ui32 res = 512 * 1024; // 512 kb is the default value for send buffer - if (TCPSocketBufferSize) { - res = TCPSocketBufferSize; - } - return res; - } - }; - - struct TWhiteboardSessionStatus { - TActorSystem* ActorSystem; - ui32 PeerId; - TString Peer; - bool Connected; - bool Green; - bool Yellow; - bool Orange; - bool Red; - i64 ClockSkew; - - TWhiteboardSessionStatus(TActorSystem* actorSystem, ui32 peerId, const TString& peer, bool connected, bool green, bool yellow, bool orange, bool red, i64 clockSkew) - : ActorSystem(actorSystem) - , PeerId(peerId) - , Peer(peer) - , Connected(connected) - , Green(green) - , Yellow(yellow) - , Orange(orange) - , Red(red) - , ClockSkew(clockSkew) - {} - }; - - struct TChannelSettings { - ui16 Weight; - }; - - typedef TMap<ui16, TChannelSettings> TChannelsConfig; - - using TRegisterMonPageCallback = std::function<void(const TString& path, const TString& title, - TActorSystem* actorSystem, const TActorId& actorId)>; - - using TInitWhiteboardCallback = std::function<void(ui16 icPort, TActorSystem* actorSystem)>; - - using TUpdateWhiteboardCallback = std::function<void(const TWhiteboardSessionStatus& data)>; - - struct TInterconnectProxyCommon : TAtomicRefCount<TInterconnectProxyCommon> { - TActorId NameserviceId; - NMonitoring::TDynamicCounterPtr MonCounters; - std::shared_ptr<NMonitoring::IMetricRegistry> Metrics; - TChannelsConfig ChannelsConfig; - TInterconnectSettings Settings; - TRegisterMonPageCallback RegisterMonPage; - TActorId DestructorId; - std::shared_ptr<std::atomic<TAtomicBase>> DestructorQueueSize; - TAtomicBase MaxDestructorQueueSize = 1024 * 1024 * 1024; - TString ClusterUUID; - TVector<TString> AcceptUUID; - ui64 StartTime = GetCycleCountFast(); - TString TechnicalSelfHostName; - TInitWhiteboardCallback InitWhiteboard; - TUpdateWhiteboardCallback UpdateWhiteboard; - ui32 HandshakeBallastSize = 0; - TAtomic StartedSessionKiller = 0; - TScopeId LocalScopeId; - std::shared_ptr<TEventFilter> EventFilter; - TString Cookie; // unique random identifier of a node instance (generated randomly at every start) - std::unordered_map<ui16, TString> ChannelName; - std::optional<ui32> OutgoingHandshakeInflightLimit; - - struct TVersionInfo { - TString Tag; // version tag for this node - TSet<TString> AcceptedTags; // we accept all enlisted version tags of peer nodes, but no others; empty = accept all - }; - - // obsolete compatibility control - TMaybe<TVersionInfo> VersionInfo; - - std::optional<TString> CompatibilityInfo; - std::function<bool(const TString&, TString&)> ValidateCompatibilityInfo; - std::function<bool(const TInterconnectProxyCommon::TVersionInfo&, TString&)> ValidateCompatibilityOldFormat; - - using TPtr = TIntrusivePtr<TInterconnectProxyCommon>; - }; - -} diff --git a/library/cpp/actors/interconnect/interconnect_counters.cpp b/library/cpp/actors/interconnect/interconnect_counters.cpp deleted file mode 100644 index 1c55eab650..0000000000 --- a/library/cpp/actors/interconnect/interconnect_counters.cpp +++ /dev/null @@ -1,703 +0,0 @@ -#include "interconnect_counters.h" - -#include <library/cpp/monlib/metrics/metric_registry.h> -#include <library/cpp/monlib/metrics/metric_sub_registry.h> - -#include <unordered_map> - -namespace NActors { - -namespace { - - class TInterconnectCounters: public IInterconnectMetrics { - public: - struct TOutputChannel { - NMonitoring::TDynamicCounters::TCounterPtr Traffic; - NMonitoring::TDynamicCounters::TCounterPtr Events; - NMonitoring::TDynamicCounters::TCounterPtr OutgoingTraffic; - NMonitoring::TDynamicCounters::TCounterPtr OutgoingEvents; - - TOutputChannel() = default; - - TOutputChannel(const TIntrusivePtr<NMonitoring::TDynamicCounters>& counters, - NMonitoring::TDynamicCounters::TCounterPtr traffic, - NMonitoring::TDynamicCounters::TCounterPtr events) - : Traffic(std::move(traffic)) - , Events(std::move(events)) - , OutgoingTraffic(counters->GetCounter("OutgoingTraffic", true)) - , OutgoingEvents(counters->GetCounter("OutgoingEvents", true)) - {} - - TOutputChannel(const TOutputChannel&) = default; - TOutputChannel &operator=(const TOutputChannel& other) = default; - }; - - struct TInputChannel { - NMonitoring::TDynamicCounters::TCounterPtr Traffic; - NMonitoring::TDynamicCounters::TCounterPtr Events; - NMonitoring::TDynamicCounters::TCounterPtr ScopeErrors; - NMonitoring::TDynamicCounters::TCounterPtr IncomingTraffic; - NMonitoring::TDynamicCounters::TCounterPtr IncomingEvents; - - TInputChannel() = default; - - TInputChannel(const TIntrusivePtr<NMonitoring::TDynamicCounters>& counters, - NMonitoring::TDynamicCounters::TCounterPtr traffic, - NMonitoring::TDynamicCounters::TCounterPtr events, - NMonitoring::TDynamicCounters::TCounterPtr scopeErrors) - : Traffic(std::move(traffic)) - , Events(std::move(events)) - , ScopeErrors(std::move(scopeErrors)) - , IncomingTraffic(counters->GetCounter("IncomingTraffic", true)) - , IncomingEvents(counters->GetCounter("IncomingEvents", true)) - {} - - TInputChannel(const TInputChannel&) = default; - TInputChannel &operator=(const TInputChannel& other) = default; - }; - - struct TInputChannels : std::unordered_map<ui16, TInputChannel> { - TInputChannel OtherInputChannel; - - TInputChannels() = default; - - TInputChannels(const TIntrusivePtr<NMonitoring::TDynamicCounters>& counters, - const std::unordered_map<ui16, TString>& names, - NMonitoring::TDynamicCounters::TCounterPtr traffic, - NMonitoring::TDynamicCounters::TCounterPtr events, - NMonitoring::TDynamicCounters::TCounterPtr scopeErrors) - : OtherInputChannel(counters->GetSubgroup("channel", "other"), traffic, events, scopeErrors) - { - for (const auto& [id, name] : names) { - try_emplace(id, counters->GetSubgroup("channel", name), traffic, events, scopeErrors); - } - } - - TInputChannels(const TInputChannels&) = default; - TInputChannels &operator=(const TInputChannels& other) = default; - - const TInputChannel& Get(ui16 id) const { - const auto it = find(id); - return it != end() ? it->second : OtherInputChannel; - } - }; - - private: - const TInterconnectProxyCommon::TPtr Common; - const bool MergePerDataCenterCounters; - const bool MergePerPeerCounters; - NMonitoring::TDynamicCounterPtr Counters; - NMonitoring::TDynamicCounterPtr PerSessionCounters; - NMonitoring::TDynamicCounterPtr PerDataCenterCounters; - NMonitoring::TDynamicCounterPtr& AdaptiveCounters; - - bool Initialized = false; - - NMonitoring::TDynamicCounters::TCounterPtr Traffic; - NMonitoring::TDynamicCounters::TCounterPtr Events; - NMonitoring::TDynamicCounters::TCounterPtr ScopeErrors; - - public: - TInterconnectCounters(const TInterconnectProxyCommon::TPtr& common) - : Common(common) - , MergePerDataCenterCounters(common->Settings.MergePerDataCenterCounters) - , MergePerPeerCounters(common->Settings.MergePerPeerCounters) - , Counters(common->MonCounters) - , AdaptiveCounters(MergePerDataCenterCounters - ? PerDataCenterCounters : - MergePerPeerCounters ? Counters : PerSessionCounters) - {} - - void AddInflightDataAmount(ui64 value) override { - *InflightDataAmount += value; - } - - void SubInflightDataAmount(ui64 value) override { - *InflightDataAmount -= value; - } - - void AddTotalBytesWritten(ui64 value) override { - *TotalBytesWritten += value; - } - - void SetClockSkewMicrosec(i64 value) override { - *ClockSkewMicrosec = value; - } - - void IncSessionDeaths() override { - ++*SessionDeaths; - } - - void IncHandshakeFails() override { - ++*HandshakeFails; - } - - void SetConnected(ui32 value) override { - *Connected = value; - } - - void IncSubscribersCount() override { - ++*SubscribersCount; - } - - void SubSubscribersCount(ui32 value) override { - *SubscribersCount -= value; - } - - void SubOutputBuffersTotalSize(ui64 value) override { - *OutputBuffersTotalSize -= value; - } - - void AddOutputBuffersTotalSize(ui64 value) override { - *OutputBuffersTotalSize += value; - } - - ui64 GetOutputBuffersTotalSize() const override { - return *OutputBuffersTotalSize; - } - - void IncDisconnections() override { - ++*Disconnections; - } - - void IncUsefulWriteWakeups() override { - ++*UsefulWriteWakeups; - } - - void IncSpuriousWriteWakeups() override { - ++*SpuriousWriteWakeups; - } - - void IncSendSyscalls(ui64 ns) override { - ++*SendSyscalls; - *SendSyscallsNs += ns; - } - - void IncInflyLimitReach() override { - ++*InflyLimitReach; - } - - void IncUsefulReadWakeups() override { - ++*UsefulReadWakeups; - } - - void IncSpuriousReadWakeups() override { - ++*SpuriousReadWakeups; - } - - void IncDisconnectByReason(const TString& s) override { - if (auto it = DisconnectByReason.find(s); it != DisconnectByReason.end()) { - it->second->Inc(); - } - } - - void AddInputChannelsIncomingTraffic(ui16 channel, ui64 incomingTraffic) override { - auto& ch = InputChannels.Get(channel); - *ch.IncomingTraffic += incomingTraffic; - } - - void IncInputChannelsIncomingEvents(ui16 channel) override { - auto& ch = InputChannels.Get(channel); - ++*ch.IncomingEvents; - } - - void IncRecvSyscalls(ui64 ns) override { - ++*RecvSyscalls; - *RecvSyscallsNs += ns; - } - - void AddTotalBytesRead(ui64 value) override { - *TotalBytesRead += value; - } - - void UpdatePingTimeHistogram(ui64 value) override { - PingTimeHistogram->Collect(value); - } - - void UpdateOutputChannelTraffic(ui16 channel, ui64 value) override { - auto& ch = GetOutputChannel(channel); - if (ch.OutgoingTraffic) { - *ch.OutgoingTraffic += value; - } - if (ch.Traffic) { - *ch.Traffic += value; - } - } - - void UpdateOutputChannelEvents(ui16 channel) override { - auto& ch = GetOutputChannel(channel); - if (ch.OutgoingEvents) { - ++*ch.OutgoingEvents; - } - if (ch.Events) { - ++*ch.Events; - } - } - - void SetPeerInfo(const TString& name, const TString& dataCenterId) override { - if (name != std::exchange(HumanFriendlyPeerHostName, name)) { - PerSessionCounters.Reset(); - } - VALGRIND_MAKE_READABLE(&DataCenterId, sizeof(DataCenterId)); - if (dataCenterId != std::exchange(DataCenterId, dataCenterId)) { - PerDataCenterCounters.Reset(); - } - - const bool updatePerDataCenter = !PerDataCenterCounters && MergePerDataCenterCounters; - if (updatePerDataCenter) { - PerDataCenterCounters = Counters->GetSubgroup("dataCenterId", *DataCenterId); - } - - const bool updatePerSession = !PerSessionCounters || updatePerDataCenter; - if (updatePerSession) { - auto base = MergePerDataCenterCounters ? PerDataCenterCounters : Counters; - PerSessionCounters = base->GetSubgroup("peer", *HumanFriendlyPeerHostName); - } - - const bool updateGlobal = !Initialized; - - const bool updateAdaptive = - &AdaptiveCounters == &Counters ? updateGlobal : - &AdaptiveCounters == &PerSessionCounters ? updatePerSession : - &AdaptiveCounters == &PerDataCenterCounters ? updatePerDataCenter : - false; - - if (updatePerSession) { - Connected = PerSessionCounters->GetCounter("Connected"); - Disconnections = PerSessionCounters->GetCounter("Disconnections", true); - ClockSkewMicrosec = PerSessionCounters->GetCounter("ClockSkewMicrosec"); - Traffic = PerSessionCounters->GetCounter("Traffic", true); - Events = PerSessionCounters->GetCounter("Events", true); - ScopeErrors = PerSessionCounters->GetCounter("ScopeErrors", true); - - for (const auto& [id, name] : Common->ChannelName) { - OutputChannels.try_emplace(id, Counters->GetSubgroup("channel", name), Traffic, Events); - } - OtherOutputChannel = TOutputChannel(Counters->GetSubgroup("channel", "other"), Traffic, Events); - - InputChannels = TInputChannels(Counters, Common->ChannelName, Traffic, Events, ScopeErrors); - } - - if (updateAdaptive) { - SessionDeaths = AdaptiveCounters->GetCounter("Session_Deaths", true); - HandshakeFails = AdaptiveCounters->GetCounter("Handshake_Fails", true); - InflyLimitReach = AdaptiveCounters->GetCounter("InflyLimitReach", true); - InflightDataAmount = AdaptiveCounters->GetCounter("Inflight_Data"); - - PingTimeHistogram = AdaptiveCounters->GetHistogram( - "PingTimeUs", NMonitoring::ExponentialHistogram(18, 2, 125)); - } - - if (updateGlobal) { - OutputBuffersTotalSize = Counters->GetCounter("OutputBuffersTotalSize"); - SendSyscalls = Counters->GetCounter("SendSyscalls", true); - SendSyscallsNs = Counters->GetCounter("SendSyscallsNs", true); - RecvSyscalls = Counters->GetCounter("RecvSyscalls", true); - RecvSyscallsNs = Counters->GetCounter("RecvSyscallsNs", true); - SpuriousReadWakeups = Counters->GetCounter("SpuriousReadWakeups", true); - UsefulReadWakeups = Counters->GetCounter("UsefulReadWakeups", true); - SpuriousWriteWakeups = Counters->GetCounter("SpuriousWriteWakeups", true); - UsefulWriteWakeups = Counters->GetCounter("UsefulWriteWakeups", true); - SubscribersCount = AdaptiveCounters->GetCounter("SubscribersCount"); - TotalBytesWritten = Counters->GetCounter("TotalBytesWritten", true); - TotalBytesRead = Counters->GetCounter("TotalBytesRead", true); - - auto disconnectReasonGroup = Counters->GetSubgroup("subsystem", "disconnectReason"); - for (const char *reason : TDisconnectReason::Reasons) { - DisconnectByReason[reason] = disconnectReasonGroup->GetCounter(reason, true); - } - } - - Initialized = true; - } - - const TOutputChannel& GetOutputChannel(ui16 index) const { - Y_ABORT_UNLESS(Initialized); - const auto it = OutputChannels.find(index); - return it != OutputChannels.end() ? it->second : OtherOutputChannel; - } - - private: - NMonitoring::TDynamicCounters::TCounterPtr SessionDeaths; - NMonitoring::TDynamicCounters::TCounterPtr HandshakeFails; - NMonitoring::TDynamicCounters::TCounterPtr Connected; - NMonitoring::TDynamicCounters::TCounterPtr Disconnections; - NMonitoring::TDynamicCounters::TCounterPtr InflightDataAmount; - NMonitoring::TDynamicCounters::TCounterPtr InflyLimitReach; - NMonitoring::TDynamicCounters::TCounterPtr OutputBuffersTotalSize; - NMonitoring::TDynamicCounters::TCounterPtr QueueUtilization; - NMonitoring::TDynamicCounters::TCounterPtr SubscribersCount; - NMonitoring::TDynamicCounters::TCounterPtr SendSyscalls; - NMonitoring::TDynamicCounters::TCounterPtr SendSyscallsNs; - NMonitoring::TDynamicCounters::TCounterPtr ClockSkewMicrosec; - NMonitoring::TDynamicCounters::TCounterPtr RecvSyscalls; - NMonitoring::TDynamicCounters::TCounterPtr RecvSyscallsNs; - NMonitoring::TDynamicCounters::TCounterPtr UsefulReadWakeups; - NMonitoring::TDynamicCounters::TCounterPtr SpuriousReadWakeups; - NMonitoring::TDynamicCounters::TCounterPtr UsefulWriteWakeups; - NMonitoring::TDynamicCounters::TCounterPtr SpuriousWriteWakeups; - NMonitoring::THistogramPtr PingTimeHistogram; - - std::unordered_map<ui16, TOutputChannel> OutputChannels; - TOutputChannel OtherOutputChannel; - TInputChannels InputChannels; - THashMap<TString, NMonitoring::TDynamicCounters::TCounterPtr> DisconnectByReason; - - NMonitoring::TDynamicCounters::TCounterPtr TotalBytesWritten, TotalBytesRead; - }; - - class TInterconnectMetrics: public IInterconnectMetrics { - public: - struct TOutputChannel { - NMonitoring::IRate* Traffic; - NMonitoring::IRate* Events; - NMonitoring::IRate* OutgoingTraffic; - NMonitoring::IRate* OutgoingEvents; - - TOutputChannel() = default; - - TOutputChannel(const std::shared_ptr<NMonitoring::IMetricRegistry>& metrics, - NMonitoring::IRate* traffic, - NMonitoring::IRate* events) - : Traffic(traffic) - , Events(events) - , OutgoingTraffic(metrics->Rate(NMonitoring::MakeLabels({{"sensor", "interconnect.outgoing_traffic"}}))) - , OutgoingEvents(metrics->Rate(NMonitoring::MakeLabels({{"sensor", "interconnect.outgoing_events"}}))) - {} - - TOutputChannel(const TOutputChannel&) = default; - TOutputChannel &operator=(const TOutputChannel& other) = default; - }; - - struct TInputChannel { - NMonitoring::IRate* Traffic; - NMonitoring::IRate* Events; - NMonitoring::IRate* ScopeErrors; - NMonitoring::IRate* IncomingTraffic; - NMonitoring::IRate* IncomingEvents; - - TInputChannel() = default; - - TInputChannel(const std::shared_ptr<NMonitoring::IMetricRegistry>& metrics, - NMonitoring::IRate* traffic, NMonitoring::IRate* events, - NMonitoring::IRate* scopeErrors) - : Traffic(traffic) - , Events(events) - , ScopeErrors(scopeErrors) - , IncomingTraffic(metrics->Rate(NMonitoring::MakeLabels({{"sensor", "interconnect.incoming_traffic"}}))) - , IncomingEvents(metrics->Rate(NMonitoring::MakeLabels({{"sensor", "interconnect.incoming_events"}}))) - {} - - TInputChannel(const TInputChannel&) = default; - TInputChannel &operator=(const TInputChannel& other) = default; - }; - - struct TInputChannels : std::unordered_map<ui16, TInputChannel> { - TInputChannel OtherInputChannel; - - TInputChannels() = default; - - TInputChannels(const std::shared_ptr<NMonitoring::IMetricRegistry>& metrics, - const std::unordered_map<ui16, TString>& names, - NMonitoring::IRate* traffic, NMonitoring::IRate* events, - NMonitoring::IRate* scopeErrors) - : OtherInputChannel(std::make_shared<NMonitoring::TMetricSubRegistry>( - NMonitoring::TLabels{{"channel", "other"}}, metrics), traffic, events, scopeErrors) - { - for (const auto& [id, name] : names) { - try_emplace(id, std::make_shared<NMonitoring::TMetricSubRegistry>(NMonitoring::TLabels{{"channel", name}}, metrics), - traffic, events, scopeErrors); - } - } - - TInputChannels(const TInputChannels&) = default; - TInputChannels &operator=(const TInputChannels& other) = default; - - const TInputChannel& Get(ui16 id) const { - const auto it = find(id); - return it != end() ? it->second : OtherInputChannel; - } - }; - - TInterconnectMetrics(const TInterconnectProxyCommon::TPtr& common) - : Common(common) - , MergePerDataCenterMetrics_(common->Settings.MergePerDataCenterCounters) - , MergePerPeerMetrics_(common->Settings.MergePerPeerCounters) - , Metrics_(common->Metrics) - , AdaptiveMetrics_(MergePerDataCenterMetrics_ - ? PerDataCenterMetrics_ : - MergePerPeerMetrics_ ? Metrics_ : PerSessionMetrics_) - {} - - void AddInflightDataAmount(ui64 value) override { - InflightDataAmount_->Add(value); - } - - void SubInflightDataAmount(ui64 value) override { - InflightDataAmount_->Add(-value); - } - - void AddTotalBytesWritten(ui64 value) override { - TotalBytesWritten_->Add(value); - } - - void SetClockSkewMicrosec(i64 value) override { - ClockSkewMicrosec_->Set(value); - } - - void IncSessionDeaths() override { - SessionDeaths_->Inc(); - } - - void IncHandshakeFails() override { - HandshakeFails_->Inc(); - } - - void SetConnected(ui32 value) override { - Connected_->Set(value); - } - - void IncSubscribersCount() override { - SubscribersCount_->Inc(); - } - - void SubSubscribersCount(ui32 value) override { - SubscribersCount_->Add(-value); - } - - void SubOutputBuffersTotalSize(ui64 value) override { - OutputBuffersTotalSize_->Add(-value); - } - - void AddOutputBuffersTotalSize(ui64 value) override { - OutputBuffersTotalSize_->Add(value); - } - - ui64 GetOutputBuffersTotalSize() const override { - return OutputBuffersTotalSize_->Get(); - } - - void IncDisconnections() override { - Disconnections_->Inc(); - } - - void IncUsefulWriteWakeups() override { - UsefulWriteWakeups_->Inc(); - } - - void IncSpuriousWriteWakeups() override { - SpuriousWriteWakeups_->Inc(); - } - - void IncSendSyscalls(ui64 /*ns*/) override { - SendSyscalls_->Inc(); - } - - void IncInflyLimitReach() override { - InflyLimitReach_->Inc(); - } - - void IncUsefulReadWakeups() override { - UsefulReadWakeups_->Inc(); - } - - void IncSpuriousReadWakeups() override { - SpuriousReadWakeups_->Inc(); - } - - void IncDisconnectByReason(const TString& s) override { - if (auto it = DisconnectByReason_.find(s); it != DisconnectByReason_.end()) { - it->second->Inc(); - } - } - - void AddInputChannelsIncomingTraffic(ui16 channel, ui64 incomingTraffic) override { - auto& ch = InputChannels_.Get(channel); - ch.IncomingTraffic->Add(incomingTraffic); - } - - void IncInputChannelsIncomingEvents(ui16 channel) override { - auto& ch = InputChannels_.Get(channel); - ch.IncomingEvents->Inc(); - } - - void IncRecvSyscalls(ui64 /*ns*/) override { - RecvSyscalls_->Inc(); - } - - void AddTotalBytesRead(ui64 value) override { - TotalBytesRead_->Add(value); - } - - void UpdatePingTimeHistogram(ui64 value) override { - PingTimeHistogram_->Record(value); - } - - void UpdateOutputChannelTraffic(ui16 channel, ui64 value) override { - auto& ch = GetOutputChannel(channel); - if (ch.OutgoingTraffic) { - ch.OutgoingTraffic->Add(value); - } - if (ch.Traffic) { - ch.Traffic->Add(value); - } - } - - void UpdateOutputChannelEvents(ui16 channel) override { - auto& ch = GetOutputChannel(channel); - if (ch.OutgoingEvents) { - ch.OutgoingEvents->Inc(); - } - if (ch.Events) { - ch.Events->Inc(); - } - } - - void SetPeerInfo(const TString& name, const TString& dataCenterId) override { - if (name != std::exchange(HumanFriendlyPeerHostName, name)) { - PerSessionMetrics_.reset(); - } - VALGRIND_MAKE_READABLE(&DataCenterId, sizeof(DataCenterId)); - if (dataCenterId != std::exchange(DataCenterId, dataCenterId)) { - PerDataCenterMetrics_.reset(); - } - - const bool updatePerDataCenter = !PerDataCenterMetrics_ && MergePerDataCenterMetrics_; - if (updatePerDataCenter) { - PerDataCenterMetrics_ = std::make_shared<NMonitoring::TMetricSubRegistry>( - NMonitoring::TLabels{{"datacenter_id", *DataCenterId}}, Metrics_); - } - - const bool updatePerSession = !PerSessionMetrics_ || updatePerDataCenter; - if (updatePerSession) { - auto base = MergePerDataCenterMetrics_ ? PerDataCenterMetrics_ : Metrics_; - PerSessionMetrics_ = std::make_shared<NMonitoring::TMetricSubRegistry>( - NMonitoring::TLabels{{"peer", *HumanFriendlyPeerHostName}}, base); - } - - const bool updateGlobal = !Initialized_; - - const bool updateAdaptive = - &AdaptiveMetrics_ == &Metrics_ ? updateGlobal : - &AdaptiveMetrics_ == &PerSessionMetrics_ ? updatePerSession : - &AdaptiveMetrics_ == &PerDataCenterMetrics_ ? updatePerDataCenter : - false; - - auto createRate = [](std::shared_ptr<NMonitoring::IMetricRegistry> metrics, TStringBuf name) mutable { - return metrics->Rate(NMonitoring::MakeLabels(NMonitoring::TLabels{{"sensor", name}})); - }; - auto createIntGauge = [](std::shared_ptr<NMonitoring::IMetricRegistry> metrics, TStringBuf name) mutable { - return metrics->IntGauge(NMonitoring::MakeLabels(NMonitoring::TLabels{{"sensor", name}})); - }; - - if (updatePerSession) { - Connected_ = createIntGauge(PerSessionMetrics_, "interconnect.connected"); - Disconnections_ = createRate(PerSessionMetrics_, "interconnect.disconnections"); - ClockSkewMicrosec_ = createIntGauge(PerSessionMetrics_, "interconnect.clock_skew_microsec"); - Traffic_ = createRate(PerSessionMetrics_, "interconnect.traffic"); - Events_ = createRate(PerSessionMetrics_, "interconnect.events"); - ScopeErrors_ = createRate(PerSessionMetrics_, "interconnect.scope_errors"); - - for (const auto& [id, name] : Common->ChannelName) { - OutputChannels_.try_emplace(id, std::make_shared<NMonitoring::TMetricSubRegistry>( - NMonitoring::TLabels{{"channel", name}}, Metrics_), Traffic_, Events_); - } - OtherOutputChannel_ = TOutputChannel(std::make_shared<NMonitoring::TMetricSubRegistry>( - NMonitoring::TLabels{{"channel", "other"}}, Metrics_), Traffic_, Events_); - - InputChannels_ = TInputChannels(Metrics_, Common->ChannelName, Traffic_, Events_, ScopeErrors_); - } - - if (updateAdaptive) { - SessionDeaths_ = createRate(AdaptiveMetrics_, "interconnect.session_deaths"); - HandshakeFails_ = createRate(AdaptiveMetrics_, "interconnect.handshake_fails"); - InflyLimitReach_ = createRate(AdaptiveMetrics_, "interconnect.infly_limit_reach"); - InflightDataAmount_ = createRate(AdaptiveMetrics_, "interconnect.inflight_data"); - PingTimeHistogram_ = AdaptiveMetrics_->HistogramRate( - NMonitoring::MakeLabels({{"sensor", "interconnect.ping_time_us"}}), NMonitoring::ExponentialHistogram(18, 2, 125)); - } - - if (updateGlobal) { - OutputBuffersTotalSize_ = createRate(Metrics_, "interconnect.output_buffers_total_size"); - SendSyscalls_ = createRate(Metrics_, "interconnect.send_syscalls"); - RecvSyscalls_ = createRate(Metrics_, "interconnect.recv_syscalls"); - SpuriousReadWakeups_ = createRate(Metrics_, "interconnect.spurious_read_wakeups"); - UsefulReadWakeups_ = createRate(Metrics_, "interconnect.useful_read_wakeups"); - SpuriousWriteWakeups_ = createRate(Metrics_, "interconnect.spurious_write_wakeups"); - UsefulWriteWakeups_ = createRate(Metrics_, "interconnect.useful_write_wakeups"); - SubscribersCount_ = createIntGauge(AdaptiveMetrics_, "interconnect.subscribers_count"); - TotalBytesWritten_ = createRate(Metrics_, "interconnect.total_bytes_written"); - TotalBytesRead_ = createRate(Metrics_, "interconnect.total_bytes_read"); - - for (const char *reason : TDisconnectReason::Reasons) { - DisconnectByReason_[reason] = Metrics_->Rate( - NMonitoring::MakeLabels({ - {"sensor", "interconnect.disconnect_reason"}, - {"reason", reason}, - })); - } - } - - Initialized_ = true; - } - - const TOutputChannel& GetOutputChannel(ui16 index) const { - Y_ABORT_UNLESS(Initialized_); - const auto it = OutputChannels_.find(index); - return it != OutputChannels_.end() ? it->second : OtherOutputChannel_; - } - - private: - const TInterconnectProxyCommon::TPtr Common; - const bool MergePerDataCenterMetrics_; - const bool MergePerPeerMetrics_; - std::shared_ptr<NMonitoring::IMetricRegistry> Metrics_; - std::shared_ptr<NMonitoring::IMetricRegistry> PerSessionMetrics_; - std::shared_ptr<NMonitoring::IMetricRegistry> PerDataCenterMetrics_; - std::shared_ptr<NMonitoring::IMetricRegistry>& AdaptiveMetrics_; - bool Initialized_ = false; - - NMonitoring::IRate* Traffic_; - - NMonitoring::IRate* Events_; - NMonitoring::IRate* ScopeErrors_; - NMonitoring::IRate* Disconnections_; - NMonitoring::IIntGauge* Connected_; - - NMonitoring::IRate* SessionDeaths_; - NMonitoring::IRate* HandshakeFails_; - NMonitoring::IRate* InflyLimitReach_; - NMonitoring::IRate* InflightDataAmount_; - NMonitoring::IRate* OutputBuffersTotalSize_; - NMonitoring::IIntGauge* SubscribersCount_; - NMonitoring::IRate* SendSyscalls_; - NMonitoring::IRate* RecvSyscalls_; - NMonitoring::IRate* SpuriousWriteWakeups_; - NMonitoring::IRate* UsefulWriteWakeups_; - NMonitoring::IRate* SpuriousReadWakeups_; - NMonitoring::IRate* UsefulReadWakeups_; - NMonitoring::IIntGauge* ClockSkewMicrosec_; - - NMonitoring::IHistogram* PingTimeHistogram_; - - THashMap<ui16, TOutputChannel> OutputChannels_; - TOutputChannel OtherOutputChannel_; - TInputChannels InputChannels_; - - THashMap<TString, NMonitoring::IRate*> DisconnectByReason_; - - NMonitoring::IRate* TotalBytesWritten_; - NMonitoring::IRate* TotalBytesRead_; - }; - -} // namespace - -std::unique_ptr<IInterconnectMetrics> CreateInterconnectCounters(const TInterconnectProxyCommon::TPtr& common) { - return std::make_unique<TInterconnectCounters>(common); -} - -std::unique_ptr<IInterconnectMetrics> CreateInterconnectMetrics(const TInterconnectProxyCommon::TPtr& common) { - return std::make_unique<TInterconnectMetrics>(common); -} - -} // NActors diff --git a/library/cpp/actors/interconnect/interconnect_counters.h b/library/cpp/actors/interconnect/interconnect_counters.h deleted file mode 100644 index 205ccf35b1..0000000000 --- a/library/cpp/actors/interconnect/interconnect_counters.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include <util/system/valgrind.h> - -#include "types.h" - -#include "interconnect_common.h" - -#include <memory> -#include <optional> - -namespace NActors { - -class IInterconnectMetrics { -public: - virtual ~IInterconnectMetrics() = default; - - virtual void AddInflightDataAmount(ui64 value) = 0; - virtual void SubInflightDataAmount(ui64 value) = 0; - virtual void AddTotalBytesWritten(ui64 value) = 0; - virtual void SetClockSkewMicrosec(i64 value) = 0; - virtual void IncSessionDeaths() = 0; - virtual void IncHandshakeFails() = 0; - virtual void SetConnected(ui32 value) = 0; - virtual void IncSubscribersCount() = 0; - virtual void SubSubscribersCount(ui32 value) = 0; - virtual void SubOutputBuffersTotalSize(ui64 value) = 0; - virtual void AddOutputBuffersTotalSize(ui64 value) = 0; - virtual ui64 GetOutputBuffersTotalSize() const = 0; - virtual void IncDisconnections() = 0; - virtual void IncUsefulWriteWakeups() = 0; - virtual void IncSpuriousWriteWakeups() = 0; - virtual void IncSendSyscalls(ui64 ns) = 0; - virtual void IncInflyLimitReach() = 0; - virtual void IncDisconnectByReason(const TString& s) = 0; - virtual void IncUsefulReadWakeups() = 0; - virtual void IncSpuriousReadWakeups() = 0; - virtual void SetPeerInfo(const TString& name, const TString& dataCenterId) = 0; - virtual void AddInputChannelsIncomingTraffic(ui16 channel, ui64 incomingTraffic) = 0; - virtual void IncInputChannelsIncomingEvents(ui16 channel) = 0; - virtual void IncRecvSyscalls(ui64 ns) = 0; - virtual void AddTotalBytesRead(ui64 value) = 0; - virtual void UpdatePingTimeHistogram(ui64 value) = 0; - virtual void UpdateOutputChannelTraffic(ui16 channel, ui64 value) = 0; - virtual void UpdateOutputChannelEvents(ui16 channel) = 0; - TString GetHumanFriendlyPeerHostName() const { - return HumanFriendlyPeerHostName.value_or(TString()); - } - -protected: - std::optional<TString> DataCenterId; - std::optional<TString> HumanFriendlyPeerHostName; -}; - -std::unique_ptr<IInterconnectMetrics> CreateInterconnectCounters(const NActors::TInterconnectProxyCommon::TPtr& common); -std::unique_ptr<IInterconnectMetrics> CreateInterconnectMetrics(const NActors::TInterconnectProxyCommon::TPtr& common); -} // NActors diff --git a/library/cpp/actors/interconnect/interconnect_handshake.cpp b/library/cpp/actors/interconnect/interconnect_handshake.cpp deleted file mode 100644 index 8c347507b2..0000000000 --- a/library/cpp/actors/interconnect/interconnect_handshake.cpp +++ /dev/null @@ -1,1237 +0,0 @@ -#include "interconnect_handshake.h" -#include "handshake_broker.h" -#include "interconnect_tcp_proxy.h" - -#include <library/cpp/actors/core/actor_coroutine.h> -#include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/protos/services_common.pb.h> -#include <util/system/getpid.h> -#include <util/random/entropy.h> - -#include <google/protobuf/text_format.h> - -#include <variant> - -namespace NActors { - static constexpr size_t StackSize = 64 * 1024; // 64k should be enough - - class THandshakeActor - : public TActorCoroImpl - , public TInterconnectLoggingBase - { - struct TExHandshakeFailed : yexception {}; - struct TExPoison {}; - - static constexpr TDuration ResolveTimeout = TDuration::Seconds(1); - -#pragma pack(push, 1) - - struct TInitialPacket { - struct { - TActorId SelfVirtualId; - TActorId PeerVirtualId; - ui64 NextPacket; - ui64 Version; - } Header; - ui32 Checksum; - - TInitialPacket() = default; - - TInitialPacket(const TActorId& self, const TActorId& peer, ui64 nextPacket, ui64 version) { - Header.SelfVirtualId = self; - Header.PeerVirtualId = peer; - Header.NextPacket = nextPacket; - Header.Version = version; - Checksum = Crc32cExtendMSanCompatible(0, &Header, sizeof(Header)); - } - - bool Check() const { - return Checksum == Crc32cExtendMSanCompatible(0, &Header, sizeof(Header)); - } - - TString ToString() const { - return TStringBuilder() - << "{SelfVirtualId# " << Header.SelfVirtualId.ToString() - << " PeerVirtualId# " << Header.PeerVirtualId.ToString() - << " NextPacket# " << Header.NextPacket - << " Version# " << Header.Version - << "}"; - } - }; - - struct TExHeader { - static constexpr ui32 MaxSize = 1024 * 1024; - - ui32 Checksum; - ui32 Size; - - ui32 CalculateChecksum(const void* data, size_t len) const { - return Crc32cExtendMSanCompatible(Crc32cExtendMSanCompatible(0, &Size, sizeof(Size)), data, len); - } - - void Sign(const void* data, size_t len) { - Checksum = CalculateChecksum(data, len); - } - - bool Check(const void* data, size_t len) const { - return Checksum == CalculateChecksum(data, len); - } - }; - -#pragma pack(pop) - - private: - class TConnection : TNonCopyable { - THandshakeActor *Actor = nullptr; - TIntrusivePtr<NInterconnect::TStreamSocket> Socket; - TPollerToken::TPtr PollerToken; - - public: - TConnection(THandshakeActor *actor, TIntrusivePtr<NInterconnect::TStreamSocket> socket) - : Actor(actor) - , Socket(std::move(socket)) - {} - - void Connect(TString *peerAddr) { - for (const NInterconnect::TAddress& address : Actor->ResolvePeer()) { - // create the socket with matching address family - int err = 0; - Socket = NInterconnect::TStreamSocket::Make(address.GetFamily(), &err); - if (err == EAFNOSUPPORT) { - Reset(); - continue; - } else if (*Socket == -1) { - Actor->Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "System error: failed to create socket"); - } - - // extract peer address - if (peerAddr) { - *peerAddr = address.ToString(); - } - - // set up socket parameters - SetupSocket(); - - // start connecting - err = -Socket->Connect(address); - if (err == EINPROGRESS) { - RegisterInPoller(); - WaitPoller(false, true, "WaitConnect"); - err = Socket->GetConnectStatus(); - } else if (!err) { - RegisterInPoller(); - } - - // check if connection succeeded - if (err) { - Reset(); - } else { - break; - } - } - - if (!Socket) { - Actor->Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "Couldn't connect to any resolved address", true); - } - } - - void Reset() { - Socket.Reset(); - PollerToken.Reset(); - } - - void SetupSocket() { - // switch to nonblocking mode - try { - SetNonBlock(*Socket); - SetNoDelay(*Socket, true); - } catch (...) { - Actor->Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "System error: can't up nonblocking mode for socket"); - } - - // setup send buffer size - Socket->SetSendBufferSize(Actor->Common->Settings.GetSendBufferSize()); - } - - void RegisterInPoller() { - Y_ABORT_UNLESS(!PollerToken); - const bool success = Actor->Send(MakePollerActorId(), new TEvPollerRegister(Socket, Actor->SelfActorId, Actor->SelfActorId)); - Y_ABORT_UNLESS(success); - auto result = Actor->WaitForSpecificEvent<TEvPollerRegisterResult>("RegisterPoller"); - PollerToken = std::move(result->Get()->PollerToken); - Y_ABORT_UNLESS(PollerToken); - Y_ABORT_UNLESS(PollerToken->RefCount() == 1); // ensure exclusive ownership - } - - void WaitPoller(bool read, bool write, TString state) { - if (!PollerToken->RequestNotificationAfterWouldBlock(read, write)) { - Actor->WaitForSpecificEvent<TEvPollerReady>(std::move(state)); - } - } - - template <typename TDataPtr, typename TSendRecvFunc> - void Process(TDataPtr buffer, size_t len, TSendRecvFunc&& sendRecv, bool read, bool write, TString state) { - Y_ABORT_UNLESS(Socket); - NInterconnect::TStreamSocket* sock = Socket.Get(); - ssize_t (NInterconnect::TStreamSocket::*pfn)(TDataPtr, size_t, TString*) const = sendRecv; - size_t processed = 0; - - auto error = [&](TString msg) { - Actor->Fail(TEvHandshakeFail::HANDSHAKE_FAIL_TRANSIENT, - Sprintf("Socket error# %s state# %s processed# %zu remain# %zu", - msg.data(), state.data(), processed, len), true); - }; - - while (len) { - TString err; - ssize_t nbytes = (sock->*pfn)(buffer, len, &err); - if (nbytes > 0) { - buffer = (char*)buffer + nbytes; - len -= nbytes; - processed += nbytes; - } else if (-nbytes == EAGAIN || -nbytes == EWOULDBLOCK) { - WaitPoller(read, write, state); - } else if (!nbytes) { - error("connection unexpectedly closed"); - } else if (-nbytes != EINTR) { - error(err ? err : TString(strerror(-nbytes))); - } - } - } - - void SendData(const void* buffer, size_t len, TString state) { - Process(buffer, len, &NInterconnect::TStreamSocket::Send, false, true, std::move(state)); - } - - void ReceiveData(void* buffer, size_t len, TString state) { - Process(buffer, len, &NInterconnect::TStreamSocket::Recv, true, false, std::move(state)); - } - - void ResetPollerToken() { - if (PollerToken) { - Y_ABORT_UNLESS(PollerToken->RefCount() == 1); - PollerToken.Reset(); // ensure we are going to destroy poller token here as we will re-register the socket within other actor - } - } - - TIntrusivePtr<NInterconnect::TStreamSocket>& GetSocketRef() { return Socket; } - operator bool() const { return static_cast<bool>(Socket); } - }; - - private: - TInterconnectProxyCommon::TPtr Common; - TActorId SelfVirtualId; - TActorId PeerVirtualId; - ui32 PeerNodeId = 0; - ui64 NextPacketToPeer = 0; - TMaybe<ui64> NextPacketFromPeer; // will be obtained from incoming initial packet - TString PeerHostName; - TString PeerAddr; - TConnection MainChannel; - TConnection ExternalDataChannel; - TString State; - TString HandshakeKind; - TMaybe<THolder<TProgramInfo>> ProgramInfo; // filled in in case of successful handshake; even if null - TSessionParams Params; - std::optional<TInstant> LastLogNotice; - const TDuration MuteDuration = TDuration::Seconds(15); - TMonotonic Deadline; - TActorId HandshakeBroker; - std::optional<TBrokerLeaseHolder> BrokerLeaseHolder; - std::optional<TString> HandshakeId; // for XDC - bool SubscribedForConnection = false; - - public: - THandshakeActor(TInterconnectProxyCommon::TPtr common, const TActorId& self, const TActorId& peer, - ui32 nodeId, ui64 nextPacket, TString peerHostName, TSessionParams params) - : TActorCoroImpl(StackSize, true) - , Common(std::move(common)) - , SelfVirtualId(self) - , PeerVirtualId(peer) - , PeerNodeId(nodeId) - , NextPacketToPeer(nextPacket) - , PeerHostName(std::move(peerHostName)) - , MainChannel(this, nullptr) - , ExternalDataChannel(this, nullptr) - , HandshakeKind("outgoing handshake") - , Params(std::move(params)) - { - Y_ABORT_UNLESS(SelfVirtualId); - Y_ABORT_UNLESS(SelfVirtualId.NodeId()); - Y_ABORT_UNLESS(PeerNodeId); - HandshakeBroker = MakeHandshakeBrokerOutId(); - - // generate random handshake id - HandshakeId = TString::Uninitialized(32); - EntropyPool().Read(HandshakeId->Detach(), HandshakeId->size()); - } - - THandshakeActor(TInterconnectProxyCommon::TPtr common, TSocketPtr socket) - : TActorCoroImpl(StackSize, true) - , Common(std::move(common)) - , MainChannel(this, std::move(socket)) - , ExternalDataChannel(this, nullptr) - , HandshakeKind("incoming handshake") - { - Y_ABORT_UNLESS(MainChannel); - PeerAddr = TString::Uninitialized(1024); - if (GetRemoteAddr(*MainChannel.GetSocketRef(), PeerAddr.Detach(), PeerAddr.size())) { - PeerAddr.resize(strlen(PeerAddr.data())); - } else { - PeerAddr.clear(); - } - } - - void UpdatePrefix() { - SetPrefix(Sprintf("Handshake %s [node %" PRIu32 "]", SelfActorId.ToString().data(), PeerNodeId)); - } - - void Run() override { - try { - RunImpl(); - } catch (const TDtorException&) { - if (BrokerLeaseHolder) { - BrokerLeaseHolder->ForgetLease(); - } - throw; - } catch (const TExPoison&) { - // just stop execution, do nothing - } catch (...) { - Y_ABORT("unhandled exception"); - } - if (SubscribedForConnection) { - SendToProxy(MakeHolder<TEvSubscribeForConnection>(*HandshakeId, false)); - } - } - - void RunImpl() { - UpdatePrefix(); - - if (!MainChannel && Common->OutgoingHandshakeInflightLimit) { - // Create holder, which sends request to broker and automatically frees the place when destroyed - BrokerLeaseHolder.emplace(SelfActorId, HandshakeBroker); - } - - if (BrokerLeaseHolder && BrokerLeaseHolder->IsLeaseRequested()) { - WaitForSpecificEvent<TEvHandshakeBrokerPermit>("HandshakeBrokerPermit"); - } - - // set up overall handshake process timer - TDuration timeout = Common->Settings.Handshake; - if (timeout == TDuration::Zero()) { - timeout = DEFAULT_HANDSHAKE_TIMEOUT; - } - timeout += ResolveTimeout * 2; - - if (MainChannel) { - // Incoming handshakes have shorter timeout than outgoing - timeout *= 0.9; - } - - Deadline = TActivationContext::Monotonic() + timeout; - Schedule(Deadline, new TEvents::TEvWakeup); - - try { - const bool incoming = MainChannel; - if (incoming) { - PerformIncomingHandshake(); - } else { - PerformOutgoingHandshake(); - } - - // establish encrypted channel, or, in case when encryption is disabled, check if it matches settings - if (ProgramInfo) { - if (Params.UseExternalDataChannel) { - if (incoming) { - Y_ABORT_UNLESS(SubscribedForConnection); - auto ev = WaitForSpecificEvent<TEvReportConnection>("WaitInboundXdcStream"); - SubscribedForConnection = false; - if (ev->Get()->HandshakeId != *HandshakeId) { - Y_DEBUG_ABORT_UNLESS(false); - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "Mismatching HandshakeId in external data channel"); - } - ExternalDataChannel.GetSocketRef() = std::move(ev->Get()->Socket); - } else { - EstablishExternalDataChannel(); - } - } - - if (Params.Encryption) { - EstablishSecureConnection(MainChannel); - if (ExternalDataChannel) { - EstablishSecureConnection(ExternalDataChannel); - } - } else if (Common->Settings.EncryptionMode == EEncryptionMode::REQUIRED && !Params.AuthOnly) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "Peer doesn't support encryption, which is required"); - } - } - } catch (const TExHandshakeFailed&) { - ProgramInfo.Clear(); - } - - if (ProgramInfo) { - LOG_LOG_IC_X(NActorsServices::INTERCONNECT, "ICH04", NLog::PRI_INFO, "handshake succeeded"); - Y_ABORT_UNLESS(NextPacketFromPeer); - MainChannel.ResetPollerToken(); - ExternalDataChannel.ResetPollerToken(); - Y_ABORT_UNLESS(!ExternalDataChannel == !Params.UseExternalDataChannel); - SendToProxy(MakeHolder<TEvHandshakeDone>(std::move(MainChannel.GetSocketRef()), PeerVirtualId, SelfVirtualId, - *NextPacketFromPeer, ProgramInfo->Release(), std::move(Params), std::move(ExternalDataChannel.GetSocketRef()))); - } - - MainChannel.Reset(); - ExternalDataChannel.Reset(); - } - - void EstablishSecureConnection(TConnection& connection) { - // wrap current socket with secure one - connection.ResetPollerToken(); - TIntrusivePtr<NInterconnect::TStreamSocket>& socketRef = connection.GetSocketRef(); - auto ev = AskProxy<TEvSecureSocket>(MakeHolder<TEvGetSecureSocket>(socketRef), "AskProxy(TEvSecureContext)"); - TIntrusivePtr<NInterconnect::TSecureSocket> secure = std::move(ev->Get()->Socket); // remember for further use - socketRef = secure; // replace the socket within the connection - connection.RegisterInPoller(); // re-register in poller - - const ui32 myNodeId = GetActorSystem()->NodeId; - const bool server = myNodeId < PeerNodeId; // keep server/client role permanent to enable easy TLS session resuming - for (;;) { - TString err; - switch (secure->Establish(server, Params.AuthOnly, err)) { - case NInterconnect::TSecureSocket::EStatus::SUCCESS: - if (Params.AuthOnly) { - Params.Encryption = false; - Params.AuthCN = secure->GetPeerCommonName(); - connection.ResetPollerToken(); - socketRef = secure->Detach(); - connection.RegisterInPoller(); - } - return; - - case NInterconnect::TSecureSocket::EStatus::ERROR: - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, err, true); - [[fallthrough]]; - - case NInterconnect::TSecureSocket::EStatus::WANT_READ: - connection.WaitPoller(true, false, "ReadEstablish"); - break; - - case NInterconnect::TSecureSocket::EStatus::WANT_WRITE: - connection.WaitPoller(false, true, "WriteEstablish"); - break; - } - } - } - - void ProcessUnexpectedEvent(TAutoPtr<IEventHandle> ev) { - switch (const ui32 type = ev->GetTypeRewrite()) { - case TEvents::TSystem::Wakeup: - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_TRANSIENT, Sprintf("Handshake timed out, State# %s", State.data()), true); - [[fallthrough]]; - - case ui32(ENetwork::NodeInfo): - case TEvInterconnect::EvNodeAddress: - case ui32(ENetwork::ResolveError): - break; // most likely a race with resolve timeout - - case TEvPollerReady::EventType: - break; - - case TEvents::TSystem::Poison: - throw TExPoison(); - - default: - Y_ABORT("unexpected event 0x%08" PRIx32, type); - } - } - - template<typename T> - void SetupCompatibilityInfo(T& proto) { - if (Common->CompatibilityInfo) { - proto.SetCompatibilityInfo(*Common->CompatibilityInfo); - } - } - - template<typename T> - void SetupVersionTag(T& proto) { - if (Common->VersionInfo) { - proto.SetVersionTag(Common->VersionInfo->Tag); - for (const TString& accepted : Common->VersionInfo->AcceptedTags) { - proto.AddAcceptedVersionTags(accepted); - } - } - } - - template<typename T> - void SetupClusterUUID(T& proto) { - auto *pb = proto.MutableClusterUUIDs(); - pb->SetClusterUUID(Common->ClusterUUID); - for (const TString& uuid : Common->AcceptUUID) { - pb->AddAcceptUUID(uuid); - } - } - - template<typename T, typename TCallback> - void ValidateCompatibilityInfo(const T& proto, TCallback&& errorCallback) { - // if possible, use new CompatibilityInfo field - if (proto.HasCompatibilityInfo() && Common->ValidateCompatibilityInfo) { - TString errorReason; - if (!Common->ValidateCompatibilityInfo(proto.GetCompatibilityInfo(), errorReason)) { - TStringStream s("Local and peer CompatibilityInfo are incompatible"); - s << ", errorReason# " << errorReason; - errorCallback(s.Str()); - } - } else if (proto.HasVersionTag() && Common->ValidateCompatibilityOldFormat) { - TInterconnectProxyCommon::TVersionInfo oldFormat; - oldFormat.Tag = proto.GetVersionTag(); - for (ui32 i = 0; i < proto.AcceptedVersionTagsSize(); ++i) { - oldFormat.AcceptedTags.insert(proto.GetAcceptedVersionTags(i)); - } - TString errorReason; - if (!Common->ValidateCompatibilityOldFormat(oldFormat, errorReason)) { - TStringStream s("Local CompatibilityInfo and peer TVersionInfo are incompatible"); - s << ", errorReason# " << errorReason; - errorCallback(s.Str()); - } - } else if (proto.HasVersionTag()) { - ValidateVersionTag(proto, std::forward<TCallback>(errorCallback)); - } else { - LOG_LOG_IC_X(NActorsServices::INTERCONNECT, "ICH09", NLog::PRI_WARN, - "Neither CompatibilityInfo nor VersionTag of the peer can be validated, accepting by default"); - } - } - - template<typename T, typename TCallback> - void ValidateVersionTag(const T& proto, TCallback&& errorCallback) { - // check if we will accept peer's version tag (if peer provides one and if we have accepted list non-empty) - if (Common->VersionInfo) { - if (!proto.HasVersionTag()) { - LOG_LOG_IC_X(NActorsServices::INTERCONNECT, "ICH06", NLog::PRI_WARN, - "peer did not report VersionTag, accepting by default"); - } else if (!Common->VersionInfo->AcceptedTags.count(proto.GetVersionTag())) { - // we will not accept peer's tag, so check if remote peer would accept our version tag - size_t i; - for (i = 0; i < proto.AcceptedVersionTagsSize() && Common->VersionInfo->Tag != proto.GetAcceptedVersionTags(i); ++i) - {} - if (i == proto.AcceptedVersionTagsSize()) { - // peer will neither accept our version -- this is total failure - TStringStream s("local/peer version tags did not match accepted ones"); - s << " local Tag# " << Common->VersionInfo->Tag << " accepted Tags# ["; - bool first = true; - for (const auto& tag : Common->VersionInfo->AcceptedTags) { - s << (std::exchange(first, false) ? "" : " ") << tag; - } - s << "] peer Tag# " << proto.GetVersionTag() << " accepted Tags# ["; - first = true; - for (const auto& tag : proto.GetAcceptedVersionTags()) { - s << (std::exchange(first, false) ? "" : " ") << tag; - } - s << "]"; - errorCallback(s.Str()); - } - } - } - } - - template<typename T, typename TCallback> - void ValidateClusterUUID(const T& proto, TCallback&& errorCallback, const TMaybe<TString>& uuid = {}) { - auto formatList = [](const auto& list) { - TStringStream s; - s << "["; - for (auto it = list.begin(); it != list.end(); ++it) { - if (it != list.begin()) { - s << " "; - } - s << *it; - } - s << "]"; - return s.Str(); - }; - if (!Common->AcceptUUID) { - return; // promiscuous mode -- we accept every other peer - } - if (!proto.HasClusterUUIDs()) { - if (uuid) { - // old-style checking, peer does not support symmetric protoocol - bool matching = false; - for (const TString& accepted : Common->AcceptUUID) { - if (*uuid == accepted) { - matching = true; - break; - } - } - if (!matching) { - errorCallback(Sprintf("Peer ClusterUUID# %s mismatch, AcceptUUID# %s", uuid->data(), formatList(Common->AcceptUUID).data())); - } - } - return; // remote side did not fill in this field -- old version, symmetric protocol is not supported - } - - const auto& uuids = proto.GetClusterUUIDs(); - - // check if our UUID matches remote accept list - for (const TString& item : uuids.GetAcceptUUID()) { - if (item == Common->ClusterUUID) { - return; // match - } - } - - // check if remote UUID matches our accept list - const TString& remoteUUID = uuids.GetClusterUUID(); - for (const TString& item : Common->AcceptUUID) { - if (item == remoteUUID) { - return; // match - } - } - - // no match - errorCallback(Sprintf("Peer ClusterUUID# %s mismatch, AcceptUUID# %s", remoteUUID.data(), formatList(Common->AcceptUUID).data())); - } - - void ParsePeerScopeId(const NActorsInterconnect::TScopeId& proto) { - Params.PeerScopeId = {proto.GetX1(), proto.GetX2()}; - } - - void FillInScopeId(NActorsInterconnect::TScopeId& proto) { - const TScopeId& scope = Common->LocalScopeId; - proto.SetX1(scope.first); - proto.SetX2(scope.second); - } - - template<typename T> - void ReportProto(const T& protobuf, const char *msg) { - auto formatString = [&] { - google::protobuf::TextFormat::Printer p; - p.SetSingleLineMode(true); - TString s; - p.PrintToString(protobuf, &s); - return s; - }; - LOG_LOG_IC_X(NActorsServices::INTERCONNECT, "ICH07", NLog::PRI_DEBUG, "%s %s", msg, - formatString().data()); - } - - bool CheckPeerCookie(const TString& cookie, TString *error) { - // set up virtual self id to ensure peer will not drop our connection - char buf[12] = {'c', 'o', 'o', 'k', 'i', 'e', ' ', 'c', 'h', 'e', 'c', 'k'}; - SelfVirtualId = TActorId(SelfActorId.NodeId(), TStringBuf(buf, 12)); - - bool success = true; - try { - // issue connection and send initial packet - TConnection tempConnection(this, nullptr); - tempConnection.Connect(nullptr); - SendInitialPacket(tempConnection); - - // wait for basic response - TInitialPacket response; - tempConnection.ReceiveData(&response, sizeof(response), "ReceiveResponse"); - if (!response.Check()) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_TRANSIENT, "Initial packet CRC error"); - } else if (response.Header.Version != INTERCONNECT_PROTOCOL_VERSION) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, Sprintf("Incompatible protocol %" PRIu64, response.Header.Version)); - } - - // issue cookie check request - NActorsInterconnect::THandshakeRequest request; - request.SetProtocol(INTERCONNECT_PROTOCOL_VERSION); - request.SetProgramPID(0); - request.SetProgramStartTime(0); - request.SetSerial(0); - request.SetReceiverNodeId(0); - request.SetSenderActorId(TString()); - request.SetCookie(cookie); - request.SetDoCheckCookie(true); - SendExBlock(tempConnection, request, "ExBlockDoCheckCookie"); - - // process cookie check reply - NActorsInterconnect::THandshakeReply reply; - if (!reply.ParseFromString(ReceiveExBlock(tempConnection, "ExBlockDoCheckCookie"))) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "Incorrect packet from peer"); - } else if (reply.HasCookieCheckResult() && !reply.GetCookieCheckResult()) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "Cookie check error -- possible network problem"); - } - } catch (const TExHandshakeFailed& e) { - *error = e.what(); - success = false; - } - - // restore state - SelfVirtualId = TActorId(); - return success; - } - - void EstablishExternalDataChannel() { - ExternalDataChannel.Connect(nullptr); - char buf[12] = {'x', 'd', 'c', ' ', 'p', 'a', 'y', 'l', 'o', 'a', 'd', 0}; - TInitialPacket packet(TActorId(SelfActorId.NodeId(), TStringBuf(buf, 12)), {}, 0, INTERCONNECT_XDC_STREAM_VERSION); - ExternalDataChannel.SendData(&packet, sizeof(packet), "SendXdcStream"); - NActorsInterconnect::TExternalDataChannelParams params; - params.SetHandshakeId(*HandshakeId); - SendExBlock(ExternalDataChannel, params, "ExternalDataChannelParams"); - } - - void PerformOutgoingHandshake() { - LOG_LOG_IC_X(NActorsServices::INTERCONNECT, "ICH01", NLog::PRI_DEBUG, - "starting outgoing handshake"); - - // perform connection and log its result - MainChannel.Connect(&PeerAddr); - auto logPriority = std::exchange(LastLogNotice, std::nullopt) ? NActors::NLog::PRI_NOTICE : NActors::NLog::PRI_DEBUG; - LOG_LOG_IC_X(NActorsServices::INTERCONNECT, "ICH05", logPriority, "connected to peer"); - - // send initial request packet - if (Params.UseExternalDataChannel && PeerVirtualId) { // special case for XDC continuation - TInitialPacket packet(SelfVirtualId, PeerVirtualId, NextPacketToPeer, INTERCONNECT_XDC_CONTINUATION_VERSION); - MainChannel.SendData(&packet, sizeof(packet), "SendInitialPacket"); - NActorsInterconnect::TContinuationParams request; - request.SetHandshakeId(*HandshakeId); - SendExBlock(MainChannel, request, "ExRequest"); - } else { - TInitialPacket packet(SelfVirtualId, PeerVirtualId, NextPacketToPeer, INTERCONNECT_PROTOCOL_VERSION); - MainChannel.SendData(&packet, sizeof(packet), "SendInitialPacket"); - } - - TInitialPacket response; - MainChannel.ReceiveData(&response, sizeof(response), "ReceiveResponse"); - if (!response.Check()) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_TRANSIENT, "Initial packet CRC error"); - } else if (response.Header.Version != INTERCONNECT_PROTOCOL_VERSION) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, Sprintf("Incompatible protocol %" PRIu64, response.Header.Version)); - } - - // extract next packet - NextPacketFromPeer = response.Header.NextPacket; - - if (!PeerVirtualId) { - // creating new session -- we have to generate request - NActorsInterconnect::THandshakeRequest request; - - request.SetProtocol(INTERCONNECT_PROTOCOL_VERSION); - request.SetProgramPID(GetPID()); - request.SetProgramStartTime(Common->StartTime); - request.SetSerial(SelfVirtualId.LocalId()); - request.SetReceiverNodeId(PeerNodeId); - request.SetSenderActorId(SelfVirtualId.ToString()); - request.SetSenderHostName(Common->TechnicalSelfHostName); - request.SetReceiverHostName(PeerHostName); - - if (Common->LocalScopeId != TScopeId()) { - FillInScopeId(*request.MutableClientScopeId()); - } - - if (Common->Cookie) { - request.SetCookie(Common->Cookie); - } - if (Common->ClusterUUID) { - request.SetUUID(Common->ClusterUUID); - } - SetupClusterUUID(request); - SetupCompatibilityInfo(request); - SetupVersionTag(request); - - if (const ui32 size = Common->HandshakeBallastSize) { - TString ballast(size, 0); - char* data = ballast.Detach(); - for (ui32 i = 0; i < size; ++i) { - data[i] = i; - } - request.SetBallast(ballast); - } - - switch (Common->Settings.EncryptionMode) { - case EEncryptionMode::DISABLED: - break; - - case EEncryptionMode::OPTIONAL: - request.SetRequireEncryption(false); - break; - - case EEncryptionMode::REQUIRED: - request.SetRequireEncryption(true); - break; - } - - request.SetRequestModernFrame(true); - request.SetRequestAuthOnly(Common->Settings.TlsAuthOnly); - request.SetRequestExtendedTraceFmt(true); - request.SetRequestExternalDataChannel(Common->Settings.EnableExternalDataChannel); - request.SetRequestXxhash(true); - request.SetRequestXdcShuffle(true); - request.SetHandshakeId(*HandshakeId); - - SendExBlock(MainChannel, request, "ExRequest"); - - NActorsInterconnect::THandshakeReply reply; - if (!reply.ParseFromString(ReceiveExBlock(MainChannel, "ExReply"))) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "Incorrect THandshakeReply"); - } - ReportProto(reply, "ReceiveExBlock ExReply"); - - if (reply.HasErrorExplaination()) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "error from peer: " + reply.GetErrorExplaination()); - } else if (!reply.HasSuccess()) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "empty reply"); - } - - auto generateError = [this](TString msg) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, msg); - }; - - const auto& success = reply.GetSuccess(); - ValidateClusterUUID(success, generateError); - ValidateCompatibilityInfo(success, generateError); - - const auto& s = success.GetSenderActorId(); - PeerVirtualId.Parse(s.data(), s.size()); - - if (!success.GetUseModernFrame()) { - generateError("UseModernFrame not set, obsolete peer version"); - } else if (!success.GetUseExtendedTraceFmt()) { - generateError("UseExtendedTraceFmt not set, obsolete peer version"); - } - - // recover flags - Params.Encryption = success.GetStartEncryption(); - Params.AuthOnly = Params.Encryption && success.GetAuthOnly(); - Params.UseExternalDataChannel = success.GetUseExternalDataChannel(); - Params.UseXxhash = success.GetUseXxhash(); - Params.UseXdcShuffle = success.GetUseXdcShuffle(); - if (success.HasServerScopeId()) { - ParsePeerScopeId(success.GetServerScopeId()); - } - - // recover peer process info from peer's reply - ProgramInfo = GetProgramInfo(success); - } else if (!response.Header.SelfVirtualId) { - // peer reported error -- empty ack was generated by proxy for this request - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_SESSION_MISMATCH, "Peer rejected session continuation handshake"); - } else if (response.Header.SelfVirtualId != PeerVirtualId || response.Header.PeerVirtualId != SelfVirtualId) { - // resuming existing session; check that virtual ids of peers match each other - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_SESSION_MISMATCH, "Session virtual ID mismatch"); - } else { - ProgramInfo.ConstructInPlace(); // successful handshake - } - } - - std::vector<NInterconnect::TAddress> ResolvePeer() { - // issue request to a nameservice to resolve peer node address - const auto mono = TActivationContext::Monotonic(); - Send(Common->NameserviceId, new TEvInterconnect::TEvResolveNode(PeerNodeId, TActivationContext::Now() + (Deadline - mono))); - - // wait for the result - auto ev = WaitForSpecificEvent<TEvResolveError, TEvLocalNodeInfo, TEvInterconnect::TEvNodeAddress>( - "ValidateIncomingPeerViaDirectLookup", mono + ResolveTimeout); - - // extract address from the result - std::vector<NInterconnect::TAddress> addresses; - if (!ev) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve timed out", true); - } else if (auto *p = ev->CastAsLocal<TEvLocalNodeInfo>()) { - addresses = std::move(p->Addresses); - if (addresses.empty()) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve error: no address returned", true); - } - } else if (auto *p = ev->CastAsLocal<TEvInterconnect::TEvNodeAddress>()) { - const auto& r = p->Record; - if (!r.HasAddress() || !r.HasPort()) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve error: no address returned", true); - } - addresses.emplace_back(r.GetAddress(), static_cast<ui16>(r.GetPort())); - } else { - Y_ABORT_UNLESS(ev->GetTypeRewrite() == ui32(ENetwork::ResolveError)); - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve error: " + ev->Get<TEvResolveError>()->Explain - + ", Unresolved host# " + ev->Get<TEvResolveError>()->Host, true); - } - - return addresses; - } - - void ValidateIncomingPeerViaDirectLookup() { - auto addresses = ResolvePeer(); - - for (const auto& address : addresses) { - if (address.GetAddress() == PeerAddr) { - return; - } - } - - auto makeList = [&] { - TStringStream s; - s << '['; - for (auto it = addresses.begin(); it != addresses.end(); ++it) { - if (it != addresses.begin()) { - s << ' '; - } - s << it->GetAddress(); - } - s << ']'; - return s.Str(); - }; - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, TStringBuilder() << "Connecting node does not resolve to peer address" - << " PeerAddr# " << PeerAddr << " AddressList# " << makeList(), true); - } - - void PerformIncomingHandshake() { - LOG_LOG_IC_X(NActorsServices::INTERCONNECT, "ICH02", NLog::PRI_DEBUG, - "starting incoming handshake"); - - // set up incoming socket - MainChannel.SetupSocket(); - MainChannel.RegisterInPoller(); - - // wait for initial request packet - TInitialPacket request; - MainChannel.ReceiveData(&request, sizeof(request), "ReceiveRequest"); - if (!request.Check()) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_TRANSIENT, "Initial packet CRC error"); - } else if (request.Header.Version != INTERCONNECT_PROTOCOL_VERSION && - request.Header.Version != INTERCONNECT_XDC_CONTINUATION_VERSION && - request.Header.Version != INTERCONNECT_XDC_STREAM_VERSION) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, Sprintf("Incompatible protocol %" PRIu64, request.Header.Version)); - } - - // extract peer node id from the peer - PeerNodeId = request.Header.SelfVirtualId.NodeId(); - if (!PeerNodeId) { - Y_DEBUG_ABORT_UNLESS(false, "PeerNodeId is zero request# %s", request.ToString().data()); - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "SelfVirtualId.NodeId is empty in initial packet"); - } - UpdatePrefix(); - - // validate incoming peer if needed - if (Common->Settings.ValidateIncomingPeerViaDirectLookup) { - ValidateIncomingPeerViaDirectLookup(); - } - - // extract next packet - NextPacketFromPeer = request.Header.NextPacket; - - // process some extra payload, if necessary - switch (request.Header.Version) { - case INTERCONNECT_XDC_CONTINUATION_VERSION: { - NActorsInterconnect::TContinuationParams params; - if (!params.ParseFromString(ReceiveExBlock(MainChannel, "ContinuationParams")) || !params.HasHandshakeId()) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "Incorrect packet from peer"); - } - HandshakeId = params.GetHandshakeId(); - SendToProxy(MakeHolder<TEvSubscribeForConnection>(*HandshakeId, true)); - SubscribedForConnection = true; - break; - } - case INTERCONNECT_XDC_STREAM_VERSION: { - NActorsInterconnect::TExternalDataChannelParams params; - if (!params.ParseFromString(ReceiveExBlock(MainChannel, "ExternalDataChannelParams")) || !params.HasHandshakeId()) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "Incorrect packet from peer"); - } - MainChannel.ResetPollerToken(); - SendToProxy(MakeHolder<TEvReportConnection>(params.GetHandshakeId(), std::move(MainChannel.GetSocketRef()))); - throw TExHandshakeFailed(); - } - } - - if (request.Header.PeerVirtualId) { - // issue request to the proxy and wait for the response - auto reply = AskProxy<TEvHandshakeAck, TEvHandshakeNak>(MakeHolder<TEvHandshakeAsk>( - request.Header.SelfVirtualId, request.Header.PeerVirtualId, request.Header.NextPacket), - "TEvHandshakeAsk"); - if (auto *ack = reply->CastAsLocal<TEvHandshakeAck>()) { - // extract self/peer virtual ids - SelfVirtualId = ack->Self; - PeerVirtualId = request.Header.SelfVirtualId; - NextPacketToPeer = ack->NextPacket; - Params = ack->Params; - - // only succeed in case when proxy returned valid SelfVirtualId; otherwise it wants us to terminate - // the handshake process and it does not expect the handshake reply - ProgramInfo.ConstructInPlace(); - } else { - LOG_LOG_IC_X(NActorsServices::INTERCONNECT, "ICH08", NLog::PRI_NOTICE, - "Continuation request rejected by proxy"); - - // report continuation reject to peer - SelfVirtualId = TActorId(); - PeerVirtualId = TActorId(); - NextPacketToPeer = 0; - } - - // issue response to the peer - SendInitialPacket(MainChannel); - } else { - // peer wants a new session, clear fields and send initial packet - SelfVirtualId = TActorId(); - PeerVirtualId = TActorId(); - NextPacketToPeer = 0; - SendInitialPacket(MainChannel); - - // wait for extended request - auto ev = MakeHolder<TEvHandshakeRequest>(); - auto& request = ev->Record; - if (!request.ParseFromString(ReceiveExBlock(MainChannel, "ExRequest"))) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "Incorrect THandshakeRequest"); - } - ReportProto(request, "ReceiveExBlock ExRequest"); - - auto generateError = [this](TString msg) { - // issue reply to the peer to prevent repeating connection retries - NActorsInterconnect::THandshakeReply reply; - reply.SetErrorExplaination(msg); - SendExBlock(MainChannel, reply, "ExReply"); - - // terminate ths handshake - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, msg); - }; - - // check request cookie - TString error; - if (request.HasDoCheckCookie()) { - NActorsInterconnect::THandshakeReply reply; - reply.SetCookieCheckResult(request.GetCookie() == Common->Cookie); - SendExBlock(MainChannel, reply, "ExReplyDoCheckCookie"); - throw TExHandshakeFailed(); - } else if (request.HasCookie() && !CheckPeerCookie(request.GetCookie(), &error)) { - generateError(TStringBuilder() << "Peer connectivity-checking failed, error# " << error); - } - - // update log prefix with the reported peer host name - PeerHostName = request.GetSenderHostName(); - - // parse peer virtual id - const auto& str = request.GetSenderActorId(); - PeerVirtualId.Parse(str.data(), str.size()); - - // validate request - ValidateClusterUUID(request, generateError, request.GetUUID()); - if (request.GetReceiverNodeId() != SelfActorId.NodeId()) { - generateError(Sprintf("Incorrect ReceiverNodeId# %" PRIu32 " from the peer, expected# %" PRIu32, - request.GetReceiverNodeId(), SelfActorId.NodeId())); - } else if (request.GetReceiverHostName() != Common->TechnicalSelfHostName) { - generateError(Sprintf("ReceiverHostName# %s mismatch, expected# %s", request.GetReceiverHostName().data(), - Common->TechnicalSelfHostName.data())); - } - ValidateCompatibilityInfo(request, generateError); - - // check peer node - auto peerNodeInfo = GetPeerNodeInfo(); - if (!peerNodeInfo) { - generateError("Peer node not registered in nameservice"); - } else if (peerNodeInfo->Host != request.GetSenderHostName()) { - generateError("SenderHostName mismatch"); - } - - // check request against encryption - switch (Common->Settings.EncryptionMode) { - case EEncryptionMode::DISABLED: - if (request.GetRequireEncryption()) { - generateError("Peer requested encryption, but it is disabled locally"); - } - break; - - case EEncryptionMode::OPTIONAL: - Params.Encryption = request.HasRequireEncryption(); - break; - - case EEncryptionMode::REQUIRED: - if (!request.HasRequireEncryption()) { - generateError("Peer did not request encryption, but it is required locally"); - } - Params.Encryption = true; - break; - } - - if (!request.GetRequestModernFrame()) { - generateError("RequestModernFrame not set, obsolete peer version"); - } else if (!request.GetRequestExtendedTraceFmt()) { - generateError("RequestExtendedTraceFmt not set, obsolete peer version"); - } - - Params.AuthOnly = Params.Encryption && request.GetRequestAuthOnly() && Common->Settings.TlsAuthOnly; - Params.UseExternalDataChannel = request.GetRequestExternalDataChannel() && Common->Settings.EnableExternalDataChannel; - Params.UseXxhash = request.GetRequestXxhash(); - Params.UseXdcShuffle = request.GetRequestXdcShuffle(); - - if (Params.UseExternalDataChannel) { - if (request.HasHandshakeId()) { - HandshakeId = request.GetHandshakeId(); - SendToProxy(MakeHolder<TEvSubscribeForConnection>(*HandshakeId, true)); - SubscribedForConnection = true; - } else { - generateError("Peer has requested ExternalDataChannel feature, but did not provide HandshakeId"); - } - } - - if (request.HasClientScopeId()) { - ParsePeerScopeId(request.GetClientScopeId()); - } - - // remember program info (assuming successful handshake) - ProgramInfo = GetProgramInfo(request); - - // send to proxy - auto reply = AskProxy<TEvHandshakeReplyOK, TEvHandshakeReplyError>(std::move(ev), "TEvHandshakeRequest"); - - // parse it - if (auto ev = reply->CastAsLocal<TEvHandshakeReplyOK>()) { - // issue successful reply to the peer - auto& record = ev->Record; - Y_ABORT_UNLESS(record.HasSuccess()); - auto& success = *record.MutableSuccess(); - SetupClusterUUID(success); - SetupCompatibilityInfo(success); - SetupVersionTag(success); - success.SetStartEncryption(Params.Encryption); - if (Common->LocalScopeId != TScopeId()) { - FillInScopeId(*success.MutableServerScopeId()); - } - success.SetUseModernFrame(true); - success.SetAuthOnly(Params.AuthOnly); - success.SetUseExtendedTraceFmt(true); - success.SetUseExternalDataChannel(Params.UseExternalDataChannel); - success.SetUseXxhash(Params.UseXxhash); - success.SetUseXdcShuffle(Params.UseXdcShuffle); - SendExBlock(MainChannel, record, "ExReply"); - - // extract sender actor id (self virtual id) - const auto& str = success.GetSenderActorId(); - SelfVirtualId.Parse(str.data(), str.size()); - } else if (auto ev = reply->CastAsLocal<TEvHandshakeReplyError>()) { - // in case of error just send reply to the peer and terminate handshake - SendExBlock(MainChannel, ev->Record, "ExReply"); - ProgramInfo.Clear(); // do not issue reply to the proxy - } else { - Y_ABORT("unexpected event Type# 0x%08" PRIx32, reply->GetTypeRewrite()); - } - } - } - - template <typename T> - void SendExBlock(TConnection& connection, const T& proto, const char* what) { - TString data; - Y_PROTOBUF_SUPPRESS_NODISCARD proto.SerializeToString(&data); - Y_ABORT_UNLESS(data.size() <= TExHeader::MaxSize); - - ReportProto(proto, Sprintf("SendExBlock %s", what).data()); - - TExHeader header; - header.Size = data.size(); - header.Sign(data.data(), data.size()); - connection.SendData(&header, sizeof(header), Sprintf("Send%sHeader", what)); - connection.SendData(data.data(), data.size(), Sprintf("Send%sData", what)); - } - - TString ReceiveExBlock(TConnection& connection, const char* what) { - TExHeader header; - connection.ReceiveData(&header, sizeof(header), Sprintf("Receive%sHeader", what)); - if (header.Size > TExHeader::MaxSize) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "Incorrect extended header size"); - } - - TString data; - data.resize(header.Size); - connection.ReceiveData(data.Detach(), data.size(), Sprintf("Receive%sData", what)); - - if (!header.Check(data.data(), data.size())) { - Fail(TEvHandshakeFail::HANDSHAKE_FAIL_TRANSIENT, "Extended header CRC error"); - } - - return data; - } - - private: - void SendToProxy(THolder<IEventBase> ev) { - Y_ABORT_UNLESS(PeerNodeId); - Send(GetActorSystem()->InterconnectProxy(PeerNodeId), ev.Release()); - } - - template <typename TEvent> - THolder<typename TEvent::THandle> WaitForSpecificEvent(TString state, TMonotonic deadline = TMonotonic::Max()) { - State = std::move(state); - return TActorCoroImpl::WaitForSpecificEvent<TEvent>(&THandshakeActor::ProcessUnexpectedEvent, deadline); - } - - template <typename T1, typename T2, typename... TEvents> - THolder<IEventHandle> WaitForSpecificEvent(TString state, TMonotonic deadline = TMonotonic::Max()) { - State = std::move(state); - return TActorCoroImpl::WaitForSpecificEvent<T1, T2, TEvents...>(&THandshakeActor::ProcessUnexpectedEvent, deadline); - } - - template <typename TEvent> - THolder<typename TEvent::THandle> AskProxy(THolder<IEventBase> ev, TString state) { - SendToProxy(std::move(ev)); - return WaitForSpecificEvent<TEvent>(std::move(state)); - } - - template <typename T1, typename T2, typename... TOther> - THolder<IEventHandle> AskProxy(THolder<IEventBase> ev, TString state) { - SendToProxy(std::move(ev)); - return WaitForSpecificEvent<T1, T2, TOther...>(std::move(state)); - } - - void Fail(TEvHandshakeFail::EnumHandshakeFail reason, TString explanation, bool network = false) { - TString msg = Sprintf("%s Peer# %s(%s) %s", HandshakeKind.data(), PeerHostName ? PeerHostName.data() : "<unknown>", - PeerAddr.size() ? PeerAddr.data() : "<unknown>", explanation.data()); - - if (network) { - TInstant now = Now(); - NActors::NLog::EPriority logPriority = NActors::NLog::PRI_DEBUG; - if (!LastLogNotice || now - *LastLogNotice > MuteDuration) { - logPriority = NActors::NLog::PRI_NOTICE; - LastLogNotice.emplace(now); - } - LOG_LOG_NET_X(logPriority, PeerNodeId, "network-related error occured on handshake: %s", msg.data()); - } else { - // calculate log severity based on failure type; permanent failures lead to error log messages - auto severity = reason == TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT - ? NActors::NLog::PRI_NOTICE - : NActors::NLog::PRI_INFO; - - LOG_LOG_IC_X(NActorsServices::INTERCONNECT, "ICH03", severity, "handshake failed, explanation# %s", msg.data()); - } - - if (PeerNodeId) { - SendToProxy(MakeHolder<TEvHandshakeFail>(reason, std::move(msg))); - } - - throw TExHandshakeFailed() << explanation; - } - - private: - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // COMMUNICATION BLOCK - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - void SendInitialPacket(TConnection& connection) { - TInitialPacket packet(SelfVirtualId, PeerVirtualId, NextPacketToPeer, INTERCONNECT_PROTOCOL_VERSION); - connection.SendData(&packet, sizeof(packet), "SendInitialPacket"); - } - - THolder<TEvInterconnect::TNodeInfo> GetPeerNodeInfo() { - Y_ABORT_UNLESS(PeerNodeId); - Send(Common->NameserviceId, new TEvInterconnect::TEvGetNode(PeerNodeId, TActivationContext::Now() + - (Deadline - TActivationContext::Monotonic()))); - auto response = WaitForSpecificEvent<TEvInterconnect::TEvNodeInfo>("GetPeerNodeInfo"); - return std::move(response->Get()->Node); - } - - template <typename T> - static THolder<TProgramInfo> GetProgramInfo(const T& proto) { - auto programInfo = MakeHolder<TProgramInfo>(); - programInfo->PID = proto.GetProgramPID(); - programInfo->StartTime = proto.GetProgramStartTime(); - programInfo->Serial = proto.GetSerial(); - return programInfo; - } - }; - - IActor* CreateOutgoingHandshakeActor(TInterconnectProxyCommon::TPtr common, const TActorId& self, - const TActorId& peer, ui32 nodeId, ui64 nextPacket, TString peerHostName, - TSessionParams params) { - return new TActorCoro(MakeHolder<THandshakeActor>(std::move(common), self, peer, nodeId, nextPacket, - std::move(peerHostName), std::move(params)), IActor::EActivityType::INTERCONNECT_HANDSHAKE); - } - - IActor* CreateIncomingHandshakeActor(TInterconnectProxyCommon::TPtr common, TSocketPtr socket) { - return new TActorCoro(MakeHolder<THandshakeActor>(std::move(common), std::move(socket)), - IActor::EActivityType::INTERCONNECT_HANDSHAKE); - } - -} diff --git a/library/cpp/actors/interconnect/interconnect_handshake.h b/library/cpp/actors/interconnect/interconnect_handshake.h deleted file mode 100644 index c8a7437b80..0000000000 --- a/library/cpp/actors/interconnect/interconnect_handshake.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/core/event_pb.h> -#include <library/cpp/actors/core/events.h> - -#include "interconnect_common.h" -#include "interconnect_impl.h" -#include "poller_tcp.h" -#include "events_local.h" - -namespace NActors { - static constexpr TDuration DEFAULT_HANDSHAKE_TIMEOUT = TDuration::Seconds(5); - static constexpr ui64 INTERCONNECT_PROTOCOL_VERSION = 2; - static constexpr ui64 INTERCONNECT_XDC_CONTINUATION_VERSION = 3; - static constexpr ui64 INTERCONNECT_XDC_STREAM_VERSION = 4; - - using TSocketPtr = TIntrusivePtr<NInterconnect::TStreamSocket>; - - IActor* CreateOutgoingHandshakeActor(TInterconnectProxyCommon::TPtr common, const TActorId& self, - const TActorId& peer, ui32 nodeId, ui64 nextPacket, TString peerHostName, - TSessionParams params); - - IActor* CreateIncomingHandshakeActor(TInterconnectProxyCommon::TPtr common, TSocketPtr socket); - -} diff --git a/library/cpp/actors/interconnect/interconnect_impl.h b/library/cpp/actors/interconnect/interconnect_impl.h deleted file mode 100644 index db598546cc..0000000000 --- a/library/cpp/actors/interconnect/interconnect_impl.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include "interconnect.h" -#include <library/cpp/actors/protos/interconnect.pb.h> -#include <library/cpp/actors/core/event_pb.h> -#include <library/cpp/monlib/dynamic_counters/counters.h> - -namespace NActors { - // resolve node info - struct TEvInterconnect::TEvResolveNode: public TEventPB<TEvInterconnect::TEvResolveNode, NActorsInterconnect::TEvResolveNode, TEvInterconnect::EvResolveNode> { - TEvResolveNode() { - } - - TEvResolveNode(ui32 nodeId, TInstant deadline = TInstant::Max()) { - Record.SetNodeId(nodeId); - if (deadline != TInstant::Max()) { - Record.SetDeadline(deadline.GetValue()); - } - } - }; - - // node info - struct TEvInterconnect::TEvNodeAddress: public TEventPB<TEvInterconnect::TEvNodeAddress, NActorsInterconnect::TEvNodeInfo, TEvInterconnect::EvNodeAddress> { - TEvNodeAddress() { - } - - TEvNodeAddress(ui32 nodeId) { - Record.SetNodeId(nodeId); - } - }; - - // register node - struct TEvInterconnect::TEvRegisterNode: public TEventBase<TEvInterconnect::TEvRegisterNode, TEvInterconnect::EvRegisterNode> { - }; - - // reply on register node - struct TEvInterconnect::TEvRegisterNodeResult: public TEventBase<TEvInterconnect::TEvRegisterNodeResult, TEvInterconnect::EvRegisterNodeResult> { - }; - - // disconnect - struct TEvInterconnect::TEvDisconnect: public TEventLocal<TEvInterconnect::TEvDisconnect, TEvInterconnect::EvDisconnect> { - }; - -} diff --git a/library/cpp/actors/interconnect/interconnect_mon.cpp b/library/cpp/actors/interconnect/interconnect_mon.cpp deleted file mode 100644 index f8245e1d72..0000000000 --- a/library/cpp/actors/interconnect/interconnect_mon.cpp +++ /dev/null @@ -1,279 +0,0 @@ -#include "interconnect_mon.h" -#include "interconnect_tcp_proxy.h" - -#include <library/cpp/json/json_value.h> -#include <library/cpp/json/json_writer.h> -#include <library/cpp/monlib/service/pages/templates.h> - -#include <openssl/ssl.h> -#include <openssl/pem.h> - -namespace NInterconnect { - - using namespace NActors; - - class TInterconnectMonActor : public TActor<TInterconnectMonActor> { - class TQueryProcessor : public TActorBootstrapped<TQueryProcessor> { - const TActorId Sender; - const bool Json; - TMap<ui32, TInterconnectProxyTCP::TProxyStats> Stats; - ui32 PendingReplies = 0; - - public: - static constexpr IActor::EActorActivity ActorActivityType() { - return EActivityType::INTERCONNECT_MONACTOR; - } - - TQueryProcessor(const TActorId& sender, bool json) - : Sender(sender) - , Json(json) - {} - - void Bootstrap(const TActorContext& ctx) { - Become(&TThis::StateFunc, ctx, TDuration::Seconds(5), new TEvents::TEvWakeup); - Send(GetNameserviceActorId(), new TEvInterconnect::TEvListNodes); - } - - void Handle(TEvInterconnect::TEvNodesInfo::TPtr ev, const TActorContext& ctx) { - TActorSystem* const as = ctx.ExecutorThread.ActorSystem; - for (const auto& node : ev->Get()->Nodes) { - Send(as->InterconnectProxy(node.NodeId), new TInterconnectProxyTCP::TEvQueryStats, IEventHandle::FlagTrackDelivery); - ++PendingReplies; - } - GenerateResultWhenReady(ctx); - } - - STRICT_STFUNC(StateFunc, - HFunc(TEvInterconnect::TEvNodesInfo, Handle) - HFunc(TInterconnectProxyTCP::TEvStats, Handle) - CFunc(TEvents::TSystem::Undelivered, HandleUndelivered) - CFunc(TEvents::TSystem::Wakeup, HandleWakeup) - ) - - void Handle(TInterconnectProxyTCP::TEvStats::TPtr& ev, const TActorContext& ctx) { - auto *msg = ev->Get(); - Stats.emplace(msg->PeerNodeId, std::move(msg->ProxyStats)); - --PendingReplies; - GenerateResultWhenReady(ctx); - } - - void HandleUndelivered(const TActorContext& ctx) { - --PendingReplies; - GenerateResultWhenReady(ctx); - } - - void HandleWakeup(const TActorContext& ctx) { - PendingReplies = 0; - GenerateResultWhenReady(ctx); - } - - void GenerateResultWhenReady(const TActorContext& ctx) { - if (!PendingReplies) { - if (Json) { - ctx.Send(Sender, new NMon::TEvHttpInfoRes(GenerateJson(), 0, NMon::IEvHttpInfoRes::EContentType::Custom)); - } else { - ctx.Send(Sender, new NMon::TEvHttpInfoRes(GenerateHtml())); - } - Die(ctx); - } - } - - TString GenerateHtml() { - TStringStream str; - HTML(str) { - TABLE_CLASS("table-sortable table") { - TABLEHEAD() { - TABLER() { - TABLEH() { str << "Peer node id"; } - TABLEH() { str << "State"; } - TABLEH() { str << "Ping"; } - TABLEH() { str << "Clock skew"; } - TABLEH() { str << "Scope id"; } - TABLEH() { str << "Encryption"; } - TABLEH() { str << "LastSessionDieTime"; } - TABLEH() { str << "TotalOutputQueueSize"; } - TABLEH() { str << "Connected"; } - TABLEH() { str << "XDC"; } - TABLEH() { str << "Host"; } - TABLEH() { str << "Port"; } - TABLEH() { str << "LastErrorTimestamp"; } - TABLEH() { str << "LastErrorKind"; } - TABLEH() { str << "LastErrorExplanation"; } - } - } - TABLEBODY() { - for (const auto& kv : Stats) { - TABLER() { - TABLED() { str << "<a href='" << kv.second.Path << "'>" << kv.first << "</a>"; } - TABLED() { str << kv.second.State; } - TABLED() { - if (kv.second.Ping != TDuration::Zero()) { - str << kv.second.Ping; - } - } - TABLED() { - if (kv.second.ClockSkew < 0) { - str << "-" << TDuration::MicroSeconds(-kv.second.ClockSkew); - } else { - str << "+" << TDuration::MicroSeconds(kv.second.ClockSkew); - } - } - TABLED() { str << ScopeIdToString(kv.second.PeerScopeId); } - TABLED() { - const char *color = kv.second.Encryption != "none" ? "green" : "red"; - str << "<font color='" << color << "'>" << kv.second.Encryption << "</font>"; - } - TABLED() { - if (kv.second.LastSessionDieTime != TInstant::Zero()) { - str << kv.second.LastSessionDieTime; - } - } - TABLED() { str << kv.second.TotalOutputQueueSize; } - TABLED() { str << (kv.second.Connected ? "yes" : "<strong>no</strong>"); } - TABLED() { str << (kv.second.ExternalDataChannel ? "yes" : "no"); } - TABLED() { str << kv.second.Host; } - TABLED() { str << kv.second.Port; } - TABLED() { - str << "<strong>"; - if (kv.second.LastErrorTimestamp != TInstant::Zero()) { - str << kv.second.LastErrorTimestamp; - } - str << "</strong>"; - } - TABLED() { str << "<strong>" << kv.second.LastErrorKind << "</strong>"; } - TABLED() { str << "<strong>" << kv.second.LastErrorExplanation << "</strong>"; } - } - } - } - } - } - return str.Str(); - } - - TString GenerateJson() { - NJson::TJsonValue json; - for (const auto& [nodeId, info] : Stats) { - NJson::TJsonValue item; - item["NodeId"] = nodeId; - - auto id = [](const auto& x) { return x; }; - auto toString = [](const auto& x) { return x.ToString(); }; - -#define JSON(NAME, FUN) item[#NAME] = FUN(info.NAME); - JSON(Path, id) - JSON(State, id) - JSON(PeerScopeId, ScopeIdToString) - JSON(LastSessionDieTime, toString) - JSON(TotalOutputQueueSize, id) - JSON(Connected, id) - JSON(ExternalDataChannel, id) - JSON(Host, id) - JSON(Port, id) - JSON(LastErrorTimestamp, toString) - JSON(LastErrorKind, id) - JSON(LastErrorExplanation, id) - JSON(Ping, toString) - JSON(ClockSkew, id) - JSON(Encryption, id) -#undef JSON - - json[ToString(nodeId)] = item; - } - TStringStream str(NMonitoring::HTTPOKJSON); - NJson::WriteJson(&str, &json); - return str.Str(); - } - }; - - private: - TIntrusivePtr<TInterconnectProxyCommon> Common; - - public: - static constexpr IActor::EActorActivity ActorActivityType() { - return EActivityType::INTERCONNECT_MONACTOR; - } - - TInterconnectMonActor(TIntrusivePtr<TInterconnectProxyCommon> common) - : TActor(&TThis::StateFunc) - , Common(std::move(common)) - {} - - STRICT_STFUNC(StateFunc, - HFunc(NMon::TEvHttpInfo, Handle) - ) - - void Handle(NMon::TEvHttpInfo::TPtr& ev, const TActorContext& ctx) { - const auto& params = ev->Get()->Request.GetParams(); - int certinfo = 0; - if (TryFromString(params.Get("certinfo"), certinfo) && certinfo) { - ctx.Send(ev->Sender, new NMon::TEvHttpInfoRes(GetCertInfoJson(), ev->Get()->SubRequestId, - NMon::TEvHttpInfoRes::Custom)); - } else { - const bool json = params.Has("fmt") && params.Get("fmt") == "json"; - ctx.Register(new TQueryProcessor(ev->Sender, json)); - } - } - - TString GetCertInfoJson() const { - NJson::TJsonValue json(NJson::JSON_MAP); - if (const TString cert = Common ? Common->Settings.Certificate : TString()) { - struct TEx : yexception {}; - try { - const auto& cert = Common->Settings.Certificate; - std::unique_ptr<BIO, void(*)(BIO*)> bio(BIO_new_mem_buf(cert.data(), cert.size()), &BIO_vfree); - if (!bio) { - throw TEx() << "BIO_new_mem_buf failed"; - } - std::unique_ptr<X509, void(*)(X509*)> x509(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr), - &X509_free); - if (!x509) { - throw TEx() << "PEM_read_bio_X509 failed"; - } - X509_NAME *name = X509_get_subject_name(x509.get()); - if (!name) { - throw TEx() << "X509_get_subject_name failed"; - } - char buffer[4096]; - if (char *p = X509_NAME_oneline(name, buffer, sizeof(buffer))) { - json["Subject"] = p; - } - if (int loc = X509_NAME_get_index_by_NID(name, NID_commonName, -1); loc >= 0) { - if (X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, loc)) { - if (ASN1_STRING *data = X509_NAME_ENTRY_get_data(entry)) { - unsigned char *cn; - if (const int len = ASN1_STRING_to_UTF8(&cn, data); len >= 0) { - json["CommonName"] = TString(reinterpret_cast<char*>(cn), len); - OPENSSL_free(cn); - } - } - } - } - auto time = [](const ASN1_TIME *t, const char *name) -> TString { - if (t) { - struct tm tm; - if (ASN1_TIME_to_tm(t, &tm)) { - return Strftime("%Y-%m-%dT%H:%M:%S%z", &tm); - } else { - throw TEx() << "ASN1_TIME_to_tm failed"; - } - } else { - throw TEx() << name << " failed"; - } - }; - json["NotBefore"] = time(X509_get0_notBefore(x509.get()), "X509_get0_notBefore"); - json["NotAfter"] = time(X509_get0_notAfter(x509.get()), "X509_get0_notAfter"); - } catch (const TEx& ex) { - json["Error"] = ex.what(); - } - } - TStringStream str(NMonitoring::HTTPOKJSON); - NJson::WriteJson(&str, &json); - return str.Str(); - } - }; - - IActor *CreateInterconnectMonActor(TIntrusivePtr<TInterconnectProxyCommon> common) { - return new TInterconnectMonActor(std::move(common)); - } - -} // NInterconnect diff --git a/library/cpp/actors/interconnect/interconnect_mon.h b/library/cpp/actors/interconnect/interconnect_mon.h deleted file mode 100644 index 3fb26053fb..0000000000 --- a/library/cpp/actors/interconnect/interconnect_mon.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/actor.h> -#include "interconnect_common.h" - -namespace NInterconnect { - - NActors::IActor *CreateInterconnectMonActor(TIntrusivePtr<NActors::TInterconnectProxyCommon> common = nullptr); - - static inline NActors::TActorId MakeInterconnectMonActorId(ui32 nodeId) { - char s[12] = {'I', 'C', 'O', 'v', 'e', 'r', 'v', 'i', 'e', 'w', 0, 0}; - return NActors::TActorId(nodeId, TStringBuf(s, 12)); - } - -} // NInterconnect diff --git a/library/cpp/actors/interconnect/interconnect_nameserver_base.h b/library/cpp/actors/interconnect/interconnect_nameserver_base.h deleted file mode 100644 index f9ce456d1c..0000000000 --- a/library/cpp/actors/interconnect/interconnect_nameserver_base.h +++ /dev/null @@ -1,83 +0,0 @@ -#include "interconnect.h" -#include "interconnect_impl.h" -#include "interconnect_address.h" -#include "events_local.h" - -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/memory_log/memlog.h> - -namespace NActors { - - template<typename TDerived> - class TInterconnectNameserverBase : public TActor<TDerived> { - protected: - const TMap<ui32, TTableNameserverSetup::TNodeInfo>& NodeTable; - - TInterconnectNameserverBase(void (TDerived::*func)(TAutoPtr<IEventHandle>& ev) - , const TMap<ui32, TTableNameserverSetup::TNodeInfo>& nodeTable) - : TActor<TDerived>(func) - , NodeTable(nodeTable) - { - } - public: - - void HandleMissedNodeId(TEvInterconnect::TEvResolveNode::TPtr& ev, - const TActorContext& ctx, - const TInstant&) { - auto reply = new TEvLocalNodeInfo; - reply->NodeId = ev->Get()->Record.GetNodeId(); - ctx.Send(ev->Sender, reply); - } - - void Handle(TEvInterconnect::TEvResolveNode::TPtr& ev, - const TActorContext& ctx) { - const TEvInterconnect::TEvResolveNode* request = ev->Get(); - auto& record = request->Record; - const ui32 nodeId = record.GetNodeId(); - const TInstant deadline = record.HasDeadline() ? TInstant::FromValue(record.GetDeadline()) : TInstant::Max(); - auto it = NodeTable.find(nodeId); - - if (it == NodeTable.end()) { - static_cast<TDerived*>(this)->HandleMissedNodeId(ev, ctx, deadline); - } else { - IActor::RegisterWithSameMailbox( - CreateResolveActor(nodeId, it->second, ev->Sender, this->SelfId(), deadline)); - } - } - - void Handle(TEvResolveAddress::TPtr& ev, - const TActorContext&) { - const TEvResolveAddress* request = ev->Get(); - - IActor::RegisterWithSameMailbox( - CreateResolveActor(request->Address, request->Port, ev->Sender, this->SelfId(), TInstant::Max())); - } - - void Handle(TEvInterconnect::TEvListNodes::TPtr& ev, - const TActorContext& ctx) { - THolder<TEvInterconnect::TEvNodesInfo> - reply(new TEvInterconnect::TEvNodesInfo()); - reply->Nodes.reserve(NodeTable.size()); - for (const auto& pr : NodeTable) { - reply->Nodes.emplace_back(pr.first, - pr.second.Address, pr.second.Host, pr.second.ResolveHost, - pr.second.Port, pr.second.Location); - } - ctx.Send(ev->Sender, reply.Release()); - } - - void Handle(TEvInterconnect::TEvGetNode::TPtr& ev, - const TActorContext& ctx) { - ui32 nodeId = ev->Get()->NodeId; - THolder<TEvInterconnect::TEvNodeInfo> - reply(new TEvInterconnect::TEvNodeInfo(nodeId)); - auto it = NodeTable.find(nodeId); - if (it != NodeTable.end()) { - reply->Node = MakeHolder<TEvInterconnect::TNodeInfo>(it->first, it->second.Address, - it->second.Host, it->second.ResolveHost, - it->second.Port, it->second.Location); - } - ctx.Send(ev->Sender, reply.Release()); - } - }; -} diff --git a/library/cpp/actors/interconnect/interconnect_nameserver_dynamic.cpp b/library/cpp/actors/interconnect/interconnect_nameserver_dynamic.cpp deleted file mode 100644 index 867b4b5d39..0000000000 --- a/library/cpp/actors/interconnect/interconnect_nameserver_dynamic.cpp +++ /dev/null @@ -1,178 +0,0 @@ -#include "interconnect.h" -#include "interconnect_impl.h" -#include "interconnect_address.h" -#include "interconnect_nameserver_base.h" -#include "events_local.h" -#include "logging.h" - -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/core/log.h> - -namespace NActors { - - class TInterconnectDynamicNameserver - : public TInterconnectNameserverBase<TInterconnectDynamicNameserver> - , public TInterconnectLoggingBase - { - struct TPendingRequest { - TEvInterconnect::TEvResolveNode::TPtr Request; - TInstant Deadline; - - TPendingRequest(TEvInterconnect::TEvResolveNode::TPtr request, const TInstant& deadline) - : Request(request), Deadline(deadline) - { - } - }; - - TMap<ui32, TTableNameserverSetup::TNodeInfo> NodeTable; - TVector<TPendingRequest> PendingRequests; - TDuration PendingPeriod; - - void PrintInfo() { - TString logMsg = TStringBuilder() << "Table size: " << NodeTable.size(); - for (const auto& [nodeId, node] : NodeTable) { - TString str = TStringBuilder() << "\n > Node " << nodeId << " `" << node.Address << "`:" << node.Port << ", host: " << node.Host << ", resolveHost: " << node.ResolveHost; - logMsg += str; - } - LOG_TRACE_IC("ICN01", "%s", logMsg.c_str()); - } - - bool IsNodeUpdated(const ui32 nodeId, const TString& address, const ui32 port) { - bool printInfo = false; - auto it = NodeTable.find(nodeId); - if (it == NodeTable.end()) { - LOG_TRACE_IC("ICN02", "New node %u `%s`: %u", - nodeId, address.c_str(), port); - printInfo = true; - } else if (it->second.Address != address || it->second.Port != port) { - LOG_TRACE_IC("ICN03", "Updated node %u `%s`: %u (from `%s`: %u)", - nodeId, address.c_str(), port, it->second.Address.c_str(), it->second.Port); - printInfo = true; - Send(TActivationContext::InterconnectProxy(nodeId), new TEvInterconnect::TEvDisconnect); - } - return printInfo; - } - - void DiscardTimedOutRequests(const TActorContext& ctx, ui32 compactionCount = 0) { - - auto now = Now(); - - for (auto& pending : PendingRequests) { - if (pending.Request && pending.Deadline > now) { - LOG_ERROR_IC("ICN06", "Unknown nodeId: %u", pending.Request->Get()->Record.GetNodeId()); - auto reply = new TEvLocalNodeInfo; - reply->NodeId = pending.Request->Get()->Record.GetNodeId(); - ctx.Send(pending.Request->Sender, reply); - pending.Request.Reset(); - compactionCount++; - } - } - - if (compactionCount) { - TVector<TPendingRequest> requests; - if (compactionCount < PendingRequests.size()) { // sanity check - requests.reserve(PendingRequests.size() - compactionCount); - } - for (auto& pending : PendingRequests) { - if (pending.Request) { - requests.emplace_back(pending.Request, pending.Deadline); - } - } - PendingRequests.swap(requests); - } - } - - void SchedulePeriodic() { - Schedule(TDuration::MilliSeconds(200), new TEvents::TEvWakeup()); - } - - public: - static constexpr EActivityType ActorActivityType() { - return EActivityType::NAMESERVICE; - } - - TInterconnectDynamicNameserver(const TIntrusivePtr<TTableNameserverSetup>& setup, const TDuration& pendingPeriod, ui32 /*resolvePoolId*/ ) - : TInterconnectNameserverBase<TInterconnectDynamicNameserver>(&TInterconnectDynamicNameserver::StateFunc, NodeTable) - , NodeTable(setup->StaticNodeTable) - , PendingPeriod(pendingPeriod) - { - Y_ABORT_UNLESS(setup->IsEntriesUnique()); - } - - STFUNC(StateFunc) { - try { - switch (ev->GetTypeRewrite()) { - HFunc(TEvInterconnect::TEvResolveNode, Handle); - HFunc(TEvResolveAddress, Handle); - HFunc(TEvInterconnect::TEvListNodes, Handle); - HFunc(TEvInterconnect::TEvGetNode, Handle); - HFunc(TEvInterconnect::TEvNodesInfo, HandleUpdate); - CFunc(TEvents::TEvWakeup::EventType, HandlePeriodic); - } - } catch (...) { - LOG_ERROR_IC("ICN09", "%s", CurrentExceptionMessage().c_str()); - } - } - - void HandleMissedNodeId(TEvInterconnect::TEvResolveNode::TPtr& ev, - const TActorContext& ctx, - const TInstant& deadline) { - if (PendingPeriod) { - if (PendingRequests.size() == 0) { - SchedulePeriodic(); - } - PendingRequests.emplace_back(std::move(ev), Min(deadline, Now() + PendingPeriod)); - } else { - LOG_ERROR_IC("ICN07", "Unknown nodeId: %u", ev->Get()->Record.GetNodeId()); - TInterconnectNameserverBase::HandleMissedNodeId(ev, ctx, deadline); - } - } - - void HandleUpdate(TEvInterconnect::TEvNodesInfo::TPtr& ev, - const TActorContext& ctx) { - - auto request = ev->Get(); - LOG_TRACE_IC("ICN04", "Update TEvNodesInfo with sz: %lu ", request->Nodes.size()); - - bool printInfo = false; - ui32 compactionCount = 0; - - for (const auto& node : request->Nodes) { - printInfo |= IsNodeUpdated(node.NodeId, node.Address, node.Port); - - NodeTable[node.NodeId] = TTableNameserverSetup::TNodeInfo( - node.Address, node.Host, node.ResolveHost, node.Port, node.Location); - - for (auto& pending : PendingRequests) { - if (pending.Request && pending.Request->Get()->Record.GetNodeId() == node.NodeId) { - LOG_TRACE_IC("ICN05", "Pending nodeId: %u discovered", node.NodeId); - RegisterWithSameMailbox( - CreateResolveActor(node.NodeId, NodeTable[node.NodeId], pending.Request->Sender, SelfId(), pending.Deadline)); - pending.Request.Reset(); - compactionCount++; - } - } - } - - if (printInfo) { - PrintInfo(); - } - - DiscardTimedOutRequests(ctx, compactionCount); - } - - void HandlePeriodic(const TActorContext& ctx) { - DiscardTimedOutRequests(ctx, 0); - if (PendingRequests.size()) { - SchedulePeriodic(); - } - } - }; - - IActor* CreateDynamicNameserver(const TIntrusivePtr<TTableNameserverSetup>& setup, - const TDuration& pendingPeriod, - ui32 poolId) { - return new TInterconnectDynamicNameserver(setup, pendingPeriod, poolId); - } - -} diff --git a/library/cpp/actors/interconnect/interconnect_nameserver_table.cpp b/library/cpp/actors/interconnect/interconnect_nameserver_table.cpp deleted file mode 100644 index ac565f6f8c..0000000000 --- a/library/cpp/actors/interconnect/interconnect_nameserver_table.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "interconnect.h" -#include "interconnect_impl.h" -#include "interconnect_address.h" -#include "interconnect_nameserver_base.h" -#include "events_local.h" - -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/memory_log/memlog.h> - -namespace NActors { - - class TInterconnectNameserverTable: public TInterconnectNameserverBase<TInterconnectNameserverTable> { - TIntrusivePtr<TTableNameserverSetup> Config; - - public: - static constexpr EActivityType ActorActivityType() { - return EActivityType::NAMESERVICE; - } - - TInterconnectNameserverTable(const TIntrusivePtr<TTableNameserverSetup>& setup, ui32 /*resolvePoolId*/) - : TInterconnectNameserverBase<TInterconnectNameserverTable>(&TInterconnectNameserverTable::StateFunc, setup->StaticNodeTable) - , Config(setup) - { - Y_ABORT_UNLESS(Config->IsEntriesUnique()); - } - - STFUNC(StateFunc) { - try { - switch (ev->GetTypeRewrite()) { - HFunc(TEvInterconnect::TEvResolveNode, Handle); - HFunc(TEvResolveAddress, Handle); - HFunc(TEvInterconnect::TEvListNodes, Handle); - HFunc(TEvInterconnect::TEvGetNode, Handle); - } - } catch (...) { - // on error - do nothing - } - } - }; - - IActor* CreateNameserverTable(const TIntrusivePtr<TTableNameserverSetup>& setup, ui32 poolId) { - return new TInterconnectNameserverTable(setup, poolId); - } - - bool TTableNameserverSetup::IsEntriesUnique() const { - TVector<const TNodeInfo*> infos; - infos.reserve(StaticNodeTable.size()); - for (const auto& x : StaticNodeTable) - infos.push_back(&x.second); - - auto CompareAddressLambda = - [](const TNodeInfo* left, const TNodeInfo* right) { - return left->Port == right->Port ? left->Address < right->Address : left->Port < right->Port; - }; - - Sort(infos, CompareAddressLambda); - - for (ui32 idx = 1, end = StaticNodeTable.size(); idx < end; ++idx) { - const TNodeInfo* left = infos[idx - 1]; - const TNodeInfo* right = infos[idx]; - if (left->Address && left->Address == right->Address && left->Port == right->Port) - return false; - } - - auto CompareHostLambda = - [](const TNodeInfo* left, const TNodeInfo* right) { - return left->Port == right->Port ? left->ResolveHost < right->ResolveHost : left->Port < right->Port; - }; - - Sort(infos, CompareHostLambda); - - for (ui32 idx = 1, end = StaticNodeTable.size(); idx < end; ++idx) { - const TNodeInfo* left = infos[idx - 1]; - const TNodeInfo* right = infos[idx]; - if (left->ResolveHost == right->ResolveHost && left->Port == right->Port) - return false; - } - - return true; - } - - TActorId GetNameserviceActorId() { - return TActorId(0, "namesvc"); - } - -} diff --git a/library/cpp/actors/interconnect/interconnect_proxy_wrapper.cpp b/library/cpp/actors/interconnect/interconnect_proxy_wrapper.cpp deleted file mode 100644 index 2c02c632c2..0000000000 --- a/library/cpp/actors/interconnect/interconnect_proxy_wrapper.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "interconnect_proxy_wrapper.h" -#include "interconnect_tcp_proxy.h" -#include <library/cpp/actors/interconnect/mock/ic_mock.h> - -namespace NActors { - - class TInterconnectProxyWrapper : public IActorCallback { - TIntrusivePtr<TInterconnectProxyCommon> Common; - const ui32 NodeId; - TInterconnectMock *Mock; - IActor *Proxy = nullptr; - - public: - TInterconnectProxyWrapper(TIntrusivePtr<TInterconnectProxyCommon> common, ui32 nodeId, TInterconnectMock *mock) - : IActorCallback(static_cast<TReceiveFunc>(&TInterconnectProxyWrapper::StateFunc), EActivityType::INTERCONNECT_PROXY_WRAPPER) - , Common(std::move(common)) - , NodeId(nodeId) - , Mock(mock) - {} - - STFUNC(StateFunc) { - if (ev->GetTypeRewrite() == TEvents::TSystem::Poison && !Proxy) { - PassAway(); - } else { - if (!Proxy) { - IActor *actor = Mock - ? Mock->CreateProxyMock(TActivationContext::ActorSystem()->NodeId, NodeId, Common) - : new TInterconnectProxyTCP(NodeId, Common, &Proxy); - RegisterWithSameMailbox(actor); - if (Mock) { - Proxy = actor; - } - Y_ABORT_UNLESS(Proxy); - } - InvokeOtherActor(*Proxy, &IActor::Receive, ev); - } - } - }; - - TProxyWrapperFactory CreateProxyWrapperFactory(TIntrusivePtr<TInterconnectProxyCommon> common, ui32 poolId, - TInterconnectMock *mock) { - return [=](TActorSystem *as, ui32 nodeId) -> TActorId { - return as->Register(new TInterconnectProxyWrapper(common, nodeId, mock), TMailboxType::HTSwap, poolId); - }; - } - -} // NActors diff --git a/library/cpp/actors/interconnect/interconnect_proxy_wrapper.h b/library/cpp/actors/interconnect/interconnect_proxy_wrapper.h deleted file mode 100644 index e5942351a7..0000000000 --- a/library/cpp/actors/interconnect/interconnect_proxy_wrapper.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "interconnect_common.h" - -#include <library/cpp/actors/core/actorsystem.h> - -namespace NActors { - - TProxyWrapperFactory CreateProxyWrapperFactory(TIntrusivePtr<TInterconnectProxyCommon> common, ui32 poolId, - class TInterconnectMock *mock = nullptr); - -} diff --git a/library/cpp/actors/interconnect/interconnect_resolve.cpp b/library/cpp/actors/interconnect/interconnect_resolve.cpp deleted file mode 100644 index 071af2f7c4..0000000000 --- a/library/cpp/actors/interconnect/interconnect_resolve.cpp +++ /dev/null @@ -1,208 +0,0 @@ -#include "interconnect.h" -#include "interconnect_address.h" -#include "events_local.h" -#include "logging.h" - -#include <library/cpp/actors/core/actor_bootstrapped.h> -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/dnsresolver/dnsresolver.h> - -namespace NActors { - - using namespace NActors::NDnsResolver; - - class TInterconnectResolveActor - : public TActorBootstrapped<TInterconnectResolveActor> - , public TInterconnectLoggingBase - { - public: - TInterconnectResolveActor( - const TString& host, ui16 port, ui32 nodeId, const TString& defaultAddress, - const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline) - : Host(host) - , NodeId(nodeId) - , Port(port) - , DefaultAddress(defaultAddress) - , ReplyTo(replyTo) - , ReplyFrom(replyFrom) - , Deadline(deadline) - { } - - TInterconnectResolveActor( - const TString& host, ui16 port, - const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline) - : Host(host) - , Port(port) - , ReplyTo(replyTo) - , ReplyFrom(replyFrom) - , Deadline(deadline) - { } - - static constexpr EActivityType ActorActivityType() { - return EActivityType::NAMESERVICE; - } - - void Bootstrap() { - TMaybe<TString> errorText; - if (auto addr = ExtractDefaultAddr(errorText)) { - LOG_TRACE_IC("ICR01", "Host: %s, CACHED address: %s", Host.c_str(), DefaultAddress.c_str()); - if (NodeId) { - return SendLocalNodeInfoAndDie({{*addr}}); - } else { - return SendAddressInfoAndDie(std::move(addr)); - } - } - - if (errorText) { - SendErrorAndDie(*errorText); - } - - auto now = TActivationContext::Now(); - if (Deadline < now) { - SendErrorAndDie("Deadline"); - return; - } - - LOG_DEBUG_IC("ICR02", "Host: %s, RESOLVING address ...", Host.c_str()); - Send(MakeDnsResolverActorId(), - NodeId - ? static_cast<IEventBase*>(new TEvDns::TEvGetHostByName(Host, AF_UNSPEC)) - : static_cast<IEventBase*>(new TEvDns::TEvGetAddr(Host, AF_UNSPEC)), - IEventHandle::FlagTrackDelivery); - - if (Deadline != TInstant::Max()) { - Schedule(Deadline, new TEvents::TEvWakeup); - } - - Become(&TThis::StateWork); - } - - STRICT_STFUNC(StateWork, { - sFunc(TEvents::TEvWakeup, HandleTimeout); - sFunc(TEvents::TEvUndelivered, HandleUndelivered); - hFunc(TEvDns::TEvGetAddrResult, Handle); - hFunc(TEvDns::TEvGetHostByNameResult, Handle); - }); - - void HandleTimeout() { - SendErrorAndDie("Deadline"); - } - - void HandleUndelivered() { - SendErrorAndDie("Dns resolver is unavailable"); - } - - void Handle(TEvDns::TEvGetAddrResult::TPtr& ev) { - if (auto addr = ExtractAddr(ev->Get())) { - SendAddressInfoAndDie(std::move(addr)); - } else { - SendErrorAndDie(ev->Get()->ErrorText); - } - } - - void Handle(TEvDns::TEvGetHostByNameResult::TPtr& ev) { - auto& msg = *ev->Get(); - if (msg.Status) { - SendErrorAndDie(msg.ErrorText); - } else { - std::vector<NInterconnect::TAddress> addresses; - for (const auto& ipv6 : msg.AddrsV6) { - addresses.emplace_back(ipv6, Port); - } - for (const auto& ipv4 : msg.AddrsV4) { - addresses.emplace_back(ipv4, Port); - } - SendLocalNodeInfoAndDie(std::move(addresses)); - } - } - - void SendAddressInfoAndDie(NAddr::IRemoteAddrPtr addr) { - LOG_DEBUG_IC("ICR03", "Host: %s, RESOLVED address", Host.c_str()); - auto reply = new TEvAddressInfo; - reply->Address = std::move(addr); - TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, reply)); - PassAway(); - } - - void SendLocalNodeInfoAndDie(std::vector<NInterconnect::TAddress> addresses) { - LOG_DEBUG_IC("ICR04", "Host: %s, RESOLVED address", Host.c_str()); - auto reply = std::make_unique<TEvLocalNodeInfo>(); - reply->NodeId = *NodeId; - reply->Addresses = std::move(addresses); - TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, reply.release())); - PassAway(); - } - - void SendErrorAndDie(const TString& errorText) { - LOG_DEBUG_IC("ICR05", "Host: %s, ERROR resolving: %s", Host.c_str(), errorText.c_str()); - auto *event = new TEvResolveError; - event->Explain = errorText; - event->Host = Host; - TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, event)); - PassAway(); - } - - NAddr::IRemoteAddrPtr ExtractAddr(TEvDns::TEvGetAddrResult* msg) { - if (msg->Status == 0) { - if (msg->IsV6()) { - struct sockaddr_in6 sin6; - Zero(sin6); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = msg->GetAddrV6(); - sin6.sin6_port = HostToInet(Port); - return MakeHolder<NAddr::TIPv6Addr>(sin6); - } - - if (msg->IsV4()) { - return MakeHolder<NAddr::TIPv4Addr>(TIpAddress(msg->GetAddrV4().s_addr, Port)); - } - - Y_ABORT("Unexpected result address family"); - } - - return nullptr; - } - - NAddr::IRemoteAddrPtr ExtractDefaultAddr(TMaybe<TString>& errorText) { - if (DefaultAddress) { - NInterconnect::TAddress address(DefaultAddress.data(), Port); - - switch (address.GetFamily()) { - case AF_INET: - return MakeHolder<NAddr::TIPv4Addr>(*(sockaddr_in*)address.SockAddr()); - case AF_INET6: - return MakeHolder<NAddr::TIPv6Addr>(*(sockaddr_in6*)address.SockAddr()); - default: - errorText = "Unsupported default address: " + DefaultAddress; - break; - } - } - - return nullptr; - } - - private: - const TString Host; - const std::optional<ui32> NodeId; - const ui16 Port; - const TString DefaultAddress; - const TActorId ReplyTo; - const TActorId ReplyFrom; - const TInstant Deadline; - }; - - IActor* CreateResolveActor( - const TString& host, ui16 port, ui32 nodeId, const TString& defaultAddress, - const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline) - { - return new TInterconnectResolveActor(host, port, nodeId, defaultAddress, replyTo, replyFrom, deadline); - } - - IActor* CreateResolveActor( - const TString& host, ui16 port, - const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline) - { - return new TInterconnectResolveActor(host, port, replyTo, replyFrom, deadline); - } - -} // namespace NActors diff --git a/library/cpp/actors/interconnect/interconnect_stream.cpp b/library/cpp/actors/interconnect/interconnect_stream.cpp deleted file mode 100644 index f8db077fa4..0000000000 --- a/library/cpp/actors/interconnect/interconnect_stream.cpp +++ /dev/null @@ -1,680 +0,0 @@ -#include "interconnect_stream.h" -#include "logging.h" -#include "poller_actor.h" -#include <library/cpp/openssl/init/init.h> -#include <util/network/socket.h> -#include <openssl/ssl.h> -#include <openssl/err.h> -#include <openssl/pem.h> - -#if defined(_win_) -#include <util/system/file.h> -#define SOCK_NONBLOCK 0 -#elif defined(_darwin_) -#define SOCK_NONBLOCK 0 -#else -#include <sys/un.h> -#include <sys/stat.h> -#endif //_win_ - -#if !defined(_win_) -#include <sys/ioctl.h> -#endif - -#include <cerrno> - -namespace NInterconnect { - namespace { - inline int - LastSocketError() { -#if defined(_win_) - return WSAGetLastError(); -#else - return errno; -#endif - } - } - - TSocket::TSocket(SOCKET fd) - : Descriptor(fd) - { - } - - TSocket::~TSocket() { - if (Descriptor == INVALID_SOCKET) { - return; - } - - auto const result = ::closesocket(Descriptor); - if (result == 0) - return; - switch (LastSocketError()) { - case EBADF: - Y_ABORT("Close bad descriptor"); - case EINTR: - break; - case EIO: - Y_ABORT("EIO"); - default: - Y_ABORT("It's something unexpected"); - } - } - - int TSocket::GetDescriptor() { - return Descriptor; - } - - int - TSocket::Bind(const TAddress& addr) const { - const auto ret = ::bind(Descriptor, addr.SockAddr(), addr.Size()); - if (ret < 0) - return -LastSocketError(); - - return 0; - } - - int - TSocket::Shutdown(int how) const { - const auto ret = ::shutdown(Descriptor, how); - if (ret < 0) - return -LastSocketError(); - - return 0; - } - - int TSocket::GetConnectStatus() const { - int err = 0; - socklen_t len = sizeof(err); - if (getsockopt(Descriptor, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&err), &len) == -1) { - err = LastSocketError(); - } - return err; - } - - ///////////////////////////////////////////////////////////////// - - TIntrusivePtr<TStreamSocket> TStreamSocket::Make(int domain, int *error) { - const SOCKET res = ::socket(domain, SOCK_STREAM | SOCK_NONBLOCK, 0); - if (res == -1) { - const int err = LastSocketError(); - Y_ABORT_UNLESS(err != EMFILE && err != ENFILE); - if (error) { - *error = err; - } - } - return MakeIntrusive<TStreamSocket>(res); - } - - TStreamSocket::TStreamSocket(SOCKET fd) - : TSocket(fd) - { - } - - ssize_t - TStreamSocket::Send(const void* msg, size_t len, TString* /*err*/) const { - const auto ret = ::send(Descriptor, static_cast<const char*>(msg), int(len), 0); - if (ret < 0) - return -LastSocketError(); - - return ret; - } - - ssize_t - TStreamSocket::Recv(void* buf, size_t len, TString* /*err*/) const { - const auto ret = ::recv(Descriptor, static_cast<char*>(buf), int(len), 0); - if (ret < 0) - return -LastSocketError(); - - return ret; - } - - ssize_t - TStreamSocket::WriteV(const struct iovec* iov, int iovcnt) const { -#ifndef _win_ - const auto ret = ::writev(Descriptor, iov, iovcnt); - if (ret < 0) - return -LastSocketError(); - return ret; -#else - Y_ABORT("WriteV() unsupported on Windows"); -#endif - } - - ssize_t - TStreamSocket::ReadV(const struct iovec* iov, int iovcnt) const { -#ifndef _win_ - const auto ret = ::readv(Descriptor, iov, iovcnt); - if (ret < 0) - return -LastSocketError(); - return ret; -#else - Y_ABORT("ReadV() unsupported on Windows"); -#endif - } - - ssize_t TStreamSocket::GetUnsentQueueSize() const { - int num = -1; -#ifndef _win_ // we have no means to determine output queue size on Windows - if (ioctl(Descriptor, TIOCOUTQ, &num) == -1) { - num = -1; - } -#endif - return num; - } - - int - TStreamSocket::Connect(const TAddress& addr) const { - const auto ret = ::connect(Descriptor, addr.SockAddr(), addr.Size()); - if (ret < 0) - return -LastSocketError(); - - return ret; - } - - int - TStreamSocket::Connect(const NAddr::IRemoteAddr* addr) const { - const auto ret = ::connect(Descriptor, addr->Addr(), addr->Len()); - if (ret < 0) - return -LastSocketError(); - - return ret; - } - - int - TStreamSocket::Listen(int backlog) const { - const auto ret = ::listen(Descriptor, backlog); - if (ret < 0) - return -LastSocketError(); - - return ret; - } - - int - TStreamSocket::Accept(TAddress& acceptedAddr) const { - socklen_t acceptedSize = sizeof(::sockaddr_in6); - const auto ret = ::accept(Descriptor, acceptedAddr.SockAddr(), &acceptedSize); - if (ret == INVALID_SOCKET) - return -LastSocketError(); - - return ret; - } - - void - TStreamSocket::SetSendBufferSize(i32 len) const { - (void)SetSockOpt(Descriptor, SOL_SOCKET, SO_SNDBUF, len); - } - - ui32 TStreamSocket::GetSendBufferSize() const { - ui32 res = 0; - CheckedGetSockOpt(Descriptor, SOL_SOCKET, SO_SNDBUF, res, "SO_SNDBUF"); - return res; - } - - void TStreamSocket::Request(NActors::TPollerToken& token, bool read, bool write) { - token.Request(read, write); - } - - bool TStreamSocket::RequestReadNotificationAfterWouldBlock(NActors::TPollerToken& token) { - return token.RequestReadNotificationAfterWouldBlock(); - } - - bool TStreamSocket::RequestWriteNotificationAfterWouldBlock(NActors::TPollerToken& token) { - return token.RequestWriteNotificationAfterWouldBlock(); - } - - size_t TStreamSocket::ExpectedWriteLength() const { - return 0; - } - - ////////////////////////////////////////////////////// - - TDatagramSocket::TPtr TDatagramSocket::Make(int domain) { - const SOCKET res = ::socket(domain, SOCK_DGRAM, 0); - if (res == -1) { - const int err = LastSocketError(); - Y_ABORT_UNLESS(err != EMFILE && err != ENFILE); - } - return std::make_shared<TDatagramSocket>(res); - } - - TDatagramSocket::TDatagramSocket(SOCKET fd) - : TSocket(fd) - { - } - - ssize_t - TDatagramSocket::SendTo(const void* msg, size_t len, const TAddress& toAddr) const { - const auto ret = ::sendto(Descriptor, static_cast<const char*>(msg), int(len), 0, toAddr.SockAddr(), toAddr.Size()); - if (ret < 0) - return -LastSocketError(); - - return ret; - } - - ssize_t - TDatagramSocket::RecvFrom(void* buf, size_t len, TAddress& fromAddr) const { - socklen_t fromSize = sizeof(::sockaddr_in6); - const auto ret = ::recvfrom(Descriptor, static_cast<char*>(buf), int(len), 0, fromAddr.SockAddr(), &fromSize); - if (ret < 0) - return -LastSocketError(); - - return ret; - } - - - // deleter for SSL objects - struct TDeleter { - void operator ()(BIO *bio) const { - BIO_free(bio); - } - - void operator ()(X509 *x509) const { - X509_free(x509); - } - - void operator ()(RSA *rsa) const { - RSA_free(rsa); - } - - void operator ()(SSL_CTX *ctx) const { - SSL_CTX_free(ctx); - } - }; - - class TSecureSocketContext::TImpl { - std::unique_ptr<SSL_CTX, TDeleter> Ctx; - - public: - TImpl(const TString& certificate, const TString& privateKey, const TString& caFilePath, - const TString& ciphers) { - int ret; - InitOpenSSL(); -#if OPENSSL_VERSION_NUMBER < 0x10100000L - Ctx.reset(SSL_CTX_new(TLSv1_2_method())); - Y_ABORT_UNLESS(Ctx, "SSL_CTX_new() failed"); -#else - Ctx.reset(SSL_CTX_new(TLS_method())); - Y_ABORT_UNLESS(Ctx, "SSL_CTX_new() failed"); - ret = SSL_CTX_set_min_proto_version(Ctx.get(), TLS1_2_VERSION); - Y_ABORT_UNLESS(ret == 1, "failed to set min proto version"); - ret = SSL_CTX_set_max_proto_version(Ctx.get(), TLS1_2_VERSION); - Y_ABORT_UNLESS(ret == 1, "failed to set max proto version"); -#endif - SSL_CTX_set_verify(Ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, &Verify); - SSL_CTX_set_mode(*this, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - - // apply certificates in SSL context - if (certificate) { - std::unique_ptr<BIO, TDeleter> bio(BIO_new_mem_buf(certificate.data(), certificate.size())); - Y_ABORT_UNLESS(bio); - - // first certificate in the chain is expected to be a leaf - std::unique_ptr<X509, TDeleter> cert(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr)); - Y_ABORT_UNLESS(cert, "failed to parse certificate"); - ret = SSL_CTX_use_certificate(Ctx.get(), cert.get()); - Y_ABORT_UNLESS(ret == 1); - - // loading additional certificates in the chain, if any - while(true) { - X509 *ca = PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr); - if (ca == nullptr) { - break; - } - ret = SSL_CTX_add0_chain_cert(Ctx.get(), ca); - Y_ABORT_UNLESS(ret == 1); - // we must not free memory if certificate was added successfully by SSL_CTX_add0_chain_cert - } - } - if (privateKey) { - std::unique_ptr<BIO, TDeleter> bio(BIO_new_mem_buf(privateKey.data(), privateKey.size())); - Y_ABORT_UNLESS(bio); - std::unique_ptr<RSA, TDeleter> pkey(PEM_read_bio_RSAPrivateKey(bio.get(), nullptr, nullptr, nullptr)); - Y_ABORT_UNLESS(pkey); - ret = SSL_CTX_use_RSAPrivateKey(Ctx.get(), pkey.get()); - Y_ABORT_UNLESS(ret == 1); - } - if (caFilePath) { - ret = SSL_CTX_load_verify_locations(Ctx.get(), caFilePath.data(), nullptr); - Y_ABORT_UNLESS(ret == 1); - } - - int success = SSL_CTX_set_cipher_list(Ctx.get(), ciphers ? ciphers.data() : "AES128-GCM-SHA256"); - Y_ABORT_UNLESS(success, "failed to set cipher list"); - } - - operator SSL_CTX*() const { - return Ctx.get(); - } - - static int GetExIndex() { - static int index = SSL_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr); - return index; - } - - private: - static int Verify(int preverify, X509_STORE_CTX *ctx) { - if (!preverify) { - X509 *badCert = X509_STORE_CTX_get_current_cert(ctx); - int err = X509_STORE_CTX_get_error(ctx); - int depth = X509_STORE_CTX_get_error_depth(ctx); - SSL *ssl = static_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx())); - TString *errp = static_cast<TString*>(SSL_get_ex_data(ssl, GetExIndex())); - char buffer[1024]; - X509_NAME_oneline(X509_get_subject_name(badCert), buffer, sizeof(buffer)); - TStringBuilder s; - s << "Error during certificate validation" - << " error# " << X509_verify_cert_error_string(err) - << " depth# " << depth - << " cert# " << buffer; - if (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) { - X509_NAME_oneline(X509_get_issuer_name(badCert), buffer, sizeof(buffer)); - s << " issuer# " << buffer; - } - *errp = s; - } - return preverify; - } - }; - - TSecureSocketContext::TSecureSocketContext(const TString& certificate, const TString& privateKey, - const TString& caFilePath, const TString& ciphers) - : Impl(new TImpl(certificate, privateKey, caFilePath, ciphers)) - {} - - TSecureSocketContext::~TSecureSocketContext() - {} - - class TSecureSocket::TImpl { - SSL *Ssl; - TString ErrorDescription; - bool WantRead_ = false; - bool WantWrite_ = false; - - public: - TImpl(SSL_CTX *ctx, int fd) - : Ssl(SSL_new(ctx)) - { - Y_ABORT_UNLESS(Ssl, "SSL_new() failed"); - SSL_set_fd(Ssl, fd); - SSL_set_ex_data(Ssl, TSecureSocketContext::TImpl::GetExIndex(), &ErrorDescription); - } - - ~TImpl() { - SSL_free(Ssl); - } - - TString GetErrorStack() { - if (ErrorDescription) { - return ErrorDescription; - } - std::unique_ptr<BIO, int(*)(BIO*)> mem(BIO_new(BIO_s_mem()), BIO_free); - ERR_print_errors(mem.get()); - char *p = nullptr; - auto len = BIO_get_mem_data(mem.get(), &p); - return TString(p, len); - } - - EStatus ConvertResult(int res, TString& err) { - switch (res) { - case SSL_ERROR_NONE: - return EStatus::SUCCESS; - - case SSL_ERROR_WANT_READ: - return EStatus::WANT_READ; - - case SSL_ERROR_WANT_WRITE: - return EStatus::WANT_WRITE; - - case SSL_ERROR_SYSCALL: - err = TStringBuilder() << "syscall error: " << strerror(LastSocketError()) << ": " << GetErrorStack(); - break; - - case SSL_ERROR_ZERO_RETURN: - err = "TLS negotiation failed"; - break; - - case SSL_ERROR_SSL: - err = "SSL error: " + GetErrorStack(); - break; - - default: - err = "unknown OpenSSL error"; - break; - } - return EStatus::ERROR; - } - - enum EConnectState { - CONNECT, - SHUTDOWN, - READ, - } ConnectState = EConnectState::CONNECT; - - EStatus Establish(bool server, bool authOnly, TString& err) { - switch (ConnectState) { - case EConnectState::CONNECT: { - auto callback = server ? SSL_accept : SSL_connect; - const EStatus status = ConvertResult(SSL_get_error(Ssl, callback(Ssl)), err); - if (status != EStatus::SUCCESS || !authOnly) { - return status; - } - ConnectState = EConnectState::SHUTDOWN; - [[fallthrough]]; - } - - case EConnectState::SHUTDOWN: { - const int res = SSL_shutdown(Ssl); - if (res == 1) { - return EStatus::SUCCESS; - } else if (res != 0) { - return ConvertResult(SSL_get_error(Ssl, res), err); - } - ConnectState = EConnectState::READ; - [[fallthrough]]; - } - - case EConnectState::READ: { - char data[256]; - size_t numRead = 0; - const int res = SSL_get_error(Ssl, SSL_read_ex(Ssl, data, sizeof(data), &numRead)); - if (res == SSL_ERROR_ZERO_RETURN) { - return EStatus::SUCCESS; - } else if (res != SSL_ERROR_NONE) { - return ConvertResult(res, err); - } else if (numRead) { - err = "non-zero return from SSL_read_ex: " + ToString(numRead); - return EStatus::ERROR; - } else { - return EStatus::SUCCESS; - } - } - } - Y_ABORT(); - } - - std::optional<std::pair<const void*, size_t>> BlockedSend; - - ssize_t Send(const void* msg, size_t len, TString *err) { - if (BlockedSend && BlockedSend->first == msg && BlockedSend->second < len) { - len = BlockedSend->second; - } - Y_ABORT_UNLESS(!BlockedSend || *BlockedSend == std::make_pair(msg, len)); - const ssize_t res = Operate(msg, len, &SSL_write_ex, err); - if (res == -EAGAIN) { - BlockedSend.emplace(msg, len); - } else { - BlockedSend.reset(); - } - return res; - } - - size_t ExpectedWriteLength() const { - return BlockedSend ? BlockedSend->second : 0; - } - - std::optional<std::pair<void*, size_t>> BlockedReceive; - - ssize_t Recv(void* msg, size_t len, TString *err) { - if (BlockedReceive && BlockedReceive->first == msg && BlockedReceive->second < len) { - len = BlockedReceive->second; - } - Y_ABORT_UNLESS(!BlockedReceive || *BlockedReceive == std::make_pair(msg, len)); - const ssize_t res = Operate(msg, len, &SSL_read_ex, err); - if (res == -EAGAIN) { - BlockedReceive.emplace(msg, len); - } else { - BlockedReceive.reset(); - } - return res; - } - - TString GetCipherName() const { - return SSL_get_cipher_name(Ssl); - } - - int GetCipherBits() const { - return SSL_get_cipher_bits(Ssl, nullptr); - } - - TString GetProtocolName() const { - return SSL_get_cipher_version(Ssl); - } - - TString GetPeerCommonName() const { - TString res; - if (X509 *cert = SSL_get_peer_certificate(Ssl)) { - char buffer[256]; - memset(buffer, 0, sizeof(buffer)); - if (X509_NAME *name = X509_get_subject_name(cert)) { - X509_NAME_get_text_by_NID(name, NID_commonName, buffer, sizeof(buffer)); - } - X509_free(cert); - res = TString(buffer, strnlen(buffer, sizeof(buffer))); - } - return res; - } - - bool WantRead() const { - return WantRead_; - } - - bool WantWrite() const { - return WantWrite_; - } - - private: - template<typename TBuffer, typename TOp> - ssize_t Operate(TBuffer* buffer, size_t len, TOp&& op, TString *err) { - WantRead_ = WantWrite_ = false; - size_t processed = 0; - int ret = op(Ssl, buffer, len, &processed); - if (ret == 1) { - return processed; - } - switch (const int status = SSL_get_error(Ssl, ret)) { - case SSL_ERROR_ZERO_RETURN: - return 0; - - case SSL_ERROR_WANT_READ: - WantRead_ = true; - return -EAGAIN; - - case SSL_ERROR_WANT_WRITE: - WantWrite_ = true; - return -EAGAIN; - - case SSL_ERROR_SYSCALL: - return -LastSocketError(); - - case SSL_ERROR_SSL: - if (err) { - *err = GetErrorStack(); - } - return -EPROTO; - - default: - Y_ABORT("unexpected SSL_get_error() status# %d", status); - } - } - }; - - TSecureSocket::TSecureSocket(TStreamSocket& socket, TSecureSocketContext::TPtr context) - : TStreamSocket(socket.ReleaseDescriptor()) - , Context(std::move(context)) - , Impl(new TImpl(*Context->Impl, Descriptor)) - {} - - TSecureSocket::~TSecureSocket() - {} - - TSecureSocket::EStatus TSecureSocket::Establish(bool server, bool authOnly, TString& err) const { - return Impl->Establish(server, authOnly, err); - } - - TIntrusivePtr<TStreamSocket> TSecureSocket::Detach() { - return MakeIntrusive<TStreamSocket>(ReleaseDescriptor()); - } - - ssize_t TSecureSocket::Send(const void* msg, size_t len, TString *err) const { - return Impl->Send(msg, len, err); - } - - ssize_t TSecureSocket::Recv(void* msg, size_t len, TString *err) const { - return Impl->Recv(msg, len, err); - } - - ssize_t TSecureSocket::WriteV(const struct iovec* /*iov*/, int /*iovcnt*/) const { - Y_ABORT("unsupported on SSL sockets"); - } - - ssize_t TSecureSocket::ReadV(const struct iovec* /*iov*/, int /*iovcnt*/) const { - Y_ABORT("unsupported on SSL sockets"); - } - - TString TSecureSocket::GetCipherName() const { - return Impl->GetCipherName(); - } - - int TSecureSocket::GetCipherBits() const { - return Impl->GetCipherBits(); - } - - TString TSecureSocket::GetProtocolName() const { - return Impl->GetProtocolName(); - } - - TString TSecureSocket::GetPeerCommonName() const { - return Impl->GetPeerCommonName(); - } - - bool TSecureSocket::WantRead() const { - return Impl->WantRead(); - } - - bool TSecureSocket::WantWrite() const { - return Impl->WantWrite(); - } - - void TSecureSocket::Request(NActors::TPollerToken& token, bool /*read*/, bool /*write*/) { - token.Request(WantRead(), WantWrite()); - } - - bool TSecureSocket::RequestReadNotificationAfterWouldBlock(NActors::TPollerToken& token) { - bool result = false; - if (WantRead()) { - result |= token.RequestReadNotificationAfterWouldBlock(); - } - if (WantWrite()) { - result |= token.RequestWriteNotificationAfterWouldBlock(); - } - return result; - } - - bool TSecureSocket::RequestWriteNotificationAfterWouldBlock(NActors::TPollerToken& token) { - return RequestReadNotificationAfterWouldBlock(token); - } - - size_t TSecureSocket::ExpectedWriteLength() const { - return Impl->ExpectedWriteLength(); - } -} diff --git a/library/cpp/actors/interconnect/interconnect_stream.h b/library/cpp/actors/interconnect/interconnect_stream.h deleted file mode 100644 index b9ca804e0e..0000000000 --- a/library/cpp/actors/interconnect/interconnect_stream.h +++ /dev/null @@ -1,145 +0,0 @@ -#pragma once - -#include <util/generic/string.h> -#include <util/generic/noncopyable.h> -#include <util/network/address.h> -#include <util/network/init.h> -#include <util/system/defaults.h> - -#include "poller.h" - -#include "interconnect_address.h" - -#include <memory> - -#include <sys/uio.h> - -namespace NActors { - class TPollerToken; -} - -namespace NInterconnect { - class TSocket: public NActors::TSharedDescriptor, public TNonCopyable { - protected: - TSocket(SOCKET fd); - - virtual ~TSocket() override; - - SOCKET Descriptor; - - virtual int GetDescriptor() override; - - private: - friend class TSecureSocket; - - SOCKET ReleaseDescriptor() { - return std::exchange(Descriptor, INVALID_SOCKET); - } - - public: - operator SOCKET() const { - return Descriptor; - } - - int Bind(const TAddress& addr) const; - int Shutdown(int how) const; - int GetConnectStatus() const; - }; - - class TStreamSocket: public TSocket { - public: - TStreamSocket(SOCKET fd); - - static TIntrusivePtr<TStreamSocket> Make(int domain, int *error = nullptr); - - virtual ssize_t Send(const void* msg, size_t len, TString *err = nullptr) const; - virtual ssize_t Recv(void* buf, size_t len, TString *err = nullptr) const; - - virtual ssize_t WriteV(const struct iovec* iov, int iovcnt) const; - virtual ssize_t ReadV(const struct iovec* iov, int iovcnt) const; - - int Connect(const TAddress& addr) const; - int Connect(const NAddr::IRemoteAddr* addr) const; - int Listen(int backlog) const; - int Accept(TAddress& acceptedAddr) const; - - ssize_t GetUnsentQueueSize() const; - - void SetSendBufferSize(i32 len) const; - ui32 GetSendBufferSize() const; - - virtual void Request(NActors::TPollerToken& token, bool read, bool write); - virtual bool RequestReadNotificationAfterWouldBlock(NActors::TPollerToken& token); - virtual bool RequestWriteNotificationAfterWouldBlock(NActors::TPollerToken& token); - - virtual size_t ExpectedWriteLength() const; - }; - - class TSecureSocketContext { - class TImpl; - THolder<TImpl> Impl; - - friend class TSecureSocket; - - public: - TSecureSocketContext(const TString& certificate, const TString& privateKey, const TString& caFilePath, - const TString& ciphers); - ~TSecureSocketContext(); - - public: - using TPtr = std::shared_ptr<TSecureSocketContext>; - }; - - class TSecureSocket : public TStreamSocket { - TSecureSocketContext::TPtr Context; - - class TImpl; - THolder<TImpl> Impl; - - public: - enum class EStatus { - SUCCESS, - ERROR, - WANT_READ, - WANT_WRITE, - }; - - public: - TSecureSocket(TStreamSocket& socket, TSecureSocketContext::TPtr context); - ~TSecureSocket(); - - EStatus Establish(bool server, bool authOnly, TString& err) const; - TIntrusivePtr<TStreamSocket> Detach(); - - ssize_t Send(const void* msg, size_t len, TString *err) const override; - ssize_t Recv(void* msg, size_t len, TString *err) const override; - - ssize_t WriteV(const struct iovec* iov, int iovcnt) const override; - ssize_t ReadV(const struct iovec* iov, int iovcnt) const override; - - TString GetCipherName() const; - int GetCipherBits() const; - TString GetProtocolName() const; - TString GetPeerCommonName() const; - - bool WantRead() const; - bool WantWrite() const; - void Request(NActors::TPollerToken& token, bool read, bool write) override; - bool RequestReadNotificationAfterWouldBlock(NActors::TPollerToken& token) override; - bool RequestWriteNotificationAfterWouldBlock(NActors::TPollerToken& token) override; - size_t ExpectedWriteLength() const override; - }; - - class TDatagramSocket: public TSocket { - public: - typedef std::shared_ptr<TDatagramSocket> TPtr; - - TDatagramSocket(SOCKET fd); - - static TPtr Make(int domain); - - ssize_t SendTo(const void* msg, size_t len, const TAddress& toAddr) const; - ssize_t RecvFrom(void* buf, size_t len, TAddress& fromAddr) const; - }; - -} diff --git a/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp b/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp deleted file mode 100644 index 1409f2cf0c..0000000000 --- a/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp +++ /dev/null @@ -1,1139 +0,0 @@ -#include "interconnect_tcp_session.h" -#include "interconnect_tcp_proxy.h" -#include <library/cpp/actors/core/probes.h> -#include <library/cpp/actors/util/datetime.h> - -namespace NActors { - LWTRACE_USING(ACTORLIB_PROVIDER); - - void TReceiveContext::TPerChannelContext::PrepareCatchBuffer() { - size_t bytesToCatch = FetchOffset; - for (auto it = XdcBuffers.begin(), end = it + FetchIndex; it != end; ++it) { - bytesToCatch += it->size(); - } - - XdcCatchBuffer = TRcBuf::Uninitialized(bytesToCatch); - XdcCatchBytesRead = 0; - } - - void TReceiveContext::TPerChannelContext::ApplyCatchBuffer() { - if (auto buffer = std::exchange(XdcCatchBuffer, {})) { - Y_ABORT_UNLESS(XdcCatchBytesRead >= buffer.size()); - - const size_t offset = XdcCatchBytesRead % buffer.size(); - const char *begin = buffer.data(); - const char *mid = begin + offset; - const char *end = begin + buffer.size(); - Y_DEBUG_ABORT_UNLESS(begin <= mid && mid < end); - - TRope rope; - rope.Insert(rope.End(), TRcBuf(TRcBuf::Piece, mid, end, buffer)); - if (begin != mid) { - rope.Insert(rope.End(), TRcBuf(TRcBuf::Piece, begin, mid, buffer)); - } - - DropFront(&rope, buffer.size()); - } else { - Y_DEBUG_ABORT_UNLESS(!XdcCatchBytesRead); - } - } - - void TReceiveContext::TPerChannelContext::FetchBuffers(ui16 channel, size_t numBytes, - std::deque<std::tuple<ui16, TMutableContiguousSpan>>& outQ) { - Y_DEBUG_ABORT_UNLESS(numBytes); - auto it = XdcBuffers.begin() + FetchIndex; - for (;;) { - Y_DEBUG_ABORT_UNLESS(it != XdcBuffers.end()); - const TMutableContiguousSpan span = it->SubSpan(FetchOffset, numBytes); - outQ.emplace_back(channel, span); - numBytes -= span.size(); - FetchOffset += span.size(); - if (FetchOffset == it->size()) { - ++FetchIndex; - ++it; - FetchOffset = 0; - } - if (!numBytes) { - break; - } - } - } - - void TReceiveContext::TPerChannelContext::DropFront(TRope *from, size_t numBytes) { - Y_DEBUG_ABORT_UNLESS(from || !XdcCatchBuffer); - - size_t n = numBytes; - for (auto& pendingEvent : PendingEvents) { - const size_t numBytesInEvent = Min(n, pendingEvent.XdcSizeLeft); - pendingEvent.XdcSizeLeft -= numBytesInEvent; - n -= numBytesInEvent; - if (!n) { - break; - } - } - - while (numBytes) { - Y_DEBUG_ABORT_UNLESS(!XdcBuffers.empty()); - auto& front = XdcBuffers.front(); - if (from) { - from->ExtractFrontPlain(front.data(), Min(numBytes, front.size())); - } - if (numBytes < front.size()) { - front = front.SubSpan(numBytes, Max<size_t>()); - if (!FetchIndex) { // we are sending this very buffer, adjust sending offset - Y_DEBUG_ABORT_UNLESS(numBytes <= FetchOffset); - FetchOffset -= numBytes; - } - break; - } else { - numBytes -= front.size(); - Y_DEBUG_ABORT_UNLESS(FetchIndex); - --FetchIndex; - XdcBuffers.pop_front(); - } - } - } - - TInputSessionTCP::TInputSessionTCP(const TActorId& sessionId, TIntrusivePtr<NInterconnect::TStreamSocket> socket, - TIntrusivePtr<NInterconnect::TStreamSocket> xdcSocket, TIntrusivePtr<TReceiveContext> context, - TInterconnectProxyCommon::TPtr common, std::shared_ptr<IInterconnectMetrics> metrics, ui32 nodeId, - ui64 lastConfirmed, TDuration deadPeerTimeout, TSessionParams params) - : SessionId(sessionId) - , Socket(std::move(socket)) - , XdcSocket(std::move(xdcSocket)) - , Context(std::move(context)) - , Common(std::move(common)) - , NodeId(nodeId) - , Params(std::move(params)) - , ConfirmedByInput(lastConfirmed) - , Metrics(std::move(metrics)) - , DeadPeerTimeout(deadPeerTimeout) - { - Y_ABORT_UNLESS(Context); - Y_ABORT_UNLESS(Socket); - Y_ABORT_UNLESS(SessionId); - Y_ABORT_UNLESS(!Params.UseExternalDataChannel == !XdcSocket); - - Metrics->SetClockSkewMicrosec(0); - - Context->UpdateState = EUpdateState::NONE; - - // ensure that we do not spawn new session while the previous one is still alive - TAtomicBase sessions = AtomicIncrement(Context->NumInputSessions); - Y_ABORT_UNLESS(sessions == 1, "sessions# %" PRIu64, ui64(sessions)); - - // calculate number of bytes to catch - for (auto& context : Context->ChannelArray) { - context.PrepareCatchBuffer(); - } - for (auto& [channel, context] : Context->ChannelMap) { - context.PrepareCatchBuffer(); - } - - UsageHisto.fill(0); - InputTrafficArray.fill(0); - - XXH3_64bits_reset(&XxhashXdcState); - } - - void TInputSessionTCP::Bootstrap() { - SetPrefix(Sprintf("InputSession %s [node %" PRIu32 "]", SelfId().ToString().data(), NodeId)); - Become(&TThis::WorkingState, DeadPeerTimeout, new TEvCheckDeadPeer); - LOG_DEBUG_IC_SESSION("ICIS01", "InputSession created"); - LastReceiveTimestamp = TActivationContext::Monotonic(); - TActivationContext::Send(new IEventHandle(EvResumeReceiveData, 0, SelfId(), {}, nullptr, 0)); - } - - STATEFN(TInputSessionTCP::WorkingState) { - std::unique_ptr<IEventBase> termEv; - - try { - WorkingStateImpl(ev); - } catch (const TExReestablishConnection& ex) { - LOG_DEBUG_IC_SESSION("ICIS09", "ReestablishConnection, reason# %s", ex.Reason.ToString().data()); - termEv = std::make_unique<TEvSocketDisconnect>(std::move(ex.Reason)); - } catch (const TExDestroySession& ex) { - LOG_DEBUG_IC_SESSION("ICIS13", "DestroySession, reason# %s", ex.Reason.ToString().data()); - termEv.reset(TInterconnectSessionTCP::NewEvTerminate(std::move(ex.Reason))); - } - - if (termEv) { - AtomicDecrement(Context->NumInputSessions); - Send(SessionId, termEv.release()); - PassAway(); - Socket.Reset(); - } - } - - void TInputSessionTCP::CloseInputSession() { - CloseInputSessionRequested = true; - ReceiveData(); - } - - void TInputSessionTCP::Handle(TEvPollerReady::TPtr ev) { - auto *msg = ev->Get(); - - bool useful = false; - bool writeBlocked = false; - - if (msg->Socket == Socket) { - useful = std::exchange(Context->MainReadPending, false); - writeBlocked = Context->MainWriteBlocked; - } else if (msg->Socket == XdcSocket) { - useful = std::exchange(Context->XdcReadPending, false); - writeBlocked = Context->XdcWriteBlocked; - } - - if (useful) { - Metrics->IncUsefulReadWakeups(); - } else if (!ev->Cookie) { - Metrics->IncSpuriousReadWakeups(); - } - - ReceiveData(); - - if (Params.Encryption && writeBlocked && ev->Sender != SessionId) { - Send(SessionId, ev->Release().Release()); - } - } - - void TInputSessionTCP::Handle(TEvPollerRegisterResult::TPtr ev) { - auto *msg = ev->Get(); - if (msg->Socket == Socket) { - PollerToken = std::move(msg->PollerToken); - } else if (msg->Socket == XdcSocket) { - XdcPollerToken = std::move(msg->PollerToken); - } - ReceiveData(); - } - - void TInputSessionTCP::ReceiveData() { - TTimeLimit limit(GetMaxCyclesPerEvent()); - ui64 numDataBytes = 0; - - LOG_DEBUG_IC_SESSION("ICIS02", "ReceiveData called"); - - bool enoughCpu = true; - bool progress = false; - - for (;;) { - if (progress && limit.CheckExceeded()) { - // we have hit processing time limit for this message, send notification to resume processing a bit later - TActivationContext::Send(new IEventHandle(EvResumeReceiveData, 0, SelfId(), {}, nullptr, 0)); - enoughCpu = false; - ++CpuStarvationEvents; - break; - } - - // clear iteration progress - progress = false; - - // try to process already fetched part from IncomingData - switch (State) { - case EState::HEADER: - if (IncomingData.GetSize() < sizeof(TTcpPacketHeader_v2)) { - break; - } else { - ProcessHeader(); - progress = true; - continue; - } - - case EState::PAYLOAD: - Y_DEBUG_ABORT_UNLESS(PayloadSize); - if (!IncomingData) { - break; - } else { - ProcessPayload(&numDataBytes); - progress = true; - continue; - } - } - - // try to read more data into buffers - progress |= ReadMore(); - progress |= ReadXdc(&numDataBytes); - - if (!progress) { // no progress was made during this iteration - PreallocateBuffers(); - break; - } - } - - SetEnoughCpu(enoughCpu); - - // calculate ping time - auto it = std::min_element(PingQ.begin(), PingQ.end()); - const TDuration ping = it != PingQ.end() ? *it : TDuration::Zero(); - - // send update to main session actor if something valuable has changed - if (!UpdateFromInputSession) { - UpdateFromInputSession = MakeHolder<TEvUpdateFromInputSession>(ConfirmedByInput, numDataBytes, ping); - } else { - Y_ABORT_UNLESS(ConfirmedByInput >= UpdateFromInputSession->ConfirmedByInput); - UpdateFromInputSession->ConfirmedByInput = ConfirmedByInput; - UpdateFromInputSession->NumDataBytes += numDataBytes; - UpdateFromInputSession->Ping = Min(UpdateFromInputSession->Ping, ping); - } - - for (;;) { - EUpdateState state = Context->UpdateState; - EUpdateState next; - - // calculate next state - switch (state) { - case EUpdateState::NONE: - case EUpdateState::CONFIRMING: - // we have no inflight messages to session actor, we will issue one a bit later - next = EUpdateState::INFLIGHT; - break; - - case EUpdateState::INFLIGHT: - case EUpdateState::INFLIGHT_AND_PENDING: - // we already have inflight message, so we will keep pending message and session actor will issue - // TEvConfirmUpdate to kick processing - next = EUpdateState::INFLIGHT_AND_PENDING; - break; - } - - if (Context->UpdateState.compare_exchange_weak(state, next)) { - switch (next) { - case EUpdateState::INFLIGHT: - Send(SessionId, UpdateFromInputSession.Release()); - break; - - case EUpdateState::INFLIGHT_AND_PENDING: - Y_ABORT_UNLESS(UpdateFromInputSession); - break; - - default: - Y_ABORT("unexpected state"); - } - break; - } - } - - for (size_t channel = 0; channel < InputTrafficArray.size(); ++channel) { - if (auto& value = InputTrafficArray[channel]) { - Metrics->AddInputChannelsIncomingTraffic(channel, std::exchange(value, 0)); - } - } - for (auto& [channel, value] : std::exchange(InputTrafficMap, {})) { - if (value) { - Metrics->AddInputChannelsIncomingTraffic(channel, std::exchange(value, 0)); - } - } - } - - void TInputSessionTCP::ProcessHeader() { - TTcpPacketHeader_v2 header; - const bool success = IncomingData.ExtractFrontPlain(&header, sizeof(header)); - Y_ABORT_UNLESS(success); - PayloadSize = header.PayloadLength; - const ui64 serial = header.Serial; - const ui64 confirm = header.Confirm; - if (!Params.Encryption) { - ChecksumExpected = std::exchange(header.Checksum, 0); - if (Params.UseXxhash) { - XXH3_64bits_reset(&XxhashState); - XXH3_64bits_update(&XxhashState, &header, sizeof(header)); - if (!PayloadSize) { - Checksum = XXH3_64bits_digest(&XxhashState); - } - } else { - Checksum = Crc32cExtendMSanCompatible(0, &header, sizeof(header)); // start calculating checksum now - } - if (!PayloadSize && Checksum != ChecksumExpected) { - LOG_ERROR_IC_SESSION("ICIS10", "payload checksum error"); - throw TExReestablishConnection{TDisconnectReason::ChecksumError()}; - } - } - if (PayloadSize >= 65536) { - LOG_CRIT_IC_SESSION("ICIS07", "payload is way too big"); - throw TExDestroySession{TDisconnectReason::FormatError()}; - } - if (ConfirmedByInput < confirm) { - ConfirmedByInput = confirm; - if (AtomicGet(Context->ControlPacketId) <= confirm && !NewPingProtocol) { - ui64 sendTime = AtomicGet(Context->ControlPacketSendTimer); - TDuration duration = CyclesToDuration(GetCycleCountFast() - sendTime); - const auto durationUs = duration.MicroSeconds(); - Metrics->UpdatePingTimeHistogram(durationUs); - PingQ.push_back(duration); - if (PingQ.size() > 16) { - PingQ.pop_front(); - } - AtomicSet(Context->ControlPacketId, 0ULL); - } - } - if (PayloadSize) { - const ui64 expectedMin = Context->GetLastPacketSerialToConfirm() + 1; - const ui64 expectedMax = Context->LastProcessedSerial + 1; - Y_DEBUG_ABORT_UNLESS(expectedMin <= expectedMax); - if (CurrentSerial ? serial != CurrentSerial + 1 : (serial == 0 || serial > expectedMin)) { - LOG_CRIT_IC_SESSION("ICIS06", "%s", TString(TStringBuilder() - << "packet serial number mismatch" - << " Serial# " << serial - << " ExpectedMin# " << expectedMin - << " ExpectedMax# " << expectedMax - << " CurrentSerial# " << CurrentSerial - ).data()); - throw TExDestroySession{TDisconnectReason::FormatError()}; - } - IgnorePayload = serial != expectedMax; - CurrentSerial = serial; - State = EState::PAYLOAD; - Y_DEBUG_ABORT_UNLESS(!Payload); - } else if (serial & TTcpPacketBuf::PingRequestMask) { - Send(SessionId, new TEvProcessPingRequest(serial & ~TTcpPacketBuf::PingRequestMask)); - } else if (serial & TTcpPacketBuf::PingResponseMask) { - const ui64 sent = serial & ~TTcpPacketBuf::PingResponseMask; - const ui64 received = GetCycleCountFast(); - HandlePingResponse(CyclesToDuration(received - sent)); - } else if (serial & TTcpPacketBuf::ClockMask) { - HandleClock(TInstant::MicroSeconds(serial & ~TTcpPacketBuf::ClockMask)); - } - if (!PayloadSize) { - ++PacketsReadFromSocket; - } - } - - void TInputSessionTCP::ProcessPayload(ui64 *numDataBytes) { - const size_t numBytes = Min(PayloadSize, IncomingData.GetSize()); - IncomingData.ExtractFront(numBytes, &Payload); - *numDataBytes += numBytes; - PayloadSize -= numBytes; - if (PayloadSize) { - return; // there is still some data to receive in the Payload rope - } - InboundPacketQ.push_back(TInboundPacket{CurrentSerial, 0}); - State = EState::HEADER; - if (!Params.Encryption) { // see if we are checksumming packet body - for (const auto&& [data, size] : Payload) { - if (Params.UseXxhash) { - XXH3_64bits_update(&XxhashState, data, size); - } else { - Checksum = Crc32cExtendMSanCompatible(Checksum, data, size); - } - } - if (Params.UseXxhash) { - Checksum = XXH3_64bits_digest(&XxhashState); - } - if (Checksum != ChecksumExpected) { // validate payload checksum - LOG_ERROR_IC_SESSION("ICIS04", "payload checksum error"); - throw TExReestablishConnection{TDisconnectReason::ChecksumError()}; - } - } - while (Payload) { - // extract channel part header from the payload stream - TChannelPart part; - if (!Payload.ExtractFrontPlain(&part, sizeof(part))) { - LOG_CRIT_IC_SESSION("ICIS14", "missing TChannelPart header in payload"); - throw TExDestroySession{TDisconnectReason::FormatError()}; - } else if (Payload.GetSize() < part.Size) { - LOG_CRIT_IC_SESSION("ICIS08", "payload format error ChannelPart# %s", part.ToString().data()); - throw TExDestroySession{TDisconnectReason::FormatError()}; - } - - const ui16 channel = part.GetChannel(); - auto& context = GetPerChannelContext(channel); - auto& pendingEvent = context.PendingEvents.empty() || context.PendingEvents.back().EventData - ? context.PendingEvents.emplace_back() - : context.PendingEvents.back(); - - if (part.IsXdc()) { // external data channel command packet - XdcCommands.resize(part.Size); - const bool success = Payload.ExtractFrontPlain(XdcCommands.data(), XdcCommands.size()); - Y_ABORT_UNLESS(success); - ProcessXdcCommand(channel, context); - } else if (IgnorePayload) { // throw payload out - Payload.EraseFront(part.Size); - } else if (!part.IsLastPart()) { // just ordinary inline event data - Payload.ExtractFront(part.Size, &pendingEvent.InternalPayload); - } else { // event final block - TEventDescr2 v2; - - if (part.Size != sizeof(v2)) { - LOG_CRIT_IC_SESSION("ICIS11", "incorrect last part of an event"); - throw TExDestroySession{TDisconnectReason::FormatError()}; - } - - const bool success = Payload.ExtractFrontPlain(&v2, sizeof(v2)); - Y_ABORT_UNLESS(success); - - pendingEvent.EventData = TEventData{ - v2.Type, - v2.Flags, - v2.Recipient, - v2.Sender, - v2.Cookie, - NWilson::TTraceId(v2.TraceId), - v2.Checksum, -#if IC_FORCE_HARDENED_PACKET_CHECKS - v2.Len -#endif - }; - - Metrics->IncInputChannelsIncomingEvents(channel); - ProcessEvents(context); - } - - const ui32 traffic = sizeof(part) + part.Size; - if (channel < InputTrafficArray.size()) { - InputTrafficArray[channel] += traffic; - } else { - InputTrafficMap[channel] += traffic; - } - } - - // mark packet as processed - if (IgnorePayload) { - Y_DEBUG_ABORT_UNLESS(CurrentSerial <= Context->LastProcessedSerial); - } else { - ++Context->LastProcessedSerial; - Y_DEBUG_ABORT_UNLESS(CurrentSerial == Context->LastProcessedSerial); - } - XdcCatchStream.Ready = Context->LastProcessedSerial == CurrentSerial; - ApplyXdcCatchStream(); - ProcessInboundPacketQ(0); - - ++PacketsReadFromSocket; - ++DataPacketsReadFromSocket; - IgnoredDataPacketsFromSocket += IgnorePayload; - } - - void TInputSessionTCP::ProcessInboundPacketQ(ui64 numXdcBytesRead) { - for (; !InboundPacketQ.empty(); InboundPacketQ.pop_front()) { - auto& front = InboundPacketQ.front(); - - const size_t n = Min(numXdcBytesRead, front.XdcUnreadBytes); - front.XdcUnreadBytes -= n; - numXdcBytesRead -= n; - - if (front.XdcUnreadBytes) { // we haven't finished this packet yet - Y_ABORT_UNLESS(!numXdcBytesRead); - break; - } - - Y_DEBUG_ABORT_UNLESS(front.Serial + InboundPacketQ.size() - 1 <= Context->LastProcessedSerial, - "front.Serial# %" PRIu64 " LastProcessedSerial# %" PRIu64 " InboundPacketQ.size# %zu", - front.Serial, Context->LastProcessedSerial, InboundPacketQ.size()); - - if (Context->GetLastPacketSerialToConfirm() < front.Serial && !Context->AdvanceLastPacketSerialToConfirm(front.Serial)) { - throw TExReestablishConnection{TDisconnectReason::NewSession()}; - } - } - } - - void TInputSessionTCP::ProcessXdcCommand(ui16 channel, TReceiveContext::TPerChannelContext& context) { - const char *ptr = XdcCommands.data(); - const char *end = ptr + XdcCommands.size(); - while (ptr != end) { - switch (const auto cmd = static_cast<EXdcCommand>(*ptr++)) { - case EXdcCommand::DECLARE_SECTION: - case EXdcCommand::DECLARE_SECTION_INLINE: { - // extract and validate command parameters - const ui64 headroom = NInterconnect::NDetail::DeserializeNumber(&ptr, end); - const ui64 size = NInterconnect::NDetail::DeserializeNumber(&ptr, end); - const ui64 tailroom = NInterconnect::NDetail::DeserializeNumber(&ptr, end); - const ui64 alignment = NInterconnect::NDetail::DeserializeNumber(&ptr, end); - if (headroom == Max<ui64>() || size == Max<ui64>() || tailroom == Max<ui64>() || alignment == Max<ui64>()) { - LOG_CRIT_IC_SESSION("ICIS00", "XDC command format error"); - throw TExDestroySession{TDisconnectReason::FormatError()}; - } - - if (!IgnorePayload) { // process command if packet is being applied - auto& pendingEvent = context.PendingEvents.back(); - const bool isInline = cmd == EXdcCommand::DECLARE_SECTION_INLINE; - pendingEvent.SerializationInfo.Sections.push_back(TEventSectionInfo{headroom, size, tailroom, - alignment, isInline}); - - Y_ABORT_UNLESS(!isInline || Params.UseXdcShuffle); - if (!isInline) { - // allocate buffer and push it into the payload - auto buffer = TRcBuf::Uninitialized(size, headroom, tailroom); - if (size) { - context.XdcBuffers.push_back(buffer.GetContiguousSpanMut()); - } - pendingEvent.ExternalPayload.Insert(pendingEvent.ExternalPayload.End(), TRope(std::move(buffer))); - pendingEvent.XdcSizeLeft += size; - ++XdcSections; - } - } - continue; - } - - case EXdcCommand::PUSH_DATA: { - const size_t cmdLen = sizeof(ui16) + (Params.Encryption ? 0 : sizeof(ui32)); - if (static_cast<size_t>(end - ptr) < cmdLen) { - LOG_CRIT_IC_SESSION("ICIS18", "XDC command format error"); - throw TExDestroySession{TDisconnectReason::FormatError()}; - } - - auto size = *reinterpret_cast<const ui16*>(ptr); - if (!size) { - LOG_CRIT_IC_SESSION("ICIS03", "XDC empty payload"); - throw TExDestroySession{TDisconnectReason::FormatError()}; - } - - if (!Params.Encryption) { - const ui32 checksumExpected = *reinterpret_cast<const ui32*>(ptr + sizeof(ui16)); - XdcChecksumQ.emplace_back(size, checksumExpected); - } - - // account channel and number of bytes in XDC for this packet - auto& packet = InboundPacketQ.back(); - packet.XdcUnreadBytes += size; - - if (IgnorePayload) { - // this packet was already marked as 'processed', all commands had been executed, but we must - // parse XDC stream from this packet correctly - const bool apply = Context->GetLastPacketSerialToConfirm() < CurrentSerial && - GetPerChannelContext(channel).XdcCatchBuffer; - XdcCatchStream.BytesPending += size; - XdcCatchStream.Markup.emplace_back(channel, apply, size); - } else { - // find buffers and acquire data buffer pointers - context.FetchBuffers(channel, size, XdcInputQ); - } - - ptr += cmdLen; - ++XdcRefs; - continue; - } - } - - LOG_CRIT_IC_SESSION("ICIS15", "unexpected XDC command"); - throw TExDestroySession{TDisconnectReason::FormatError()}; - } - } - - void TInputSessionTCP::ProcessEvents(TReceiveContext::TPerChannelContext& context) { - for (; !context.PendingEvents.empty(); context.PendingEvents.pop_front()) { - auto& pendingEvent = context.PendingEvents.front(); - if (!pendingEvent.EventData || pendingEvent.XdcSizeLeft) { - break; // event is not ready yet - } - auto& descr = *pendingEvent.EventData; - - // create aggregated payload - TRope payload; - if (!pendingEvent.SerializationInfo.Sections.empty()) { - // unshuffle inline and external payloads into single event content - TRope *prev = nullptr; - size_t accumSize = 0; - for (const auto& s : pendingEvent.SerializationInfo.Sections) { - TRope *rope = s.IsInline - ? &pendingEvent.InternalPayload - : &pendingEvent.ExternalPayload; - if (rope != prev) { - if (accumSize) { - prev->ExtractFront(accumSize, &payload); - } - prev = rope; - accumSize = 0; - } - accumSize += s.Size; - } - if (accumSize) { - prev->ExtractFront(accumSize, &payload); - } - - if (pendingEvent.InternalPayload || pendingEvent.ExternalPayload) { - LOG_CRIT_IC_SESSION("ICIS19", "unprocessed payload remains after shuffling" - " Type# 0x%08" PRIx32 " InternalPayload.size# %zu ExternalPayload.size# %zu", - descr.Type, pendingEvent.InternalPayload.size(), pendingEvent.ExternalPayload.size()); - Y_DEBUG_ABORT_UNLESS(false); - throw TExReestablishConnection{TDisconnectReason::FormatError()}; - } - } - - // we add any remains of internal payload to the end - if (auto& rope = pendingEvent.InternalPayload) { - rope.ExtractFront(rope.size(), &payload); - } - // and ensure there is no unprocessed external payload - Y_ABORT_UNLESS(!pendingEvent.ExternalPayload); - -#if IC_FORCE_HARDENED_PACKET_CHECKS - if (descr.Len != payload.GetSize()) { - LOG_CRIT_IC_SESSION("ICIS17", "event length mismatch Type# 0x%08" PRIx32 " received# %zu expected# %" PRIu32, - descr.Type, payload.GetSize(), descr.Len); - throw TExReestablishConnection{TDisconnectReason::ChecksumError()}; - } -#endif - if (descr.Checksum) { - ui32 checksum = 0; - for (const auto&& [data, size] : payload) { - checksum = Crc32cExtendMSanCompatible(checksum, data, size); - } - if (checksum != descr.Checksum) { - LOG_CRIT_IC_SESSION("ICIS05", "event checksum error Type# 0x%08" PRIx32, descr.Type); - throw TExReestablishConnection{TDisconnectReason::ChecksumError()}; - } - } - pendingEvent.SerializationInfo.IsExtendedFormat = descr.Flags & IEventHandle::FlagExtendedFormat; - auto ev = std::make_unique<IEventHandle>(SessionId, - descr.Type, - descr.Flags & ~IEventHandle::FlagExtendedFormat, - descr.Recipient, - descr.Sender, - MakeIntrusive<TEventSerializedData>(std::move(payload), std::move(pendingEvent.SerializationInfo)), - descr.Cookie, - Params.PeerScopeId, - std::move(descr.TraceId)); - if (Common->EventFilter && !Common->EventFilter->CheckIncomingEvent(*ev, Common->LocalScopeId)) { - LOG_CRIT_IC_SESSION("ICIC03", "Event dropped due to scope error LocalScopeId# %s PeerScopeId# %s Type# 0x%08" PRIx32, - ScopeIdToString(Common->LocalScopeId).data(), ScopeIdToString(Params.PeerScopeId).data(), descr.Type); - ev.reset(); - } - if (ev) { - TActivationContext::Send(ev.release()); - } - } - } - - void TInputSessionTCP::HandleConfirmUpdate() { - for (;;) { - switch (EUpdateState state = Context->UpdateState) { - case EUpdateState::NONE: - case EUpdateState::INFLIGHT: - case EUpdateState::INFLIGHT_AND_PENDING: - // here we may have a race - return; - - case EUpdateState::CONFIRMING: - Y_ABORT_UNLESS(UpdateFromInputSession); - if (Context->UpdateState.compare_exchange_weak(state, EUpdateState::INFLIGHT)) { - Send(SessionId, UpdateFromInputSession.Release()); - return; - } - } - } - } - - ssize_t TInputSessionTCP::Read(NInterconnect::TStreamSocket& socket, const TPollerToken::TPtr& token, - bool *readPending, const TIoVec *iov, size_t num) { - for (;;) { - ssize_t recvres = 0; - TString err; - LWPROBE_IF_TOO_LONG(SlowICReadFromSocket, ms) { - do { - const ui64 begin = GetCycleCountFast(); - if (num == 1) { - recvres = socket.Recv(iov->Data, iov->Size, &err); - } else { - recvres = socket.ReadV(reinterpret_cast<const iovec*>(iov), num); - } - const ui64 end = GetCycleCountFast(); - Metrics->IncRecvSyscalls((end - begin) * 1'000'000 / GetCyclesPerMillisecond()); - } while (recvres == -EINTR); - } - - LOG_DEBUG_IC_SESSION("ICIS12", "Read recvres# %zd num# %zu err# %s", recvres, num, err.data()); - - if (recvres <= 0 || CloseInputSessionRequested) { - if ((-recvres != EAGAIN && -recvres != EWOULDBLOCK) || CloseInputSessionRequested) { - TString message = CloseInputSessionRequested ? "connection closed by debug command" - : recvres == 0 ? "connection closed by peer" - : err ? err - : Sprintf("socket: %s", strerror(-recvres)); - LOG_NOTICE_NET(NodeId, "%s", message.data()); - throw TExReestablishConnection{CloseInputSessionRequested ? TDisconnectReason::Debug() : - recvres == 0 ? TDisconnectReason::EndOfStream() : TDisconnectReason::FromErrno(-recvres)}; - } else if (token && !*readPending) { - if (socket.RequestReadNotificationAfterWouldBlock(*token)) { - continue; // can try again - } else { - *readPending = true; - } - } - return -1; - } - - return recvres; - } - } - - constexpr ui64 GetUsageCountClearMask(size_t items, int bits) { - ui64 mask = 0; - for (size_t i = 0; i < items; ++i) { - mask |= ui64(1 << bits - 2) << i * bits; - } - return mask; - } - - bool TInputSessionTCP::ReadMore() { - PreallocateBuffers(); - - TStackVec<TIoVec, MaxBuffers> buffs; - for (auto& item : Buffers) { - buffs.push_back({item.GetDataMut(), item.size()}); - if (Params.Encryption) { - break; // do not put more than one buffer in queue to prevent using ReadV - } -#ifdef _win_ - break; // do the same thing for Windows build -#endif - } - - ssize_t recvres = Read(*Socket, PollerToken, &Context->MainReadPending, buffs.data(), buffs.size()); - if (recvres == -1) { - return false; - } - - Y_ABORT_UNLESS(recvres > 0); - Metrics->AddTotalBytesRead(recvres); - BytesReadFromSocket += recvres; - - size_t numBuffersCovered = 0; - - while (recvres) { - Y_ABORT_UNLESS(!Buffers.empty()); - auto& buffer = Buffers.front(); - const size_t bytes = Min<size_t>(recvres, buffer.size()); - recvres -= bytes; - if (const size_t newSize = buffer.size() - bytes) { - IncomingData.Insert(IncomingData.End(), TRcBuf(TRcBuf::Piece, buffer.data(), bytes, buffer)); - buffer.TrimFront(newSize); - } else { - IncomingData.Insert(IncomingData.End(), std::move(buffer)); - Buffers.pop_front(); - } - ++numBuffersCovered; - } - - if (Buffers.empty()) { // we have read all the data, increase number of buffers - CurrentBuffers = Min(CurrentBuffers * 2, MaxBuffers); - } else { - Y_DEBUG_ABORT_UNLESS(numBuffersCovered); - - const size_t index = numBuffersCovered - 1; - - static constexpr ui64 itemMask = (1 << BitsPerUsageCount) - 1; - - const size_t word = index / ItemsPerUsageCount; - const size_t offset = index % ItemsPerUsageCount * BitsPerUsageCount; - - if ((UsageHisto[word] >> offset & itemMask) == itemMask) { // time to shift - for (ui64& w : UsageHisto) { - static constexpr ui64 mask = GetUsageCountClearMask(ItemsPerUsageCount, BitsPerUsageCount); - w = (w & mask) >> 1; - } - } - UsageHisto[word] += ui64(1) << offset; - - while (CurrentBuffers > 1) { - const size_t index = CurrentBuffers - 1; - if (UsageHisto[index / ItemsPerUsageCount] >> index % ItemsPerUsageCount * BitsPerUsageCount & itemMask) { - break; - } else { - --CurrentBuffers; - } - } - } - - LastReceiveTimestamp = TActivationContext::Monotonic(); - - return true; - } - - bool TInputSessionTCP::ReadXdcCatchStream(ui64 *numDataBytes) { - bool progress = false; - - while (XdcCatchStream.BytesPending) { - if (!XdcCatchStream.Buffer) { - XdcCatchStream.Buffer = TRcBuf::Uninitialized(64 * 1024); - } - - const size_t numBytesToRead = Min<size_t>(XdcCatchStream.BytesPending, XdcCatchStream.Buffer.size()); - - TIoVec iov{XdcCatchStream.Buffer.GetDataMut(), numBytesToRead}; - ssize_t recvres = Read(*XdcSocket, XdcPollerToken, &Context->XdcReadPending, &iov, 1); - if (recvres == -1) { - return progress; - } - - HandleXdcChecksum({XdcCatchStream.Buffer.data(), static_cast<size_t>(recvres)}); - - XdcCatchStream.BytesPending -= recvres; - XdcCatchStream.BytesProcessed += recvres; - *numDataBytes += recvres; - BytesReadFromXdcSocket += recvres; - - // scatter read data - const char *in = XdcCatchStream.Buffer.data(); - while (recvres) { - Y_DEBUG_ABORT_UNLESS(!XdcCatchStream.Markup.empty()); - auto& [channel, apply, bytes] = XdcCatchStream.Markup.front(); - size_t bytesInChannel = Min<size_t>(recvres, bytes); - bytes -= bytesInChannel; - recvres -= bytesInChannel; - - if (apply) { - auto& context = GetPerChannelContext(channel); - while (bytesInChannel) { - const size_t offset = context.XdcCatchBytesRead % context.XdcCatchBuffer.size(); - TMutableContiguousSpan out = context.XdcCatchBuffer.GetContiguousSpanMut().SubSpan(offset, bytesInChannel); - memcpy(out.data(), in, out.size()); - context.XdcCatchBytesRead += out.size(); - in += out.size(); - bytesInChannel -= out.size(); - } - } else { - in += bytesInChannel; - } - - if (!bytes) { - XdcCatchStream.Markup.pop_front(); - } - } - - progress = true; - } - - ApplyXdcCatchStream(); - - return progress; - } - - void TInputSessionTCP::ApplyXdcCatchStream() { - if (!XdcCatchStream.Applied && XdcCatchStream.Ready && !XdcCatchStream.BytesPending) { - Y_DEBUG_ABORT_UNLESS(XdcCatchStream.Markup.empty()); - - auto process = [&](auto& context) { - context.ApplyCatchBuffer(); - ProcessEvents(context); - }; - for (auto& context : Context->ChannelArray) { - process(context); - } - for (auto& [channel, context] : Context->ChannelMap) { - process(context); - } - - ProcessInboundPacketQ(XdcCatchStream.BytesProcessed); - - XdcCatchStream.Buffer = {}; - XdcCatchStream.Applied = true; - } - } - - bool TInputSessionTCP::ReadXdc(ui64 *numDataBytes) { - bool progress = ReadXdcCatchStream(numDataBytes); - - // exit if we have no work to do - if (XdcInputQ.empty() || !XdcCatchStream.Applied) { - return progress; - } - - TStackVec<TIoVec, 64> buffs; - size_t size = 0; - for (auto& [channel, span] : XdcInputQ) { - buffs.push_back(TIoVec{span.data(), span.size()}); - size += span.size(); - if (buffs.size() == 64 || size >= 1024 * 1024 || Params.Encryption) { - break; - } - } - - ssize_t recvres = Read(*XdcSocket, XdcPollerToken, &Context->XdcReadPending, buffs.data(), buffs.size()); - if (recvres == -1) { - return progress; - } - - // calculate stream checksums - { - size_t bytesToChecksum = recvres; - for (const auto& iov : buffs) { - const size_t n = Min(bytesToChecksum, iov.Size); - HandleXdcChecksum({static_cast<const char*>(iov.Data), n}); - bytesToChecksum -= n; - if (!bytesToChecksum) { - break; - } - } - } - - Y_ABORT_UNLESS(recvres > 0); - Metrics->AddTotalBytesRead(recvres); - *numDataBytes += recvres; - BytesReadFromXdcSocket += recvres; - - // cut the XdcInputQ deque - for (size_t bytesToCut = recvres; bytesToCut; ) { - Y_ABORT_UNLESS(!XdcInputQ.empty()); - auto& [channel, span] = XdcInputQ.front(); - size_t n = Min(bytesToCut, span.size()); - bytesToCut -= n; - if (n == span.size()) { - XdcInputQ.pop_front(); - } else { - span = span.SubSpan(n, Max<size_t>()); - Y_ABORT_UNLESS(!bytesToCut); - } - - Y_DEBUG_ABORT_UNLESS(n); - auto& context = GetPerChannelContext(channel); - context.DropFront(nullptr, n); - ProcessEvents(context); - } - - // drop fully processed inbound packets - ProcessInboundPacketQ(recvres); - - LastReceiveTimestamp = TActivationContext::Monotonic(); - - return true; - } - - void TInputSessionTCP::HandleXdcChecksum(TContiguousSpan span) { - if (Params.Encryption) { - return; - } - while (span.size()) { - Y_DEBUG_ABORT_UNLESS(!XdcChecksumQ.empty()); - auto& [size, expected] = XdcChecksumQ.front(); - const size_t n = Min<size_t>(size, span.size()); - if (Params.UseXxhash) { - XXH3_64bits_update(&XxhashXdcState, span.data(), n); - } else { - XdcCurrentChecksum = Crc32cExtendMSanCompatible(XdcCurrentChecksum, span.data(), n); - } - span = span.SubSpan(n, Max<size_t>()); - size -= n; - if (!size) { - if (Params.UseXxhash) { - XdcCurrentChecksum = XXH3_64bits_digest(&XxhashXdcState); - XXH3_64bits_reset(&XxhashXdcState); - } - if (XdcCurrentChecksum != expected) { - LOG_ERROR_IC_SESSION("ICIS16", "payload checksum error"); - throw TExReestablishConnection{TDisconnectReason::ChecksumError()}; - } - XdcChecksumQ.pop_front(); - XdcCurrentChecksum = 0; - } - } - } - - void TInputSessionTCP::PreallocateBuffers() { - // ensure that we have exactly "numBuffers" in queue - LWPROBE_IF_TOO_LONG(SlowICReadLoopAdjustSize, ms) { - while (Buffers.size() < CurrentBuffers) { - Buffers.push_back(TRcBuf::Uninitialized(Common->Settings.PreallocatedBufferSize)); - } - } - } - - void TInputSessionTCP::PassAway() { - Metrics->SetClockSkewMicrosec(0); - TActorBootstrapped::PassAway(); - } - - void TInputSessionTCP::HandleCheckDeadPeer() { - const TMonotonic now = TActivationContext::Monotonic(); - if (now >= LastReceiveTimestamp + DeadPeerTimeout) { - ReceiveData(); - if (Socket && now >= LastReceiveTimestamp + DeadPeerTimeout) { - // nothing has changed, terminate session - throw TExDestroySession{TDisconnectReason::DeadPeer()}; - } - } - Schedule(LastReceiveTimestamp + DeadPeerTimeout, new TEvCheckDeadPeer); - } - - void TInputSessionTCP::HandlePingResponse(TDuration passed) { - PingQ.push_back(passed); - if (PingQ.size() > 16) { - PingQ.pop_front(); - } - const TDuration ping = *std::min_element(PingQ.begin(), PingQ.end()); - const auto pingUs = ping.MicroSeconds(); - Context->PingRTT_us = pingUs; - NewPingProtocol = true; - Metrics->UpdatePingTimeHistogram(pingUs); - } - - void TInputSessionTCP::HandleClock(TInstant clock) { - const TInstant here = TInstant::Now(); // wall clock - const TInstant remote = clock + TDuration::MicroSeconds(Context->PingRTT_us / 2); - i64 skew = remote.MicroSeconds() - here.MicroSeconds(); - SkewQ.push_back(skew); - if (SkewQ.size() > 16) { - SkewQ.pop_front(); - } - i64 clockSkew = SkewQ.front(); - for (i64 skew : SkewQ) { - if (abs(skew) < abs(clockSkew)) { - clockSkew = skew; - } - } - Context->ClockSkew_us = clockSkew; - Metrics->SetClockSkewMicrosec(clockSkew); - } - - TReceiveContext::TPerChannelContext& TInputSessionTCP::GetPerChannelContext(ui16 channel) const { - return channel < std::size(Context->ChannelArray) - ? Context->ChannelArray[channel] - : Context->ChannelMap[channel]; - } - - void TInputSessionTCP::GenerateHttpInfo(NMon::TEvHttpInfoRes::TPtr ev) { - TStringStream str; - ev->Get()->Output(str); - - HTML(str) { - DIV_CLASS("panel panel-info") { - DIV_CLASS("panel-heading") { - str << "Input Session"; - } - DIV_CLASS("panel-body") { - TABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() { - str << "Sensor"; - } - TABLEH() { - str << "Value"; - } - } - } -#define MON_VAR(KEY) \ - TABLER() { \ - TABLED() { str << #KEY; } \ - TABLED() { str << (KEY); } \ - } - - TABLEBODY() { - MON_VAR(BytesReadFromSocket) - MON_VAR(PacketsReadFromSocket) - MON_VAR(DataPacketsReadFromSocket) - MON_VAR(IgnoredDataPacketsFromSocket) - - MON_VAR(BytesReadFromXdcSocket) - MON_VAR(XdcSections) - MON_VAR(XdcRefs) - MON_VAR(CpuStarvationEvents) - - MON_VAR(PayloadSize) - MON_VAR(InboundPacketQ.size()) - MON_VAR(XdcInputQ.size()) - MON_VAR(Buffers.size()) - MON_VAR(IncomingData.GetSize()) - MON_VAR(Payload.GetSize()) - MON_VAR(CurrentBuffers) - - MON_VAR(Context->LastProcessedSerial) - MON_VAR(ConfirmedByInput) - } - } - } - } - } - - TActivationContext::Send(new IEventHandle(ev->Recipient, ev->Sender, new NMon::TEvHttpInfoRes(str.Str()))); - } - -} diff --git a/library/cpp/actors/interconnect/interconnect_tcp_proxy.cpp b/library/cpp/actors/interconnect/interconnect_tcp_proxy.cpp deleted file mode 100644 index 514bfb0b84..0000000000 --- a/library/cpp/actors/interconnect/interconnect_tcp_proxy.cpp +++ /dev/null @@ -1,944 +0,0 @@ -#include "interconnect_tcp_proxy.h" -#include "interconnect_handshake.h" -#include "interconnect_tcp_session.h" -#include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/protos/services_common.pb.h> -#include <library/cpp/monlib/service/pages/templates.h> -#include <util/system/getpid.h> - -namespace NActors { - static constexpr TDuration GetNodeRequestTimeout = TDuration::Seconds(5); - - static constexpr TDuration FirstErrorSleep = TDuration::MilliSeconds(10); - static constexpr TDuration MaxErrorSleep = TDuration::Seconds(10); - static constexpr ui32 SleepRetryMultiplier = 4; - - static TString PeerNameForHuman(ui32 nodeNum, const TString& longName, ui16 port) { - TStringBuf token; - TStringBuf(longName).NextTok('.', token); - return ToString<ui32>(nodeNum) + ":" + (token.size() > 0 ? TString(token) : longName) + ":" + ToString<ui16>(port); - } - - TInterconnectProxyTCP::TInterconnectProxyTCP(const ui32 node, TInterconnectProxyCommon::TPtr common, - IActor **dynamicPtr) - : TActor(&TThis::StateInit) - , PeerNodeId(node) - , DynamicPtr(dynamicPtr) - , Common(std::move(common)) - , SecureContext(new NInterconnect::TSecureSocketContext(Common->Settings.Certificate, Common->Settings.PrivateKey, - Common->Settings.CaFilePath, Common->Settings.CipherList)) - { - Y_ABORT_UNLESS(Common); - Y_ABORT_UNLESS(Common->NameserviceId); - if (DynamicPtr) { - Y_ABORT_UNLESS(!*DynamicPtr); - *DynamicPtr = this; - } - } - - void TInterconnectProxyTCP::Bootstrap() { - SetPrefix(Sprintf("Proxy %s [node %" PRIu32 "]", SelfId().ToString().data(), PeerNodeId)); - - SwitchToInitialState(); - - LOG_INFO_IC("ICP01", "ready to work"); - } - - void TInterconnectProxyTCP::Registered(TActorSystem* sys, const TActorId& owner) { - if (!DynamicPtr) { - // perform usual bootstrap for static nodes - sys->Send(new IEventHandle(TEvents::TSystem::Bootstrap, 0, SelfId(), owner, nullptr, 0)); - } - if (const auto& mon = Common->RegisterMonPage) { - TString path = Sprintf("peer%04" PRIu32, PeerNodeId); - TString title = Sprintf("Peer #%04" PRIu32, PeerNodeId); - mon(path, title, sys, SelfId()); - } - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // PendingActivation - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - void TInterconnectProxyTCP::RequestNodeInfo(STATEFN_SIG) { - ICPROXY_PROFILED; - - Y_ABORT_UNLESS(!IncomingHandshakeActor && !OutgoingHandshakeActor && !PendingIncomingHandshakeEvents && !PendingSessionEvents); - EnqueueSessionEvent(ev); - StartConfiguring(); - } - - void TInterconnectProxyTCP::RequestNodeInfoForIncomingHandshake(STATEFN_SIG) { - ICPROXY_PROFILED; - - if (!Terminated) { - Y_ABORT_UNLESS(!IncomingHandshakeActor && !OutgoingHandshakeActor && !PendingIncomingHandshakeEvents && !PendingSessionEvents); - EnqueueIncomingHandshakeEvent(ev); - StartConfiguring(); - } - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // PendingNodeInfo - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - void TInterconnectProxyTCP::StartConfiguring() { - ICPROXY_PROFILED; - - Y_ABORT_UNLESS(!IncomingHandshakeActor && !OutgoingHandshakeActor); - - // issue node info request - Send(Common->NameserviceId, new TEvInterconnect::TEvGetNode(PeerNodeId)); - - // arm configure timer; store pointer to event to ensure that we will handle correct one if there were any other - // wakeup events in flight - SwitchToState(__LINE__, "PendingNodeInfo", &TThis::PendingNodeInfo, GetNodeRequestTimeout, - ConfigureTimeoutCookie = new TEvents::TEvWakeup); - } - - void TInterconnectProxyTCP::Configure(TEvInterconnect::TEvNodeInfo::TPtr& ev) { - ICPROXY_PROFILED; - - Y_ABORT_UNLESS(!IncomingHandshakeActor && !OutgoingHandshakeActor && !Session); - - if (!ev->Get()->Node) { - TransitToErrorState("cannot get node info"); - } else { - auto& info = *ev->Get()->Node; - TString name = PeerNameForHuman(PeerNodeId, info.Host, info.Port); - TechnicalPeerHostName = info.Host; - if (!Metrics) { - Metrics = Common->Metrics ? CreateInterconnectMetrics(Common) : CreateInterconnectCounters(Common); - } - Metrics->SetPeerInfo(name, info.Location.GetDataCenterId()); - - LOG_DEBUG_IC("ICP02", "configured for host %s", name.data()); - - ProcessConfigured(); - } - } - - void TInterconnectProxyTCP::ConfigureTimeout(TEvents::TEvWakeup::TPtr& ev) { - ICPROXY_PROFILED; - - if (ev->Get() == ConfigureTimeoutCookie) { - TransitToErrorState("timed out while waiting for node info"); - } - } - - void TInterconnectProxyTCP::ProcessConfigured() { - ICPROXY_PROFILED; - - // if the request was initiated by some activity involving Interconnect, then we are expected to start handshake - if (PendingSessionEvents) { - StartInitialHandshake(); - } - - // process incoming handshake requests; all failures were ejected from the queue along with the matching initiation requests - for (THolder<IEventHandle>& ev : PendingIncomingHandshakeEvents) { - TAutoPtr<IEventHandle> x(ev.Release()); - IncomingHandshake(x); - } - PendingIncomingHandshakeEvents.clear(); - - // possible situation -- incoming handshake arrives, but actually it is not satisfied and rejected; in this case - // we are going to return to initial state as we have nothing to do - if (!IncomingHandshakeActor && !OutgoingHandshakeActor) { - SwitchToInitialState(); - } - } - - void TInterconnectProxyTCP::StartInitialHandshake() { - ICPROXY_PROFILED; - - // since we are starting initial handshake for some reason, we'll drop any existing handshakes, if any - DropHandshakes(); - - // create and register handshake actor - OutgoingHandshakeActor = Register(CreateOutgoingHandshakeActor(Common, GenerateSessionVirtualId(), - TActorId(), PeerNodeId, 0, TechnicalPeerHostName, TSessionParams()), TMailboxType::ReadAsFilled); - OutgoingHandshakeActorCreated = TActivationContext::Now(); - - // prepare for new handshake - PrepareNewSessionHandshake(); - } - - void TInterconnectProxyTCP::StartResumeHandshake(ui64 inputCounter) { - ICPROXY_PROFILED; - - // drop outgoing handshake if we have one; keep incoming handshakes as they may be useful - DropOutgoingHandshake(); - - // ensure that we have session - Y_ABORT_UNLESS(Session); - - // ensure that we have both virtual ids - Y_ABORT_UNLESS(SessionVirtualId); - Y_ABORT_UNLESS(RemoteSessionVirtualId); - - // create and register handshake actor - OutgoingHandshakeActor = Register(CreateOutgoingHandshakeActor(Common, SessionVirtualId, - RemoteSessionVirtualId, PeerNodeId, inputCounter, TechnicalPeerHostName, Session->Params), - TMailboxType::ReadAsFilled); - OutgoingHandshakeActorCreated = TActivationContext::Now(); - } - - void TInterconnectProxyTCP::IssueIncomingHandshakeReply(const TActorId& handshakeId, ui64 peerLocalId, - THolder<IEventBase> event) { - ICPROXY_PROFILED; - - Y_ABORT_UNLESS(!IncomingHandshakeActor); - IncomingHandshakeActor = handshakeId; - IncomingHandshakeActorFilledIn = TActivationContext::Now(); - Y_ABORT_UNLESS(!LastSerialFromIncomingHandshake || *LastSerialFromIncomingHandshake <= peerLocalId); - LastSerialFromIncomingHandshake = peerLocalId; - - if (OutgoingHandshakeActor && SelfId().NodeId() < PeerNodeId) { - // Both outgoing and incoming handshake are in progress. To prevent race condition during semultanous handshake - // incoming handshake must be held till outgoing handshake is complete or failed - LOG_DEBUG_IC("ICP06", "reply for incoming handshake (actor %s) is held", IncomingHandshakeActor.ToString().data()); - HeldHandshakeReply = std::move(event); - - // Check that we are in one of acceptable states that would properly handle handshake statuses. - const auto state = CurrentStateFunc(); - Y_ABORT_UNLESS(state == &TThis::PendingConnection || state == &TThis::StateWork, "invalid handshake request in state# %s", State); - } else { - LOG_DEBUG_IC("ICP07", "issued incoming handshake reply"); - - // No race, so we can send reply immediately. - Y_ABORT_UNLESS(!HeldHandshakeReply); - Send(IncomingHandshakeActor, event.Release()); - - // Start waiting for handshake reply, if not yet started; also, if session is already created, then we don't - // switch from working state. - if (!Session) { - LOG_INFO_IC("ICP08", "No active sessions, becoming PendingConnection"); - SwitchToState(__LINE__, "PendingConnection", &TThis::PendingConnection); - } else { - Y_ABORT_UNLESS(CurrentStateFunc() == &TThis::StateWork); - } - } - } - - void TInterconnectProxyTCP::IncomingHandshake(TEvHandshakeAsk::TPtr& ev) { - ICPROXY_PROFILED; - - TEvHandshakeAsk *msg = ev->Get(); - - // TEvHandshakeAsk is only applicable for continuation requests - LOG_DEBUG_IC("ICP09", "(actor %s) from: %s for: %s", ev->Sender.ToString().data(), - ev->Get()->Self.ToString().data(), ev->Get()->Peer.ToString().data()); - - if (!Session) { - // if there is no open session, report error -- continuation request works only with open sessions - LOG_NOTICE_IC("ICP12", "(actor %s) peer tries to resume nonexistent session Self# %s Peer# %s", - ev->Sender.ToString().data(), msg->Self.ToString().data(), msg->Peer.ToString().data()); - } else if (SessionVirtualId != ev->Get()->Peer || RemoteSessionVirtualId != ev->Get()->Self) { - // check session virtual ids for continuation - LOG_NOTICE_IC("ICP13", "(actor %s) virtual id mismatch with existing session (Peer: %s Self: %s" - " SessionVirtualId: %s RemoteSessionVirtualId: %s)", ev->Sender.ToString().data(), - ev->Get()->Peer.ToString().data(), ev->Get()->Self.ToString().data(), SessionVirtualId.ToString().data(), - RemoteSessionVirtualId.ToString().data()); - } else { - // if we already have incoming handshake, then terminate existing one - DropIncomingHandshake(); - - // issue reply to the sender, possibly holding it while outgoing handshake is at race - THolder<IEventBase> reply = IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::ProcessHandshakeRequest, ev); - return IssueIncomingHandshakeReply(ev->Sender, RemoteSessionVirtualId.LocalId(), std::move(reply)); - } - - // error case -- report error to the handshake actor - Send(ev->Sender, new TEvHandshakeNak); - } - - void TInterconnectProxyTCP::IncomingHandshake(TEvHandshakeRequest::TPtr& ev) { - ICPROXY_PROFILED; - - LOG_DEBUG_IC("ICP17", "incoming handshake (actor %s)", ev->Sender.ToString().data()); - - const auto& record = ev->Get()->Record; - ui64 remotePID = record.GetProgramPID(); - ui64 remoteStartTime = record.GetProgramStartTime(); - ui64 remoteSerial = record.GetSerial(); - - if (RemoteProgramInfo && remotePID == RemoteProgramInfo->PID && remoteStartTime == RemoteProgramInfo->StartTime) { - if (remoteSerial < RemoteProgramInfo->Serial) { - LOG_INFO_IC("ICP18", "handshake (actor %s) is too old", ev->Sender.ToString().data()); - Send(ev->Sender, new TEvents::TEvPoisonPill); - return; - } else { - RemoteProgramInfo->Serial = remoteSerial; - } - } else { - const auto ptr = new TProgramInfo; - ptr->PID = remotePID; - ptr->StartTime = remoteStartTime; - ptr->Serial = remoteSerial; - RemoteProgramInfo.Reset(ptr); - } - - /* Let's check peer technical hostname */ - if (record.HasSenderHostName() && TechnicalPeerHostName != record.GetSenderHostName()) { - Send(ev->Sender, new TEvHandshakeReplyError("host name mismatch")); - return; - } - - // check sender actor id and check if it is not very old - if (LastSerialFromIncomingHandshake) { - const ui64 serial = record.GetSerial(); - if (serial < *LastSerialFromIncomingHandshake) { - LOG_NOTICE_IC("ICP15", "Handshake# %s has duplicate serial# %" PRIu64 - " LastSerialFromIncomingHandshake# %" PRIu64, ev->Sender.ToString().data(), - serial, *LastSerialFromIncomingHandshake); - Send(ev->Sender, new TEvHandshakeReplyError("duplicate serial")); - return; - } else if (serial == *LastSerialFromIncomingHandshake) { - LOG_NOTICE_IC("ICP00", "Handshake# %s is obsolete, serial# %" PRIu64 - " LastSerialFromIncomingHandshake# %" PRIu64, ev->Sender.ToString().data(), - serial, *LastSerialFromIncomingHandshake); - Send(ev->Sender, new TEvents::TEvPoisonPill); - return; - } - } - - // drop incoming handshake as this is definitely more recent - DropIncomingHandshake(); - - // prepare for new session - PrepareNewSessionHandshake(); - - auto event = MakeHolder<TEvHandshakeReplyOK>(); - auto* pb = event->Record.MutableSuccess(); - const TActorId virtualId = GenerateSessionVirtualId(); - pb->SetProtocol(INTERCONNECT_PROTOCOL_VERSION); - pb->SetSenderActorId(virtualId.ToString()); - pb->SetProgramPID(GetPID()); - pb->SetProgramStartTime(Common->StartTime); - pb->SetSerial(virtualId.LocalId()); - - IssueIncomingHandshakeReply(ev->Sender, 0, std::move(event)); - } - - void TInterconnectProxyTCP::HandleHandshakeStatus(TEvHandshakeDone::TPtr& ev) { - ICPROXY_PROFILED; - - TEvHandshakeDone *msg = ev->Get(); - - // Terminate handshake actor working in opposite direction, if set up. - if (ev->Sender == IncomingHandshakeActor) { - LOG_INFO_IC("ICP19", "incoming handshake succeeded"); - DropIncomingHandshake(false); - DropOutgoingHandshake(); - } else if (ev->Sender == OutgoingHandshakeActor) { - LOG_INFO_IC("ICP20", "outgoing handshake succeeded"); - DropIncomingHandshake(); - DropOutgoingHandshake(false); - } else { - /* It seems to be an old handshake. */ - return; - } - - // drop any pending XDC subscriptions - ConnectionSubscriptions.clear(); - - Y_ABORT_UNLESS(!IncomingHandshakeActor && !OutgoingHandshakeActor); - SwitchToState(__LINE__, "StateWork", &TThis::StateWork); - - if (Session) { - // this is continuation request, check that virtual ids match - Y_ABORT_UNLESS(SessionVirtualId == msg->Self && RemoteSessionVirtualId == msg->Peer); - } else { - // this is initial request, check that we have virtual ids not filled in - Y_ABORT_UNLESS(!SessionVirtualId && !RemoteSessionVirtualId); - } - - auto error = [&](const char* description) { - TransitToErrorState(description); - }; - - // If session is not created, then create new one. - if (!Session) { - RemoteProgramInfo = std::move(msg->ProgramInfo); - if (!RemoteProgramInfo) { - // we have received resume handshake, but session was closed concurrently while handshaking - return error("Session continuation race"); - } - - // Create new session actor. - SessionID = RegisterWithSameMailbox(Session = new TInterconnectSessionTCP(this, msg->Params)); - IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::Init); - SessionVirtualId = msg->Self; - RemoteSessionVirtualId = msg->Peer; - LOG_INFO_IC("ICP22", "created new session: %s", SessionID.ToString().data()); - } - - // ensure that we have session local/peer virtual ids - Y_ABORT_UNLESS(Session && SessionVirtualId && RemoteSessionVirtualId); - - // Set up new connection for the session. - IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::SetNewConnection, ev); - - // Reset retry timer - HoldByErrorWakeupDuration = TDuration::Zero(); - - /* Forward all held events */ - ProcessPendingSessionEvents(); - } - - void TInterconnectProxyTCP::HandleHandshakeStatus(TEvHandshakeFail::TPtr& ev) { - ICPROXY_PROFILED; - - // update error state log; this fail is inconclusive unless this is the last pending handshake - const bool inconclusive = (ev->Sender != IncomingHandshakeActor && ev->Sender != OutgoingHandshakeActor) || - (IncomingHandshakeActor && OutgoingHandshakeActor); - LogHandshakeFail(ev, inconclusive); - - if (ev->Sender == IncomingHandshakeActor) { - LOG_NOTICE_IC("ICP24", "incoming handshake failed, temporary: %" PRIu32 " explanation: %s outgoing: %s", - ui32(ev->Get()->Temporary), ev->Get()->Explanation.data(), OutgoingHandshakeActor.ToString().data()); - DropIncomingHandshake(false); - } else if (ev->Sender == OutgoingHandshakeActor) { - LOG_NOTICE_IC("ICP25", "outgoing handshake failed, temporary: %" PRIu32 " explanation: %s incoming: %s held: %s", - ui32(ev->Get()->Temporary), ev->Get()->Explanation.data(), IncomingHandshakeActor.ToString().data(), - HeldHandshakeReply ? "yes" : "no"); - DropOutgoingHandshake(false); - - if (IEventBase* reply = HeldHandshakeReply.Release()) { - Y_ABORT_UNLESS(IncomingHandshakeActor); - LOG_DEBUG_IC("ICP26", "sent held handshake reply to %s", IncomingHandshakeActor.ToString().data()); - Send(IncomingHandshakeActor, reply); - } - - // if we have no current session, then we have to drop all pending events as the outgoing handshake has failed - ProcessPendingSessionEvents(); - } else { - /* It seems to be an old fail, just ignore it */ - LOG_NOTICE_IC("ICP27", "obsolete handshake fail ignored"); - return; - } - - if (Metrics) { - Metrics->IncHandshakeFails(); - } - - if (IncomingHandshakeActor || OutgoingHandshakeActor) { - // one of handshakes is still going on - LOG_DEBUG_IC("ICP28", "other handshake is still going on"); - return; - } - - switch (ev->Get()->Temporary) { - case TEvHandshakeFail::HANDSHAKE_FAIL_TRANSIENT: - if (!Session) { - if (PendingSessionEvents) { - // try to start outgoing handshake as we have some events enqueued - StartInitialHandshake(); - } else { - // return back to initial state as we have no session and no pending handshakes - SwitchToInitialState(); - } - } else if (Session->Socket) { - // try to reestablish connection -- meaning restart handshake from the last known position - IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::ReestablishConnectionWithHandshake, - TDisconnectReason::HandshakeFailTransient()); - } else { - // we have no active connection in that session, so just restart handshake from last known position - IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::StartHandshake); - } - break; - - case TEvHandshakeFail::HANDSHAKE_FAIL_SESSION_MISMATCH: - StartInitialHandshake(); - break; - - case TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT: - TString timeExplanation = " LastSessionDieTime# " + LastSessionDieTime.ToString(); - if (Session) { - InvokeOtherActor(*Session, &TInterconnectSessionTCP::Terminate, - TDisconnectReason::HandshakeFailPermanent()); - } - TransitToErrorState(ev->Get()->Explanation + timeExplanation, false); - break; - } - } - - void TInterconnectProxyTCP::LogHandshakeFail(TEvHandshakeFail::TPtr& ev, bool inconclusive) { - ICPROXY_PROFILED; - - TString kind = "unknown"; - switch (ev->Get()->Temporary) { - case TEvHandshakeFail::HANDSHAKE_FAIL_TRANSIENT: - kind = Session ? "transient w/session" : "transient w/o session"; - break; - - case TEvHandshakeFail::HANDSHAKE_FAIL_SESSION_MISMATCH: - kind = "session_mismatch"; - break; - - case TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT: - kind = "permanent"; - break; - } - if (inconclusive) { - kind += " inconclusive"; - } - UpdateErrorStateLog(TActivationContext::Now(), kind, ev->Get()->Explanation); - } - - void TInterconnectProxyTCP::ProcessPendingSessionEvents() { - ICPROXY_PROFILED; - - while (PendingSessionEvents) { - TPendingSessionEvent ev = std::move(PendingSessionEvents.front()); - PendingSessionEventsSize -= ev.Size; - TAutoPtr<IEventHandle> event(ev.Event.Release()); - PendingSessionEvents.pop_front(); - - if (Session) { - ForwardSessionEventToSession(event); - } else { - DropSessionEvent(event); - } - } - } - - void TInterconnectProxyTCP::DropSessionEvent(STATEFN_SIG) { - ICPROXY_PROFILED; - - ValidateEvent(ev, "DropSessionEvent"); - switch (ev->GetTypeRewrite()) { - case TEvInterconnect::EvForward: - if (ev->Flags & IEventHandle::FlagSubscribeOnSession) { - Send(ev->Sender, new TEvInterconnect::TEvNodeDisconnected(PeerNodeId), 0, ev->Cookie); - } - TActivationContext::Send(IEventHandle::ForwardOnNondelivery(ev, TEvents::TEvUndelivered::Disconnected)); - break; - - case TEvInterconnect::TEvConnectNode::EventType: - case TEvents::TEvSubscribe::EventType: - Send(ev->Sender, new TEvInterconnect::TEvNodeDisconnected(PeerNodeId), 0, ev->Cookie); - break; - - case TEvents::TEvUnsubscribe::EventType: - /* Do nothing */ - break; - - default: - Y_ABORT("Unexpected type of event in held event queue"); - } - } - - void TInterconnectProxyTCP::UnregisterSession(TInterconnectSessionTCP* session) { - ICPROXY_PROFILED; - - Y_ABORT_UNLESS(Session && Session == session && SessionID); - - LOG_INFO_IC("ICP30", "unregister session Session# %s VirtualId# %s", SessionID.ToString().data(), - SessionVirtualId.ToString().data()); - - Session = nullptr; - SessionID = TActorId(); - - // drop all pending events as we are closed - ProcessPendingSessionEvents(); - - // reset virtual ids as this session is terminated - SessionVirtualId = TActorId(); - RemoteSessionVirtualId = TActorId(); - - if (Metrics) { - Metrics->IncSessionDeaths(); - } - LastSessionDieTime = TActivationContext::Now(); - - if (IncomingHandshakeActor || OutgoingHandshakeActor) { - PrepareNewSessionHandshake(); - } else { - SwitchToInitialState(); - } - } - - void TInterconnectProxyTCP::EnqueueSessionEvent(STATEFN_SIG) { - ICPROXY_PROFILED; - - ValidateEvent(ev, "EnqueueSessionEvent"); - const ui32 size = ev->GetSize(); - PendingSessionEventsSize += size; - PendingSessionEvents.emplace_back(TActivationContext::Monotonic() + Common->Settings.MessagePendingTimeout, size, ev); - ScheduleCleanupEventQueue(); - CleanupEventQueue(); - } - - void TInterconnectProxyTCP::EnqueueIncomingHandshakeEvent(STATEFN_SIG) { - ICPROXY_PROFILED; - - // enqueue handshake request - Y_UNUSED(); - PendingIncomingHandshakeEvents.emplace_back(ev); - } - - void TInterconnectProxyTCP::EnqueueIncomingHandshakeEvent(TEvHandshakeDone::TPtr& /*ev*/) { - ICPROXY_PROFILED; - - // TEvHandshakeDone can't get into the queue, because we have to process handshake request first; this may be the - // race with the previous handshakes, so simply ignore it - } - - void TInterconnectProxyTCP::EnqueueIncomingHandshakeEvent(TEvHandshakeFail::TPtr& ev) { - ICPROXY_PROFILED; - - for (auto it = PendingIncomingHandshakeEvents.begin(); it != PendingIncomingHandshakeEvents.end(); ++it) { - THolder<IEventHandle>& pendingEvent = *it; - if (pendingEvent->Sender == ev->Sender) { - // we have found cancellation request for the pending handshake request; so simply remove it from the - // deque, as we are not interested in failure reason; must likely it happens because of handshake timeout - if (pendingEvent->GetTypeRewrite() == TEvHandshakeFail::EventType) { - TEvHandshakeFail::TPtr tmp(static_cast<TEventHandle<TEvHandshakeFail>*>(pendingEvent.Release())); - LogHandshakeFail(tmp, true); - } - PendingIncomingHandshakeEvents.erase(it); - break; - } - } - } - - void TInterconnectProxyTCP::ForwardSessionEventToSession(STATEFN_SIG) { - ICPROXY_PROFILED; - - Y_ABORT_UNLESS(Session && SessionID); - ValidateEvent(ev, "ForwardSessionEventToSession"); - InvokeOtherActor(*Session, &TInterconnectSessionTCP::Receive, ev); - } - - void TInterconnectProxyTCP::GenerateHttpInfo(NMon::TEvHttpInfo::TPtr& ev) { - ICPROXY_PROFILED; - - LOG_INFO_IC("ICP31", "proxy http called"); - - TStringStream str; - - HTML(str) { - DIV_CLASS("panel panel-info") { - DIV_CLASS("panel-heading") { - str << "Proxy"; - } - DIV_CLASS("panel-body") { - TABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() { - str << "Sensor"; - } - TABLEH() { - str << "Value"; - } - } - } -#define MON_VAR(NAME) \ - TABLER() { \ - TABLED() { \ - str << #NAME; \ - } \ - TABLED() { \ - str << NAME; \ - } \ - } - - TABLEBODY() { - MON_VAR(TActivationContext::Now()) - MON_VAR(SessionID) - MON_VAR(LastSessionDieTime) - MON_VAR(IncomingHandshakeActor) - MON_VAR(IncomingHandshakeActorFilledIn) - MON_VAR(IncomingHandshakeActorReset) - MON_VAR(OutgoingHandshakeActor) - MON_VAR(OutgoingHandshakeActorCreated) - MON_VAR(OutgoingHandshakeActorReset) - MON_VAR(State) - MON_VAR(StateSwitchTime) - } - } - } - } - - DIV_CLASS("panel panel-info") { - DIV_CLASS("panel-heading") { - str << "Error Log"; - } - DIV_CLASS("panel-body") { - TABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() { - str << "Timestamp"; - } - TABLEH() { - str << "Elapsed"; - } - TABLEH() { - str << "Kind"; - } - TABLEH() { - str << "Explanation"; - } - } - } - TABLEBODY() { - const TInstant now = TActivationContext::Now(); - const TInstant barrier = now - TDuration::Minutes(1); - for (auto it = ErrorStateLog.rbegin(); it != ErrorStateLog.rend(); ++it) { - auto wrapper = [&](const auto& lambda) { - if (std::get<0>(*it) > barrier) { - str << "<strong>"; - lambda(); - str << "</strong>"; - } else { - lambda(); - } - }; - TABLER() { - TABLED() { - wrapper([&] { - str << std::get<0>(*it); - }); - } - TABLED() { - wrapper([&] { - str << now - std::get<0>(*it); - }); - } - TABLED() { - wrapper([&] { - str << std::get<1>(*it); - }); - } - TABLED() { - wrapper([&] { - str << std::get<2>(*it); - }); - - ui32 rep = std::get<3>(*it); - if (rep != 1) { - str << " <strong>x" << rep << "</strong>"; - } - } - } - } - } - } - } - } - } - - TAutoPtr<IEventHandle> h(new IEventHandle(ev->Sender, ev->Recipient, new NMon::TEvHttpInfoRes(str.Str()))); - if (Session) { - switch (auto& ev = h; ev->GetTypeRewrite()) { - hFunc(NMon::TEvHttpInfoRes, Session->GenerateHttpInfo); - default: - Y_ABORT(); - } - } else { - TActivationContext::Send(h.Release()); - } - } - - void TInterconnectProxyTCP::TransitToErrorState(TString explanation, bool updateErrorLog) { - ICPROXY_PROFILED; - - LOG_NOTICE_IC("ICP32", "transit to hold-by-error state Explanation# %s", explanation.data()); - LOG_INFO(*TlsActivationContext, NActorsServices::INTERCONNECT_STATUS, "[%u] error state: %s", PeerNodeId, explanation.data()); - - if (updateErrorLog) { - UpdateErrorStateLog(TActivationContext::Now(), "permanent conclusive", explanation); - } - - Y_ABORT_UNLESS(Session == nullptr); - Y_ABORT_UNLESS(!SessionID); - - // recalculate wakeup timeout -- if this is the first failure, then we sleep for default timeout; otherwise we - // sleep N times longer than the previous try, but not longer than desired number of seconds - HoldByErrorWakeupDuration = HoldByErrorWakeupDuration != TDuration::Zero() - ? Min(HoldByErrorWakeupDuration * SleepRetryMultiplier, MaxErrorSleep) - : FirstErrorSleep; - - // transit to required state and arm wakeup timer - if (Terminated) { - // switch to this state permanently - SwitchToState(__LINE__, "HoldByError", &TThis::HoldByError); - HoldByErrorWakeupCookie = nullptr; - } else { - SwitchToState(__LINE__, "HoldByError", &TThis::HoldByError, HoldByErrorWakeupDuration, - HoldByErrorWakeupCookie = new TEvents::TEvWakeup); - } - - /* Process all pending events. */ - ProcessPendingSessionEvents(); - - /* Terminate handshakes */ - DropHandshakes(); - - /* Terminate pending incoming handshake requests. */ - for (auto& ev : PendingIncomingHandshakeEvents) { - Send(ev->Sender, new TEvents::TEvPoisonPill); - if (ev->GetTypeRewrite() == TEvHandshakeFail::EventType) { - TEvHandshakeFail::TPtr tmp(static_cast<TEventHandle<TEvHandshakeFail>*>(ev.Release())); - LogHandshakeFail(tmp, true); - } - } - PendingIncomingHandshakeEvents.clear(); - } - - void TInterconnectProxyTCP::WakeupFromErrorState(TEvents::TEvWakeup::TPtr& ev) { - ICPROXY_PROFILED; - - LOG_INFO_IC("ICP33", "wake up from error state"); - - if (ev->Get() == HoldByErrorWakeupCookie) { - SwitchToInitialState(); - } - } - - void TInterconnectProxyTCP::Disconnect() { - ICPROXY_PROFILED; - - // terminate handshakes (if any) - DropHandshakes(); - - if (Session) { - IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::Terminate, TDisconnectReason::UserRequest()); - } else { - TransitToErrorState("forced disconnect"); - } - } - - void TInterconnectProxyTCP::ScheduleCleanupEventQueue() { - ICPROXY_PROFILED; - - if (!CleanupEventQueueScheduled && PendingSessionEvents) { - // apply batching at 50 ms granularity - Schedule(Max(TDuration::MilliSeconds(50), PendingSessionEvents.front().Deadline - TActivationContext::Monotonic()), new TEvCleanupEventQueue); - CleanupEventQueueScheduled = true; - } - } - - void TInterconnectProxyTCP::HandleCleanupEventQueue() { - ICPROXY_PROFILED; - - Y_ABORT_UNLESS(CleanupEventQueueScheduled); - CleanupEventQueueScheduled = false; - CleanupEventQueue(); - ScheduleCleanupEventQueue(); - } - - void TInterconnectProxyTCP::CleanupEventQueue() { - ICPROXY_PROFILED; - - const TMonotonic now = TActivationContext::Monotonic(); - while (PendingSessionEvents) { - TPendingSessionEvent& ev = PendingSessionEvents.front(); - if (now >= ev.Deadline || PendingSessionEventsSize > Common->Settings.MessagePendingSize) { - TAutoPtr<IEventHandle> event(ev.Event.Release()); - PendingSessionEventsSize -= ev.Size; - DropSessionEvent(event); - PendingSessionEvents.pop_front(); - } else { - break; - } - } - } - - void TInterconnectProxyTCP::HandleClosePeerSocket() { - ICPROXY_PROFILED; - - if (Session && Session->Socket) { - LOG_INFO_IC("ICP34", "closed connection by debug command"); - Session->Socket->Shutdown(SHUT_RDWR); - } - } - - void TInterconnectProxyTCP::HandleCloseInputSession() { - ICPROXY_PROFILED; - - if (Session) { - IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::CloseInputSession); - } - } - - void TInterconnectProxyTCP::HandlePoisonSession() { - ICPROXY_PROFILED; - - if (Session) { - IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::Terminate, TDisconnectReason::Debug()); - } - } - - void TInterconnectProxyTCP::HandleSessionBufferSizeRequest(TEvSessionBufferSizeRequest::TPtr& ev) { - ICPROXY_PROFILED; - - ui64 bufSize = 0; - if (Session) { - bufSize = Session->TotalOutputQueueSize; - } - - Send(ev->Sender, new TEvSessionBufferSizeResponse(SessionID, bufSize)); - } - - void TInterconnectProxyTCP::Handle(TEvQueryStats::TPtr& ev) { - ICPROXY_PROFILED; - - TProxyStats stats; - stats.Path = Sprintf("peer%04" PRIu32, PeerNodeId); - stats.State = State; - stats.PeerScopeId = Session ? Session->Params.PeerScopeId : TScopeId(); - stats.LastSessionDieTime = LastSessionDieTime; - stats.TotalOutputQueueSize = Session ? Session->TotalOutputQueueSize : 0; - stats.Connected = Session ? (bool)Session->Socket : false; - stats.ExternalDataChannel = Session && Session->XdcSocket; - stats.Host = TechnicalPeerHostName; - stats.Port = 0; - ui32 rep = 0; - std::tie(stats.LastErrorTimestamp, stats.LastErrorKind, stats.LastErrorExplanation, rep) = ErrorStateLog - ? ErrorStateLog.back() - : std::make_tuple(TInstant(), TString(), TString(), 1U); - if (rep != 1) { - stats.LastErrorExplanation += Sprintf(" x%" PRIu32, rep); - } - stats.Ping = Session ? Session->GetPingRTT() : TDuration::Zero(); - stats.ClockSkew = Session ? Session->GetClockSkew() : 0; - if (Session) { - if (auto *x = dynamic_cast<NInterconnect::TSecureSocket*>(Session->Socket.Get())) { - stats.Encryption = Sprintf("%s/%u", x->GetCipherName().data(), x->GetCipherBits()); - } else { - stats.Encryption = "none"; - } - } - - auto response = MakeHolder<TEvStats>(); - response->PeerNodeId = PeerNodeId; - response->ProxyStats = std::move(stats); - Send(ev->Sender, response.Release()); - } - - void TInterconnectProxyTCP::HandleTerminate() { - ICPROXY_PROFILED; - - if (Session) { - IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::Terminate, TDisconnectReason()); - } - Terminated = true; - TransitToErrorState("terminated"); - } - - void TInterconnectProxyTCP::PassAway() { - if (Session) { - IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::Terminate, TDisconnectReason()); - } - if (DynamicPtr) { - Y_ABORT_UNLESS(*DynamicPtr == this); - *DynamicPtr = nullptr; - } - // TODO: unregister actor mon page - TActor::PassAway(); - } -} diff --git a/library/cpp/actors/interconnect/interconnect_tcp_proxy.h b/library/cpp/actors/interconnect/interconnect_tcp_proxy.h deleted file mode 100644 index 81f043a2e9..0000000000 --- a/library/cpp/actors/interconnect/interconnect_tcp_proxy.h +++ /dev/null @@ -1,570 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/actor_bootstrapped.h> -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/core/event_pb.h> -#include <library/cpp/actors/core/events.h> -#include <library/cpp/monlib/dynamic_counters/counters.h> - -#include "interconnect_common.h" -#include "interconnect_counters.h" -#include "interconnect_tcp_session.h" -#include "profiler.h" - -#define ICPROXY_PROFILED TFunction func(*this, __func__, __LINE__) - -namespace NActors { - - - /* WARNING: all proxy actors should be alive during actorsystem activity */ - class TInterconnectProxyTCP - : public TActor<TInterconnectProxyTCP> - , public TInterconnectLoggingBase - , public TProfiled - { - enum { - EvCleanupEventQueue = EventSpaceBegin(TEvents::ES_PRIVATE), - EvQueryStats, - EvStats, - EvPassAwayIfNeeded, - }; - - struct TEvCleanupEventQueue : TEventLocal<TEvCleanupEventQueue, EvCleanupEventQueue> {}; - - public: - struct TEvQueryStats : TEventLocal<TEvQueryStats, EvQueryStats> {}; - - struct TProxyStats { - TString Path; - TString State; - TScopeId PeerScopeId; - TInstant LastSessionDieTime; - ui64 TotalOutputQueueSize; - bool Connected; - bool ExternalDataChannel; - TString Host; - ui16 Port; - TInstant LastErrorTimestamp; - TString LastErrorKind; - TString LastErrorExplanation; - TDuration Ping; - i64 ClockSkew; - TString Encryption; - }; - - struct TEvStats : TEventLocal<TEvStats, EvStats> { - ui32 PeerNodeId; - TProxyStats ProxyStats; - }; - - static constexpr EActivityType ActorActivityType() { - return EActivityType::INTERCONNECT_PROXY_TCP; - } - - TInterconnectProxyTCP(const ui32 node, TInterconnectProxyCommon::TPtr common, IActor **dynamicPtr = nullptr); - - STFUNC(StateInit) { - Bootstrap(); - if (ev->Type != TEvents::TSystem::Bootstrap) { // for dynamic nodes we do not receive Bootstrap event - Receive(ev); - } - } - - void Bootstrap(); - void Registered(TActorSystem* sys, const TActorId& owner) override; - - private: - friend class TInterconnectSessionTCP; - friend class TInterconnectSessionTCPv0; - friend class THandshake; - friend class TInputSessionTCP; - - void UnregisterSession(TInterconnectSessionTCP* session); - -#define SESSION_EVENTS(HANDLER) \ - fFunc(TEvInterconnect::EvForward, HANDLER) \ - fFunc(TEvInterconnect::TEvConnectNode::EventType, HANDLER) \ - fFunc(TEvents::TEvSubscribe::EventType, HANDLER) \ - fFunc(TEvents::TEvUnsubscribe::EventType, HANDLER) - -#define INCOMING_HANDSHAKE_EVENTS(HANDLER) \ - fFunc(TEvHandshakeAsk::EventType, HANDLER) \ - fFunc(TEvHandshakeRequest::EventType, HANDLER) - -#define HANDSHAKE_STATUS_EVENTS(HANDLER) \ - hFunc(TEvHandshakeDone, HANDLER) \ - hFunc(TEvHandshakeFail, HANDLER) - -#define PROXY_STFUNC(STATE, SESSION_HANDLER, INCOMING_HANDSHAKE_HANDLER, \ - HANDSHAKE_STATUS_HANDLER, DISCONNECT_HANDLER, \ - WAKEUP_HANDLER, NODE_INFO_HANDLER) \ - STATEFN(STATE) { \ - const ui32 type = ev->GetTypeRewrite(); \ - const bool profiled = type != TEvInterconnect::EvForward \ - && type != TEvInterconnect::EvConnectNode \ - && type != TEvents::TSystem::Subscribe \ - && type != TEvents::TSystem::Unsubscribe; \ - if (profiled) { \ - TProfiled::Start(); \ - } \ - { \ - TProfiled::TFunction func(*this, __func__, __LINE__); \ - switch (type) { \ - SESSION_EVENTS(SESSION_HANDLER) \ - INCOMING_HANDSHAKE_EVENTS(INCOMING_HANDSHAKE_HANDLER) \ - HANDSHAKE_STATUS_EVENTS(HANDSHAKE_STATUS_HANDLER) \ - cFunc(TEvInterconnect::EvDisconnect, DISCONNECT_HANDLER) \ - hFunc(TEvents::TEvWakeup, WAKEUP_HANDLER) \ - hFunc(TEvGetSecureSocket, Handle) \ - hFunc(NMon::TEvHttpInfo, GenerateHttpInfo) \ - cFunc(EvCleanupEventQueue, HandleCleanupEventQueue) \ - hFunc(TEvInterconnect::TEvNodeInfo, NODE_INFO_HANDLER) \ - cFunc(TEvInterconnect::EvClosePeerSocket, HandleClosePeerSocket) \ - cFunc(TEvInterconnect::EvCloseInputSession, HandleCloseInputSession) \ - cFunc(TEvInterconnect::EvPoisonSession, HandlePoisonSession) \ - hFunc(TEvSessionBufferSizeRequest, HandleSessionBufferSizeRequest) \ - hFunc(TEvQueryStats, Handle) \ - cFunc(TEvInterconnect::EvTerminate, HandleTerminate) \ - cFunc(EvPassAwayIfNeeded, HandlePassAwayIfNeeded) \ - hFunc(TEvSubscribeForConnection, Handle); \ - hFunc(TEvReportConnection, Handle); \ - default: \ - Y_ABORT("unexpected event Type# 0x%08" PRIx32, type); \ - } \ - } \ - if (profiled) { \ - if (TProfiled::Duration() >= TDuration::MilliSeconds(16)) { \ - const TString report = TProfiled::Format(); \ - LOG_ERROR_IC("ICP35", "event processing took too much time %s", report.data()); \ - } \ - TProfiled::Finish(); \ - } \ - } - - template <typename T> - void Ignore(T& /*ev*/) { - ICPROXY_PROFILED; - } - - void Ignore() { - ICPROXY_PROFILED; - } - - void Ignore(TEvHandshakeDone::TPtr& ev) { - ICPROXY_PROFILED; - - Y_ABORT_UNLESS(ev->Sender != IncomingHandshakeActor); - Y_ABORT_UNLESS(ev->Sender != OutgoingHandshakeActor); - } - - void Ignore(TEvHandshakeFail::TPtr& ev) { - ICPROXY_PROFILED; - - Y_ABORT_UNLESS(ev->Sender != IncomingHandshakeActor); - Y_ABORT_UNLESS(ev->Sender != OutgoingHandshakeActor); - LogHandshakeFail(ev, true); - } - - const char* State = nullptr; - TInstant StateSwitchTime; - - template <typename... TArgs> - void SwitchToState(int line, const char* name, TArgs&&... args) { - ICPROXY_PROFILED; - - LOG_DEBUG_IC("ICP77", "@%d %s -> %s", line, State, name); - State = name; - StateSwitchTime = TActivationContext::Now(); - Become(std::forward<TArgs>(args)...); - Y_ABORT_UNLESS(!Terminated || CurrentStateFunc() == &TThis::HoldByError); // ensure we never escape this state - if (CurrentStateFunc() != &TThis::PendingActivation) { - PassAwayTimestamp = TMonotonic::Max(); - } else if (DynamicPtr) { - PassAwayTimestamp = TActivationContext::Monotonic() + TDuration::Seconds(15); - if (!PassAwayScheduled) { - TActivationContext::Schedule(PassAwayTimestamp, new IEventHandle(EvPassAwayIfNeeded, 0, SelfId(), - {}, nullptr, 0)); - PassAwayScheduled = true; - } - } - } - - TMonotonic PassAwayTimestamp; - bool PassAwayScheduled = false; - - void SwitchToInitialState() { - ICPROXY_PROFILED; - - Y_ABORT_UNLESS(!PendingSessionEvents && !PendingIncomingHandshakeEvents, "%s PendingSessionEvents# %zu" - " PendingIncomingHandshakeEvents# %zu State# %s", LogPrefix.data(), PendingSessionEvents.size(), - PendingIncomingHandshakeEvents.size(), State); - SwitchToState(__LINE__, "PendingActivation", &TThis::PendingActivation); - } - - void HandlePassAwayIfNeeded() { - Y_ABORT_UNLESS(PassAwayScheduled); - const TMonotonic now = TActivationContext::Monotonic(); - if (now >= PassAwayTimestamp) { - PassAway(); - } else if (PassAwayTimestamp != TMonotonic::Max()) { - TActivationContext::Schedule(PassAwayTimestamp, new IEventHandle(EvPassAwayIfNeeded, 0, SelfId(), - {}, nullptr, 0)); - } else { - PassAwayScheduled = false; - } - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // PendingActivation - // - // In this state we are just waiting for some activities, which may include: - // * an external Session event - // * incoming handshake request - // - // Upon receiving such event, we put it to corresponding queue and initiate start up by calling IssueGetNodeRequest, - // which, as the name says, issued TEvGetNode to the nameservice and arms timer to handle timeout (which should not - // occur, but we want to be sure we don't hang on this), and then switches to PendingNodeInfo state. - - PROXY_STFUNC(PendingActivation, - RequestNodeInfo, // Session events - RequestNodeInfoForIncomingHandshake, // Incoming handshake requests - Ignore, // Handshake status - Ignore, // Disconnect request - Ignore, // Wakeup - Ignore // Node info - ) - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // PendingNodeInfo - // - // This state is entered when we asked nameserver to provide description for peer node we are working with. All - // external Session events and incoming handshake requests are enqueued into their respective queues, TEvNodeInfo - // is main event that triggers processing. On success, we try to initiate outgoing handshake if needed, or process - // incoming handshakes. On error, we enter HoldByError state. - // - // NOTE: handshake status events are also enqueued as the handshake actor may have generated failure event due to - // timeout or some other reason without waiting for acknowledge, and it must be processed correctly to prevent - // session hang - - PROXY_STFUNC(PendingNodeInfo, - EnqueueSessionEvent, // Session events - EnqueueIncomingHandshakeEvent, // Incoming handshake requests - EnqueueIncomingHandshakeEvent, // Handshake status - Disconnect, // Disconnect request - ConfigureTimeout, // Wakeup - Configure // Node info - ) - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // PendingConnection - // - // Here we have issued outgoing handshake or have accepted (or may be both) incoming handshake and we are waiting for - // the status of the handshake. When one if handshakes finishes, we use this status to establish connection (or to - // go to error state). When one handshake terminates with error while other is running, we will still wait for the - // second one to finish. - - PROXY_STFUNC(PendingConnection, - EnqueueSessionEvent, // Session events - IncomingHandshake, // Incoming handshake requests - HandleHandshakeStatus, // Handshake status - Disconnect, // Disconnect request - Ignore, // Wakeup - Ignore // Node info - ) - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // StateWork - // - // We have accepted session and process any incoming messages with the session. Incoming handshakes are accepted - // concurrently and applied when finished. - - PROXY_STFUNC(StateWork, - ForwardSessionEventToSession, // Session events - IncomingHandshake, // Incoming handshake requests - HandleHandshakeStatus, // Handshake status - Disconnect, // Disconnect request - Ignore, // Wakeup - Ignore // Node info - ) - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // HoldByError - // - // When something bad happens with the connection, we sleep in this state. After wake up we go back to - // PendingActivation. - - PROXY_STFUNC(HoldByError, - DropSessionEvent, // Session events - RequestNodeInfoForIncomingHandshake, // Incoming handshake requests - Ignore, // Handshake status - Ignore, // Disconnect request - WakeupFromErrorState, // Wakeup - Ignore // Node info - ) - -#undef SESSION_EVENTS -#undef INCOMING_HANDSHAKE_EVENTS -#undef HANDSHAKE_STATUS_EVENTS -#undef PROXY_STFUNC - - void ForwardSessionEventToSession(STATEFN_SIG); - void EnqueueSessionEvent(STATEFN_SIG); - - // Incoming handshake handlers, including special wrapper when the IncomingHandshake is used as fFunc - void IncomingHandshake(STATEFN_SIG) { - switch (ev->GetTypeRewrite()) { - hFunc(TEvHandshakeAsk, IncomingHandshake); - hFunc(TEvHandshakeRequest, IncomingHandshake); - default: - Y_ABORT(); - } - } - void IncomingHandshake(TEvHandshakeAsk::TPtr& ev); - void IncomingHandshake(TEvHandshakeRequest::TPtr& ev); - - void RequestNodeInfo(STATEFN_SIG); - void RequestNodeInfoForIncomingHandshake(STATEFN_SIG); - - void StartInitialHandshake(); - void StartResumeHandshake(ui64 inputCounter); - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Incoming handshake event queue processing - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - void EnqueueIncomingHandshakeEvent(STATEFN_SIG); - void EnqueueIncomingHandshakeEvent(TEvHandshakeDone::TPtr& ev); - void EnqueueIncomingHandshakeEvent(TEvHandshakeFail::TPtr& ev); - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // PendingNodeInfo - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - IEventBase* ConfigureTimeoutCookie; // pointer to the scheduled event used to match sent and received events - - void StartConfiguring(); - void Configure(TEvInterconnect::TEvNodeInfo::TPtr& ev); - void ConfigureTimeout(TEvents::TEvWakeup::TPtr& ev); - void ProcessConfigured(); - - void HandleHandshakeStatus(TEvHandshakeDone::TPtr& ev); - void HandleHandshakeStatus(TEvHandshakeFail::TPtr& ev); - - void TransitToErrorState(TString Explanation, bool updateErrorLog = true); - void WakeupFromErrorState(TEvents::TEvWakeup::TPtr& ev); - void Disconnect(); - - const ui32 PeerNodeId; - IActor **DynamicPtr; - - void ValidateEvent(TAutoPtr<IEventHandle>& ev, const char* func) { - if (SelfId().NodeId() == PeerNodeId) { - TString msg = Sprintf("Event Type# 0x%08" PRIx32 " TypeRewrite# 0x%08" PRIx32 - " from Sender# %s sent to the proxy for the node itself via Interconnect;" - " THIS IS NOT A BUG IN INTERCONNECT, check the event sender instead", - ev->Type, ev->GetTypeRewrite(), ev->Sender.ToString().data()); - LOG_ERROR_IC("ICP03", "%s", msg.data()); - Y_DEBUG_ABORT_UNLESS(false, "%s", msg.data()); - } - - Y_ABORT_UNLESS(ev->GetTypeRewrite() != TEvInterconnect::EvForward || ev->Recipient.NodeId() == PeerNodeId, - "Recipient/Proxy NodeId mismatch Recipient# %s Type# 0x%08" PRIx32 " PeerNodeId# %" PRIu32 " Func# %s", - ev->Recipient.ToString().data(), ev->Type, PeerNodeId, func); - } - - // Common with helpers - // All proxy actors share the same information in the object - // read only - TInterconnectProxyCommon::TPtr const Common; - - const TActorId& GetNameserviceId() const { - return Common->NameserviceId; - } - - TString TechnicalPeerHostName; - - std::shared_ptr<IInterconnectMetrics> Metrics; - - void HandleClosePeerSocket(); - void HandleCloseInputSession(); - void HandlePoisonSession(); - - void HandleSessionBufferSizeRequest(TEvSessionBufferSizeRequest::TPtr& ev); - - bool CleanupEventQueueScheduled = false; - void ScheduleCleanupEventQueue(); - void HandleCleanupEventQueue(); - void CleanupEventQueue(); - - // hold all events before connection is established - struct TPendingSessionEvent { - TMonotonic Deadline; - ui32 Size; - THolder<IEventHandle> Event; - - TPendingSessionEvent(TMonotonic deadline, ui32 size, TAutoPtr<IEventHandle> event) - : Deadline(deadline) - , Size(size) - , Event(event) - {} - }; - TDeque<TPendingSessionEvent> PendingSessionEvents; - ui64 PendingSessionEventsSize = 0; - void ProcessPendingSessionEvents(); - void DropSessionEvent(STATEFN_SIG); - - TInterconnectSessionTCP* Session = nullptr; - TActorId SessionID; - - // virtual ids used during handshake to check if it is the connection - // for the same session or to find out the latest shandshake - // it's virtual because session actor apears after successfull handshake - TActorId SessionVirtualId; - TActorId RemoteSessionVirtualId; - - TActorId GenerateSessionVirtualId() { - ICPROXY_PROFILED; - - const ui64 localId = TlsActivationContext->ExecutorThread.ActorSystem->AllocateIDSpace(1); - return NActors::TActorId(SelfId().NodeId(), 0, localId, 0); - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - TActorId IncomingHandshakeActor; - TInstant IncomingHandshakeActorFilledIn; - TInstant IncomingHandshakeActorReset; - TMaybe<ui64> LastSerialFromIncomingHandshake; - THolder<IEventBase> HeldHandshakeReply; - - void DropIncomingHandshake(bool poison = true) { - ICPROXY_PROFILED; - - if (const TActorId& actorId = std::exchange(IncomingHandshakeActor, TActorId())) { - LOG_DEBUG_IC("ICP111", "dropped incoming handshake: %s poison: %s", actorId.ToString().data(), - poison ? "true" : "false"); - if (poison) { - Send(actorId, new TEvents::TEvPoisonPill); - } - LastSerialFromIncomingHandshake.Clear(); - HeldHandshakeReply.Reset(); - IncomingHandshakeActorReset = TActivationContext::Now(); - } - } - - void DropOutgoingHandshake(bool poison = true) { - ICPROXY_PROFILED; - - if (const TActorId& actorId = std::exchange(OutgoingHandshakeActor, TActorId())) { - LOG_DEBUG_IC("ICP052", "dropped outgoing handshake: %s poison: %s", actorId.ToString().data(), - poison ? "true" : "false"); - if (poison) { - Send(actorId, new TEvents::TEvPoisonPill); - } - OutgoingHandshakeActorReset = TActivationContext::Now(); - } - } - - void DropHandshakes() { - ICPROXY_PROFILED; - - DropIncomingHandshake(); - DropOutgoingHandshake(); - } - - void PrepareNewSessionHandshake() { - ICPROXY_PROFILED; - - // drop existing session if we have one - if (Session) { - LOG_INFO_IC("ICP04", "terminating current session as we are negotiating a new one"); - IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::Terminate, TDisconnectReason::NewSession()); - } - - // ensure we have no current session - Y_ABORT_UNLESS(!Session); - - // switch to pending connection state -- we wait for handshakes, we want more handshakes! - SwitchToState(__LINE__, "PendingConnection", &TThis::PendingConnection); - } - - void IssueIncomingHandshakeReply(const TActorId& handshakeId, ui64 peerLocalId, - THolder<IEventBase> event); - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - std::unordered_map<TString, TActorId> ConnectionSubscriptions; - - void Handle(TEvSubscribeForConnection::TPtr ev) { - auto& msg = *ev->Get(); - if (msg.Subscribe) { - if (const auto [it, inserted] = ConnectionSubscriptions.emplace(msg.HandshakeId, ev->Sender); !inserted) { - Y_DEBUG_ABORT_UNLESS(false); - ConnectionSubscriptions.erase(it); // collision happened somehow? - } - } else { - ConnectionSubscriptions.erase(msg.HandshakeId); - } - } - - void Handle(TEvReportConnection::TPtr ev) { - if (auto nh = ConnectionSubscriptions.extract(ev->Get()->HandshakeId)) { - TActivationContext::Send(IEventHandle::Forward(ev, nh.mapped())); - } - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - TActorId OutgoingHandshakeActor; - TInstant OutgoingHandshakeActorCreated; - TInstant OutgoingHandshakeActorReset; - - TInstant LastSessionDieTime; - - void GenerateHttpInfo(NMon::TEvHttpInfo::TPtr& ev); - - void Handle(TEvQueryStats::TPtr& ev); - - TDuration HoldByErrorWakeupDuration = TDuration::Zero(); - TEvents::TEvWakeup* HoldByErrorWakeupCookie; - - THolder<TProgramInfo> RemoteProgramInfo; - NInterconnect::TSecureSocketContext::TPtr SecureContext; - - void Handle(TEvGetSecureSocket::TPtr ev) { - auto socket = MakeIntrusive<NInterconnect::TSecureSocket>(*ev->Get()->Socket, SecureContext); - Send(ev->Sender, new TEvSecureSocket(std::move(socket))); - } - - TDeque<THolder<IEventHandle>> PendingIncomingHandshakeEvents; - - TDeque<std::tuple<TInstant, TString, TString, ui32>> ErrorStateLog; - - void UpdateErrorStateLog(TInstant now, TString kind, TString explanation) { - ICPROXY_PROFILED; - - if (ErrorStateLog) { - auto& back = ErrorStateLog.back(); - TString lastKind, lastExpl; - if (kind == std::get<1>(back) && explanation == std::get<2>(back)) { - std::get<0>(back) = now; - ++std::get<3>(back); - return; - } - } - - ErrorStateLog.emplace_back(now, std::move(kind), std::move(explanation), 1); - if (ErrorStateLog.size() > 20) { - ErrorStateLog.pop_front(); - } - } - - void LogHandshakeFail(TEvHandshakeFail::TPtr& ev, bool inconclusive); - - bool Terminated = false; - void HandleTerminate(); - - void PassAway() override; - }; - -} diff --git a/library/cpp/actors/interconnect/interconnect_tcp_server.cpp b/library/cpp/actors/interconnect/interconnect_tcp_server.cpp deleted file mode 100644 index df0c172dc1..0000000000 --- a/library/cpp/actors/interconnect/interconnect_tcp_server.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include "interconnect_tcp_server.h" -#include "interconnect_handshake.h" - -#include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/protos/services_common.pb.h> - -#include "interconnect_common.h" - -namespace NActors { - TInterconnectListenerTCP::TInterconnectListenerTCP(const TString& address, ui16 port, TInterconnectProxyCommon::TPtr common, const TMaybe<SOCKET>& socket) - : TActor(&TThis::Initial) - , TInterconnectLoggingBase(Sprintf("ICListener: %s", SelfId().ToString().data())) - , Address(address) - , Port(port) - , Listener( - socket - ? new NInterconnect::TStreamSocket(*socket) - : nullptr) - , ExternalSocket(!!Listener) - , ProxyCommonCtx(std::move(common)) - { - if (ExternalSocket) { - SetNonBlock(*Listener); - } - } - - TAutoPtr<IEventHandle> TInterconnectListenerTCP::AfterRegister(const TActorId& self, const TActorId& parentId) { - return new IEventHandle(self, parentId, new TEvents::TEvBootstrap, 0); - } - - void TInterconnectListenerTCP::Die(const TActorContext& ctx) { - LOG_DEBUG_IC("ICL08", "Dying"); - TActor::Die(ctx); - } - - int TInterconnectListenerTCP::Bind() { - auto doTry = [&](NInterconnect::TAddress addr) { - int error; - Listener = NInterconnect::TStreamSocket::Make(addr.GetFamily(), &error); - if (*Listener == -1) { - return error; - } - SetNonBlock(*Listener); - Listener->SetSendBufferSize(ProxyCommonCtx->Settings.GetSendBufferSize()); // TODO(alexvru): WTF? - SetSockOpt(*Listener, SOL_SOCKET, SO_REUSEADDR, 1); - if (addr.GetFamily() == AF_INET6) { - SetSockOpt(*Listener, IPPROTO_IPV6, IPV6_V6ONLY, 0); - } - const ui32 backlog = ProxyCommonCtx->Settings.SocketBacklogSize; - if (const auto e = -Listener->Bind(addr)) { - return e; - } else if (const auto e = -Listener->Listen(backlog ? backlog : SOMAXCONN)) { - return e; - } else { - return 0; - } - }; - - if (Address) { - NInterconnect::TAddress addr(Address, Port); - if (ProxyCommonCtx->Settings.BindOnAllAddresses) { - addr = addr.GetFamily() == AF_INET ? NInterconnect::TAddress::AnyIPv4(Port) : - addr.GetFamily() == AF_INET6 ? NInterconnect::TAddress::AnyIPv6(Port) : addr; - } - return doTry(addr); - } else { - int error = doTry(NInterconnect::TAddress::AnyIPv6(Port)); - if (error == EAFNOSUPPORT || error == EPROTONOSUPPORT) { - error = doTry(NInterconnect::TAddress::AnyIPv4(Port)); - } - return error; - } - } - - void TInterconnectListenerTCP::Bootstrap(const TActorContext& ctx) { - if (!Listener) { - if (const int err = Bind()) { - LOG_ERROR_IC("ICL01", "Bind failed: %s (%s:%u)", strerror(err), Address.data(), Port); - Listener.Reset(); - Become(&TThis::Initial, TDuration::Seconds(1), new TEvents::TEvBootstrap); - return; - } - } - if (const auto& callback = ProxyCommonCtx->InitWhiteboard) { - callback(Port, TlsActivationContext->ExecutorThread.ActorSystem); - } - const bool success = ctx.Send(MakePollerActorId(), new TEvPollerRegister(Listener, SelfId(), {})); - Y_ABORT_UNLESS(success); - Become(&TThis::Listen); - } - - void TInterconnectListenerTCP::Handle(TEvPollerRegisterResult::TPtr ev, const TActorContext& ctx) { - PollerToken = std::move(ev->Get()->PollerToken); - Process(ctx); - } - - void TInterconnectListenerTCP::Process(const TActorContext& ctx) { - for (;;) { - NInterconnect::TAddress address; - const int r = Listener->Accept(address); - if (r >= 0) { - LOG_DEBUG_IC("ICL04", "Accepted from: %s", address.ToString().data()); - auto socket = MakeIntrusive<NInterconnect::TStreamSocket>(static_cast<SOCKET>(r)); - ctx.Register(CreateIncomingHandshakeActor(ProxyCommonCtx, std::move(socket))); - continue; - } else if (-r != EAGAIN && -r != EWOULDBLOCK) { - Y_ABORT_UNLESS(-r != ENFILE && -r != EMFILE && !ExternalSocket); - LOG_ERROR_IC("ICL06", "Listen failed: %s (%s:%u)", strerror(-r), Address.data(), Port); - Listener.Reset(); - PollerToken.Reset(); - Become(&TThis::Initial, TDuration::Seconds(1), new TEvents::TEvBootstrap); - } else if (PollerToken && PollerToken->RequestReadNotificationAfterWouldBlock()) { - continue; - } - break; - } - } - -} diff --git a/library/cpp/actors/interconnect/interconnect_tcp_server.h b/library/cpp/actors/interconnect/interconnect_tcp_server.h deleted file mode 100644 index 41f46ab6d4..0000000000 --- a/library/cpp/actors/interconnect/interconnect_tcp_server.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/core/event_pb.h> -#include <library/cpp/actors/core/events.h> - -#include "interconnect_common.h" -#include "poller_actor.h" -#include "events_local.h" - -namespace NActors { - class TInterconnectListenerTCP: public TActor<TInterconnectListenerTCP>, public TInterconnectLoggingBase { - public: - static constexpr EActivityType ActorActivityType() { - return EActivityType::INTERCONNECT_COMMON; - } - - TInterconnectListenerTCP(const TString& address, ui16 port, TInterconnectProxyCommon::TPtr common, const TMaybe<SOCKET>& socket = Nothing()); - int Bind(); - - private: - STFUNC(Initial) { - switch (ev->GetTypeRewrite()) { - CFunc(TEvents::TEvBootstrap::EventType, Bootstrap); - CFunc(TEvents::TEvPoisonPill::EventType, Die); - } - } - - STFUNC(Listen) { - switch (ev->GetTypeRewrite()) { - CFunc(TEvents::TEvPoisonPill::EventType, Die); - HFunc(TEvPollerRegisterResult, Handle); - CFunc(TEvPollerReady::EventType, Process); - } - } - - TAutoPtr<IEventHandle> AfterRegister(const TActorId& self, const TActorId& parentId) override; - - void Die(const TActorContext& ctx) override; - - void Bootstrap(const TActorContext& ctx); - void Handle(TEvPollerRegisterResult::TPtr ev, const TActorContext& ctx); - - void Process(const TActorContext& ctx); - - const TString Address; - const ui16 Port; - TIntrusivePtr<NInterconnect::TStreamSocket> Listener; - const bool ExternalSocket; - TPollerToken::TPtr PollerToken; - TInterconnectProxyCommon::TPtr const ProxyCommonCtx; - }; - - static inline TActorId MakeInterconnectListenerActorId(bool dynamic) { - char x[12] = {'I', 'C', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '/', dynamic ? 'D' : 'S'}; - return TActorId(0, TStringBuf(x, 12)); - } -} diff --git a/library/cpp/actors/interconnect/interconnect_tcp_session.cpp b/library/cpp/actors/interconnect/interconnect_tcp_session.cpp deleted file mode 100644 index 7d6f8d012f..0000000000 --- a/library/cpp/actors/interconnect/interconnect_tcp_session.cpp +++ /dev/null @@ -1,1322 +0,0 @@ -#include "interconnect_tcp_proxy.h" -#include "interconnect_tcp_session.h" -#include "interconnect_handshake.h" - -#include <library/cpp/actors/core/probes.h> -#include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/core/interconnect.h> -#include <library/cpp/actors/util/datetime.h> -#include <library/cpp/actors/protos/services_common.pb.h> -#include <library/cpp/monlib/service/pages/templates.h> - -namespace NActors { - LWTRACE_USING(ACTORLIB_PROVIDER); - - template<typename T> - T Coalesce(T&& x) { - return x; - } - - template<typename T, typename T2, typename... TRest> - typename std::common_type<T, T2, TRest...>::type Coalesce(T&& first, T2&& mid, TRest&&... rest) { - if (first != typename std::remove_reference<T>::type()) { - return first; - } else { - return Coalesce(std::forward<T2>(mid), std::forward<TRest>(rest)...); - } - } - - TInterconnectSessionTCP::TInterconnectSessionTCP(TInterconnectProxyTCP* const proxy, TSessionParams params) - : TActor(&TInterconnectSessionTCP::StateFunc) - , Created(TInstant::Now()) - , Proxy(proxy) - , CloseOnIdleWatchdog(GetCloseOnIdleTimeout(), std::bind(&TThis::OnCloseOnIdleTimerHit, this)) - , LostConnectionWatchdog(GetLostConnectionTimeout(), std::bind(&TThis::OnLostConnectionTimerHit, this)) - , Params(std::move(params)) - , TotalOutputQueueSize(0) - , OutputStuckFlag(false) - , OutputQueueUtilization(16) - , OutputCounter(0ULL) - { - Proxy->Metrics->SetConnected(0); - ReceiveContext.Reset(new TReceiveContext); - } - - TInterconnectSessionTCP::~TInterconnectSessionTCP() { - // close socket ASAP when actor system is being shut down - if (Socket) { - Socket->Shutdown(SHUT_RDWR); - } - if (XdcSocket) { - XdcSocket->Shutdown(SHUT_RDWR); - } - } - - void TInterconnectSessionTCP::Init() { - auto destroyCallback = [as = TlsActivationContext->ExecutorThread.ActorSystem, id = Proxy->Common->DestructorId](THolder<IEventBase> event) { - as->Send(id, event.Release()); - }; - Pool.ConstructInPlace(Proxy->Common, std::move(destroyCallback)); - ChannelScheduler.ConstructInPlace(Proxy->PeerNodeId, Proxy->Common->ChannelsConfig, Proxy->Metrics, *Pool, - Proxy->Common->Settings.MaxSerializedEventSize, Params); - - LOG_INFO(*TlsActivationContext, NActorsServices::INTERCONNECT_STATUS, "[%u] session created", Proxy->PeerNodeId); - SetPrefix(Sprintf("Session %s [node %" PRIu32 "]", SelfId().ToString().data(), Proxy->PeerNodeId)); - SendUpdateToWhiteboard(); - } - - void TInterconnectSessionTCP::CloseInputSession() { - Send(ReceiverId, new TEvInterconnect::TEvCloseInputSession); - } - - void TInterconnectSessionTCP::Handle(TEvTerminate::TPtr& ev) { - Terminate(ev->Get()->Reason); - } - - void TInterconnectSessionTCP::HandlePoison() { - Terminate(TDisconnectReason()); - } - - void TInterconnectSessionTCP::Terminate(TDisconnectReason reason) { - LOG_INFO_IC_SESSION("ICS01", "socket: %" PRIi64 " reason# %s", (Socket ? i64(*Socket) : -1), reason.ToString().data()); - - IActor::InvokeOtherActor(*Proxy, &TInterconnectProxyTCP::UnregisterSession, this); - ShutdownSocket(std::move(reason)); - - for (const auto& kv : Subscribers) { - Send(kv.first, new TEvInterconnect::TEvNodeDisconnected(Proxy->PeerNodeId), 0, kv.second); - } - Proxy->Metrics->SubSubscribersCount(Subscribers.size()); - Subscribers.clear(); - - ChannelScheduler->ForEach([&](TEventOutputChannel& channel) { - channel.NotifyUndelivered(); - }); - - if (ReceiverId) { - Send(ReceiverId, new TEvents::TEvPoisonPill); - } - - SendUpdateToWhiteboard(false); - - Proxy->Metrics->SubOutputBuffersTotalSize(TotalOutputQueueSize); - Proxy->Metrics->SubInflightDataAmount(InflightDataAmount); - - LOG_INFO(*TlsActivationContext, NActorsServices::INTERCONNECT_STATUS, "[%u] session destroyed", Proxy->PeerNodeId); - - if (!Subscribers.empty()) { - Proxy->Metrics->SubSubscribersCount(Subscribers.size()); - } - - TActor::PassAway(); - } - - void TInterconnectSessionTCP::PassAway() { - Y_ABORT("TInterconnectSessionTCP::PassAway() can't be called directly"); - } - - void TInterconnectSessionTCP::Forward(STATEFN_SIG) { - Proxy->ValidateEvent(ev, "Forward"); - - LOG_DEBUG_IC_SESSION("ICS02", "send event from: %s to: %s", ev->Sender.ToString().data(), ev->Recipient.ToString().data()); - ++MessagesGot; - - if (ev->Flags & IEventHandle::FlagSubscribeOnSession) { - Subscribe(ev); - } - - ui16 evChannel = ev->GetChannel(); - auto& oChannel = ChannelScheduler->GetOutputChannel(evChannel); - const bool wasWorking = oChannel.IsWorking(); - - const auto [dataSize, event] = oChannel.Push(*ev); - LWTRACK(ForwardEvent, event->Orbit, Proxy->PeerNodeId, event->Descr.Type, event->Descr.Flags, LWACTORID(event->Descr.Recipient), LWACTORID(event->Descr.Sender), event->Descr.Cookie, event->EventSerializedSize); - - TotalOutputQueueSize += dataSize; - Proxy->Metrics->AddOutputBuffersTotalSize(dataSize); - if (!wasWorking) { - // this channel has returned to work -- it was empty and this we have just put first event in the queue - ChannelScheduler->AddToHeap(oChannel, EqualizeCounter); - } - - SetOutputStuckFlag(true); - ++NumEventsInQueue; - RearmCloseOnIdle(); - - LWTRACK(EnqueueEvent, event->Orbit, Proxy->PeerNodeId, NumEventsInQueue, GetWriteBlockedTotal(), evChannel, oChannel.GetQueueSize(), oChannel.GetBufferedAmountOfData()); - - // check for overloaded queues - ui64 sendBufferDieLimit = Proxy->Common->Settings.SendBufferDieLimitInMB * ui64(1 << 20); - if (sendBufferDieLimit != 0 && TotalOutputQueueSize > sendBufferDieLimit) { - LOG_ERROR_IC_SESSION("ICS03", "socket: %" PRIi64 " output queue is overloaded, actual %" PRIu64 " bytes, limit is %" PRIu64, - Socket ? i64(*Socket) : -1, TotalOutputQueueSize, sendBufferDieLimit); - return Terminate(TDisconnectReason::QueueOverload()); - } - - ui64 outputBuffersTotalSizeLimit = Proxy->Common->Settings.OutputBuffersTotalSizeLimitInMB * ui64(1 << 20); - if (outputBuffersTotalSizeLimit != 0 && static_cast<ui64>(Proxy->Metrics->GetOutputBuffersTotalSize()) > outputBuffersTotalSizeLimit) { - LOG_ERROR_IC_SESSION("ICS77", "Exceeded total limit on output buffers size"); - if (AtomicTryLock(&Proxy->Common->StartedSessionKiller)) { - CreateSessionKillingActor(Proxy->Common); - } - } - - IssueRam(true); - } - - void TInterconnectSessionTCP::Subscribe(STATEFN_SIG) { - LOG_DEBUG_IC_SESSION("ICS04", "subscribe for session state for %s", ev->Sender.ToString().data()); - const auto [it, inserted] = Subscribers.emplace(ev->Sender, ev->Cookie); - if (inserted) { - Proxy->Metrics->IncSubscribersCount(); - } else { - it->second = ev->Cookie; - } - Send(ev->Sender, new TEvInterconnect::TEvNodeConnected(Proxy->PeerNodeId), 0, ev->Cookie); - } - - void TInterconnectSessionTCP::Unsubscribe(STATEFN_SIG) { - LOG_DEBUG_IC_SESSION("ICS05", "unsubscribe for session state for %s", ev->Sender.ToString().data()); - Proxy->Metrics->SubSubscribersCount( Subscribers.erase(ev->Sender)); - } - - THolder<TEvHandshakeAck> TInterconnectSessionTCP::ProcessHandshakeRequest(TEvHandshakeAsk::TPtr& ev) { - TEvHandshakeAsk *msg = ev->Get(); - - // close existing input session, if any, and do nothing upon its destruction - ReestablishConnection({}, false, TDisconnectReason::NewSession()); - const ui64 lastInputSerial = ReceiveContext->LockLastPacketSerialToConfirm(); - - LOG_INFO_IC_SESSION("ICS08", "incoming handshake Self# %s Peer# %s Counter# %" PRIu64 " LastInputSerial# %" PRIu64, - msg->Self.ToString().data(), msg->Peer.ToString().data(), msg->Counter, lastInputSerial); - - return MakeHolder<TEvHandshakeAck>(msg->Peer, lastInputSerial, Params); - } - - void TInterconnectSessionTCP::SetNewConnection(TEvHandshakeDone::TPtr& ev) { - if (ReceiverId) { - // upon destruction of input session actor invoke this callback again - ReestablishConnection(std::move(ev), false, TDisconnectReason::NewSession()); - return; - } - - LOG_INFO_IC_SESSION("ICS09", "handshake done sender: %s self: %s peer: %s socket: %" PRIi64, - ev->Sender.ToString().data(), ev->Get()->Self.ToString().data(), ev->Get()->Peer.ToString().data(), - i64(*ev->Get()->Socket)); - - NewConnectionSet = TActivationContext::Now(); - BytesWrittenToSocket = 0; - - SendBufferSize = ev->Get()->Socket->GetSendBufferSize(); - Socket = std::move(ev->Get()->Socket); - XdcSocket = std::move(ev->Get()->XdcSocket); - - // there may be a race - const ui64 nextPacket = Max(LastConfirmed, ev->Get()->NextPacket); - - // arm watchdogs - RearmCloseOnIdle(); - - // reset activity timestamps - LastInputActivityTimestamp = LastPayloadActivityTimestamp = TActivationContext::Monotonic(); - - LOG_INFO_IC_SESSION("ICS10", "traffic start"); - - // reset parameters to initial values - WriteBlockedByFullSendBuffer = false; - ReceiveContext->MainWriteBlocked = false; - ReceiveContext->XdcWriteBlocked = false; - ReceiveContext->MainReadPending = false; - ReceiveContext->XdcReadPending = false; - - // create input session actor - ReceiveContext->UnlockLastPacketSerialToConfirm(); - auto actor = MakeHolder<TInputSessionTCP>(SelfId(), Socket, XdcSocket, ReceiveContext, Proxy->Common, - Proxy->Metrics, Proxy->PeerNodeId, nextPacket, GetDeadPeerTimeout(), Params); - ReceiverId = RegisterWithSameMailbox(actor.Release()); - - // register our socket in poller actor - LOG_DEBUG_IC_SESSION("ICS11", "registering socket in PollerActor"); - const bool success = Send(MakePollerActorId(), new TEvPollerRegister(Socket, ReceiverId, SelfId())); - Y_ABORT_UNLESS(success); - if (XdcSocket) { - const bool success = Send(MakePollerActorId(), new TEvPollerRegister(XdcSocket, ReceiverId, SelfId())); - Y_ABORT_UNLESS(success); - } - - LostConnectionWatchdog.Disarm(); - Proxy->Metrics->SetConnected(1); - LOG_INFO(*TlsActivationContext, NActorsServices::INTERCONNECT_STATUS, "[%u] connected", Proxy->PeerNodeId); - - // arm pinger timer - ResetFlushLogic(); - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // REINITIALIZE SEND QUEUE - // - // scan through send queue and leave only those packets who have data -- we will simply resend them; drop all other - // auxiliary packets; also reset packet metrics to zero to start sending from the beginning - // also reset send queue - - // drop confirmed packets first as we do not need unwanted retransmissions - OutgoingStream.RewindToEnd(); - XdcStream.RewindToEnd(); - XdcOffset = Max<size_t>(); - OutgoingOffset = 0; - OutgoingIndex = SendQueue.size(); - DropConfirmed(nextPacket); - OutgoingStream.Rewind(); - OutOfBandStream = {}; - XdcStream.Rewind(); - OutgoingOffset = XdcOffset = 0; - OutgoingIndex = 0; - ForcedWriteLength = 0; - - const ui64 serial = OutputCounter - SendQueue.size() + 1; - Y_ABORT_UNLESS(serial > LastConfirmed, "%s serial# %" PRIu64 " LastConfirmed# %" PRIu64, LogPrefix.data(), serial, LastConfirmed); - LOG_DEBUG_IC_SESSION("ICS06", "rewind SendQueue size# %zu LastConfirmed# %" PRIu64 " NextSerial# %" PRIu64, - SendQueue.size(), LastConfirmed, serial); - - SwitchStuckPeriod(); - - LastHandshakeDone = TActivationContext::Now(); - - GenerateTraffic(); - } - - void TInterconnectSessionTCP::Handle(TEvUpdateFromInputSession::TPtr& ev) { - if (ev->Sender == ReceiverId) { - TEvUpdateFromInputSession& msg = *ev->Get(); - - // update ping time - Ping = msg.Ping; - LWPROBE(UpdateFromInputSession, Proxy->PeerNodeId, Ping.MillisecondsFloat()); - - bool needConfirm = false; - - // update activity timer for dead peer checker - LastInputActivityTimestamp = TActivationContext::Monotonic(); - - if (msg.NumDataBytes) { - UnconfirmedBytes += msg.NumDataBytes; - if (UnconfirmedBytes >= GetTotalInflightAmountOfData() / 4) { - needConfirm = true; - } else { - SetForcePacketTimestamp(Proxy->Common->Settings.ForceConfirmPeriod); - } - - // reset payload watchdog that controls close-on-idle behaviour - LastPayloadActivityTimestamp = TActivationContext::Monotonic(); - RearmCloseOnIdle(); - } - - LWPROBE_IF_TOO_LONG(SlowICDropConfirmed, Proxy->PeerNodeId, ms) { - DropConfirmed(msg.ConfirmedByInput); - } - - // if we haven't generated any packets, then make a lone Flush packet without any data - if (needConfirm && Socket) { - ++ConfirmPacketsForcedBySize; - MakePacket(false); - } - - GenerateTraffic(); - - for (;;) { - switch (EUpdateState state = ReceiveContext->UpdateState) { - case EUpdateState::NONE: - case EUpdateState::CONFIRMING: - Y_ABORT("unexpected state"); - - case EUpdateState::INFLIGHT: - // this message we are processing was the only one in flight, so we can reset state to NONE here - if (ReceiveContext->UpdateState.compare_exchange_weak(state, EUpdateState::NONE)) { - return; - } - break; - - case EUpdateState::INFLIGHT_AND_PENDING: - // there is more messages pending from the input session actor, so we have to inform it to release - // that message - if (ReceiveContext->UpdateState.compare_exchange_weak(state, EUpdateState::CONFIRMING)) { - Send(ev->Sender, new TEvConfirmUpdate); - return; - } - break; - } - } - } - } - - void TInterconnectSessionTCP::IssueRam(bool batching) { - const auto& batchPeriod = Proxy->Common->Settings.BatchPeriod; - if (!RamInQueue || (!batching && RamInQueue->Batching && batchPeriod != TDuration())) { - auto ev = std::make_unique<TEvRam>(batching); - RamInQueue = ev.get(); - auto handle = std::make_unique<IEventHandle>(SelfId(), SelfId(), ev.release()); - if (batching && batchPeriod != TDuration()) { - TActivationContext::Schedule(batchPeriod, handle.release()); - } else { - TActivationContext::Send(handle.release()); - } - LWPROBE(StartRam, Proxy->PeerNodeId); - RamStartedCycles = GetCycleCountFast(); - } - } - - void TInterconnectSessionTCP::HandleRam(TEvRam::TPtr& ev) { - if (ev->Get() == RamInQueue) { - LWPROBE(FinishRam, Proxy->PeerNodeId, NHPTimer::GetSeconds(GetCycleCountFast() - ev->SendTime) * 1000.0); - RamInQueue = nullptr; - GenerateTraffic(); - } - } - - void TInterconnectSessionTCP::GenerateTraffic() { - if (!TimeLimit) { - TimeLimit.emplace(GetMaxCyclesPerEvent()); - } - - // generate ping request, if needed - IssuePingRequest(); - - while (Socket) { - ProducePackets(); - if (!Socket) { - return; - } - - WriteData(); - if (!Socket) { - return; - } - - bool canProducePackets; - bool canWriteData; - - canProducePackets = NumEventsInQueue && InflightDataAmount < GetTotalInflightAmountOfData() && - GetUnsentSize() < GetUnsentLimit(); - - canWriteData = ((OutgoingStream || OutOfBandStream) && !ReceiveContext->MainWriteBlocked) || - (XdcStream && !ReceiveContext->XdcWriteBlocked); - - if (!canProducePackets && !canWriteData) { - SetEnoughCpu(true); // we do not starve - break; - } else if (TimeLimit->CheckExceeded()) { - SetEnoughCpu(false); - IssueRam(false); - break; - } - } - - // account traffic changes - ChannelScheduler->ForEach([](TEventOutputChannel& channel) { - channel.AccountTraffic(); - }); - - // equalize channel weights - EqualizeCounter += ChannelScheduler->Equalize(); - } - - void TInterconnectSessionTCP::ProducePackets() { - // first, we create as many data packets as we can generate under certain conditions; they include presence - // of events in channels queues and in flight fitting into requested limit; after we hit one of these conditions - // we exit cycle - static constexpr ui32 maxBytesToProduce = 64 * 1024; - ui32 bytesProduced = 0; - while (NumEventsInQueue && InflightDataAmount < GetTotalInflightAmountOfData() && GetUnsentSize() < GetUnsentLimit()) { - if ((bytesProduced && TimeLimit->CheckExceeded()) || bytesProduced >= maxBytesToProduce) { - break; - } - try { - bytesProduced += MakePacket(true); - } catch (const TExSerializedEventTooLarge& ex) { - // terminate session if the event can't be serialized properly - LOG_CRIT_IC("ICS31", "serialized event Type# 0x%08" PRIx32 " is too large", ex.Type); - return Terminate(TDisconnectReason::EventTooLarge()); - } - } - } - - void TInterconnectSessionTCP::StartHandshake() { - LOG_INFO_IC_SESSION("ICS15", "start handshake"); - IActor::InvokeOtherActor(*Proxy, &TInterconnectProxyTCP::StartResumeHandshake, ReceiveContext->LockLastPacketSerialToConfirm()); - } - - void TInterconnectSessionTCP::ReestablishConnectionWithHandshake(TDisconnectReason reason) { - ReestablishConnection({}, true, std::move(reason)); - } - - void TInterconnectSessionTCP::ReestablishConnection(TEvHandshakeDone::TPtr&& ev, bool startHandshakeOnSessionClose, - TDisconnectReason reason) { - if (Socket) { - LOG_INFO_IC_SESSION("ICS13", "reestablish connection"); - ShutdownSocket(std::move(reason)); // stop sending/receiving on socket - PendingHandshakeDoneEvent = std::move(ev); - StartHandshakeOnSessionClose = startHandshakeOnSessionClose; - if (!ReceiverId) { - ReestablishConnectionExecute(); - } - } - } - - void TInterconnectSessionTCP::OnDisconnect(TEvSocketDisconnect::TPtr& ev) { - if (ev->Sender == ReceiverId) { - if (ev->Get()->Reason == TDisconnectReason::EndOfStream() && !NumEventsInQueue && OutputCounter == LastConfirmed) { - return Terminate(ev->Get()->Reason); - } - - const bool wasConnected(Socket); - LOG_INFO_IC_SESSION("ICS07", "socket disconnect %" PRIi64 " reason# %s", Socket ? i64(*Socket) : -1, ev->Get()->Reason.ToString().data()); - ReceiverId = TActorId(); // reset receiver actor id as we have no more receiver yet - if (wasConnected) { - // we were sucessfully connected and did not expect failure, so it arrived from the input side; we should - // restart handshake process, closing our part of socket first - ShutdownSocket(ev->Get()->Reason); - StartHandshake(); - } else { - ReestablishConnectionExecute(); - } - } - } - - void TInterconnectSessionTCP::ShutdownSocket(TDisconnectReason reason) { - if (Socket) { - if (const TString& s = reason.ToString()) { - Proxy->Metrics->IncDisconnectByReason(s); - } - - LOG_INFO_IC_SESSION("ICS25", "shutdown socket, reason# %s", reason.ToString().data()); - Proxy->UpdateErrorStateLog(TActivationContext::Now(), "close_socket", reason.ToString().data()); - Socket->Shutdown(SHUT_RDWR); - Socket.Reset(); - Proxy->Metrics->IncDisconnections(); - CloseOnIdleWatchdog.Disarm(); - LostConnectionWatchdog.Rearm(SelfId()); - Proxy->Metrics->SetConnected(0); - LOG_INFO(*TlsActivationContext, NActorsServices::INTERCONNECT_STATUS, "[%u] disconnected", Proxy->PeerNodeId); - } - if (XdcSocket) { - XdcSocket->Shutdown(SHUT_RDWR); - XdcSocket.Reset(); - } - } - - void TInterconnectSessionTCP::ReestablishConnectionExecute() { - bool startHandshakeOnSessionClose = std::exchange(StartHandshakeOnSessionClose, false); - TEvHandshakeDone::TPtr ev = std::move(PendingHandshakeDoneEvent); - - if (startHandshakeOnSessionClose) { - StartHandshake(); - } else if (ev) { - SetNewConnection(ev); - } - } - - void TInterconnectSessionTCP::Handle(TEvPollerReady::TPtr& ev) { - LOG_DEBUG_IC_SESSION("ICS29", "HandleReadyWrite WriteBlockedByFullSendBuffer# %s", - WriteBlockedByFullSendBuffer ? "true" : "false"); - - auto *msg = ev->Get(); - bool useful = false; - bool readPending = false; - - if (msg->Socket == Socket) { - useful = std::exchange(ReceiveContext->MainWriteBlocked, false); - readPending = ReceiveContext->MainReadPending; - } else if (msg->Socket == XdcSocket) { - useful = std::exchange(ReceiveContext->XdcWriteBlocked, false); - readPending = ReceiveContext->XdcReadPending; - } - - if (useful) { - Proxy->Metrics->IncUsefulWriteWakeups(); - } else if (!ev->Cookie) { - Proxy->Metrics->IncSpuriousWriteWakeups(); - } - - if (Params.Encryption && readPending && ev->Sender != ReceiverId) { - Send(ReceiverId, ev->Release().Release()); - } - - GenerateTraffic(); - } - - void TInterconnectSessionTCP::Handle(TEvPollerRegisterResult::TPtr ev) { - auto *msg = ev->Get(); - bool sendPollerReady = false; - - if (msg->Socket == Socket) { - PollerToken = std::move(msg->PollerToken); - sendPollerReady = ReceiveContext->MainWriteBlocked; - } else if (msg->Socket == XdcSocket) { - XdcPollerToken = std::move(msg->PollerToken); - sendPollerReady = ReceiveContext->XdcWriteBlocked; - } - - if (sendPollerReady) { - Send(SelfId(), new TEvPollerReady(msg->Socket, false, true)); - } - } - - void TInterconnectSessionTCP::WriteData() { - // total bytes written during this call - ui64 written = 0; - - auto process = [&](NInterconnect::TOutgoingStream& stream, const TIntrusivePtr<NInterconnect::TStreamSocket>& socket, - const TPollerToken::TPtr& token, bool *writeBlocked, size_t maxBytes) { - size_t totalWritten = 0; - - if (stream && socket && !*writeBlocked) { - for (;;) { - if (const ssize_t r = Write(stream, *socket, maxBytes); r > 0) { - stream.Advance(r); - totalWritten += r; - } else if (r == -1) { - if (token && socket->RequestWriteNotificationAfterWouldBlock(*token)) { - continue; // we can try again - } - *writeBlocked = true; - } else if (r == 0) { - // error condition - } else { - Y_UNREACHABLE(); - } - break; - } - } - - written += totalWritten; - return totalWritten; - }; - - auto sendQueueIt = SendQueue.begin() + OutgoingIndex; - static constexpr size_t maxBytesAtOnce = 256 * 1024; - size_t bytesToSendInMain = maxBytesAtOnce; - - Y_DEBUG_ABORT_UNLESS(OutgoingIndex < SendQueue.size() || (OutgoingIndex == SendQueue.size() && !OutgoingOffset && !OutgoingStream)); - - if (OutOfBandStream) { - bytesToSendInMain = 0; - - if (!ForcedWriteLength && OutgoingOffset) { - ForcedWriteLength = 1; // send at least one byte from current packet - } - - // align send up to packet boundary - size_t offset = OutgoingOffset; - for (auto it = sendQueueIt; ForcedWriteLength; ++it, offset = 0) { - Y_DEBUG_ABORT_UNLESS(it != SendQueue.end()); - bytesToSendInMain += it->PacketSize - offset; // send remainder of current packet - ForcedWriteLength -= Min(it->PacketSize - offset, ForcedWriteLength); - } - } - - if (bytesToSendInMain) { - const size_t w = process(OutgoingStream, Socket, PollerToken, &ReceiveContext->MainWriteBlocked, bytesToSendInMain); - - // adjust sending queue iterator - for (OutgoingOffset += w; OutgoingOffset && sendQueueIt->PacketSize <= OutgoingOffset; ++sendQueueIt, ++OutgoingIndex) { - OutgoingOffset -= sendQueueIt->PacketSize; - } - - BytesWrittenToSocket += w; - - if (OutOfBandStream) { - BytesAlignedForOutOfBand += w; - bytesToSendInMain -= w; - } - - ForcedWriteLength = Socket ? Socket->ExpectedWriteLength() : 0; - } - - if (!bytesToSendInMain && !ForcedWriteLength) { - if (const size_t w = process(OutOfBandStream, Socket, PollerToken, &ReceiveContext->MainWriteBlocked, maxBytesAtOnce)) { - OutOfBandStream.DropFront(w); - BytesWrittenToSocket += w; - OutOfBandBytesSent += w; - } - } - - if (const size_t w = process(XdcStream, XdcSocket, XdcPollerToken, &ReceiveContext->XdcWriteBlocked, maxBytesAtOnce)) { - XdcBytesSent += w; - XdcOffset += w; - } - - if (written) { - Proxy->Metrics->AddTotalBytesWritten(written); - } - - DropConfirmed(LastConfirmed); - - const bool writeBlockedByFullSendBuffer = ReceiveContext->MainWriteBlocked || ReceiveContext->XdcWriteBlocked; - if (WriteBlockedByFullSendBuffer < writeBlockedByFullSendBuffer) { // became blocked - WriteBlockedCycles = GetCycleCountFast(); - LOG_DEBUG_IC_SESSION("ICS18", "hit send buffer limit"); - } else if (writeBlockedByFullSendBuffer < WriteBlockedByFullSendBuffer) { // became unblocked - WriteBlockedTotal += TDuration::Seconds(NHPTimer::GetSeconds(GetCycleCountFast() - WriteBlockedCycles)); - } - WriteBlockedByFullSendBuffer = writeBlockedByFullSendBuffer; - } - - ssize_t TInterconnectSessionTCP::Write(NInterconnect::TOutgoingStream& stream, NInterconnect::TStreamSocket& socket, - size_t maxBytes) { - LWPROBE_IF_TOO_LONG(SlowICWriteData, Proxy->PeerNodeId, ms) { - constexpr ui32 iovLimit = 256; - - ui32 maxElementsInIOV; - if (Params.Encryption) { - maxElementsInIOV = 1; - } else { -#if defined(_win_) - maxElementsInIOV = 1; -#elif defined(_linux_) - maxElementsInIOV = Min<ui32>(iovLimit, sysconf(_SC_IOV_MAX)); -#else - maxElementsInIOV = 64; -#endif - } - - TStackVec<TConstIoVec, iovLimit> wbuffers; - - stream.ProduceIoVec(wbuffers, maxElementsInIOV, maxBytes); - Y_ABORT_UNLESS(!wbuffers.empty()); - - TString err; - ssize_t r = 0; - { // issue syscall with timing - const ui64 begin = GetCycleCountFast(); - - do { - if (wbuffers.size() == 1) { - auto& front = wbuffers.front(); - r = socket.Send(front.Data, front.Size, &err); - } else { - r = socket.WriteV(reinterpret_cast<const iovec*>(wbuffers.data()), wbuffers.size()); - } - } while (r == -EINTR); - - const ui64 end = GetCycleCountFast(); - Proxy->Metrics->IncSendSyscalls((end - begin) * 1'000'000 / GetCyclesPerMillisecond()); - } - - if (r > 0) { - return r; - } else if (-r != EAGAIN && -r != EWOULDBLOCK) { - const TString message = r == 0 ? "connection closed by peer" - : err ? err - : Sprintf("socket: %s", strerror(-r)); - LOG_NOTICE_NET(Proxy->PeerNodeId, "%s", message.data()); - if (r == 0 && !NumEventsInQueue && LastConfirmed == OutputCounter) { - Terminate(TDisconnectReason::EndOfStream()); - } else { - ReestablishConnectionWithHandshake(r == 0 ? TDisconnectReason::EndOfStream() : TDisconnectReason::FromErrno(-r)); - } - return 0; // error indicator - } else { - return -1; // temporary error - } - } - - Y_UNREACHABLE(); - } - - void TInterconnectSessionTCP::SetForcePacketTimestamp(TDuration period) { - if (period != TDuration::Max()) { - // randomize period a bit - period = TDuration::FromValue(period.GetValue() - RandomNumber<ui64>(period.GetValue() / 10)); - const TMonotonic when = TActivationContext::Monotonic() + period; - if (when < ForcePacketTimestamp) { - ForcePacketTimestamp = when; - ScheduleFlush(); - } - } - } - - void TInterconnectSessionTCP::ScheduleFlush() { - if (FlushSchedule.empty() || ForcePacketTimestamp < FlushSchedule.top()) { - Schedule(ForcePacketTimestamp, new TEvFlush); - FlushSchedule.push(ForcePacketTimestamp); - MaxFlushSchedule = Max(MaxFlushSchedule, FlushSchedule.size()); - ++FlushEventsScheduled; - } - } - - void TInterconnectSessionTCP::HandleFlush() { - const TMonotonic now = TActivationContext::Monotonic(); - while (FlushSchedule && now >= FlushSchedule.top()) { - FlushSchedule.pop(); - } - if (Socket) { - if (now >= ForcePacketTimestamp) { - ++ConfirmPacketsForcedByTimeout; - ++FlushEventsProcessed; - MakePacket(false); // just generate confirmation packet if we have preconditions for this - } else if (ForcePacketTimestamp != TMonotonic::Max()) { - ScheduleFlush(); - } - GenerateTraffic(); - } - } - - void TInterconnectSessionTCP::ResetFlushLogic() { - ForcePacketTimestamp = TMonotonic::Max(); - UnconfirmedBytes = 0; - const TDuration ping = Proxy->Common->Settings.PingPeriod; - if (ping != TDuration::Zero() && !NumEventsInQueue) { - SetForcePacketTimestamp(ping); - } - } - - ui32 TInterconnectSessionTCP::MakePacket(bool data, TMaybe<ui64> pingMask) { - NInterconnect::TOutgoingStream& stream = data ? OutgoingStream : OutOfBandStream; - -#ifndef NDEBUG - const size_t outgoingStreamSizeBefore = stream.CalculateOutgoingSize(); - const size_t xdcStreamSizeBefore = XdcStream.CalculateOutgoingSize(); -#endif - - stream.Align(); - XdcStream.Align(); - - TTcpPacketOutTask packet(Params, stream, XdcStream); - ui64 serial = 0; - - if (data) { - // generate serial for this data packet - serial = ++OutputCounter; - - // fill the data packet - Y_ABORT_UNLESS(NumEventsInQueue); - LWPROBE_IF_TOO_LONG(SlowICFillSendingBuffer, Proxy->PeerNodeId, ms) { - FillSendingBuffer(packet, serial); - } - Y_ABORT_UNLESS(!packet.IsEmpty()); - - InflightDataAmount += packet.GetDataSize(); - Proxy->Metrics->AddInflightDataAmount(packet.GetDataSize()); - if (InflightDataAmount > GetTotalInflightAmountOfData()) { - Proxy->Metrics->IncInflyLimitReach(); - } - - if (AtomicGet(ReceiveContext->ControlPacketId) == 0) { - AtomicSet(ReceiveContext->ControlPacketSendTimer, GetCycleCountFast()); - AtomicSet(ReceiveContext->ControlPacketId, OutputCounter); - } - - // update payload activity timer - LastPayloadActivityTimestamp = TActivationContext::Monotonic(); - } else if (pingMask) { - serial = *pingMask; - } - - const ui64 lastInputSerial = ReceiveContext->GetLastPacketSerialToConfirm(); - - packet.Finish(serial, lastInputSerial); - - // count number of bytes pending for write - const size_t packetSize = packet.GetPacketSize(); - -#ifndef NDEBUG - const size_t outgoingStreamSizeAfter = stream.CalculateOutgoingSize(); - const size_t xdcStreamSizeAfter = XdcStream.CalculateOutgoingSize(); - - Y_ABORT_UNLESS(outgoingStreamSizeAfter == outgoingStreamSizeBefore + packetSize && - xdcStreamSizeAfter == xdcStreamSizeBefore + packet.GetExternalSize(), - "outgoingStreamSizeBefore# %zu outgoingStreamSizeAfter# %zu packetSize# %zu" - " xdcStreamSizeBefore# %zu xdcStreamSizeAfter# %zu externalSize# %" PRIu32, - outgoingStreamSizeBefore, outgoingStreamSizeAfter, packetSize, - xdcStreamSizeBefore, xdcStreamSizeAfter, packet.GetExternalSize()); -#endif - - // put outgoing packet metadata here - if (data) { - SendQueue.push_back(TOutgoingPacket{ - static_cast<ui32>(packetSize), - static_cast<ui32>(packet.GetExternalSize()) - }); - } - - LOG_DEBUG_IC_SESSION("ICS22", "outgoing packet Serial# %" PRIu64 " Confirm# %" PRIu64 " DataSize# %" PRIu32 - " InflightDataAmount# %" PRIu64, serial, lastInputSerial, packet.GetDataSize(), InflightDataAmount); - - // reset forced packet sending timestamp as we have confirmed all received data - ResetFlushLogic(); - - ++PacketsGenerated; - - return packetSize; - } - - void TInterconnectSessionTCP::DropConfirmed(ui64 confirm) { - LOG_DEBUG_IC_SESSION("ICS23", "confirm count: %" PRIu64, confirm); - - Y_ABORT_UNLESS(LastConfirmed <= confirm && confirm <= OutputCounter, - "%s confirm# %" PRIu64 " LastConfirmed# %" PRIu64 " OutputCounter# %" PRIu64, - LogPrefix.data(), confirm, LastConfirmed, OutputCounter); - LastConfirmed = confirm; - - std::optional<ui64> lastDroppedSerial; - ui32 numDropped = 0; - - // drop confirmed packets; this also includes any auxiliary packets as their serial is set to zero, effectively - // making Serial <= confirm true - size_t bytesDropped = 0; - size_t bytesDroppedFromXdc = 0; - ui64 frontPacketSerial = OutputCounter - SendQueue.size() + 1; - Y_DEBUG_ABORT_UNLESS(OutgoingIndex < SendQueue.size() || (OutgoingIndex == SendQueue.size() && !OutgoingOffset && !OutgoingStream), - "OutgoingIndex# %zu SendQueue.size# %zu OutgoingOffset# %zu Unsent# %zu Total# %zu", - OutgoingIndex, SendQueue.size(), OutgoingOffset, OutgoingStream.CalculateUnsentSize(), - OutgoingStream.CalculateOutgoingSize()); - while (OutgoingIndex && frontPacketSerial <= confirm && SendQueue.front().ExternalSize <= XdcOffset) { - auto& front = SendQueue.front(); - lastDroppedSerial.emplace(frontPacketSerial); - XdcOffset -= front.ExternalSize; - bytesDropped += front.PacketSize; - bytesDroppedFromXdc += front.ExternalSize; - ++numDropped; - - ++frontPacketSerial; - SendQueue.pop_front(); - --OutgoingIndex; - } - - if (!numDropped) { - return; - } - - const ui64 droppedDataAmount = bytesDropped + bytesDroppedFromXdc - sizeof(TTcpPacketHeader_v2) * numDropped; - OutgoingStream.DropFront(bytesDropped); - XdcStream.DropFront(bytesDroppedFromXdc); - if (lastDroppedSerial) { - ChannelScheduler->ForEach([&](TEventOutputChannel& channel) { - channel.DropConfirmed(*lastDroppedSerial); - }); - } - - PacketsConfirmed += numDropped; - InflightDataAmount -= droppedDataAmount; - Proxy->Metrics->SubInflightDataAmount(droppedDataAmount); - LWPROBE(DropConfirmed, Proxy->PeerNodeId, droppedDataAmount, InflightDataAmount); - - LOG_DEBUG_IC_SESSION("ICS24", "exit InflightDataAmount: %" PRIu64 " bytes droppedDataAmount: %" PRIu64 " bytes" - " dropped %" PRIu32 " packets", InflightDataAmount, droppedDataAmount, numDropped); - - Pool->Trim(); // send any unsent free requests - - RearmCloseOnIdle(); - } - - void TInterconnectSessionTCP::FillSendingBuffer(TTcpPacketOutTask& task, ui64 serial) { - ui32 bytesGenerated = 0; - - Y_ABORT_UNLESS(NumEventsInQueue); - while (NumEventsInQueue) { - TEventOutputChannel *channel = ChannelScheduler->PickChannelWithLeastConsumedWeight(); - Y_DEBUG_ABORT_UNLESS(!channel->IsEmpty()); - - // generate some data within this channel - const ui64 netBefore = channel->GetBufferedAmountOfData(); - ui64 gross = 0; - const bool eventDone = channel->FeedBuf(task, serial, &gross); - channel->UnaccountedTraffic += gross; - const ui64 netAfter = channel->GetBufferedAmountOfData(); - Y_DEBUG_ABORT_UNLESS(netAfter <= netBefore); // net amount should shrink - const ui64 net = netBefore - netAfter; // number of net bytes serialized - - // adjust metrics for local and global queue size - TotalOutputQueueSize -= net; - Proxy->Metrics->SubOutputBuffersTotalSize(net); - bytesGenerated += gross; - Y_DEBUG_ABORT_UNLESS(!!net == !!gross && gross >= net, "net# %" PRIu64 " gross# %" PRIu64, net, gross); - - // return it back to queue or delete, depending on whether this channel is still working or not - ChannelScheduler->FinishPick(gross, EqualizeCounter); - - // update some stats if the packet was fully serialized - if (eventDone) { - ++MessagesWrittenToBuffer; - - Y_ABORT_UNLESS(NumEventsInQueue); - --NumEventsInQueue; - - if (!NumEventsInQueue) { - SetOutputStuckFlag(false); - } - } - - if (!gross) { // no progress -- almost full packet buffer - break; - } - } - - Y_ABORT_UNLESS(bytesGenerated); // ensure we are not stalled in serialization - } - - ui32 TInterconnectSessionTCP::CalculateQueueUtilization() { - SwitchStuckPeriod(); - ui64 sumBusy = 0, sumPeriod = 0; - for (auto iter = OutputQueueUtilization.begin(); iter != OutputQueueUtilization.end() - 1; ++iter) { - sumBusy += iter->first; - sumPeriod += iter->second; - } - return sumBusy * 1000000 / sumPeriod; - } - - void TInterconnectSessionTCP::SendUpdateToWhiteboard(bool connected) { - const ui32 utilization = Socket ? CalculateQueueUtilization() : 0; - - if (const auto& callback = Proxy->Common->UpdateWhiteboard) { - enum class EFlag { - GREEN, - YELLOW, - ORANGE, - RED, - }; - EFlag flagState = EFlag::RED; - - if (Socket) { - flagState = EFlag::GREEN; - - do { - auto lastInputDelay = TActivationContext::Monotonic() - LastInputActivityTimestamp; - if (lastInputDelay * 4 >= GetDeadPeerTimeout() * 3) { - flagState = EFlag::ORANGE; - break; - } else if (lastInputDelay * 2 >= GetDeadPeerTimeout()) { - flagState = EFlag::YELLOW; - } - - // check utilization - if (utilization > 875000) { // 7/8 - flagState = EFlag::ORANGE; - break; - } else if (utilization > 500000) { // 1/2 - flagState = EFlag::YELLOW; - } - } while (false); - } - - callback({TlsActivationContext->ExecutorThread.ActorSystem, - Proxy->PeerNodeId, - Proxy->Metrics->GetHumanFriendlyPeerHostName(), - connected, - flagState == EFlag::GREEN, - flagState == EFlag::YELLOW, - flagState == EFlag::ORANGE, - flagState == EFlag::RED, - ReceiveContext->ClockSkew_us.load()}); - } - - if (connected) { - Schedule(TDuration::Seconds(1), new TEvents::TEvWakeup); - } - } - - void TInterconnectSessionTCP::SetOutputStuckFlag(bool state) { - if (OutputStuckFlag == state) - return; - - if (OutputQueueUtilization.Size() == 0) - return; - - auto& lastpair = OutputQueueUtilization.Last(); - if (state) - lastpair.first -= GetCycleCountFast(); - else - lastpair.first += GetCycleCountFast(); - - OutputStuckFlag = state; - } - - void TInterconnectSessionTCP::SwitchStuckPeriod() { - auto now = GetCycleCountFast(); - if (OutputQueueUtilization.Size() != 0) { - auto& lastpair = OutputQueueUtilization.Last(); - lastpair.second = now - lastpair.second; - if (OutputStuckFlag) - lastpair.first += now; - } - - OutputQueueUtilization.Push(std::pair<ui64, ui64>(0, now)); - if (OutputStuckFlag) - OutputQueueUtilization.Last().first -= now; - } - - TDuration TInterconnectSessionTCP::GetDeadPeerTimeout() const { - return Coalesce(Proxy->Common->Settings.DeadPeer, DEFAULT_DEADPEER_TIMEOUT); - } - - TDuration TInterconnectSessionTCP::GetCloseOnIdleTimeout() const { - return Proxy->Common->Settings.CloseOnIdle; - } - - TDuration TInterconnectSessionTCP::GetLostConnectionTimeout() const { - return Coalesce(Proxy->Common->Settings.LostConnection, DEFAULT_LOST_CONNECTION_TIMEOUT); - } - - ui32 TInterconnectSessionTCP::GetTotalInflightAmountOfData() const { - return Coalesce(Proxy->Common->Settings.TotalInflightAmountOfData, DEFAULT_TOTAL_INFLIGHT_DATA); - } - - ui64 TInterconnectSessionTCP::GetMaxCyclesPerEvent() const { - return DurationToCycles(TDuration::MicroSeconds(50)); - } - - void TInterconnectSessionTCP::IssuePingRequest() { - const TMonotonic now = TActivationContext::Monotonic(); - if (now >= LastPingTimestamp + PingPeriodicity) { - LOG_DEBUG_IC_SESSION("ICS00", "Issuing ping request"); - if (Socket) { - MakePacket(false, GetCycleCountFast() | TTcpPacketBuf::PingRequestMask); - MakePacket(false, TInstant::Now().MicroSeconds() | TTcpPacketBuf::ClockMask); - } - LastPingTimestamp = now; - } - } - - void TInterconnectSessionTCP::Handle(TEvProcessPingRequest::TPtr ev) { - if (Socket) { - MakePacket(false, ev->Get()->Payload | TTcpPacketBuf::PingResponseMask); - GenerateTraffic(); - } - } - - void TInterconnectSessionTCP::GenerateHttpInfo(NMon::TEvHttpInfoRes::TPtr& ev) { - TStringStream str; - ev->Get()->Output(str); - - HTML(str) { - DIV_CLASS("panel panel-info") { - DIV_CLASS("panel-heading") { - str << "Session"; - } - DIV_CLASS("panel-body") { - TABLE_CLASS("table") { - TABLEHEAD() { - TABLER() { - TABLEH() { - str << "Sensor"; - } - TABLEH() { - str << "Value"; - } - } - } - TABLEBODY() { - TABLER() { - TABLED() { - str << "Encryption"; - } - TABLED() { - str << (Params.Encryption ? "<font color=green>Enabled</font>" : "<font color=red>Disabled</font>"); - } - } - if (auto *x = dynamic_cast<NInterconnect::TSecureSocket*>(Socket.Get())) { - TABLER() { - TABLED() { - str << "Cipher name"; - } - TABLED() { - str << x->GetCipherName(); - } - } - TABLER() { - TABLED() { - str << "Cipher bits"; - } - TABLED() { - str << x->GetCipherBits(); - } - } - TABLER() { - TABLED() { - str << "Protocol"; - } - TABLED() { - str << x->GetProtocolName(); - } - } - TABLER() { - TABLED() { - str << "Peer CN"; - } - TABLED() { - str << x->GetPeerCommonName(); - } - } - } - TABLER() { - TABLED() { str << "AuthOnly CN"; } - TABLED() { str << Params.AuthCN; } - } - TABLER() { - TABLED() { - str << "Local scope id"; - } - TABLED() { - str << ScopeIdToString(Proxy->Common->LocalScopeId); - } - } - TABLER() { - TABLED() { - str << "Peer scope id"; - } - TABLED() { - str << ScopeIdToString(Params.PeerScopeId); - } - } - TABLER() { - TABLED() { - str << "This page generated at"; - } - TABLED() { - str << TActivationContext::Now() << " / " << Now(); - } - } - TABLER() { - TABLED() { - str << "SelfID"; - } - TABLED() { - str << SelfId().ToString(); - } - } - TABLER() { - TABLED() { str << "Frame version/Checksum"; } - TABLED() { str << (Params.Encryption ? "v2/none" : Params.UseXxhash ? "v2/xxhash" : "v2/crc32c"); } - } -#define MON_VAR(NAME) \ - TABLER() { \ - TABLED() { \ - str << #NAME; \ - } \ - TABLED() { \ - str << NAME; \ - } \ - } - - MON_VAR(Created) - MON_VAR(Params.UseExternalDataChannel) - MON_VAR(NewConnectionSet) - MON_VAR(ReceiverId) - MON_VAR(MessagesGot) - MON_VAR(MessagesWrittenToBuffer) - MON_VAR(PacketsGenerated) - MON_VAR(PacketsConfirmed) - MON_VAR(ConfirmPacketsForcedBySize) - MON_VAR(ConfirmPacketsForcedByTimeout) - - TABLER() { - TABLED() { - str << "Virtual self ID"; - } - TABLED() { - str << Proxy->SessionVirtualId.ToString(); - } - } - TABLER() { - TABLED() { - str << "Virtual peer ID"; - } - TABLED() { - str << Proxy->RemoteSessionVirtualId.ToString(); - } - } - TABLER() { - TABLED() { - str << "Socket"; - } - TABLED() { - str << (Socket ? i64(*Socket) : -1); - } - } - TABLER() { - TABLED() { - str << "XDC socket"; - } - TABLED() { - str << (XdcSocket ? i64(*XdcSocket) : -1); - } - } - - ui32 unsentQueueSize = Socket ? Socket->GetUnsentQueueSize() : 0; - - const TMonotonic now = TActivationContext::Monotonic(); - - MON_VAR(OutputStuckFlag) - MON_VAR(SendQueue.size()) - MON_VAR(NumEventsInQueue) - MON_VAR(TotalOutputQueueSize) - MON_VAR(InflightDataAmount) - MON_VAR(unsentQueueSize) - MON_VAR(SendBufferSize) - MON_VAR(now - LastInputActivityTimestamp) - MON_VAR(now - LastPayloadActivityTimestamp) - MON_VAR(LastHandshakeDone) - MON_VAR(OutputCounter) - MON_VAR(LastConfirmed) - MON_VAR(FlushSchedule.size()) - MON_VAR(MaxFlushSchedule) - MON_VAR(FlushEventsScheduled) - MON_VAR(FlushEventsProcessed) - - MON_VAR(GetWriteBlockedTotal()) - - MON_VAR(BytesWrittenToSocket) - MON_VAR(XdcBytesSent) - - MON_VAR(OutgoingStream.CalculateOutgoingSize()) - MON_VAR(OutgoingStream.CalculateUnsentSize()) - MON_VAR(OutgoingStream.GetSendQueueSize()) - MON_VAR(OutgoingOffset) - MON_VAR(OutgoingIndex) - - MON_VAR(OutOfBandStream.CalculateOutgoingSize()) - MON_VAR(OutOfBandStream.CalculateUnsentSize()) - MON_VAR(OutOfBandStream.GetSendQueueSize()) - MON_VAR(BytesAlignedForOutOfBand) - MON_VAR(OutOfBandBytesSent) - - MON_VAR(XdcStream.CalculateOutgoingSize()) - MON_VAR(XdcStream.CalculateUnsentSize()) - MON_VAR(XdcStream.GetSendQueueSize()) - MON_VAR(XdcOffset) - - MON_VAR(CpuStarvationEvents) - MON_VAR(CpuStarvationEventsOnWriteData) - - TString clockSkew; - i64 x = GetClockSkew(); - if (x < 0) { - clockSkew = Sprintf("-%s", TDuration::MicroSeconds(-x).ToString().data()); - } else { - clockSkew = Sprintf("+%s", TDuration::MicroSeconds(x).ToString().data()); - } - - MON_VAR(now - LastPingTimestamp) - MON_VAR(GetPingRTT()) - MON_VAR(clockSkew) - - MON_VAR(GetDeadPeerTimeout()) - MON_VAR(GetTotalInflightAmountOfData()) - MON_VAR(GetCloseOnIdleTimeout()) - MON_VAR(Subscribers.size()) - } - } - } - } - } - - auto h = std::make_unique<IEventHandle>(ev->Recipient, ev->Sender, new NMon::TEvHttpInfoRes(str.Str())); - if (ReceiverId) { - h->Rewrite(h->Type, ReceiverId); - } - TActivationContext::Send(h.release()); - } - - void CreateSessionKillingActor(TInterconnectProxyCommon::TPtr common) { - TlsActivationContext->ExecutorThread.ActorSystem->Register(new TInterconnectSessionKiller(common)); - } -} diff --git a/library/cpp/actors/interconnect/interconnect_tcp_session.h b/library/cpp/actors/interconnect/interconnect_tcp_session.h deleted file mode 100644 index 64519b2667..0000000000 --- a/library/cpp/actors/interconnect/interconnect_tcp_session.h +++ /dev/null @@ -1,692 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/core/event_pb.h> -#include <library/cpp/actors/core/events.h> -#include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/protos/services_common.pb.h> -#include <library/cpp/actors/util/datetime.h> -#include <library/cpp/actors/util/rope.h> -#include <library/cpp/actors/util/funnel_queue.h> -#include <library/cpp/actors/util/recentwnd.h> -#include <library/cpp/monlib/dynamic_counters/counters.h> -#include <library/cpp/actors/core/actor_bootstrapped.h> - -#define XXH_INLINE_ALL -#include <contrib/libs/xxhash/xxhash.h> - -#include <util/generic/queue.h> -#include <util/generic/deque.h> -#include <util/datetime/cputimer.h> - -#include "interconnect_impl.h" -#include "poller_tcp.h" -#include "poller_actor.h" -#include "interconnect_channel.h" -#include "logging.h" -#include "watchdog_timer.h" -#include "event_holder_pool.h" -#include "channel_scheduler.h" -#include "outgoing_stream.h" - -#include <unordered_set> -#include <unordered_map> - -namespace NActors { - class TSlowPathChecker { - using TTraceCallback = std::function<void(double)>; - TTraceCallback Callback; - const NHPTimer::STime Start; - - public: - TSlowPathChecker(TTraceCallback&& callback) - : Callback(std::move(callback)) - , Start(GetCycleCountFast()) - { - } - - ~TSlowPathChecker() { - const NHPTimer::STime end = GetCycleCountFast(); - const NHPTimer::STime elapsed = end - Start; - if (elapsed > 1000000) { - Callback(NHPTimer::GetSeconds(elapsed) * 1000); - } - } - - operator bool() const { - return false; - } - }; - -#define LWPROBE_IF_TOO_LONG(...) \ - if (auto __x = TSlowPathChecker{[&](double ms) { LWPROBE(__VA_ARGS__); }}) \ - ; \ - else - - class TTimeLimit { - public: - TTimeLimit(ui64 limitInCycles) - : UpperLimit(limitInCycles == 0 ? 0 : GetCycleCountFast() + limitInCycles) - { - } - - TTimeLimit(ui64 startTS, ui64 limitInCycles) - : UpperLimit(limitInCycles == 0 ? 0 : startTS + limitInCycles) - { - } - - bool CheckExceeded() { - return UpperLimit != 0 && GetCycleCountFast() > UpperLimit; - } - - const ui64 UpperLimit; - }; - - static constexpr TDuration DEFAULT_DEADPEER_TIMEOUT = TDuration::Seconds(10); - static constexpr TDuration DEFAULT_LOST_CONNECTION_TIMEOUT = TDuration::Seconds(10); - static constexpr ui32 DEFAULT_MAX_INFLIGHT_DATA = 10240 * 1024; - static constexpr ui32 DEFAULT_TOTAL_INFLIGHT_DATA = 4 * 10240 * 1024; - - class TInterconnectProxyTCP; - - enum class EUpdateState : ui8 { - NONE, // no updates generated by input session yet - INFLIGHT, // one update is inflight, and no more pending - INFLIGHT_AND_PENDING, // one update is inflight, and one is pending - CONFIRMING, // confirmation inflight - }; - - struct TReceiveContext: public TAtomicRefCount<TReceiveContext> { - /* All invokations to these fields should be thread-safe */ - - ui64 ControlPacketSendTimer = 0; - ui64 ControlPacketId = 0; - - // last processed packet by input session - std::atomic_uint64_t LastPacketSerialToConfirm = 0; - static constexpr uint64_t LastPacketSerialToConfirmLockBit = uint64_t(1) << 63; - - // for hardened checks - TAtomic NumInputSessions = 0; - - NHPTimer::STime StartTime; - - std::atomic<ui64> PingRTT_us = 0; - std::atomic<i64> ClockSkew_us = 0; - - std::atomic<EUpdateState> UpdateState; - static_assert(std::atomic<EUpdateState>::is_always_lock_free); - - bool MainWriteBlocked = false; - bool XdcWriteBlocked = false; - bool MainReadPending = false; - bool XdcReadPending = false; - - struct TPerChannelContext { - struct TPendingEvent { - TEventSerializationInfo SerializationInfo; - TRope InternalPayload; - TRope ExternalPayload; - std::optional<TEventData> EventData; - - // number of bytes remaining through XDC channel - size_t XdcSizeLeft = 0; - }; - - std::deque<TPendingEvent> PendingEvents; - std::deque<TMutableContiguousSpan> XdcBuffers; // receive queue for current channel - size_t FetchIndex = 0; - size_t FetchOffset = 0; - - ui64 XdcCatchBytesRead = 0; // number of bytes actually read into cyclic buffer - TRcBuf XdcCatchBuffer; - - void PrepareCatchBuffer(); - void ApplyCatchBuffer(); - void FetchBuffers(ui16 channel, size_t numBytes, std::deque<std::tuple<ui16, TMutableContiguousSpan>>& outQ); - void DropFront(TRope *from, size_t numBytes); - }; - - std::array<TPerChannelContext, 16> ChannelArray; - std::unordered_map<ui16, TPerChannelContext> ChannelMap; - ui64 LastProcessedSerial = 0; - - TReceiveContext() { - GetTimeFast(&StartTime); - } - - // returns false if sessions needs to be terminated - bool AdvanceLastPacketSerialToConfirm(ui64 nextValue) { - for (;;) { - uint64_t value = LastPacketSerialToConfirm.load(); - if (value & LastPacketSerialToConfirmLockBit) { - return false; - } - Y_DEBUG_ABORT_UNLESS(value + 1 == nextValue); - if (LastPacketSerialToConfirm.compare_exchange_weak(value, nextValue)) { - return true; - } - } - } - - ui64 LockLastPacketSerialToConfirm() { - for (;;) { - uint64_t value = LastPacketSerialToConfirm.load(); - if (value & LastPacketSerialToConfirmLockBit) { - return value & ~LastPacketSerialToConfirmLockBit; - } - if (LastPacketSerialToConfirm.compare_exchange_strong(value, value | LastPacketSerialToConfirmLockBit)) { - return value; - } - } - } - - void UnlockLastPacketSerialToConfirm() { - LastPacketSerialToConfirm &= ~LastPacketSerialToConfirmLockBit; - } - - ui64 GetLastPacketSerialToConfirm() { - return LastPacketSerialToConfirm.load() & ~LastPacketSerialToConfirmLockBit; - } - }; - - class TInputSessionTCP - : public TActorBootstrapped<TInputSessionTCP> - , public TInterconnectLoggingBase - { - enum { - EvCheckDeadPeer = EventSpaceBegin(TEvents::ES_PRIVATE), - EvResumeReceiveData, - }; - - struct TEvCheckDeadPeer : TEventLocal<TEvCheckDeadPeer, EvCheckDeadPeer> {}; - - public: - static constexpr EActivityType ActorActivityType() { - return EActivityType::INTERCONNECT_SESSION_TCP; - } - - TInputSessionTCP(const TActorId& sessionId, - TIntrusivePtr<NInterconnect::TStreamSocket> socket, - TIntrusivePtr<NInterconnect::TStreamSocket> xdcSocket, - TIntrusivePtr<TReceiveContext> context, - TInterconnectProxyCommon::TPtr common, - std::shared_ptr<IInterconnectMetrics> metrics, - ui32 nodeId, - ui64 lastConfirmed, - TDuration deadPeerTimeout, - TSessionParams params); - - private: - friend class TActorBootstrapped<TInputSessionTCP>; - - void Bootstrap(); - - struct TExReestablishConnection { - TDisconnectReason Reason; - }; - - struct TExDestroySession { - TDisconnectReason Reason; - }; - - STATEFN(WorkingState); - - STRICT_STFUNC(WorkingStateImpl, - cFunc(TEvents::TSystem::PoisonPill, PassAway) - hFunc(TEvPollerReady, Handle) - hFunc(TEvPollerRegisterResult, Handle) - cFunc(EvResumeReceiveData, ReceiveData) - cFunc(TEvInterconnect::TEvCloseInputSession::EventType, CloseInputSession) - cFunc(EvCheckDeadPeer, HandleCheckDeadPeer) - cFunc(TEvConfirmUpdate::EventType, HandleConfirmUpdate) - hFunc(NMon::TEvHttpInfoRes, GenerateHttpInfo) - ) - - private: - TRope IncomingData; - - const TActorId SessionId; - TIntrusivePtr<NInterconnect::TStreamSocket> Socket; - TIntrusivePtr<NInterconnect::TStreamSocket> XdcSocket; - TPollerToken::TPtr PollerToken; - TPollerToken::TPtr XdcPollerToken; - TIntrusivePtr<TReceiveContext> Context; - TInterconnectProxyCommon::TPtr Common; - const ui32 NodeId; - const TSessionParams Params; - XXH3_state_t XxhashState; - XXH3_state_t XxhashXdcState; - - size_t PayloadSize; - ui32 ChecksumExpected, Checksum; - bool IgnorePayload; - TRope Payload; - enum class EState { - HEADER, - PAYLOAD, - }; - EState State = EState::HEADER; - ui64 CurrentSerial = 0; - - std::vector<char> XdcCommands; - - struct TInboundPacket { - ui64 Serial; - size_t XdcUnreadBytes; // number of unread bytes from XDC stream for this exact unprocessed packet - }; - std::deque<TInboundPacket> InboundPacketQ; - std::deque<std::tuple<ui16, TMutableContiguousSpan>> XdcInputQ; // target buffers for the XDC stream with channel reference - std::deque<std::tuple<ui16, ui32>> XdcChecksumQ; // (size, expectedChecksum) - ui32 XdcCurrentChecksum = 0; - - // catch stream -- used after TCP reconnect to match XDC stream with main packet stream - struct TXdcCatchStream { - TRcBuf Buffer; - ui64 BytesPending = 0; - ui64 BytesProcessed = 0; - std::deque<std::tuple<ui16, bool, size_t>> Markup; // a queue of tuples (channel, apply, bytes) - bool Ready = false; - bool Applied = false; - }; - TXdcCatchStream XdcCatchStream; - - THolder<TEvUpdateFromInputSession> UpdateFromInputSession; - - ui64 ConfirmedByInput; - - std::shared_ptr<IInterconnectMetrics> Metrics; - std::array<ui32, 16> InputTrafficArray; - THashMap<ui16, ui32> InputTrafficMap; - - bool CloseInputSessionRequested = false; - - void CloseInputSession(); - - void Handle(TEvPollerReady::TPtr ev); - void Handle(TEvPollerRegisterResult::TPtr ev); - void HandleConfirmUpdate(); - void ReceiveData(); - void ProcessHeader(); - void ProcessPayload(ui64 *numDataBytes); - void ProcessInboundPacketQ(ui64 numXdcBytesRead); - void ProcessXdcCommand(ui16 channel, TReceiveContext::TPerChannelContext& context); - void ProcessEvents(TReceiveContext::TPerChannelContext& context); - ssize_t Read(NInterconnect::TStreamSocket& socket, const TPollerToken::TPtr& token, bool *readPending, - const TIoVec *iov, size_t num); - bool ReadMore(); - bool ReadXdcCatchStream(ui64 *numDataBytes); - void ApplyXdcCatchStream(); - bool ReadXdc(ui64 *numDataBytes); - void HandleXdcChecksum(TContiguousSpan span); - - TReceiveContext::TPerChannelContext& GetPerChannelContext(ui16 channel) const; - - void PassAway() override; - - TDeque<TRcBuf> Buffers; - - size_t CurrentBuffers = 1; // number of buffers currently required to allocate - static constexpr size_t MaxBuffers = 72; // maximum buffers possible - static constexpr int BitsPerUsageCount = 5; - static constexpr size_t ItemsPerUsageCount = sizeof(ui64) * CHAR_BIT / BitsPerUsageCount; - std::array<ui64, (MaxBuffers + ItemsPerUsageCount - 1) / ItemsPerUsageCount> UsageHisto; // read count histogram - - void PreallocateBuffers(); - - inline ui64 GetMaxCyclesPerEvent() const { - return DurationToCycles(TDuration::MicroSeconds(500)); - } - - const TDuration DeadPeerTimeout; - TMonotonic LastReceiveTimestamp; - void HandleCheckDeadPeer(); - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // pinger logic - - bool NewPingProtocol = false; - TDeque<TDuration> PingQ; // last N ping samples - TDeque<i64> SkewQ; // last N calculated clock skew samples - - void HandlePingResponse(TDuration passed); - void HandleClock(TInstant clock); - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Stats - - ui64 BytesReadFromSocket = 0; - ui64 PacketsReadFromSocket = 0; - ui64 DataPacketsReadFromSocket = 0; - ui64 IgnoredDataPacketsFromSocket = 0; - - ui64 BytesReadFromXdcSocket = 0; - ui64 XdcSections = 0; - ui64 XdcRefs = 0; - - ui64 CpuStarvationEvents = 0; - - void GenerateHttpInfo(NMon::TEvHttpInfoRes::TPtr ev); - }; - - class TInterconnectSessionTCP - : public TActor<TInterconnectSessionTCP> - , public TInterconnectLoggingBase - { - enum { - EvCheckCloseOnIdle = EventSpaceBegin(TEvents::ES_PRIVATE), - EvCheckLostConnection, - EvRam, - EvTerminate, - EvFreeItems, - }; - - struct TEvCheckCloseOnIdle : TEventLocal<TEvCheckCloseOnIdle, EvCheckCloseOnIdle> {}; - struct TEvCheckLostConnection : TEventLocal<TEvCheckLostConnection, EvCheckLostConnection> {}; - - struct TEvRam : TEventLocal<TEvRam, EvRam> { - const bool Batching; - TEvRam(bool batching) : Batching(batching) {} - }; - - struct TEvTerminate : TEventLocal<TEvTerminate, EvTerminate> { - TDisconnectReason Reason; - - TEvTerminate(TDisconnectReason reason) - : Reason(std::move(reason)) - {} - }; - - const TInstant Created; - TInstant NewConnectionSet; - ui64 MessagesGot = 0; - ui64 MessagesWrittenToBuffer = 0; - ui64 PacketsGenerated = 0; - ui64 BytesWrittenToSocket = 0; - ui64 PacketsConfirmed = 0; - ui64 BytesAlignedForOutOfBand = 0; - ui64 OutOfBandBytesSent = 0; - ui64 CpuStarvationEvents = 0; - ui64 CpuStarvationEventsOnWriteData = 0; - - public: - static constexpr EActivityType ActorActivityType() { - return EActivityType::INTERCONNECT_SESSION_TCP; - } - - TInterconnectSessionTCP(TInterconnectProxyTCP* const proxy, TSessionParams params); - ~TInterconnectSessionTCP(); - - void Init(); - void CloseInputSession(); - - static TEvTerminate* NewEvTerminate(TDisconnectReason reason) { - return new TEvTerminate(std::move(reason)); - } - - TDuration GetPingRTT() const { - return TDuration::MicroSeconds(ReceiveContext->PingRTT_us); - } - - i64 GetClockSkew() const { - return ReceiveContext->ClockSkew_us; - } - - private: - friend class TInterconnectProxyTCP; - - void Handle(TEvTerminate::TPtr& ev); - void HandlePoison(); - void Terminate(TDisconnectReason reason); - void PassAway() override; - - void Forward(STATEFN_SIG); - void Subscribe(STATEFN_SIG); - void Unsubscribe(STATEFN_SIG); - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::optional<TTimeLimit> TimeLimit; - - STATEFN(StateFunc) { - TimeLimit.emplace(GetMaxCyclesPerEvent()); - STRICT_STFUNC_BODY( - fFunc(TEvInterconnect::EvForward, Forward) - cFunc(TEvents::TEvPoisonPill::EventType, HandlePoison) - fFunc(TEvInterconnect::TEvConnectNode::EventType, Subscribe) - fFunc(TEvents::TEvSubscribe::EventType, Subscribe) - fFunc(TEvents::TEvUnsubscribe::EventType, Unsubscribe) - cFunc(TEvFlush::EventType, HandleFlush) - hFunc(TEvPollerReady, Handle) - hFunc(TEvPollerRegisterResult, Handle) - hFunc(TEvUpdateFromInputSession, Handle) - hFunc(TEvRam, HandleRam) - hFunc(TEvCheckCloseOnIdle, CloseOnIdleWatchdog) - hFunc(TEvCheckLostConnection, LostConnectionWatchdog) - cFunc(TEvents::TSystem::Wakeup, SendUpdateToWhiteboard) - hFunc(TEvSocketDisconnect, OnDisconnect) - hFunc(TEvTerminate, Handle) - hFunc(TEvProcessPingRequest, Handle) - ) - } - - void Handle(TEvUpdateFromInputSession::TPtr& ev); - - void OnDisconnect(TEvSocketDisconnect::TPtr& ev); - - THolder<TEvHandshakeAck> ProcessHandshakeRequest(TEvHandshakeAsk::TPtr& ev); - void SetNewConnection(TEvHandshakeDone::TPtr& ev); - - TEvRam* RamInQueue = nullptr; - ui64 RamStartedCycles = 0; - void IssueRam(bool batching); - void HandleRam(TEvRam::TPtr& ev); - void GenerateTraffic(); - void ProducePackets(); - - size_t GetUnsentSize() const { - return OutgoingStream.CalculateUnsentSize() + OutOfBandStream.CalculateUnsentSize() + - XdcStream.CalculateUnsentSize(); - } - - size_t GetUnsentLimit() const { - return 128 * 1024; - } - - void SendUpdateToWhiteboard(bool connected = true); - ui32 CalculateQueueUtilization(); - - void Handle(TEvPollerReady::TPtr& ev); - void Handle(TEvPollerRegisterResult::TPtr ev); - void WriteData(); - ssize_t Write(NInterconnect::TOutgoingStream& stream, NInterconnect::TStreamSocket& socket, size_t maxBytes); - - ui32 MakePacket(bool data, TMaybe<ui64> pingMask = {}); - void FillSendingBuffer(TTcpPacketOutTask& packet, ui64 serial); - void DropConfirmed(ui64 confirm); - void ShutdownSocket(TDisconnectReason reason); - - void StartHandshake(); - void ReestablishConnection(TEvHandshakeDone::TPtr&& ev, bool startHandshakeOnSessionClose, - TDisconnectReason reason); - void ReestablishConnectionWithHandshake(TDisconnectReason reason); - void ReestablishConnectionExecute(); - - TInterconnectProxyTCP* const Proxy; - - // various connection settings access - TDuration GetDeadPeerTimeout() const; - TDuration GetCloseOnIdleTimeout() const; - TDuration GetLostConnectionTimeout() const; - ui32 GetTotalInflightAmountOfData() const; - ui64 GetMaxCyclesPerEvent() const; - - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // pinger - - TMonotonic LastPingTimestamp; - static constexpr TDuration PingPeriodicity = TDuration::Seconds(1); - void IssuePingRequest(); - void Handle(TEvProcessPingRequest::TPtr ev); - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - TMonotonic LastInputActivityTimestamp; - TMonotonic LastPayloadActivityTimestamp; - TWatchdogTimer<TEvCheckCloseOnIdle> CloseOnIdleWatchdog; - TWatchdogTimer<TEvCheckLostConnection> LostConnectionWatchdog; - - void OnCloseOnIdleTimerHit() { - LOG_INFO_IC("ICS27", "CloseOnIdle timer hit, session terminated"); - Terminate(TDisconnectReason::CloseOnIdle()); - } - - void OnLostConnectionTimerHit() { - LOG_ERROR_IC("ICS28", "LostConnection timer hit, session terminated"); - Terminate(TDisconnectReason::LostConnection()); - } - - void RearmCloseOnIdle() { - if (!NumEventsInQueue && OutputCounter == LastConfirmed) { - CloseOnIdleWatchdog.Rearm(SelfId()); - } else { - CloseOnIdleWatchdog.Disarm(); - } - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - const TSessionParams Params; - TMaybe<TEventHolderPool> Pool; - TMaybe<TChannelScheduler> ChannelScheduler; - ui64 TotalOutputQueueSize; - bool OutputStuckFlag; - TRecentWnd<std::pair<ui64, ui64>> OutputQueueUtilization; - size_t NumEventsInQueue = 0; - - void SetOutputStuckFlag(bool state); - void SwitchStuckPeriod(); - - NInterconnect::TOutgoingStream OutgoingStream; - NInterconnect::TOutgoingStream OutOfBandStream; - NInterconnect::TOutgoingStream XdcStream; - - struct TOutgoingPacket { - ui32 PacketSize; // including header - ui32 ExternalSize; - }; - std::deque<TOutgoingPacket> SendQueue; // packet boundaries - size_t OutgoingOffset = 0; - size_t XdcOffset = 0; - size_t OutgoingIndex = 0; // index into current packet in SendQueue - size_t ForcedWriteLength = 0; - - ui64 XdcBytesSent = 0; - - ui64 WriteBlockedCycles = 0; // start of current block period - TDuration WriteBlockedTotal; // total incremental duration that session has been blocked - bool WriteBlockedByFullSendBuffer = false; - - TDuration GetWriteBlockedTotal() const { - return WriteBlockedTotal + (WriteBlockedByFullSendBuffer - ? TDuration::Seconds(NHPTimer::GetSeconds(GetCycleCountFast() - WriteBlockedCycles)) - : TDuration::Zero()); - } - - ui64 OutputCounter; - - TInstant LastHandshakeDone; - - TIntrusivePtr<NInterconnect::TStreamSocket> Socket; - TIntrusivePtr<NInterconnect::TStreamSocket> XdcSocket; - TPollerToken::TPtr PollerToken; - TPollerToken::TPtr XdcPollerToken; - ui32 SendBufferSize; - ui64 InflightDataAmount = 0; - - std::unordered_map<TActorId, ui64, TActorId::THash> Subscribers; - - // time at which we want to send confirmation packet even if there was no outgoing data - ui64 UnconfirmedBytes = 0; - TMonotonic ForcePacketTimestamp = TMonotonic::Max(); - TPriorityQueue<TMonotonic, TVector<TMonotonic>, std::greater<TMonotonic>> FlushSchedule; - size_t MaxFlushSchedule = 0; - ui64 FlushEventsScheduled = 0; - ui64 FlushEventsProcessed = 0; - - void SetForcePacketTimestamp(TDuration period); - void ScheduleFlush(); - void HandleFlush(); - void ResetFlushLogic(); - - void GenerateHttpInfo(NMon::TEvHttpInfoRes::TPtr& ev); - - TIntrusivePtr<TReceiveContext> ReceiveContext; - TActorId ReceiverId; - TDuration Ping; - - ui64 ConfirmPacketsForcedBySize = 0; - ui64 ConfirmPacketsForcedByTimeout = 0; - - ui64 LastConfirmed = 0; - - TEvHandshakeDone::TPtr PendingHandshakeDoneEvent; - bool StartHandshakeOnSessionClose = false; - - ui64 EqualizeCounter = 0; - }; - - class TInterconnectSessionKiller - : public TActorBootstrapped<TInterconnectSessionKiller> { - ui32 RepliesReceived = 0; - ui32 RepliesNumber = 0; - TActorId LargestSession = TActorId(); - ui64 MaxBufferSize = 0; - TInterconnectProxyCommon::TPtr Common; - - public: - static constexpr EActivityType ActorActivityType() { - return EActivityType::INTERCONNECT_SESSION_KILLER; - } - - TInterconnectSessionKiller(TInterconnectProxyCommon::TPtr common) - : Common(common) - { - } - - void Bootstrap() { - auto sender = SelfId(); - const auto eventFabric = [&sender](const TActorId& recp) -> IEventHandle* { - auto ev = new TEvSessionBufferSizeRequest(); - return new IEventHandle(recp, sender, ev, IEventHandle::FlagTrackDelivery); - }; - RepliesNumber = TlsActivationContext->ExecutorThread.ActorSystem->BroadcastToProxies(eventFabric); - Become(&TInterconnectSessionKiller::StateFunc); - } - - STRICT_STFUNC(StateFunc, - hFunc(TEvSessionBufferSizeResponse, ProcessResponse) - cFunc(TEvents::TEvUndelivered::EventType, ProcessUndelivered) - ) - - void ProcessResponse(TEvSessionBufferSizeResponse::TPtr& ev) { - RepliesReceived++; - if (MaxBufferSize < ev->Get()->BufferSize) { - MaxBufferSize = ev->Get()->BufferSize; - LargestSession = ev->Get()->SessionID; - } - if (RepliesReceived == RepliesNumber) { - Send(LargestSession, new TEvents::TEvPoisonPill); - AtomicUnlock(&Common->StartedSessionKiller); - PassAway(); - } - } - - void ProcessUndelivered() { - RepliesReceived++; - } - }; - - void CreateSessionKillingActor(TInterconnectProxyCommon::TPtr common); - -} diff --git a/library/cpp/actors/interconnect/load.cpp b/library/cpp/actors/interconnect/load.cpp deleted file mode 100644 index 20ca0ef8a9..0000000000 --- a/library/cpp/actors/interconnect/load.cpp +++ /dev/null @@ -1,405 +0,0 @@ -#include "load.h" -#include "interconnect_common.h" -#include "events_local.h" -#include <library/cpp/actors/protos/services_common.pb.h> -#include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/core/actor_bootstrapped.h> -#include <library/cpp/actors/core/events.h> -#include <library/cpp/actors/core/hfunc.h> -#include <util/generic/queue.h> - -namespace NInterconnect { - using namespace NActors; - - enum { - EvGenerateMessages = EventSpaceBegin(TEvents::ES_PRIVATE), - EvPublishResults, - EvQueryTrafficCounter, - EvTrafficCounter, - }; - - struct TEvQueryTrafficCounter : TEventLocal<TEvQueryTrafficCounter, EvQueryTrafficCounter> {}; - - struct TEvTrafficCounter : TEventLocal<TEvTrafficCounter, EvTrafficCounter> { - std::shared_ptr<std::atomic_uint64_t> Traffic; - - TEvTrafficCounter(std::shared_ptr<std::atomic_uint64_t> traffic) - : Traffic(std::move(traffic)) - {} - }; - - class TLoadResponderActor : public TActor<TLoadResponderActor> { - STRICT_STFUNC(StateFunc, - HFunc(TEvLoadMessage, Handle); - CFunc(TEvents::TSystem::PoisonPill, Die); - ) - - void Handle(TEvLoadMessage::TPtr& ev, const TActorContext& ctx) { - ui64 bytes = ev->Get()->CalculateSerializedSizeCached(); - auto& record = ev->Get()->Record; - auto *hops = record.MutableHops(); - while (!hops->empty() && !hops->begin()->HasNextHop()) { - record.ClearPayload(); - ev->Get()->StripPayload(); - hops->erase(hops->begin()); - } - if (!hops->empty()) { - // extract actor id of the next hop - const TActorId nextHopActorId = ActorIdFromProto(hops->begin()->GetNextHop()); - hops->erase(hops->begin()); - - // forward message to next hop; preserve flags and cookie - auto msg = MakeHolder<TEvLoadMessage>(); - record.Swap(&msg->Record); - bytes += msg->CalculateSerializedSizeCached(); - ctx.Send(nextHopActorId, msg.Release(), ev->Flags, ev->Cookie); - } - *Traffic += bytes; - } - - public: - TLoadResponderActor(std::shared_ptr<std::atomic_uint64_t> traffic) - : TActor(&TLoadResponderActor::StateFunc) - , Traffic(std::move(traffic)) - {} - - static constexpr IActor::EActivityType ActorActivityType() { - return IActor::EActivityType::INTERCONNECT_LOAD_RESPONDER; - } - - private: - std::shared_ptr<std::atomic_uint64_t> Traffic; - }; - - class TLoadResponderMasterActor : public TActorBootstrapped<TLoadResponderMasterActor> { - TVector<TActorId> Slaves; - ui32 SlaveIndex = 0; - - STRICT_STFUNC(StateFunc, - HFunc(TEvLoadMessage, Handle); - HFunc(TEvQueryTrafficCounter, Handle); - CFunc(TEvents::TSystem::PoisonPill, Die); - ) - - void Handle(TEvLoadMessage::TPtr& ev, const TActorContext& ctx) { - ctx.ExecutorThread.ActorSystem->Send(ev->Forward(Slaves[SlaveIndex])); - if (++SlaveIndex == Slaves.size()) { - SlaveIndex = 0; - } - } - - void Handle(TEvQueryTrafficCounter::TPtr ev, const TActorContext& ctx) { - ctx.Send(ev->Sender, new TEvTrafficCounter(Traffic)); - } - - void Die(const TActorContext& ctx) override { - for (const TActorId& actorId : Slaves) { - ctx.Send(actorId, new TEvents::TEvPoisonPill); - } - TActorBootstrapped::Die(ctx); - } - - public: - static constexpr IActor::EActivityType ActorActivityType() { - return IActor::EActivityType::INTERCONNECT_LOAD_RESPONDER; - } - - TLoadResponderMasterActor() - {} - - void Bootstrap(const TActorContext& ctx) { - Become(&TLoadResponderMasterActor::StateFunc); - while (Slaves.size() < 10) { - Slaves.push_back(ctx.Register(new TLoadResponderActor(Traffic))); - } - } - - private: - std::shared_ptr<std::atomic_uint64_t> Traffic = std::make_shared<std::atomic_uint64_t>(); - }; - - IActor* CreateLoadResponderActor() { - return new TLoadResponderMasterActor(); - } - - TActorId MakeLoadResponderActorId(ui32 nodeId) { - char x[12] = {'I', 'C', 'L', 'o', 'a', 'd', 'R', 'e', 's', 'p', 'A', 'c'}; - return TActorId(nodeId, TStringBuf(x, 12)); - } - - class TLoadActor: public TActorBootstrapped<TLoadActor> { - struct TEvGenerateMessages : TEventLocal<TEvGenerateMessages, EvGenerateMessages> {}; - struct TEvPublishResults : TEventLocal<TEvPublishResults, EvPublishResults> {}; - - struct TMessageInfo { - TInstant SendTimestamp; - - TMessageInfo(const TInstant& sendTimestamp) - : SendTimestamp(sendTimestamp) - { - } - }; - - const TLoadParams Params; - TInstant NextMessageTimestamp; - THashMap<TString, TMessageInfo> InFly; - ui64 NextId = 1; - TVector<TActorId> Hops; - TActorId FirstHop; - ui64 NumDropped = 0; - std::shared_ptr<std::atomic_uint64_t> Traffic; - - public: - static constexpr IActor::EActivityType ActorActivityType() { - return IActor::EActivityType::INTERCONNECT_LOAD_ACTOR; - } - - TLoadActor(const TLoadParams& params) - : Params(params) - {} - - void Bootstrap(const TActorContext& ctx) { - Become(&TLoadActor::QueryTrafficCounter); - ctx.Send(MakeLoadResponderActorId(SelfId().NodeId()), new TEvQueryTrafficCounter); - } - - void Handle(TEvTrafficCounter::TPtr ev, const TActorContext& ctx) { - Traffic = std::move(ev->Get()->Traffic); - - for (const ui32 nodeId : Params.NodeHops) { - const TActorId& actorId = nodeId ? MakeLoadResponderActorId(nodeId) : TActorId(); - if (!FirstHop) { - FirstHop = actorId; - } else { - Hops.push_back(actorId); - } - } - - Hops.push_back(ctx.SelfID); - - Become(&TLoadActor::StateFunc); - NextMessageTimestamp = ctx.Now(); - ResetThroughput(NextMessageTimestamp, *Traffic); - GenerateMessages(ctx); - ctx.Schedule(Params.Duration, new TEvents::TEvPoisonPill); - SchedulePublishResults(ctx); - } - - void GenerateMessages(const TActorContext& ctx) { - while (InFly.size() < Params.InFlyMax && ctx.Now() >= NextMessageTimestamp) { - // generate payload - const ui32 size = Params.SizeMin + RandomNumber(Params.SizeMax - Params.SizeMin + 1); - - // generate message id - const ui64 cookie = NextId++; - TString id = Sprintf("%" PRIu64, cookie); - - // create message and send it to the first hop - THolder<TEvLoadMessage> ev; - if (Params.UseProtobufWithPayload && size) { - auto buffer = TRopeAlignedBuffer::Allocate(size); - memset(buffer->GetBuffer(), '*', size); - ev.Reset(new TEvLoadMessage(Hops, id, TRope(buffer))); - } else { - TString payload; - if (size) { - payload = TString::Uninitialized(size); - memset(payload.Detach(), '*', size); - } - ev.Reset(new TEvLoadMessage(Hops, id, payload ? &payload : nullptr)); - } - UpdateThroughput(ev->CalculateSerializedSizeCached()); - ctx.Send(FirstHop, ev.Release(), IEventHandle::MakeFlags(Params.Channel, 0), cookie); - - // register in the map - InFly.emplace(id, TMessageInfo(ctx.Now())); - - // put item into timeout queue - PutTimeoutQueueItem(ctx, id); - - const TDuration duration = TDuration::MicroSeconds(Params.IntervalMin.GetValue() + - RandomNumber(Params.IntervalMax.GetValue() - Params.IntervalMin.GetValue() + 1)); - if (Params.SoftLoad) { - NextMessageTimestamp += duration; - } else { - NextMessageTimestamp = ctx.Now() + duration; - } - } - - // schedule next generate messages call - if (NextMessageTimestamp > ctx.Now() && InFly.size() < Params.InFlyMax) { - ctx.Schedule(NextMessageTimestamp - ctx.Now(), new TEvGenerateMessages); - } - } - - void Handle(TEvLoadMessage::TPtr& ev, const TActorContext& ctx) { - const auto& record = ev->Get()->Record; - auto it = InFly.find(record.GetId()); - if (it != InFly.end()) { - // record message rtt - const TDuration rtt = ctx.Now() - it->second.SendTimestamp; - UpdateHistogram(ctx.Now(), rtt); - - // update throughput - UpdateThroughput(ev->Get()->CalculateSerializedSizeCached()); - - // remove message from the in fly map - InFly.erase(it); - } else { - ++NumDropped; - } - GenerateMessages(ctx); - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // RTT HISTOGRAM - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - const TDuration AggregationPeriod = TDuration::Seconds(20); - TDeque<std::pair<TInstant, TDuration>> Histogram; - - void UpdateHistogram(TInstant when, TDuration rtt) { - Histogram.emplace_back(when, rtt); - - const TInstant barrier = when - AggregationPeriod; - while (Histogram && Histogram.front().first < barrier) { - Histogram.pop_front(); - } - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // THROUGHPUT - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - TInstant ThroughputFirstSample = TInstant::Zero(); - ui64 ThroughputSamples = 0; - ui64 ThroughputBytes = 0; - ui64 TrafficAtBegin = 0; - - void UpdateThroughput(ui64 bytes) { - ThroughputBytes += bytes; - ++ThroughputSamples; - } - - void ResetThroughput(TInstant when, ui64 traffic) { - ThroughputFirstSample = when; - ThroughputSamples = 0; - ThroughputBytes = 0; - TrafficAtBegin = traffic; - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // TIMEOUT QUEUE OPERATIONS - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - TQueue<std::pair<TInstant, TString>> TimeoutQueue; - - void PutTimeoutQueueItem(const TActorContext& ctx, TString id) { - TimeoutQueue.emplace(ctx.Now() + TDuration::Minutes(1), std::move(id)); - if (TimeoutQueue.size() == 1) { - ScheduleWakeup(ctx); - } - } - - void ScheduleWakeup(const TActorContext& ctx) { - ctx.Schedule(TimeoutQueue.front().first - ctx.Now(), new TEvents::TEvWakeup); - } - - void HandleWakeup(const TActorContext& ctx) { - // ui32 numDropped = 0; - - while (TimeoutQueue && TimeoutQueue.front().first <= ctx.Now()) { - /*numDropped += */InFly.erase(TimeoutQueue.front().second); - TimeoutQueue.pop(); - } - if (TimeoutQueue) { - // we still have some elements in timeout queue, so schedule next wake up to tidy up - ScheduleWakeup(ctx); - } - - GenerateMessages(ctx); - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // RESULT PUBLISHING - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - const TDuration ResultPublishPeriod = TDuration::Seconds(15); - - void SchedulePublishResults(const TActorContext& ctx) { - ctx.Schedule(ResultPublishPeriod, new TEvPublishResults); - } - - void PublishResults(const TActorContext& ctx, bool schedule = true) { - const TInstant now = ctx.Now(); - - TStringStream msg; - - msg << "Load# '" << Params.Name << "'"; - - msg << " Throughput# "; - const TDuration duration = now - ThroughputFirstSample; - const ui64 traffic = *Traffic; - msg << "{window# " << duration - << " bytes# " << ThroughputBytes - << " samples# " << ThroughputSamples - << " b/s# " << ui64(ThroughputBytes * 1000000 / duration.MicroSeconds()) - << " common# " << ui64((traffic - TrafficAtBegin) * 1000000 / duration.MicroSeconds()) - << "}"; - ResetThroughput(now, traffic); - - msg << " RTT# "; - if (Histogram) { - const TDuration duration = Histogram.back().first - Histogram.front().first; - msg << "{window# " << duration << " samples# " << Histogram.size(); - TVector<TDuration> v; - v.reserve(Histogram.size()); - for (const auto& item : Histogram) { - v.push_back(item.second); - } - std::sort(v.begin(), v.end()); - for (double q : {0.5, 0.9, 0.99, 0.999, 0.9999, 1.0}) { - const size_t pos = q * (v.size() - 1); - msg << Sprintf(" %.4f# %s", q, v[pos].ToString().data()); - } - msg << "}"; - } else { - msg << "<empty>"; - } - - msg << " NumDropped# " << NumDropped; - - if (!schedule) { - msg << " final"; - } - - LOG_NOTICE(ctx, NActorsServices::INTERCONNECT_SPEED_TEST, "%s", msg.Str().data()); - - if (schedule) { - SchedulePublishResults(ctx); - } - } - - STRICT_STFUNC(QueryTrafficCounter, - HFunc(TEvTrafficCounter, Handle); - ) - - STRICT_STFUNC(StateFunc, - CFunc(TEvents::TSystem::PoisonPill, Die); - CFunc(TEvents::TSystem::Wakeup, HandleWakeup); - CFunc(EvPublishResults, PublishResults); - CFunc(EvGenerateMessages, GenerateMessages); - HFunc(TEvLoadMessage, Handle); - ) - - void Die(const TActorContext& ctx) override { - PublishResults(ctx, false); - TActorBootstrapped::Die(ctx); - } - }; - - IActor* CreateLoadActor(const TLoadParams& params) { - return new TLoadActor(params); - } - -} diff --git a/library/cpp/actors/interconnect/load.h b/library/cpp/actors/interconnect/load.h deleted file mode 100644 index 0a01a0dc04..0000000000 --- a/library/cpp/actors/interconnect/load.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/actor.h> - -namespace NInterconnect { - // load responder -- lives on every node as a service actor - NActors::IActor* CreateLoadResponderActor(); - NActors::TActorId MakeLoadResponderActorId(ui32 node); - - // load actor -- generates load with specific parameters - struct TLoadParams { - TString Name; - ui32 Channel; - TVector<ui32> NodeHops; // node ids for the message route - ui32 SizeMin, SizeMax; // min and max size for payloads - ui32 InFlyMax; // maximum number of in fly messages - TDuration IntervalMin, IntervalMax; // min and max intervals between sending messages - bool SoftLoad; // is the load soft? - TDuration Duration; // test duration - bool UseProtobufWithPayload; // store payload separately - }; - NActors::IActor* CreateLoadActor(const TLoadParams& params); - -} diff --git a/library/cpp/actors/interconnect/logging.h b/library/cpp/actors/interconnect/logging.h deleted file mode 100644 index 010a4aa93b..0000000000 --- a/library/cpp/actors/interconnect/logging.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/protos/services_common.pb.h> - -#define LOG_LOG_IC_X(component, marker, priority, ...) \ - do { \ - LOG_LOG(this->GetActorContext(), (priority), (component), "%s " marker " %s", LogPrefix.data(), Sprintf(__VA_ARGS__).data()); \ - } while (false) - -#define LOG_LOG_NET_X(priority, NODE_ID, FMT, ...) \ - do { \ - const TActorContext& ctx = this->GetActorContext(); \ - LOG_LOG(ctx, (priority), ::NActorsServices::INTERCONNECT_NETWORK, "[%" PRIu32 " <-> %" PRIu32 "] %s", \ - ctx.SelfID.NodeId(), (NODE_ID), Sprintf(FMT, __VA_ARGS__).data()); \ - } while (false) - -#define LOG_LOG_IC(component, marker, priority, ...) \ - do { \ - LOG_LOG(::NActors::TActivationContext::AsActorContext(), (priority), (component), "%s " marker " %s", LogPrefix.data(), Sprintf(__VA_ARGS__).data()); \ - } while (false) - -#define LOG_LOG_NET(priority, NODE_ID, FMT, ...) \ - do { \ - const TActorContext& ctx = ::NActors::TActivationContext::AsActorContext(); \ - LOG_LOG(ctx, (priority), ::NActorsServices::INTERCONNECT_NETWORK, "[%" PRIu32 " <-> %" PRIu32 "] %s", \ - ctx.SelfID.NodeId(), (NODE_ID), Sprintf(FMT, __VA_ARGS__).data()); \ - } while (false) - -#define LOG_EMER_IC(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT, marker, ::NActors::NLog::PRI_EMER, __VA_ARGS__) -#define LOG_ALERT_IC(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT, marker, ::NActors::NLog::PRI_ALERT, __VA_ARGS__) -#define LOG_CRIT_IC(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT, marker, ::NActors::NLog::PRI_CRIT, __VA_ARGS__) -#define LOG_ERROR_IC(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT, marker, ::NActors::NLog::PRI_ERROR, __VA_ARGS__) -#define LOG_WARN_IC(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT, marker, ::NActors::NLog::PRI_WARN, __VA_ARGS__) -#define LOG_NOTICE_IC(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT, marker, ::NActors::NLog::PRI_NOTICE, __VA_ARGS__) -#define LOG_INFO_IC(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT, marker, ::NActors::NLog::PRI_INFO, __VA_ARGS__) -#define LOG_DEBUG_IC(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT, marker, ::NActors::NLog::PRI_DEBUG, __VA_ARGS__) -#define LOG_TRACE_IC(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT, marker, ::NActors::NLog::PRI_TRACE, __VA_ARGS__) - -#define LOG_EMER_IC_SESSION(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT_SESSION, marker, ::NActors::NLog::PRI_EMER, __VA_ARGS__) -#define LOG_ALERT_IC_SESSION(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT_SESSION, marker, ::NActors::NLog::PRI_ALERT, __VA_ARGS__) -#define LOG_CRIT_IC_SESSION(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT_SESSION, marker, ::NActors::NLog::PRI_CRIT, __VA_ARGS__) -#define LOG_ERROR_IC_SESSION(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT_SESSION, marker, ::NActors::NLog::PRI_ERROR, __VA_ARGS__) -#define LOG_WARN_IC_SESSION(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT_SESSION, marker, ::NActors::NLog::PRI_WARN, __VA_ARGS__) -#define LOG_NOTICE_IC_SESSION(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT_SESSION, marker, ::NActors::NLog::PRI_NOTICE, __VA_ARGS__) -#define LOG_INFO_IC_SESSION(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT_SESSION, marker, ::NActors::NLog::PRI_INFO, __VA_ARGS__) -#define LOG_DEBUG_IC_SESSION(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT_SESSION, marker, ::NActors::NLog::PRI_DEBUG, __VA_ARGS__) - -#define LOG_NOTICE_NET(NODE_ID, FMT, ...) LOG_LOG_NET(::NActors::NLog::PRI_NOTICE, NODE_ID, FMT, __VA_ARGS__) -#define LOG_DEBUG_NET(NODE_ID, FMT, ...) LOG_LOG_NET(::NActors::NLog::PRI_DEBUG, NODE_ID, FMT, __VA_ARGS__) - -namespace NActors { - class TInterconnectLoggingBase { - protected: - const TString LogPrefix; - - public: - TInterconnectLoggingBase() = default; - - TInterconnectLoggingBase(const TString& prefix) - : LogPrefix(prefix) - { - } - - void SetPrefix(TString logPrefix) const { - logPrefix.swap(const_cast<TString&>(LogPrefix)); - } - }; -} diff --git a/library/cpp/actors/interconnect/mock/CMakeLists.darwin-arm64.txt b/library/cpp/actors/interconnect/mock/CMakeLists.darwin-arm64.txt deleted file mode 100644 index c29d87b0ce..0000000000 --- a/library/cpp/actors/interconnect/mock/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,18 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(actors-interconnect-mock) -target_link_libraries(actors-interconnect-mock PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-interconnect -) -target_sources(actors-interconnect-mock PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/mock/ic_mock.cpp -) diff --git a/library/cpp/actors/interconnect/mock/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/interconnect/mock/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index c29d87b0ce..0000000000 --- a/library/cpp/actors/interconnect/mock/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,18 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(actors-interconnect-mock) -target_link_libraries(actors-interconnect-mock PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-interconnect -) -target_sources(actors-interconnect-mock PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/mock/ic_mock.cpp -) diff --git a/library/cpp/actors/interconnect/mock/CMakeLists.linux-aarch64.txt b/library/cpp/actors/interconnect/mock/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 85d0cf4696..0000000000 --- a/library/cpp/actors/interconnect/mock/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(actors-interconnect-mock) -target_link_libraries(actors-interconnect-mock PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-actors-interconnect -) -target_sources(actors-interconnect-mock PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/mock/ic_mock.cpp -) diff --git a/library/cpp/actors/interconnect/mock/CMakeLists.linux-x86_64.txt b/library/cpp/actors/interconnect/mock/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 85d0cf4696..0000000000 --- a/library/cpp/actors/interconnect/mock/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(actors-interconnect-mock) -target_link_libraries(actors-interconnect-mock PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-actors-interconnect -) -target_sources(actors-interconnect-mock PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/mock/ic_mock.cpp -) diff --git a/library/cpp/actors/interconnect/mock/CMakeLists.txt b/library/cpp/actors/interconnect/mock/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/interconnect/mock/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/interconnect/mock/CMakeLists.windows-x86_64.txt b/library/cpp/actors/interconnect/mock/CMakeLists.windows-x86_64.txt deleted file mode 100644 index c29d87b0ce..0000000000 --- a/library/cpp/actors/interconnect/mock/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,18 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(actors-interconnect-mock) -target_link_libraries(actors-interconnect-mock PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-interconnect -) -target_sources(actors-interconnect-mock PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/mock/ic_mock.cpp -) diff --git a/library/cpp/actors/interconnect/mock/ic_mock.cpp b/library/cpp/actors/interconnect/mock/ic_mock.cpp deleted file mode 100644 index 81e181b673..0000000000 --- a/library/cpp/actors/interconnect/mock/ic_mock.cpp +++ /dev/null @@ -1,385 +0,0 @@ -#include "ic_mock.h" -#include <library/cpp/actors/core/interconnect.h> -#include <util/system/yield.h> -#include <thread> -#include <deque> - -namespace NActors { - - class TInterconnectMock::TImpl { - enum { - EvInject = EventSpaceBegin(TEvents::ES_PRIVATE), - EvCheckSession, - EvRam, - }; - - struct TEvInject : TEventLocal<TEvInject, EvInject> { - std::deque<std::unique_ptr<IEventHandle>> Messages; - const TScopeId OriginScopeId; - const ui64 SenderSessionId; - - TEvInject(std::deque<std::unique_ptr<IEventHandle>>&& messages, const TScopeId& originScopeId, ui64 senderSessionId) - : Messages(std::move(messages)) - , OriginScopeId(originScopeId) - , SenderSessionId(senderSessionId) - {} - }; - - class TProxyMockActor; - - class TConnectionState { - struct TPeerInfo { - TRWMutex Mutex; - TActorSystem *ActorSystem = nullptr; - TActorId ProxyId; - }; - - const ui64 Key; - TPeerInfo PeerInfo[2]; - std::atomic_uint64_t SessionId = 0; - - public: - TConnectionState(ui64 key) - : Key(key) - {} - - void Attach(ui32 nodeId, TActorSystem *as, const TActorId& actorId) { - TPeerInfo *peer = GetPeer(nodeId); - auto guard = TWriteGuard(peer->Mutex); - Y_ABORT_UNLESS(!peer->ActorSystem); - peer->ActorSystem = as; - peer->ProxyId = actorId; - as->DeferPreStop([peer] { - auto guard = TWriteGuard(peer->Mutex); - peer->ActorSystem = nullptr; - }); - } - - void Inject(ui32 peerNodeId, std::deque<std::unique_ptr<IEventHandle>>&& messages, - const TScopeId& originScopeId, ui64 senderSessionId) { - TPeerInfo *peer = GetPeer(peerNodeId); - auto guard = TReadGuard(peer->Mutex); - if (peer->ActorSystem) { - peer->ActorSystem->Send(new IEventHandle(peer->ProxyId, TActorId(), new TEvInject(std::move(messages), - originScopeId, senderSessionId))); - } else { - for (auto&& ev : messages) { - TActivationContext::Send(IEventHandle::ForwardOnNondelivery(std::move(ev), TEvents::TEvUndelivered::Disconnected)); - } - } - } - - ui64 GetValidSessionId() const { - return SessionId; - } - - void InvalidateSessionId(ui32 peerNodeId) { - ++SessionId; - TPeerInfo *peer = GetPeer(peerNodeId); - auto guard = TReadGuard(peer->Mutex); - if (peer->ActorSystem) { - peer->ActorSystem->Send(new IEventHandle(EvCheckSession, 0, peer->ProxyId, {}, nullptr, 0)); - } - } - - private: - TPeerInfo *GetPeer(ui32 nodeId) { - if (nodeId == ui32(Key)) { - return PeerInfo; - } else if (nodeId == ui32(Key >> 32)) { - return PeerInfo + 1; - } else { - Y_ABORT(); - } - } - }; - - class TProxyMockActor : public TActor<TProxyMockActor> { - class TSessionMockActor : public TActor<TSessionMockActor> { - std::map<TActorId, ui64> Subscribers; - TProxyMockActor* const Proxy; - std::deque<std::unique_ptr<IEventHandle>> Queue; - - public: - const ui64 SessionId; - - public: - TSessionMockActor(TProxyMockActor *proxy, ui64 sessionId) - : TActor(&TThis::StateFunc) - , Proxy(proxy) - , SessionId(sessionId) - {} - - static constexpr char ActorName[] = "SESSION_MOCK_ACTOR"; - - void Terminate() { - for (auto&& ev : std::exchange(Queue, {})) { - TActivationContext::Send(IEventHandle::ForwardOnNondelivery(std::move(ev), TEvents::TEvUndelivered::Disconnected)); - } - for (const auto& kv : Subscribers) { - Send(kv.first, new TEvInterconnect::TEvNodeDisconnected(Proxy->PeerNodeId), 0, kv.second); - } - Y_ABORT_UNLESS(Proxy->Session == this); - Proxy->Session = nullptr; - PassAway(); - } - - void HandleForward(TAutoPtr<IEventHandle> ev) { - if (CheckNodeStatus(ev)) { - if (ev->Flags & IEventHandle::FlagSubscribeOnSession) { - Subscribe(ev->Sender, ev->Cookie); - } - if (Queue.empty()) { - TActivationContext::Send(new IEventHandle(EvRam, 0, SelfId(), {}, {}, 0)); - } - Queue.emplace_back(ev.Release()); - } - } - - void HandleRam() { - if (SessionId != Proxy->State.GetValidSessionId()) { - Terminate(); - } else { - Proxy->PeerInject(std::exchange(Queue, {})); - } - } - - void Handle(TEvInterconnect::TEvConnectNode::TPtr ev) { - if (CheckNodeStatus(ev)) { - Subscribe(ev->Sender, ev->Cookie); - } - } - - void Handle(TEvents::TEvSubscribe::TPtr ev) { - if (CheckNodeStatus(ev)) { - Subscribe(ev->Sender, ev->Cookie); - } - } - - void Handle(TEvents::TEvUnsubscribe::TPtr ev) { - if (CheckNodeStatus(ev)) { - Subscribers.erase(ev->Sender); - } - } - - void HandlePoison() { - Proxy->Disconnect(); - } - - STRICT_STFUNC(StateFunc, - fFunc(TEvInterconnect::EvForward, HandleForward) - hFunc(TEvInterconnect::TEvConnectNode, Handle) - hFunc(TEvents::TEvSubscribe, Handle) - hFunc(TEvents::TEvUnsubscribe, Handle) - hFunc(TEvInterconnect::TEvNodeInfo, HandleNodeInfo) - cFunc(TEvents::TSystem::Poison, HandlePoison) - cFunc(EvRam, HandleRam) - ) - - private: - enum EPeerNodeStatus { - UNKNOWN, - EXISTS, - MISSING - }; - - bool IsWaitingForNodeInfo = false; - std::deque<std::unique_ptr<IEventHandle>> WaitingConnections; - EPeerNodeStatus PeerNodeStatus = EPeerNodeStatus::UNKNOWN; - - void Subscribe(const TActorId& actorId, ui64 cookie) { - Subscribers[actorId] = cookie; - Send(actorId, new TEvInterconnect::TEvNodeConnected(Proxy->PeerNodeId), 0, cookie); - } - - template <typename TEvent> - bool CheckNodeStatus(TAutoPtr<TEventHandle<TEvent>>& ev) { - if (PeerNodeStatus != EPeerNodeStatus::EXISTS) { - std::unique_ptr<IEventHandle> tmp(ev.Release()); - CheckNonexistentNode(tmp); - return false; - } - return true; - } - - bool CheckNodeStatus(TAutoPtr<IEventHandle>& ev) { - if (PeerNodeStatus != EPeerNodeStatus::EXISTS) { - std::unique_ptr<IEventHandle> tmp(ev.Release()); - CheckNonexistentNode(tmp); - return false; - } - return true; - } - - void CheckNonexistentNode(std::unique_ptr<IEventHandle>& ev) { - if (PeerNodeStatus == EPeerNodeStatus::UNKNOWN) { - WaitingConnections.emplace_back(ev.release()); - if (!IsWaitingForNodeInfo) { - Send(Proxy->Common->NameserviceId, new TEvInterconnect::TEvGetNode(Proxy->PeerNodeId)); - IsWaitingForNodeInfo = true; - } - } else if (PeerNodeStatus == EPeerNodeStatus::MISSING) { - switch (ev->GetTypeRewrite()) { - case TEvInterconnect::EvForward: - if (ev->Flags & IEventHandle::FlagSubscribeOnSession) { - Send(ev->Sender, new TEvInterconnect::TEvNodeDisconnected(Proxy->PeerNodeId), 0, ev->Cookie); - } - TActivationContext::Send(IEventHandle::ForwardOnNondelivery(std::move(ev), TEvents::TEvUndelivered::Disconnected)); - break; - - case TEvents::TEvSubscribe::EventType: - case TEvInterconnect::TEvConnectNode::EventType: - Send(ev->Sender, new TEvInterconnect::TEvNodeDisconnected(Proxy->PeerNodeId), 0, ev->Cookie); - break; - - case TEvents::TEvUnsubscribe::EventType: - break; - - default: - Y_ABORT(); - } - } - } - - void HandleNodeInfo(TEvInterconnect::TEvNodeInfo::TPtr ev) { - Y_ABORT_UNLESS(IsWaitingForNodeInfo); - if (!ev->Get()->Node) { - PeerNodeStatus = EPeerNodeStatus::MISSING; - } else { - PeerNodeStatus = EPeerNodeStatus::EXISTS; - } - IsWaitingForNodeInfo = false; - while (!WaitingConnections.empty()) { - TAutoPtr<IEventHandle> tmp(WaitingConnections.front().release()); - WaitingConnections.pop_front(); - Receive(tmp); - } - } - }; - - friend class TSessionMockActor; - - const ui32 NodeId; - const ui32 PeerNodeId; - TConnectionState& State; - const TInterconnectProxyCommon::TPtr Common; - TSessionMockActor *Session = nullptr; - - public: - TProxyMockActor(ui32 nodeId, ui32 peerNodeId, TConnectionState& state, TInterconnectProxyCommon::TPtr common) - : TActor(&TThis::StateFunc) - , NodeId(nodeId) - , PeerNodeId(peerNodeId) - , State(state) - , Common(std::move(common)) - {} - - static constexpr char ActorName[] = "PROXY_MOCK_ACTOR"; - - void Registered(TActorSystem *as, const TActorId& parent) override { - TActor::Registered(as, parent); - State.Attach(NodeId, as, SelfId()); - } - - void Handle(TEvInject::TPtr ev) { - auto *msg = ev->Get(); - if (Session && Session->SessionId != msg->SenderSessionId) { - return; // drop messages from other sessions - } - if (auto *session = GetSession()) { - for (auto&& ev : ev->Get()->Messages) { - auto fw = std::make_unique<IEventHandle>( - session->SelfId(), - ev->Type, - ev->Flags & ~IEventHandle::FlagForwardOnNondelivery, - ev->Recipient, - ev->Sender, - ev->ReleaseChainBuffer(), - ev->Cookie, - msg->OriginScopeId, - std::move(ev->TraceId) - ); - if (!Common->EventFilter || Common->EventFilter->CheckIncomingEvent(*fw, Common->LocalScopeId)) { - TActivationContext::Send(fw.release()); - } - } - } - } - - void PassAway() override { - Disconnect(); - TActor::PassAway(); - } - - TSessionMockActor *GetSession() { - CheckSession(); - if (!Session) { - Session = new TSessionMockActor(this, State.GetValidSessionId()); - RegisterWithSameMailbox(Session); - } - return Session; - } - - void HandleSessionEvent(TAutoPtr<IEventHandle> ev) { - auto *session = GetSession(); - InvokeOtherActor(*session, &TSessionMockActor::Receive, ev); - } - - void Disconnect() { - State.InvalidateSessionId(PeerNodeId); - if (Session) { - Session->Terminate(); - } - } - - void CheckSession() { - if (Session && Session->SessionId != State.GetValidSessionId()) { - Session->Terminate(); - } - } - - void PeerInject(std::deque<std::unique_ptr<IEventHandle>>&& messages) { - Y_ABORT_UNLESS(Session); - return State.Inject(PeerNodeId, std::move(messages), Common->LocalScopeId, Session->SessionId); - } - - STRICT_STFUNC(StateFunc, - cFunc(TEvents::TSystem::Poison, PassAway) - fFunc(TEvInterconnect::EvForward, HandleSessionEvent) - fFunc(TEvInterconnect::EvConnectNode, HandleSessionEvent) - fFunc(TEvents::TSystem::Subscribe, HandleSessionEvent) - fFunc(TEvents::TSystem::Unsubscribe, HandleSessionEvent) - cFunc(TEvInterconnect::EvDisconnect, Disconnect) - IgnoreFunc(TEvInterconnect::TEvClosePeerSocket) - IgnoreFunc(TEvInterconnect::TEvCloseInputSession) - cFunc(TEvInterconnect::EvPoisonSession, Disconnect) - hFunc(TEvInject, Handle) - cFunc(EvCheckSession, CheckSession) - ) - }; - - std::unordered_map<ui64, TConnectionState> States; - - public: - IActor *CreateProxyMock(ui32 nodeId, ui32 peerNodeId, TInterconnectProxyCommon::TPtr common) { - Y_ABORT_UNLESS(nodeId != peerNodeId); - Y_ABORT_UNLESS(nodeId); - Y_ABORT_UNLESS(peerNodeId); - const ui64 key = std::min(nodeId, peerNodeId) | ui64(std::max(nodeId, peerNodeId)) << 32; - auto it = States.try_emplace(key, key).first; - return new TProxyMockActor(nodeId, peerNodeId, it->second, std::move(common)); - } - }; - - TInterconnectMock::TInterconnectMock() - : Impl(std::make_unique<TImpl>()) - {} - - TInterconnectMock::~TInterconnectMock() - {} - - IActor *TInterconnectMock::CreateProxyMock(ui32 nodeId, ui32 peerNodeId, TInterconnectProxyCommon::TPtr common) { - return Impl->CreateProxyMock(nodeId, peerNodeId, std::move(common)); - } - -} // NActors diff --git a/library/cpp/actors/interconnect/mock/ic_mock.h b/library/cpp/actors/interconnect/mock/ic_mock.h deleted file mode 100644 index 636bdc2b7f..0000000000 --- a/library/cpp/actors/interconnect/mock/ic_mock.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/actor.h> - -#include <library/cpp/actors/interconnect/interconnect_common.h> - -namespace NActors { - - class TInterconnectMock { - class TImpl; - std::unique_ptr<TImpl> Impl; - - public: - TInterconnectMock(); - ~TInterconnectMock(); - IActor *CreateProxyMock(ui32 nodeId, ui32 peerNodeId, TInterconnectProxyCommon::TPtr common); - }; - -} // NActors diff --git a/library/cpp/actors/interconnect/mock/ya.make b/library/cpp/actors/interconnect/mock/ya.make deleted file mode 100644 index d097e3f094..0000000000 --- a/library/cpp/actors/interconnect/mock/ya.make +++ /dev/null @@ -1,14 +0,0 @@ -LIBRARY() - -SRCS( - ic_mock.cpp - ic_mock.h -) - -SUPPRESSIONS(tsan.supp) - -PEERDIR( - library/cpp/actors/interconnect -) - -END() diff --git a/library/cpp/actors/interconnect/outgoing_stream.h b/library/cpp/actors/interconnect/outgoing_stream.h deleted file mode 100644 index 304fa925a8..0000000000 --- a/library/cpp/actors/interconnect/outgoing_stream.h +++ /dev/null @@ -1,272 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/event_load.h> -#include <library/cpp/actors/util/rc_buf.h> -#include <library/cpp/containers/stack_vector/stack_vec.h> -#include <deque> - -namespace NInterconnect { - - template<size_t TotalSize> - class TOutgoingStreamT { - static constexpr size_t BufferSize = TotalSize - sizeof(ui32) * 2; - - struct TBuffer { - char Data[BufferSize]; - ui32 RefCount; - ui32 Index; - - struct TDeleter { - void operator ()(TBuffer *buffer) const { - free(buffer); - } - }; - }; - - static_assert(sizeof(TBuffer) == TotalSize); - - struct TSendChunk { - TContiguousSpan Span; - TBuffer *Buffer; - }; - - std::vector<std::unique_ptr<TBuffer, typename TBuffer::TDeleter>> Buffers; - TBuffer *AppendBuffer = nullptr; - size_t AppendOffset = BufferSize; // into the last buffer - std::deque<TSendChunk> SendQueue; - size_t SendQueuePos = 0; - size_t SendOffset = 0; - size_t UnsentBytes = 0; - - public: - operator bool() const { - return SendQueuePos != SendQueue.size(); - } - - size_t CalculateOutgoingSize() const { - size_t res = 0; - for (const TSendChunk& chunk : SendQueue) { - res += chunk.Span.size(); - } - return res; - } - - size_t CalculateUnsentSize() const { -#ifndef NDEBUG - size_t res = 0; - for (auto it = SendQueue.begin() + SendQueuePos; it != SendQueue.end(); ++it) { - res += it->Span.size(); - } - Y_ABORT_UNLESS(UnsentBytes == res - SendOffset); -#endif - return UnsentBytes; - } - - size_t GetSendQueueSize() const { - return SendQueue.size(); - } - - TMutableContiguousSpan AcquireSpanForWriting(size_t maxLen) { - if (!maxLen) { - return {nullptr, 0}; - } - if (AppendOffset == BufferSize) { // we have no free buffer, allocate one - Buffers.emplace_back(static_cast<TBuffer*>(malloc(sizeof(TBuffer)))); - AppendBuffer = Buffers.back().get(); - Y_ABORT_UNLESS(AppendBuffer); - AppendBuffer->RefCount = 1; // through AppendBuffer pointer - AppendBuffer->Index = Buffers.size() - 1; - AppendOffset = 0; - } - return {AppendBuffer->Data + AppendOffset, Min(maxLen, BufferSize - AppendOffset)}; - } - - void Align() { - if (AppendOffset != BufferSize) { - AppendOffset += -(reinterpret_cast<uintptr_t>(AppendBuffer->Data) + AppendOffset) & 63; - if (AppendOffset > BufferSize) { - AppendOffset = BufferSize; - DropBufferReference(std::exchange(AppendBuffer, nullptr)); - } - } - } - - void Append(TContiguousSpan span) { - if (AppendBuffer && span.data() == AppendBuffer->Data + AppendOffset) { // the only valid case to use previously acquired span - AppendAcquiredSpan(span); - } else { -#ifndef NDEBUG - // ensure this span does not point into any existing buffer part - const char *begin = span.data(); - const char *end = span.data() + span.size(); - for (const auto& buffer : Buffers) { - const char *bufferBegin = buffer->Data; - const char *bufferEnd = bufferBegin + BufferSize; - if (bufferBegin < end && begin < bufferEnd) { - Y_ABORT(); - } - } -#endif - AppendSpanWithGlueing(span, nullptr); - } - } - - void Write(TContiguousSpan in) { - while (in.size()) { - auto outChunk = AcquireSpanForWriting(in.size()); - memcpy(outChunk.data(), in.data(), outChunk.size()); - AppendAcquiredSpan(outChunk); - in = in.SubSpan(outChunk.size(), Max<size_t>()); - } - } - - using TBookmark = TStackVec<TMutableContiguousSpan, 2>; - - TBookmark Bookmark(size_t len) { - TBookmark bookmark; - - while (len) { - const auto span = AcquireSpanForWriting(len); - AppendAcquiredSpan(span); - bookmark.push_back(span); - len -= span.size(); - } - - return bookmark; - } - - void WriteBookmark(TBookmark&& bookmark, TContiguousSpan in) { - for (auto& outChunk : bookmark) { - Y_DEBUG_ABORT_UNLESS(outChunk.size() <= in.size()); - memcpy(outChunk.data(), in.data(), outChunk.size()); - in = in.SubSpan(outChunk.size(), Max<size_t>()); - } - } - - void Rewind() { - SendQueuePos = 0; - SendOffset = 0; - UnsentBytes = 0; - for (const auto& item : SendQueue) { - UnsentBytes += item.Span.size(); - } - } - - void RewindToEnd() { - SendQueuePos = SendQueue.size(); - SendOffset = 0; - UnsentBytes = 0; - } - - template<typename T> - void ProduceIoVec(T& container, size_t maxItems, size_t maxBytes) { - size_t offset = SendOffset; - for (auto it = SendQueue.begin() + SendQueuePos; it != SendQueue.end() && std::size(container) < maxItems && maxBytes; ++it) { - const TContiguousSpan span = it->Span.SubSpan(offset, maxBytes); - container.push_back(NActors::TConstIoVec{span.data(), span.size()}); - offset = 0; - maxBytes -= span.size(); - } - } - - void Advance(size_t numBytes) { // called when numBytes portion of data has been sent - Y_DEBUG_ABORT_UNLESS(numBytes == 0 || SendQueuePos != SendQueue.size()); - Y_DEBUG_ABORT_UNLESS(numBytes <= UnsentBytes); - SendOffset += numBytes; - UnsentBytes -= numBytes; - for (auto it = SendQueue.begin() + SendQueuePos; SendOffset && it->Span.size() <= SendOffset; ++SendQueuePos, ++it) { - SendOffset -= it->Span.size(); - Y_DEBUG_ABORT_UNLESS(SendOffset == 0 || SendQueuePos != SendQueue.size() - 1); - } - } - - void DropFront(size_t numBytes) { // drops first numBytes from the queue, freeing buffers when necessary - while (numBytes) { - Y_DEBUG_ABORT_UNLESS(!SendQueue.empty()); - auto& front = SendQueue.front(); - if (numBytes < front.Span.size()) { - front.Span = front.Span.SubSpan(numBytes, Max<size_t>()); - if (SendQueuePos == 0) { - Y_DEBUG_ABORT_UNLESS(numBytes <= SendOffset, "numBytes# %zu SendOffset# %zu SendQueuePos# %zu" - " SendQueue.size# %zu CalculateUnsentSize# %zu", numBytes, SendOffset, SendQueuePos, - SendQueue.size(), CalculateUnsentSize()); - SendOffset -= numBytes; - } - break; - } else { - numBytes -= front.Span.size(); - } - Y_DEBUG_ABORT_UNLESS(!front.Buffer || (front.Span.data() >= front.Buffer->Data && - front.Span.data() + front.Span.size() <= front.Buffer->Data + BufferSize)); - DropBufferReference(front.Buffer); - SendQueue.pop_front(); - if (SendQueuePos) { - --SendQueuePos; - } else { - SendOffset = 0; - } - } - } - - template<typename T> - void ScanLastBytes(size_t numBytes, T&& callback) const { - auto it = SendQueue.end(); - ssize_t offset = -numBytes; - while (offset < 0) { - Y_DEBUG_ABORT_UNLESS(it != SendQueue.begin()); - const TSendChunk& chunk = *--it; - offset += chunk.Span.size(); - } - for (; it != SendQueue.end(); ++it, offset = 0) { - callback(it->Span.SubSpan(offset, Max<size_t>())); - } - } - - private: - void AppendAcquiredSpan(TContiguousSpan span) { - TBuffer *buffer = AppendBuffer; - Y_DEBUG_ABORT_UNLESS(buffer); - Y_DEBUG_ABORT_UNLESS(span.data() == AppendBuffer->Data + AppendOffset); - AppendOffset += span.size(); - Y_DEBUG_ABORT_UNLESS(AppendOffset <= BufferSize); - if (AppendOffset == BufferSize) { - AppendBuffer = nullptr; - } else { - ++buffer->RefCount; - } - AppendSpanWithGlueing(span, buffer); - } - - void AppendSpanWithGlueing(TContiguousSpan span, TBuffer *buffer) { - UnsentBytes += span.size(); - if (!SendQueue.empty()) { - auto& back = SendQueue.back(); - if (back.Span.data() + back.Span.size() == span.data()) { // check if it is possible just to extend the last span - Y_DEBUG_ABORT_UNLESS(buffer == back.Buffer); - if (SendQueuePos == SendQueue.size()) { - --SendQueuePos; - SendOffset = back.Span.size(); - } - back.Span = {back.Span.data(), back.Span.size() + span.size()}; - DropBufferReference(buffer); - return; - } - } - SendQueue.push_back(TSendChunk{span, buffer}); - } - - void DropBufferReference(TBuffer *buffer) { - if (buffer && !--buffer->RefCount) { - const size_t index = buffer->Index; - auto& cell = Buffers[index]; - Y_DEBUG_ABORT_UNLESS(cell.get() == buffer); - std::swap(cell, Buffers.back()); - cell->Index = index; - Buffers.pop_back(); - } - } - }; - - using TOutgoingStream = TOutgoingStreamT<262144>; - -} // NInterconnect diff --git a/library/cpp/actors/interconnect/packet.cpp b/library/cpp/actors/interconnect/packet.cpp deleted file mode 100644 index 9ba173e330..0000000000 --- a/library/cpp/actors/interconnect/packet.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "packet.h" - -#include <library/cpp/actors/core/probes.h> - -#include <util/system/datetime.h> - -LWTRACE_USING(ACTORLIB_PROVIDER); - -ui32 TEventHolder::Fill(IEventHandle& ev) { - Serial = 0; - Descr.Type = ev.Type; - Descr.Flags = ev.Flags; - Descr.Recipient = ev.Recipient; - Descr.Sender = ev.Sender; - Descr.Cookie = ev.Cookie; - ForwardRecipient = ev.GetForwardOnNondeliveryRecipient(); - EventActuallySerialized = 0; - Descr.Checksum = 0; - - if (ev.HasBuffer()) { - Buffer = ev.ReleaseChainBuffer(); - EventSerializedSize = Buffer->GetSize(); - } else if (ev.HasEvent()) { - Event.Reset(ev.ReleaseBase()); - EventSerializedSize = Event->CalculateSerializedSize(); - } else { - EventSerializedSize = 0; - } - - return EventSerializedSize; -} diff --git a/library/cpp/actors/interconnect/packet.h b/library/cpp/actors/interconnect/packet.h deleted file mode 100644 index 0a748cda2a..0000000000 --- a/library/cpp/actors/interconnect/packet.h +++ /dev/null @@ -1,304 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/event_pb.h> -#include <library/cpp/actors/core/event_load.h> -#include <library/cpp/actors/core/events.h> -#include <library/cpp/actors/core/actor.h> -#include <library/cpp/containers/stack_vector/stack_vec.h> -#include <library/cpp/actors/util/rope.h> -#include <library/cpp/actors/prof/tag.h> -#include <library/cpp/actors/wilson/wilson_span.h> -#include <library/cpp/digest/crc32c/crc32c.h> -#include <library/cpp/lwtrace/shuttle.h> -#include <util/generic/string.h> -#include <util/generic/list.h> - -#define XXH_INLINE_ALL -#include <contrib/libs/xxhash/xxhash.h> - -#include "types.h" -#include "outgoing_stream.h" - -#ifndef FORCE_EVENT_CHECKSUM -#define FORCE_EVENT_CHECKSUM 0 -#endif - -// WARNING: turning this feature on will make protocol incompatible with ordinary Interconnect, use with caution -#define IC_FORCE_HARDENED_PACKET_CHECKS 0 - -#if IC_FORCE_HARDENED_PACKET_CHECKS -#undef FORCE_EVENT_CHECKSUM -#define FORCE_EVENT_CHECKSUM 1 -#endif - -Y_FORCE_INLINE ui32 Crc32cExtendMSanCompatible(ui32 checksum, const void *data, size_t len) { - if constexpr (NSan::MSanIsOn()) { - const char *begin = static_cast<const char*>(data); - const char *end = begin + len; - begin -= reinterpret_cast<uintptr_t>(begin) & 15; - end += -reinterpret_cast<uintptr_t>(end) & 15; - NSan::Unpoison(begin, end - begin); - } - return Crc32cExtend(checksum, data, len); -} - -#pragma pack(push, 1) -struct TTcpPacketHeader_v2 { - ui64 Confirm; - ui64 Serial; - ui32 Checksum; // for the whole frame - ui16 PayloadLength; -}; -#pragma pack(pop) - -struct TTcpPacketBuf { - static constexpr ui64 PingRequestMask = 0x8000000000000000ULL; - static constexpr ui64 PingResponseMask = 0x4000000000000000ULL; - static constexpr ui64 ClockMask = 0x2000000000000000ULL; - - static constexpr size_t PacketDataLen = 4096 * 2 - 96 - sizeof(TTcpPacketHeader_v2); -}; - -struct TEventData { - ui32 Type; - ui32 Flags; - TActorId Recipient; - TActorId Sender; - ui64 Cookie; - NWilson::TTraceId TraceId; - ui32 Checksum; -#if IC_FORCE_HARDENED_PACKET_CHECKS - ui32 Len; -#endif -}; - -#pragma pack(push, 1) - -struct TEventDescr2 { - ui32 Type; - ui32 Flags; - TActorId Recipient; - TActorId Sender; - ui64 Cookie; - NWilson::TTraceId::TSerializedTraceId TraceId; - ui32 Checksum; -#if IC_FORCE_HARDENED_PACKET_CHECKS - ui32 Len; -#endif -}; - -#pragma pack(pop) - -struct TEventHolder : TNonCopyable { - TEventData Descr; - TActorId ForwardRecipient; - THolder<IEventBase> Event; - TIntrusivePtr<TEventSerializedData> Buffer; - ui64 Serial; - ui32 EventSerializedSize; - ui32 EventActuallySerialized; - mutable NLWTrace::TOrbit Orbit; - NWilson::TSpan Span; - - ui32 Fill(IEventHandle& ev); - - void InitChecksum() { - Descr.Checksum = 0; - } - - void UpdateChecksum(const void *buffer, size_t len) { - if (FORCE_EVENT_CHECKSUM) { - Descr.Checksum = Crc32cExtendMSanCompatible(Descr.Checksum, buffer, len); - } - } - - void ForwardOnNondelivery(bool unsure) { - TEventData& d = Descr; - const TActorId& r = d.Recipient; - const TActorId& s = d.Sender; - const TActorId *f = ForwardRecipient ? &ForwardRecipient : nullptr; - Span.EndError("nondelivery"); - auto ev = Event - ? std::make_unique<IEventHandle>(r, s, Event.Release(), d.Flags, d.Cookie, f, Span.GetTraceId()) - : std::make_unique<IEventHandle>(d.Type, d.Flags, r, s, std::move(Buffer), d.Cookie, f, Span.GetTraceId()); - NActors::TActivationContext::Send(IEventHandle::ForwardOnNondelivery(std::move(ev), NActors::TEvents::TEvUndelivered::Disconnected, unsure)); - } - - void Clear() { - Event.Reset(); - Buffer.Reset(); - Orbit.Reset(); - Span = {}; - } -}; - -namespace NActors { - class TEventOutputChannel; -} - -struct TTcpPacketOutTask : TNonCopyable { - const TSessionParams& Params; - NInterconnect::TOutgoingStream& OutgoingStream; - NInterconnect::TOutgoingStream& XdcStream; - NInterconnect::TOutgoingStream::TBookmark HeaderBookmark; - ui32 InternalSize = 0; - ui32 ExternalSize = 0; - - ui32 PreBookmarkChecksum = 0; - ui32 InternalChecksum = 0; - ui32 InternalChecksumLen = 0; - bool InsideBookmark = false; - - ui32 ExternalChecksum = 0; - - TTcpPacketOutTask(const TSessionParams& params, NInterconnect::TOutgoingStream& outgoingStream, - NInterconnect::TOutgoingStream& xdcStream) - : Params(params) - , OutgoingStream(outgoingStream) - , XdcStream(xdcStream) - , HeaderBookmark(OutgoingStream.Bookmark(sizeof(TTcpPacketHeader_v2))) - {} - - // Preallocate some space to fill it later. - NInterconnect::TOutgoingStream::TBookmark Bookmark(size_t len) { - if (ChecksummingCrc32c()) { - Y_DEBUG_ABORT_UNLESS(!InsideBookmark); - InsideBookmark = true; - PreBookmarkChecksum = std::exchange(InternalChecksum, 0); - InternalChecksumLen = 0; - } - Y_DEBUG_ABORT_UNLESS(len <= GetInternalFreeAmount()); - InternalSize += len; - return OutgoingStream.Bookmark(len); - } - - // Write previously bookmarked space. - void WriteBookmark(NInterconnect::TOutgoingStream::TBookmark&& bookmark, const void *buffer, size_t len) { - if (ChecksummingCrc32c()) { - Y_DEBUG_ABORT_UNLESS(InsideBookmark); - InsideBookmark = false; - const ui32 bookmarkChecksum = Crc32cExtendMSanCompatible(PreBookmarkChecksum, buffer, len); - InternalChecksum = Crc32cCombine(bookmarkChecksum, InternalChecksum, InternalChecksumLen); - } - OutgoingStream.WriteBookmark(std::move(bookmark), {static_cast<const char*>(buffer), len}); - } - - // Acquire raw pointer to write some data. - template<bool External> - TMutableContiguousSpan AcquireSpanForWriting() { - if (External) { - return XdcStream.AcquireSpanForWriting(GetExternalFreeAmount()); - } else { - return OutgoingStream.AcquireSpanForWriting(GetInternalFreeAmount()); - } - } - - // Append reference to some data (acquired previously or external pointer). - template<bool External> - void Append(const void *buffer, size_t len) { - Y_DEBUG_ABORT_UNLESS(len <= (External ? GetExternalFreeAmount() : GetInternalFreeAmount())); - (External ? ExternalSize : InternalSize) += len; - (External ? XdcStream : OutgoingStream).Append({static_cast<const char*>(buffer), len}); - ProcessChecksum<External>(buffer, len); - } - - // Write some data with copying. - template<bool External> - void Write(const void *buffer, size_t len) { - Y_DEBUG_ABORT_UNLESS(len <= (External ? GetExternalFreeAmount() : GetInternalFreeAmount())); - (External ? ExternalSize : InternalSize) += len; - (External ? XdcStream : OutgoingStream).Write({static_cast<const char*>(buffer), len}); - ProcessChecksum<External>(buffer, len); - } - - template<bool External> - void ProcessChecksum(const void *buffer, size_t len) { - if (ChecksummingCrc32c()) { - if (External) { - ExternalChecksum = Crc32cExtendMSanCompatible(ExternalChecksum, buffer, len); - } else { - InternalChecksum = Crc32cExtendMSanCompatible(InternalChecksum, buffer, len); - InternalChecksumLen += len; - } - } - } - - void Finish(ui64 serial, ui64 confirm) { - Y_ABORT_UNLESS(InternalSize <= Max<ui16>()); - - TTcpPacketHeader_v2 header{ - confirm, - serial, - 0, - static_cast<ui16>(InternalSize) - }; - - if (ChecksummingXxhash()) { - // write header with zero checksum to calculate whole packet checksum correctly - OutgoingStream.WriteBookmark(NInterconnect::TOutgoingStream::TBookmark(HeaderBookmark), - {reinterpret_cast<const char*>(&header), sizeof(header)}); - - // calculate packet checksum - XXH3_state_t state; - XXH3_64bits_reset(&state); - OutgoingStream.ScanLastBytes(GetPacketSize(), [&state](TContiguousSpan span) { - XXH3_64bits_update(&state, span.data(), span.size()); - }); - header.Checksum = XXH3_64bits_digest(&state); - } else if (ChecksummingCrc32c()) { - Y_DEBUG_ABORT_UNLESS(!InsideBookmark); - const ui32 headerChecksum = Crc32cExtendMSanCompatible(0, &header, sizeof(header)); - header.Checksum = Crc32cCombine(headerChecksum, InternalChecksum, InternalSize); - } - - OutgoingStream.WriteBookmark(std::exchange(HeaderBookmark, {}), {reinterpret_cast<const char*>(&header), - sizeof(header)}); - } - - bool ChecksummingCrc32c() const { - return !Params.Encryption && !Params.UseXxhash; - } - - bool ChecksummingXxhash() const { - return !Params.Encryption && Params.UseXxhash; - } - - bool IsEmpty() const { return GetDataSize() == 0; } - ui32 GetDataSize() const { return InternalSize + ExternalSize; } - ui32 GetPacketSize() const { return sizeof(TTcpPacketHeader_v2) + InternalSize; } - ui32 GetInternalFreeAmount() const { return TTcpPacketBuf::PacketDataLen - InternalSize; } - ui32 GetExternalFreeAmount() const { return 16384 - ExternalSize; } - ui32 GetExternalSize() const { return ExternalSize; } -}; - -namespace NInterconnect::NDetail { - static constexpr size_t MaxNumberBytes = (sizeof(ui64) * CHAR_BIT + 6) / 7; - - inline size_t SerializeNumber(ui64 num, char *buffer) { - char *begin = buffer; - do { - *buffer++ = (num & 0x7F) | (num >= 128 ? 0x80 : 0x00); - num >>= 7; - } while (num); - return buffer - begin; - } - - inline ui64 DeserializeNumber(const char **ptr, const char *end) { - const char *p = *ptr; - size_t res = 0; - size_t offset = 0; - for (;;) { - if (p == end) { - return Max<ui64>(); - } - const char byte = *p++; - res |= (static_cast<size_t>(byte) & 0x7F) << offset; - offset += 7; - if (!(byte & 0x80)) { - break; - } - } - *ptr = p; - return res; - } -} diff --git a/library/cpp/actors/interconnect/poller.h b/library/cpp/actors/interconnect/poller.h deleted file mode 100644 index ff7979369f..0000000000 --- a/library/cpp/actors/interconnect/poller.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include <functional> -#include <library/cpp/actors/core/events.h> - -namespace NActors { - class TSharedDescriptor: public TThrRefBase { - public: - virtual int GetDescriptor() = 0; - }; - - using TDelegate = std::function<void()>; - using TFDDelegate = std::function<TDelegate(const TIntrusivePtr<TSharedDescriptor>&)>; - - class IPoller: public TThrRefBase { - public: - virtual ~IPoller() = default; - - virtual void StartRead(const TIntrusivePtr<TSharedDescriptor>& s, TFDDelegate&& operation) = 0; - virtual void StartWrite(const TIntrusivePtr<TSharedDescriptor>& s, TFDDelegate&& operation) = 0; - }; - -} diff --git a/library/cpp/actors/interconnect/poller_actor.cpp b/library/cpp/actors/interconnect/poller_actor.cpp deleted file mode 100644 index 040bdf8651..0000000000 --- a/library/cpp/actors/interconnect/poller_actor.cpp +++ /dev/null @@ -1,318 +0,0 @@ -#include "poller_actor.h" -#include "interconnect_common.h" - -#include <library/cpp/actors/core/actor_bootstrapped.h> -#include <library/cpp/actors/core/actorsystem.h> -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/core/probes.h> -#include <library/cpp/actors/protos/services_common.pb.h> -#include <library/cpp/actors/util/funnel_queue.h> - -#include <util/generic/intrlist.h> -#include <util/system/thread.h> -#include <util/system/event.h> -#include <util/system/pipe.h> - -#include <variant> - -namespace NActors { - - LWTRACE_USING(ACTORLIB_PROVIDER); - - namespace { - int LastSocketError() { -#if defined(_win_) - return WSAGetLastError(); -#else - return errno; -#endif - } - } - - struct TSocketRecord : TThrRefBase { - const TIntrusivePtr<TSharedDescriptor> Socket; - const TActorId ReadActorId; - const TActorId WriteActorId; - std::atomic_uint32_t Flags = 0; - - TSocketRecord(TEvPollerRegister& ev) - : Socket(std::move(ev.Socket)) - , ReadActorId(ev.ReadActorId) - , WriteActorId(ev.WriteActorId) - {} - }; - - template<typename TDerived> - class TPollerThreadBase : public ISimpleThread { - protected: - struct TPollerExitThread {}; // issued then we need to terminate the poller thread - - struct TPollerWakeup {}; - - struct TPollerUnregisterSocket { - TIntrusivePtr<TSharedDescriptor> Socket; - - TPollerUnregisterSocket(TIntrusivePtr<TSharedDescriptor> socket) - : Socket(std::move(socket)) - {} - }; - - using TPollerSyncOperation = std::variant<TPollerExitThread, TPollerWakeup, TPollerUnregisterSocket>; - - struct TPollerSyncOperationWrapper { - TPollerSyncOperation Operation; - TManualEvent Event; - - TPollerSyncOperationWrapper(TPollerSyncOperation&& operation) - : Operation(std::move(operation)) - {} - - void Wait() { - Event.WaitI(); - } - - void SignalDone() { - Event.Signal(); - } - }; - - TActorSystem *ActorSystem; - TPipeHandle ReadEnd, WriteEnd; // pipe for sync event processor - TFunnelQueue<TPollerSyncOperationWrapper*> SyncOperationsQ; // operation queue - - public: - TPollerThreadBase(TActorSystem *actorSystem) - : ActorSystem(actorSystem) - { - // create a pipe for notifications - try { - TPipeHandle::Pipe(ReadEnd, WriteEnd, CloseOnExec); - } catch (const TFileError& err) { - Y_ABORT("failed to create pipe"); - } - - // switch the read/write ends to nonblocking mode - SetNonBlock(ReadEnd); - SetNonBlock(WriteEnd); - } - - void UnregisterSocket(const TIntrusivePtr<TSocketRecord>& record) { - ExecuteSyncOperation(TPollerUnregisterSocket(record->Socket)); - } - - protected: - void Notify(TSocketRecord *record, bool read, bool write) { - auto issue = [&](const TActorId& recipient) { - ActorSystem->Send(new IEventHandle(recipient, {}, new TEvPollerReady(record->Socket, read, write))); - }; - if (read && record->ReadActorId) { - issue(record->ReadActorId); - if (write && record->WriteActorId && record->WriteActorId != record->ReadActorId) { - issue(record->WriteActorId); - } - } else if (write && record->WriteActorId) { - issue(record->WriteActorId); - } - } - - void Stop() { - // signal poller thread to stop and wait for the thread - ExecuteSyncOperation(TPollerExitThread()); - ISimpleThread::Join(); - } - - void ExecuteSyncOperation(TPollerSyncOperation&& op) { - TPollerSyncOperationWrapper wrapper(std::move(op)); - if (SyncOperationsQ.Push(&wrapper)) { - // this was the first entry, so we push notification through the pipe - for (;;) { - char buffer = '\x00'; - ssize_t nwritten = WriteEnd.Write(&buffer, sizeof(buffer)); - if (nwritten < 0) { - const int err = LastSocketError(); - if (err == EINTR) { - continue; - } else { - Y_ABORT("WriteEnd.Write() failed with %s", strerror(err)); - } - } else { - Y_ABORT_UNLESS(nwritten); - break; - } - } - } - // wait for operation to complete - wrapper.Wait(); - } - - void DrainReadEnd() { - char buffer[4096]; - for (;;) { - ssize_t n = ReadEnd.Read(buffer, sizeof(buffer)); - if (n < 0) { - const int error = LastSocketError(); - if (error == EINTR) { - continue; - } else if (error == EAGAIN || error == EWOULDBLOCK) { - break; - } else { - Y_ABORT("read() failed with %s", strerror(errno)); - } - } else { - Y_ABORT_UNLESS(n); - } - } - } - - bool ProcessSyncOpQueue() { - Y_ABORT_UNLESS(!SyncOperationsQ.IsEmpty()); - do { - TPollerSyncOperationWrapper *op = SyncOperationsQ.Top(); - if (auto *unregister = std::get_if<TPollerUnregisterSocket>(&op->Operation)) { - static_cast<TDerived&>(*this).UnregisterSocketInLoop(unregister->Socket); - op->SignalDone(); - } else if (std::get_if<TPollerExitThread>(&op->Operation)) { - op->SignalDone(); - return false; // terminate the thread - } else if (std::get_if<TPollerWakeup>(&op->Operation)) { - op->SignalDone(); - } else { - Y_ABORT(); - } - } while (SyncOperationsQ.Pop()); - return true; - } - - void *ThreadProc() override { - SetCurrentThreadName("network poller"); - for (;;) { - if (static_cast<TDerived&>(*this).ProcessEventsInLoop()) { // need to process the queue - DrainReadEnd(); - if (!ProcessSyncOpQueue()) { - break; - } - } - } - return nullptr; - } - }; - -} // namespace NActors - -#if defined(_linux_) -# include "poller_actor_linux.h" -#elif defined(_darwin_) -# include "poller_actor_darwin.h" -#elif defined(_win_) -# include "poller_actor_win.h" -#else -# error "Unsupported platform" -#endif - -namespace NActors { - - class TPollerToken::TImpl { - std::weak_ptr<TPollerThread> Thread; - TIntrusivePtr<TSocketRecord> Record; // valid only when Thread is held locked - - public: - TImpl(std::shared_ptr<TPollerThread> thread, TIntrusivePtr<TSocketRecord> record) - : Thread(thread) - , Record(std::move(record)) - { - thread->RegisterSocket(Record); - } - - ~TImpl() { - if (auto thread = Thread.lock()) { - thread->UnregisterSocket(Record); - } - } - - void Request(bool read, bool write) { - if (auto thread = Thread.lock()) { - thread->Request(Record, read, write, false, false); - } - } - - bool RequestReadNotificationAfterWouldBlock() { - if (auto thread = Thread.lock()) { - return thread->Request(Record, true, false, true, true); - } else { - return false; - } - } - - bool RequestWriteNotificationAfterWouldBlock() { - if (auto thread = Thread.lock()) { - return thread->Request(Record, false, true, true, true); - } else { - return false; - } - } - - const TIntrusivePtr<TSharedDescriptor>& Socket() const { - return Record->Socket; - } - }; - - class TPollerActor: public TActorBootstrapped<TPollerActor> { - // poller thread - std::shared_ptr<TPollerThread> PollerThread; - - public: - static constexpr IActor::EActivityType ActorActivityType() { - return IActor::EActivityType::INTERCONNECT_POLLER; - } - - void Bootstrap() { - PollerThread = std::make_shared<TPollerThread>(TlsActivationContext->ExecutorThread.ActorSystem); - Become(&TPollerActor::StateFunc); - } - - STRICT_STFUNC(StateFunc, - hFunc(TEvPollerRegister, Handle); - cFunc(TEvents::TSystem::Poison, PassAway); - ) - - void Handle(TEvPollerRegister::TPtr& ev) { - auto *msg = ev->Get(); - auto impl = std::make_unique<TPollerToken::TImpl>(PollerThread, MakeIntrusive<TSocketRecord>(*msg)); - auto socket = impl->Socket(); - TPollerToken::TPtr token(new TPollerToken(std::move(impl))); - if (msg->ReadActorId && msg->WriteActorId && msg->WriteActorId != msg->ReadActorId) { - Send(msg->ReadActorId, new TEvPollerRegisterResult(socket, token)); - Send(msg->WriteActorId, new TEvPollerRegisterResult(socket, std::move(token))); - } else if (msg->ReadActorId) { - Send(msg->ReadActorId, new TEvPollerRegisterResult(socket, std::move(token))); - } else if (msg->WriteActorId) { - Send(msg->WriteActorId, new TEvPollerRegisterResult(socket, std::move(token))); - } - } - }; - - TPollerToken::TPollerToken(std::unique_ptr<TImpl> impl) - : Impl(std::move(impl)) - {} - - TPollerToken::~TPollerToken() - {} - - void TPollerToken::Request(bool read, bool write) { - Impl->Request(read, write); - } - - bool TPollerToken::RequestReadNotificationAfterWouldBlock() { - return Impl->RequestReadNotificationAfterWouldBlock(); - } - - bool TPollerToken::RequestWriteNotificationAfterWouldBlock() { - return Impl->RequestWriteNotificationAfterWouldBlock(); - } - - IActor* CreatePollerActor() { - return new TPollerActor(); - } - -} diff --git a/library/cpp/actors/interconnect/poller_actor.h b/library/cpp/actors/interconnect/poller_actor.h deleted file mode 100644 index 4fb2d49a65..0000000000 --- a/library/cpp/actors/interconnect/poller_actor.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include "events_local.h" -#include "poller.h" -#include <library/cpp/actors/core/actor.h> - -namespace NActors { - struct TEvPollerRegister : TEventLocal<TEvPollerRegister, ui32(ENetwork::EvPollerRegister)> { - const TIntrusivePtr<TSharedDescriptor> Socket; // socket to watch for - const TActorId ReadActorId; // actor id to notify about read availability - const TActorId WriteActorId; // actor id to notify about write availability; may be the same as the ReadActorId - - TEvPollerRegister(TIntrusivePtr<TSharedDescriptor> socket, const TActorId& readActorId, const TActorId& writeActorId) - : Socket(std::move(socket)) - , ReadActorId(readActorId) - , WriteActorId(writeActorId) - {} - }; - - // poller token is sent in response to TEvPollerRegister; it allows requesting poll when read/write returns EAGAIN - class TPollerToken : public TThrRefBase { - class TImpl; - std::unique_ptr<TImpl> Impl; - - friend class TPollerActor; - TPollerToken(std::unique_ptr<TImpl> impl); - - public: - ~TPollerToken(); - void Request(bool read, bool write); - bool RequestReadNotificationAfterWouldBlock(); - bool RequestWriteNotificationAfterWouldBlock(); - - bool RequestNotificationAfterWouldBlock(bool read, bool write) { - bool status = false; - status |= read && RequestReadNotificationAfterWouldBlock(); - status |= write && RequestWriteNotificationAfterWouldBlock(); - return status; - } - - using TPtr = TIntrusivePtr<TPollerToken>; - }; - - struct TEvPollerRegisterResult : TEventLocal<TEvPollerRegisterResult, ui32(ENetwork::EvPollerRegisterResult)> { - TIntrusivePtr<TSharedDescriptor> Socket; - TPollerToken::TPtr PollerToken; - - TEvPollerRegisterResult(TIntrusivePtr<TSharedDescriptor> socket, TPollerToken::TPtr pollerToken) - : Socket(std::move(socket)) - , PollerToken(std::move(pollerToken)) - {} - }; - - struct TEvPollerReady : TEventLocal<TEvPollerReady, ui32(ENetwork::EvPollerReady)> { - TIntrusivePtr<TSharedDescriptor> Socket; - const bool Read, Write; - - TEvPollerReady(TIntrusivePtr<TSharedDescriptor> socket, bool read, bool write) - : Socket(std::move(socket)) - , Read(read) - , Write(write) - {} - }; - - IActor* CreatePollerActor(); - - inline TActorId MakePollerActorId() { - char x[12] = {'I', 'C', 'P', 'o', 'l', 'l', 'e', 'r', '\xDE', '\xAD', '\xBE', '\xEF'}; - return TActorId(0, TStringBuf(std::begin(x), std::end(x))); - } - -} diff --git a/library/cpp/actors/interconnect/poller_actor_darwin.h b/library/cpp/actors/interconnect/poller_actor_darwin.h deleted file mode 100644 index cd763ac589..0000000000 --- a/library/cpp/actors/interconnect/poller_actor_darwin.h +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once - -#include <sys/event.h> - -namespace NActors { - - class TKqueueThread : public TPollerThreadBase<TKqueueThread> { - // KQueue file descriptor - int KqDescriptor; - - void SafeKevent(const struct kevent* ev, int size) { - int rc; - do { - rc = kevent(KqDescriptor, ev, size, nullptr, 0, nullptr); - } while (rc == -1 && errno == EINTR); - Y_ABORT_UNLESS(rc != -1, "kevent() failed with %s", strerror(errno)); - } - - public: - TKqueueThread(TActorSystem *actorSystem) - : TPollerThreadBase(actorSystem) - { - // create kqueue - KqDescriptor = kqueue(); - Y_ABORT_UNLESS(KqDescriptor != -1, "kqueue() failed with %s", strerror(errno)); - - // set close-on-exit flag - { - int flags = fcntl(KqDescriptor, F_GETFD); - Y_ABORT_UNLESS(flags >= 0, "fcntl(F_GETFD) failed with %s", strerror(errno)); - int rc = fcntl(KqDescriptor, F_SETFD, flags | FD_CLOEXEC); - Y_ABORT_UNLESS(rc != -1, "fcntl(F_SETFD, +FD_CLOEXEC) failed with %s", strerror(errno)); - } - - // register pipe's read end in poller - struct kevent ev; - EV_SET(&ev, (int)ReadEnd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, nullptr); - SafeKevent(&ev, 1); - - ISimpleThread::Start(); // start poller thread - } - - ~TKqueueThread() { - Stop(); - close(KqDescriptor); - } - - bool ProcessEventsInLoop() { - std::array<struct kevent, 256> events; - - int numReady = kevent(KqDescriptor, nullptr, 0, events.data(), events.size(), nullptr); - if (numReady == -1) { - if (errno == EINTR) { - return false; - } else { - Y_ABORT("kevent() failed with %s", strerror(errno)); - } - } - - bool res = false; - - for (int i = 0; i < numReady; ++i) { - const struct kevent& ev = events[i]; - if (ev.udata) { - TSocketRecord *it = static_cast<TSocketRecord*>(ev.udata); - const bool error = ev.flags & (EV_EOF | EV_ERROR); - const bool read = error || ev.filter == EVFILT_READ; - const bool write = error || ev.filter == EVFILT_WRITE; - Notify(it, read, write); - } else { - res = true; - } - } - - return res; - } - - void UnregisterSocketInLoop(const TIntrusivePtr<TSharedDescriptor>& socket) { - struct kevent ev[2]; - const int fd = socket->GetDescriptor(); - EV_SET(&ev[0], fd, EVFILT_READ, EV_DELETE, 0, 0, nullptr); - EV_SET(&ev[1], fd, EVFILT_WRITE, EV_DELETE, 0, 0, nullptr); - SafeKevent(ev, 2); - } - - void RegisterSocket(const TIntrusivePtr<TSocketRecord>& record) { - int flags = EV_ADD | EV_CLEAR | EV_ENABLE; - struct kevent ev[2]; - const int fd = record->Socket->GetDescriptor(); - EV_SET(&ev[0], fd, EVFILT_READ, flags, 0, 0, record.Get()); - EV_SET(&ev[1], fd, EVFILT_WRITE, flags, 0, 0, record.Get()); - SafeKevent(ev, 2); - } - - bool Request(const TIntrusivePtr<TSocketRecord>& /*socket*/, bool /*read*/, bool /*write*/, bool /*suppressNotify*/, - bool /*afterWouldBlock*/) { - return false; // no special processing here as we use kqueue in edge-triggered mode - } - }; - - using TPollerThread = TKqueueThread; - -} diff --git a/library/cpp/actors/interconnect/poller_actor_linux.h b/library/cpp/actors/interconnect/poller_actor_linux.h deleted file mode 100644 index 2cd557e347..0000000000 --- a/library/cpp/actors/interconnect/poller_actor_linux.h +++ /dev/null @@ -1,132 +0,0 @@ -#pragma once - -#include <sys/epoll.h> - -namespace NActors { - - enum { - ReadExpected = 1, - ReadHit = 2, - WriteExpected = 4, - WriteHit = 8, - }; - - class TEpollThread : public TPollerThreadBase<TEpollThread> { - // epoll file descriptor - int EpollDescriptor; - - public: - TEpollThread(TActorSystem *actorSystem) - : TPollerThreadBase(actorSystem) - { - EpollDescriptor = epoll_create1(EPOLL_CLOEXEC); - Y_ABORT_UNLESS(EpollDescriptor != -1, "epoll_create1() failed with %s", strerror(errno)); - - epoll_event event; - event.data.ptr = nullptr; - event.events = EPOLLIN; - if (epoll_ctl(EpollDescriptor, EPOLL_CTL_ADD, ReadEnd, &event) == -1) { - Y_ABORT("epoll_ctl(EPOLL_CTL_ADD) failed with %s", strerror(errno)); - } - - ISimpleThread::Start(); // start poller thread - } - - ~TEpollThread() { - Stop(); - close(EpollDescriptor); - } - - bool ProcessEventsInLoop() { - // preallocated array for events - std::array<epoll_event, 256> events; - - // wait indefinitely for event to arrive - LWPROBE(EpollStartWaitIn); - int numReady = epoll_wait(EpollDescriptor, events.data(), events.size(), -1); - LWPROBE(EpollFinishWaitIn, numReady); - - // check return status for any errors - if (numReady == -1) { - if (errno == EINTR) { - return false; // restart the call a bit later - } else { - Y_ABORT("epoll_wait() failed with %s", strerror(errno)); - } - } - - bool res = false; - - for (int i = 0; i < numReady; ++i) { - const epoll_event& ev = events[i]; - if (auto *record = static_cast<TSocketRecord*>(ev.data.ptr)) { - const bool read = ev.events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR); - const bool write = ev.events & (EPOLLOUT | EPOLLERR); - UpdateFlags(record, (read ? ReadHit : 0) | (write ? WriteHit : 0), false /*suppressNotify*/, - false /*checkQueues*/); - } else { - res = true; - } - } - - return res; - } - - bool UpdateFlags(TSocketRecord *record, ui32 addMask, bool suppressNotify, bool checkQueues) { - ui32 flags = record->Flags.load(std::memory_order_acquire); - for (;;) { - ui32 updated = flags | addMask; - static constexpr ui32 fullRead = ReadExpected | ReadHit; - static constexpr ui32 fullWrite = WriteExpected | WriteHit; - bool read = (updated & fullRead) == fullRead; - bool write = (updated & fullWrite) == fullWrite; - updated &= ~((read ? fullRead : 0) | (write ? fullWrite : 0)); - if (record->Flags.compare_exchange_weak(flags, updated, std::memory_order_acq_rel)) { - if (suppressNotify) { - return read || write; - } else { - if (checkQueues) { - pollfd fd; - fd.fd = record->Socket->GetDescriptor(); - const bool queryRead = updated & ReadExpected && !read; - const bool queryWrite = updated & WriteExpected && !write; - if (queryRead || queryWrite) { - fd.events = (queryRead ? POLLIN : 0) | (queryWrite ? POLLOUT : 0); - if (poll(&fd, 1, 0) != -1) { - read = queryRead && fd.revents & (POLLIN | POLLHUP | POLLRDHUP | POLLERR); - write = queryWrite && fd.revents & (POLLOUT | POLLERR); - } - } - } - Notify(record, read, write); - return false; - } - } - } - } - - void UnregisterSocketInLoop(const TIntrusivePtr<TSharedDescriptor>& socket) { - if (epoll_ctl(EpollDescriptor, EPOLL_CTL_DEL, socket->GetDescriptor(), nullptr) == -1) { - Y_ABORT("epoll_ctl(EPOLL_CTL_DEL) failed with %s", strerror(errno)); - } - } - - void RegisterSocket(const TIntrusivePtr<TSocketRecord>& record) { - epoll_event event; - event.events = EPOLLET | EPOLLRDHUP | EPOLLIN | EPOLLOUT; - event.data.ptr = record.Get(); - if (epoll_ctl(EpollDescriptor, EPOLL_CTL_ADD, record->Socket->GetDescriptor(), &event) == -1) { - Y_ABORT("epoll_ctl(EPOLL_CTL_ADD) failed with %s", strerror(errno)); - } - } - - bool Request(const TIntrusivePtr<TSocketRecord>& record, bool read, bool write, bool suppressNotify, - bool afterWouldBlock) { - return UpdateFlags(record.Get(), (read ? ReadExpected : 0) | (write ? WriteExpected : 0), suppressNotify, - !afterWouldBlock); - } - }; - - using TPollerThread = TEpollThread; - -} // namespace NActors diff --git a/library/cpp/actors/interconnect/poller_actor_win.h b/library/cpp/actors/interconnect/poller_actor_win.h deleted file mode 100644 index a4b213ff8c..0000000000 --- a/library/cpp/actors/interconnect/poller_actor_win.h +++ /dev/null @@ -1,111 +0,0 @@ -#pragma once - -namespace NActors { - - class TSelectThread : public TPollerThreadBase<TSelectThread> { - TMutex Mutex; - std::unordered_map<SOCKET, TIntrusivePtr<TSocketRecord>> Descriptors; - - enum { - READ = 1, - WRITE = 2, - }; - - public: - TSelectThread(TActorSystem *actorSystem) - : TPollerThreadBase(actorSystem) - { - Descriptors.emplace(ReadEnd, nullptr); - ISimpleThread::Start(); - } - - ~TSelectThread() { - Stop(); - } - - bool ProcessEventsInLoop() { - fd_set readfds, writefds, exceptfds; - - FD_ZERO(&readfds); - FD_ZERO(&writefds); - FD_ZERO(&exceptfds); - int nfds = 0; - with_lock (Mutex) { - for (const auto& [key, record] : Descriptors) { - const int fd = key; - auto add = [&](auto& set) { - FD_SET(fd, &set); - nfds = Max<int>(nfds, fd + 1); - }; - if (!record || (record->Flags & READ)) { - add(readfds); - } - if (!record || (record->Flags & WRITE)) { - add(writefds); - } - add(exceptfds); - } - } - - int res = select(nfds, &readfds, &writefds, &exceptfds, nullptr); - if (res == -1) { - const int err = LastSocketError(); - if (err == EINTR) { - return false; // try a bit later - } else { - Y_ABORT("select() failed with %s", strerror(err)); - } - } - - bool flag = false; - - with_lock (Mutex) { - for (const auto& [fd, record] : Descriptors) { - if (record) { - const bool error = FD_ISSET(fd, &exceptfds); - const bool read = error || FD_ISSET(fd, &readfds); - const bool write = error || FD_ISSET(fd, &writefds); - if (read) { - record->Flags &= ~READ; - } - if (write) { - record->Flags &= ~WRITE; - } - Notify(record.Get(), read, write); - } else { - flag = true; - } - } - } - - return flag; - } - - void UnregisterSocketInLoop(const TIntrusivePtr<TSharedDescriptor>& socket) { - with_lock (Mutex) { - Descriptors.erase(socket->GetDescriptor()); - } - } - - void RegisterSocket(const TIntrusivePtr<TSocketRecord>& record) { - with_lock (Mutex) { - Descriptors.emplace(record->Socket->GetDescriptor(), record); - } - ExecuteSyncOperation(TPollerWakeup()); - } - - bool Request(const TIntrusivePtr<TSocketRecord>& record, bool read, bool write, bool /*suppressNotify*/, - bool /*afterWouldBlock*/) { - with_lock (Mutex) { - const auto it = Descriptors.find(record->Socket->GetDescriptor()); - Y_ABORT_UNLESS(it != Descriptors.end()); - it->second->Flags |= (read ? READ : 0) | (write ? WRITE : 0); - } - ExecuteSyncOperation(TPollerWakeup()); - return false; - } - }; - - using TPollerThread = TSelectThread; - -} // NActors diff --git a/library/cpp/actors/interconnect/poller_tcp.cpp b/library/cpp/actors/interconnect/poller_tcp.cpp deleted file mode 100644 index ab9b7c85ea..0000000000 --- a/library/cpp/actors/interconnect/poller_tcp.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "poller_tcp.h" - -namespace NInterconnect { - TPollerThreads::TPollerThreads(size_t units, bool useSelect) - : Units(units) - { - Y_DEBUG_ABORT_UNLESS(!Units.empty()); - for (auto& unit : Units) - unit = TPollerUnit::Make(useSelect); - } - - TPollerThreads::~TPollerThreads() { - } - - void TPollerThreads::Start() { - for (const auto& unit : Units) - unit->Start(); - } - - void TPollerThreads::Stop() { - for (const auto& unit : Units) - unit->Stop(); - } - - void TPollerThreads::StartRead(const TIntrusivePtr<TSharedDescriptor>& s, TFDDelegate&& operation) { - auto& unit = Units[THash<SOCKET>()(s->GetDescriptor()) % Units.size()]; - unit->StartReadOperation(s, std::move(operation)); - } - - void TPollerThreads::StartWrite(const TIntrusivePtr<TSharedDescriptor>& s, TFDDelegate&& operation) { - auto& unit = Units[THash<SOCKET>()(s->GetDescriptor()) % Units.size()]; - unit->StartWriteOperation(s, std::move(operation)); - } - -} diff --git a/library/cpp/actors/interconnect/poller_tcp.h b/library/cpp/actors/interconnect/poller_tcp.h deleted file mode 100644 index 310265eccd..0000000000 --- a/library/cpp/actors/interconnect/poller_tcp.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "poller_tcp_unit.h" -#include "poller.h" - -#include <util/generic/vector.h> -#include <util/generic/hash.h> - -namespace NInterconnect { - class TPollerThreads: public NActors::IPoller { - public: - TPollerThreads(size_t units = 1U, bool useSelect = false); - ~TPollerThreads(); - - void Start(); - void Stop(); - - void StartRead(const TIntrusivePtr<TSharedDescriptor>& s, TFDDelegate&& operation) override; - void StartWrite(const TIntrusivePtr<TSharedDescriptor>& s, TFDDelegate&& operation) override; - - private: - TVector<TPollerUnit::TPtr> Units; - }; - -} diff --git a/library/cpp/actors/interconnect/poller_tcp_unit.cpp b/library/cpp/actors/interconnect/poller_tcp_unit.cpp deleted file mode 100644 index 994d907004..0000000000 --- a/library/cpp/actors/interconnect/poller_tcp_unit.cpp +++ /dev/null @@ -1,126 +0,0 @@ -#include "poller_tcp_unit.h" - -#if !defined(_win_) && !defined(_darwin_) -#include "poller_tcp_unit_epoll.h" -#endif - -#include "poller_tcp_unit_select.h" -#include "poller.h" - -#include <library/cpp/actors/prof/tag.h> -#include <library/cpp/actors/util/intrinsics.h> - -#if defined _linux_ -#include <pthread.h> -#endif - -namespace NInterconnect { - TPollerUnit::TPtr - TPollerUnit::Make(bool useSelect) { -#if defined(_win_) || defined(_darwin_) - Y_UNUSED(useSelect); - return TPtr(new TPollerUnitSelect); -#else - return useSelect ? TPtr(new TPollerUnitSelect) : TPtr(new TPollerUnitEpoll); -#endif - } - - TPollerUnit::TPollerUnit() - : StopFlag(true) - , ReadLoop(TThread::TParams(IdleThread<false>, this).SetName("network read")) - , WriteLoop(TThread::TParams(IdleThread<true>, this).SetName("network write")) - { - } - - TPollerUnit::~TPollerUnit() { - if (!AtomicLoad(&StopFlag)) - Stop(); - } - - void - TPollerUnit::Start() { - AtomicStore(&StopFlag, false); - ReadLoop.Start(); - WriteLoop.Start(); - } - - void - TPollerUnit::Stop() { - AtomicStore(&StopFlag, true); - ReadLoop.Join(); - WriteLoop.Join(); - } - - template <> - TPollerUnit::TSide& - TPollerUnit::GetSide<false>() { - return Read; - } - - template <> - TPollerUnit::TSide& - TPollerUnit::GetSide<true>() { - return Write; - } - - void - TPollerUnit::StartReadOperation( - const TIntrusivePtr<TSharedDescriptor>& stream, - TFDDelegate&& operation) { - Y_DEBUG_ABORT_UNLESS(stream); - if (AtomicLoad(&StopFlag)) - return; - GetSide<false>().InputQueue.Push(TSide::TItem(stream, std::move(operation))); - } - - void - TPollerUnit::StartWriteOperation( - const TIntrusivePtr<TSharedDescriptor>& stream, - TFDDelegate&& operation) { - Y_DEBUG_ABORT_UNLESS(stream); - if (AtomicLoad(&StopFlag)) - return; - GetSide<true>().InputQueue.Push(TSide::TItem(stream, std::move(operation))); - } - - template <bool IsWrite> - void* - TPollerUnit::IdleThread(void* param) { - // TODO: musl-libc version of `sched_param` struct is for some reason different from pthread - // version in Ubuntu 12.04 -#if defined(_linux_) && !defined(_musl_) - pthread_t threadSelf = pthread_self(); - sched_param sparam = {20}; - pthread_setschedparam(threadSelf, SCHED_FIFO, &sparam); -#endif - - static_cast<TPollerUnit*>(param)->RunLoop<IsWrite>(); - return nullptr; - } - - template <> - void - TPollerUnit::RunLoop<false>() { - NProfiling::TMemoryTagScope tag("INTERCONNECT_RECEIVED_DATA"); - while (!AtomicLoad(&StopFlag)) - ProcessRead(); - } - - template <> - void - TPollerUnit::RunLoop<true>() { - NProfiling::TMemoryTagScope tag("INTERCONNECT_SEND_DATA"); - while (!AtomicLoad(&StopFlag)) - ProcessWrite(); - } - - void - TPollerUnit::TSide::ProcessInput() { - if (!InputQueue.IsEmpty()) - do { - auto sock = InputQueue.Top().first->GetDescriptor(); - if (!Operations.emplace(sock, std::move(InputQueue.Top())).second) - Y_ABORT("Descriptor is already in pooler."); - } while (InputQueue.Pop()); - } -} diff --git a/library/cpp/actors/interconnect/poller_tcp_unit.h b/library/cpp/actors/interconnect/poller_tcp_unit.h deleted file mode 100644 index 692168b968..0000000000 --- a/library/cpp/actors/interconnect/poller_tcp_unit.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include <util/system/thread.h> -#include <library/cpp/actors/util/funnel_queue.h> - -#include "interconnect_stream.h" - -#include <memory> -#include <functional> -#include <unordered_map> - -namespace NInterconnect { - using NActors::TFDDelegate; - using NActors::TSharedDescriptor; - - class TPollerUnit { - public: - typedef std::unique_ptr<TPollerUnit> TPtr; - - static TPtr Make(bool useSelect); - - void Start(); - void Stop(); - - virtual void StartReadOperation( - const TIntrusivePtr<TSharedDescriptor>& stream, - TFDDelegate&& operation); - - virtual void StartWriteOperation( - const TIntrusivePtr<TSharedDescriptor>& stream, - TFDDelegate&& operation); - - virtual ~TPollerUnit(); - - private: - virtual void ProcessRead() = 0; - virtual void ProcessWrite() = 0; - - template <bool IsWrite> - static void* IdleThread(void* param); - - template <bool IsWrite> - void RunLoop(); - - volatile bool StopFlag; - TThread ReadLoop, WriteLoop; - - protected: - TPollerUnit(); - - struct TSide { - using TOperations = - std::unordered_map<SOCKET, - std::pair<TIntrusivePtr<TSharedDescriptor>, TFDDelegate>>; - - TOperations Operations; - using TItem = TOperations::mapped_type; - TFunnelQueue<TItem> InputQueue; - - void ProcessInput(); - } Read, Write; - - template <bool IsWrite> - TSide& GetSide(); - }; - -} diff --git a/library/cpp/actors/interconnect/poller_tcp_unit_epoll.cpp b/library/cpp/actors/interconnect/poller_tcp_unit_epoll.cpp deleted file mode 100644 index aac6d52bb4..0000000000 --- a/library/cpp/actors/interconnect/poller_tcp_unit_epoll.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "poller_tcp_unit_epoll.h" -#if !defined(_win_) && !defined(_darwin_) -#include <unistd.h> -#include <sys/epoll.h> - -#include <csignal> -#include <cerrno> - -namespace NInterconnect { - namespace { - void - DeleteEpoll(int epoll, SOCKET stream) { - ::epoll_event event = {0, {.fd = stream}}; - if (::epoll_ctl(epoll, EPOLL_CTL_DEL, stream, &event)) { - Cerr << "epoll_ctl errno: " << errno << Endl; - Y_ABORT("epoll delete error!"); - } - } - - template <ui32 Events> - void - AddEpoll(int epoll, SOCKET stream) { - ::epoll_event event = {.events = Events}; - event.data.fd = stream; - if (::epoll_ctl(epoll, EPOLL_CTL_ADD, stream, &event)) { - Cerr << "epoll_ctl errno: " << errno << Endl; - Y_ABORT("epoll add error!"); - } - } - - int - Initialize() { - const auto epoll = ::epoll_create(10000); - Y_DEBUG_ABORT_UNLESS(epoll > 0); - return epoll; - } - - } - - TPollerUnitEpoll::TPollerUnitEpoll() - : ReadDescriptor(Initialize()) - , WriteDescriptor(Initialize()) - { - // Block on the epoll descriptor. - ::sigemptyset(&sigmask); - ::sigaddset(&sigmask, SIGPIPE); - ::sigaddset(&sigmask, SIGTERM); - } - - TPollerUnitEpoll::~TPollerUnitEpoll() { - ::close(ReadDescriptor); - ::close(WriteDescriptor); - } - - template <> - int TPollerUnitEpoll::GetDescriptor<false>() const { - return ReadDescriptor; - } - - template <> - int TPollerUnitEpoll::GetDescriptor<true>() const { - return WriteDescriptor; - } - - void - TPollerUnitEpoll::StartReadOperation( - const TIntrusivePtr<TSharedDescriptor>& s, - TFDDelegate&& operation) { - TPollerUnit::StartReadOperation(s, std::move(operation)); - AddEpoll<EPOLLRDHUP | EPOLLIN>(ReadDescriptor, s->GetDescriptor()); - } - - void - TPollerUnitEpoll::StartWriteOperation( - const TIntrusivePtr<TSharedDescriptor>& s, - TFDDelegate&& operation) { - TPollerUnit::StartWriteOperation(s, std::move(operation)); - AddEpoll<EPOLLRDHUP | EPOLLOUT>(WriteDescriptor, s->GetDescriptor()); - } - - constexpr int EVENTS_BUF_SIZE = 128; - - template <bool WriteOp> - void - TPollerUnitEpoll::Process() { - ::epoll_event events[EVENTS_BUF_SIZE]; - - const int epoll = GetDescriptor<WriteOp>(); - - /* Timeout just to check StopFlag sometimes */ - const int result = - ::epoll_pwait(epoll, events, EVENTS_BUF_SIZE, 200, &sigmask); - - if (result == -1 && errno != EINTR) - Y_ABORT("epoll wait error!"); - - auto& side = GetSide<WriteOp>(); - side.ProcessInput(); - - for (int i = 0; i < result; ++i) { - const auto it = side.Operations.find(events[i].data.fd); - if (side.Operations.end() == it) - continue; - if (const auto& finalizer = it->second.second(it->second.first)) { - DeleteEpoll(epoll, it->first); - side.Operations.erase(it); - finalizer(); - } - } - } - - void - TPollerUnitEpoll::ProcessRead() { - Process<false>(); - } - - void - TPollerUnitEpoll::ProcessWrite() { - Process<true>(); - } - -} - -#endif diff --git a/library/cpp/actors/interconnect/poller_tcp_unit_epoll.h b/library/cpp/actors/interconnect/poller_tcp_unit_epoll.h deleted file mode 100644 index ff7893eba2..0000000000 --- a/library/cpp/actors/interconnect/poller_tcp_unit_epoll.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include "poller_tcp_unit.h" - -namespace NInterconnect { - class TPollerUnitEpoll: public TPollerUnit { - public: - TPollerUnitEpoll(); - virtual ~TPollerUnitEpoll(); - - private: - virtual void StartReadOperation( - const TIntrusivePtr<TSharedDescriptor>& s, - TFDDelegate&& operation) override; - - virtual void StartWriteOperation( - const TIntrusivePtr<TSharedDescriptor>& s, - TFDDelegate&& operation) override; - - virtual void ProcessRead() override; - virtual void ProcessWrite() override; - - template <bool Write> - void Process(); - - template <bool Write> - int GetDescriptor() const; - - const int ReadDescriptor, WriteDescriptor; - ::sigset_t sigmask; - }; - -} diff --git a/library/cpp/actors/interconnect/poller_tcp_unit_select.cpp b/library/cpp/actors/interconnect/poller_tcp_unit_select.cpp deleted file mode 100644 index 1615d4679d..0000000000 --- a/library/cpp/actors/interconnect/poller_tcp_unit_select.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "poller_tcp_unit_select.h" - -#include <csignal> - -#if defined(_win_) -#include <winsock2.h> -#define SOCKET_ERROR_SOURCE ::WSAGetLastError() -#elif defined(_darwin_) -#include <cerrno> -#define SOCKET_ERROR_SOURCE errno -typedef timeval TIMEVAL; -#else -#include <cerrno> -#define SOCKET_ERROR_SOURCE errno -#endif - -namespace NInterconnect { - TPollerUnitSelect::TPollerUnitSelect() { - } - - TPollerUnitSelect::~TPollerUnitSelect() { - } - - template <bool IsWrite> - void - TPollerUnitSelect::Process() { - auto& side = GetSide<IsWrite>(); - side.ProcessInput(); - - enum : size_t { R, - W, - E }; - static const auto O = IsWrite ? W : R; - - ::fd_set sets[3]; - - FD_ZERO(&sets[R]); - FD_ZERO(&sets[W]); - FD_ZERO(&sets[E]); - - for (const auto& operation : side.Operations) { - FD_SET(operation.first, &sets[O]); - FD_SET(operation.first, &sets[E]); - } - -#if defined(_win_) - ::TIMEVAL timeout = {0L, 99991L}; - const auto numberEvents = !side.Operations.empty() ? ::select(FD_SETSIZE, &sets[R], &sets[W], &sets[E], &timeout) - : (::Sleep(100), 0); -#elif defined(_darwin_) - ::TIMEVAL timeout = {0L, 99991L}; - const auto numberEvents = ::select(FD_SETSIZE, &sets[R], &sets[W], &sets[E], &timeout); -#else - ::sigset_t sigmask; - ::sigemptyset(&sigmask); - ::sigaddset(&sigmask, SIGPIPE); - ::sigaddset(&sigmask, SIGTERM); - - struct ::timespec timeout = {0L, 99999989L}; - const auto numberEvents = ::pselect(FD_SETSIZE, &sets[R], &sets[W], &sets[E], &timeout, &sigmask); -#endif - - Y_DEBUG_ABORT_UNLESS(numberEvents >= 0); - - for (auto it = side.Operations.cbegin(); side.Operations.cend() != it;) { - if (FD_ISSET(it->first, &sets[O]) || FD_ISSET(it->first, &sets[E])) - if (const auto& finalizer = it->second.second(it->second.first)) { - side.Operations.erase(it++); - finalizer(); - continue; - } - ++it; - } - } - - void - TPollerUnitSelect::ProcessRead() { - Process<false>(); - } - - void - TPollerUnitSelect::ProcessWrite() { - Process<true>(); - } - -} diff --git a/library/cpp/actors/interconnect/poller_tcp_unit_select.h b/library/cpp/actors/interconnect/poller_tcp_unit_select.h deleted file mode 100644 index 0c15217796..0000000000 --- a/library/cpp/actors/interconnect/poller_tcp_unit_select.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "poller_tcp_unit.h" - -namespace NInterconnect { - class TPollerUnitSelect: public TPollerUnit { - public: - TPollerUnitSelect(); - virtual ~TPollerUnitSelect(); - - private: - virtual void ProcessRead() override; - virtual void ProcessWrite() override; - - template <bool IsWrite> - void Process(); - }; - -} diff --git a/library/cpp/actors/interconnect/profiler.h b/library/cpp/actors/interconnect/profiler.h deleted file mode 100644 index 11dac077ea..0000000000 --- a/library/cpp/actors/interconnect/profiler.h +++ /dev/null @@ -1,142 +0,0 @@ -#pragma once - -#include <library/cpp/actors/util/datetime.h> - -namespace NActors { - - class TProfiled { - enum class EType : ui32 { - ENTRY, - EXIT, - }; - - struct TItem { - EType Type; // entry kind - int Line; - const char *Marker; // name of the profiled function/part - ui64 Timestamp; // cycles - }; - - bool Enable = false; - mutable TDeque<TItem> Items; - - friend class TFunction; - - public: - class TFunction { - const TProfiled& Profiled; - - public: - TFunction(const TProfiled& profiled, const char *name, int line) - : Profiled(profiled) - { - Log(EType::ENTRY, name, line); - } - - ~TFunction() { - Log(EType::EXIT, nullptr, 0); - } - - private: - void Log(EType type, const char *marker, int line) { - if (Profiled.Enable) { - Profiled.Items.push_back(TItem{ - type, - line, - marker, - GetCycleCountFast() - }); - } - } - }; - - public: - void Start() { - Enable = true; - } - - void Finish() { - Items.clear(); - Enable = false; - } - - TDuration Duration() const { - return CyclesToDuration(Items ? Items.back().Timestamp - Items.front().Timestamp : 0); - } - - TString Format() const { - TDeque<TItem>::iterator it = Items.begin(); - TString res = FormatLevel(it); - Y_ABORT_UNLESS(it == Items.end()); - return res; - } - - private: - TString FormatLevel(TDeque<TItem>::iterator& it) const { - struct TRecord { - TString Marker; - ui64 Duration; - TString Interior; - - bool operator <(const TRecord& other) const { - return Duration < other.Duration; - } - }; - TVector<TRecord> records; - - while (it != Items.end() && it->Type != EType::EXIT) { - Y_ABORT_UNLESS(it->Type == EType::ENTRY); - const TString marker = Sprintf("%s:%d", it->Marker, it->Line); - const ui64 begin = it->Timestamp; - ++it; - const TString interior = FormatLevel(it); - Y_ABORT_UNLESS(it != Items.end()); - Y_ABORT_UNLESS(it->Type == EType::EXIT); - const ui64 end = it->Timestamp; - records.push_back(TRecord{marker, end - begin, interior}); - ++it; - } - - TStringStream s; - const ui64 cyclesPerMs = GetCyclesPerMillisecond(); - - if (records.size() <= 10) { - bool first = true; - for (const TRecord& record : records) { - if (first) { - first = false; - } else { - s << " "; - } - s << record.Marker << "(" << (record.Duration * 1000000 / cyclesPerMs) << "ns)"; - if (record.Interior) { - s << " {" << record.Interior << "}"; - } - } - } else { - TMap<TString, TVector<TRecord>> m; - for (TRecord& r : records) { - const TString key = r.Marker; - m[key].push_back(std::move(r)); - } - - s << "unordered "; - for (auto& [key, value] : m) { - auto i = std::max_element(value.begin(), value.end()); - ui64 sum = 0; - for (const auto& item : value) { - sum += item.Duration; - } - sum = sum * 1000000 / cyclesPerMs; - s << key << " num# " << value.size() << " sum# " << sum << "ns max# " << (i->Duration * 1000000 / cyclesPerMs) << "ns"; - if (i->Interior) { - s << " {" << i->Interior << "}"; - } - } - } - - return s.Str(); - } - }; - -} // NActors diff --git a/library/cpp/actors/interconnect/slowpoke_actor.h b/library/cpp/actors/interconnect/slowpoke_actor.h deleted file mode 100644 index 4b02e5da48..0000000000 --- a/library/cpp/actors/interconnect/slowpoke_actor.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/actor_bootstrapped.h> - -namespace NActors { - - class TSlowpokeActor : public TActorBootstrapped<TSlowpokeActor> { - const TDuration Duration; - const TDuration SleepMin; - const TDuration SleepMax; - const TDuration RescheduleMin; - const TDuration RescheduleMax; - - public: - static constexpr NKikimrServices::TActivity::EType ActorActivityType() { - return NKikimrServices::TActivity::INTERCONNECT_COMMON; - } - - TSlowpokeActor(TDuration duration, TDuration sleepMin, TDuration sleepMax, TDuration rescheduleMin, TDuration rescheduleMax) - : Duration(duration) - , SleepMin(sleepMin) - , SleepMax(sleepMax) - , RescheduleMin(rescheduleMin) - , RescheduleMax(rescheduleMax) - {} - - void Bootstrap(const TActorContext& ctx) { - Become(&TThis::StateFunc, ctx, Duration, new TEvents::TEvPoisonPill); - HandleWakeup(ctx); - } - - void HandleWakeup(const TActorContext& ctx) { - Sleep(RandomDuration(SleepMin, SleepMax)); - ctx.Schedule(RandomDuration(RescheduleMin, RescheduleMax), new TEvents::TEvWakeup); - } - - static TDuration RandomDuration(TDuration min, TDuration max) { - return min + TDuration::FromValue(RandomNumber<ui64>(max.GetValue() - min.GetValue() + 1)); - } - - STRICT_STFUNC(StateFunc, - CFunc(TEvents::TSystem::PoisonPill, Die) - CFunc(TEvents::TSystem::Wakeup, HandleWakeup) - ) - }; - -} // NActors diff --git a/library/cpp/actors/interconnect/types.cpp b/library/cpp/actors/interconnect/types.cpp deleted file mode 100644 index 979c55f277..0000000000 --- a/library/cpp/actors/interconnect/types.cpp +++ /dev/null @@ -1,564 +0,0 @@ -#include "types.h" -#include <util/string/printf.h> -#include <util/generic/vector.h> -#include <errno.h> - -namespace NActors { - - TVector<const char*> TDisconnectReason::Reasons = { - "EndOfStream", - "CloseOnIdle", - "LostConnection", - "DeadPeer", - "NewSession", - "HandshakeFailTransient", - "HandshakeFailPermanent", - "UserRequest", - "Debug", - "ChecksumError", - "FormatError", - "EventTooLarge", - "QueueOverload", - "E2BIG", - "EACCES", - "EADDRINUSE", - "EADDRNOTAVAIL", - "EADV", - "EAFNOSUPPORT", - "EAGAIN", - "EALREADY", - "EBADE", - "EBADF", - "EBADFD", - "EBADMSG", - "EBADR", - "EBADRQC", - "EBADSLT", - "EBFONT", - "EBUSY", - "ECANCELED", - "ECHILD", - "ECHRNG", - "ECOMM", - "ECONNABORTED", - "ECONNREFUSED", - "ECONNRESET", - "EDEADLK", - "EDEADLOCK", - "EDESTADDRREQ", - "EDOM", - "EDOTDOT", - "EDQUOT", - "EEXIST", - "EFAULT", - "EFBIG", - "EHOSTDOWN", - "EHOSTUNREACH", - "EHWPOISON", - "EIDRM", - "EILSEQ", - "EINPROGRESS", - "EINTR", - "EINVAL", - "EIO", - "EISCONN", - "EISDIR", - "EISNAM", - "EKEYEXPIRED", - "EKEYREJECTED", - "EKEYREVOKED", - "EL2HLT", - "EL2NSYNC", - "EL3HLT", - "EL3RST", - "ELIBACC", - "ELIBBAD", - "ELIBEXEC", - "ELIBMAX", - "ELIBSCN", - "ELNRNG", - "ELOOP", - "EMEDIUMTYPE", - "EMFILE", - "EMLINK", - "EMSGSIZE", - "EMULTIHOP", - "ENAMETOOLONG", - "ENAVAIL", - "ENETDOWN", - "ENETRESET", - "ENETUNREACH", - "ENFILE", - "ENOANO", - "ENOBUFS", - "ENOCSI", - "ENODATA", - "ENODEV", - "ENOENT", - "ENOEXEC", - "ENOKEY", - "ENOLCK", - "ENOLINK", - "ENOMEDIUM", - "ENOMEM", - "ENOMSG", - "ENONET", - "ENOPKG", - "ENOPROTOOPT", - "ENOSPC", - "ENOSR", - "ENOSTR", - "ENOSYS", - "ENOTBLK", - "ENOTCONN", - "ENOTDIR", - "ENOTEMPTY", - "ENOTNAM", - "ENOTRECOVERABLE", - "ENOTSOCK", - "ENOTTY", - "ENOTUNIQ", - "ENXIO", - "EOPNOTSUPP", - "EOVERFLOW", - "EOWNERDEAD", - "EPERM", - "EPFNOSUPPORT", - "EPIPE", - "EPROTO", - "EPROTONOSUPPORT", - "EPROTOTYPE", - "ERANGE", - "EREMCHG", - "EREMOTE", - "EREMOTEIO", - "ERESTART", - "ERFKILL", - "EROFS", - "ESHUTDOWN", - "ESOCKTNOSUPPORT", - "ESPIPE", - "ESRCH", - "ESRMNT", - "ESTALE", - "ESTRPIPE", - "ETIME", - "ETIMEDOUT", - "ETOOMANYREFS", - "ETXTBSY", - "EUCLEAN", - "EUNATCH", - "EUSERS", - "EWOULDBLOCK", - "EXDEV", - "EXFULL", - }; - - TDisconnectReason TDisconnectReason::FromErrno(int err) { - switch (err) { -#define REASON(ERRNO) case ERRNO: return TDisconnectReason(TString(#ERRNO)) -#if defined(E2BIG) - REASON(E2BIG); -#endif -#if defined(EACCES) - REASON(EACCES); -#endif -#if defined(EADDRINUSE) - REASON(EADDRINUSE); -#endif -#if defined(EADDRNOTAVAIL) - REASON(EADDRNOTAVAIL); -#endif -#if defined(EADV) - REASON(EADV); -#endif -#if defined(EAFNOSUPPORT) - REASON(EAFNOSUPPORT); -#endif -#if defined(EAGAIN) - REASON(EAGAIN); -#endif -#if defined(EALREADY) - REASON(EALREADY); -#endif -#if defined(EBADE) - REASON(EBADE); -#endif -#if defined(EBADF) - REASON(EBADF); -#endif -#if defined(EBADFD) - REASON(EBADFD); -#endif -#if defined(EBADMSG) - REASON(EBADMSG); -#endif -#if defined(EBADR) - REASON(EBADR); -#endif -#if defined(EBADRQC) - REASON(EBADRQC); -#endif -#if defined(EBADSLT) - REASON(EBADSLT); -#endif -#if defined(EBFONT) - REASON(EBFONT); -#endif -#if defined(EBUSY) - REASON(EBUSY); -#endif -#if defined(ECANCELED) - REASON(ECANCELED); -#endif -#if defined(ECHILD) - REASON(ECHILD); -#endif -#if defined(ECHRNG) - REASON(ECHRNG); -#endif -#if defined(ECOMM) - REASON(ECOMM); -#endif -#if defined(ECONNABORTED) - REASON(ECONNABORTED); -#endif -#if defined(ECONNREFUSED) - REASON(ECONNREFUSED); -#endif -#if defined(ECONNRESET) - REASON(ECONNRESET); -#endif -#if defined(EDEADLK) - REASON(EDEADLK); -#endif -#if defined(EDEADLOCK) && (!defined(EDEADLK) || EDEADLOCK != EDEADLK) - REASON(EDEADLOCK); -#endif -#if defined(EDESTADDRREQ) - REASON(EDESTADDRREQ); -#endif -#if defined(EDOM) - REASON(EDOM); -#endif -#if defined(EDOTDOT) - REASON(EDOTDOT); -#endif -#if defined(EDQUOT) - REASON(EDQUOT); -#endif -#if defined(EEXIST) - REASON(EEXIST); -#endif -#if defined(EFAULT) - REASON(EFAULT); -#endif -#if defined(EFBIG) - REASON(EFBIG); -#endif -#if defined(EHOSTDOWN) - REASON(EHOSTDOWN); -#endif -#if defined(EHOSTUNREACH) - REASON(EHOSTUNREACH); -#endif -#if defined(EHWPOISON) - REASON(EHWPOISON); -#endif -#if defined(EIDRM) - REASON(EIDRM); -#endif -#if defined(EILSEQ) - REASON(EILSEQ); -#endif -#if defined(EINPROGRESS) - REASON(EINPROGRESS); -#endif -#if defined(EINTR) - REASON(EINTR); -#endif -#if defined(EINVAL) - REASON(EINVAL); -#endif -#if defined(EIO) - REASON(EIO); -#endif -#if defined(EISCONN) - REASON(EISCONN); -#endif -#if defined(EISDIR) - REASON(EISDIR); -#endif -#if defined(EISNAM) - REASON(EISNAM); -#endif -#if defined(EKEYEXPIRED) - REASON(EKEYEXPIRED); -#endif -#if defined(EKEYREJECTED) - REASON(EKEYREJECTED); -#endif -#if defined(EKEYREVOKED) - REASON(EKEYREVOKED); -#endif -#if defined(EL2HLT) - REASON(EL2HLT); -#endif -#if defined(EL2NSYNC) - REASON(EL2NSYNC); -#endif -#if defined(EL3HLT) - REASON(EL3HLT); -#endif -#if defined(EL3RST) - REASON(EL3RST); -#endif -#if defined(ELIBACC) - REASON(ELIBACC); -#endif -#if defined(ELIBBAD) - REASON(ELIBBAD); -#endif -#if defined(ELIBEXEC) - REASON(ELIBEXEC); -#endif -#if defined(ELIBMAX) - REASON(ELIBMAX); -#endif -#if defined(ELIBSCN) - REASON(ELIBSCN); -#endif -#if defined(ELNRNG) - REASON(ELNRNG); -#endif -#if defined(ELOOP) - REASON(ELOOP); -#endif -#if defined(EMEDIUMTYPE) - REASON(EMEDIUMTYPE); -#endif -#if defined(EMFILE) - REASON(EMFILE); -#endif -#if defined(EMLINK) - REASON(EMLINK); -#endif -#if defined(EMSGSIZE) - REASON(EMSGSIZE); -#endif -#if defined(EMULTIHOP) - REASON(EMULTIHOP); -#endif -#if defined(ENAMETOOLONG) - REASON(ENAMETOOLONG); -#endif -#if defined(ENAVAIL) - REASON(ENAVAIL); -#endif -#if defined(ENETDOWN) - REASON(ENETDOWN); -#endif -#if defined(ENETRESET) - REASON(ENETRESET); -#endif -#if defined(ENETUNREACH) - REASON(ENETUNREACH); -#endif -#if defined(ENFILE) - REASON(ENFILE); -#endif -#if defined(ENOANO) - REASON(ENOANO); -#endif -#if defined(ENOBUFS) - REASON(ENOBUFS); -#endif -#if defined(ENOCSI) - REASON(ENOCSI); -#endif -#if defined(ENODATA) - REASON(ENODATA); -#endif -#if defined(ENODEV) - REASON(ENODEV); -#endif -#if defined(ENOENT) - REASON(ENOENT); -#endif -#if defined(ENOEXEC) - REASON(ENOEXEC); -#endif -#if defined(ENOKEY) - REASON(ENOKEY); -#endif -#if defined(ENOLCK) - REASON(ENOLCK); -#endif -#if defined(ENOLINK) - REASON(ENOLINK); -#endif -#if defined(ENOMEDIUM) - REASON(ENOMEDIUM); -#endif -#if defined(ENOMEM) - REASON(ENOMEM); -#endif -#if defined(ENOMSG) - REASON(ENOMSG); -#endif -#if defined(ENONET) - REASON(ENONET); -#endif -#if defined(ENOPKG) - REASON(ENOPKG); -#endif -#if defined(ENOPROTOOPT) - REASON(ENOPROTOOPT); -#endif -#if defined(ENOSPC) - REASON(ENOSPC); -#endif -#if defined(ENOSR) - REASON(ENOSR); -#endif -#if defined(ENOSTR) - REASON(ENOSTR); -#endif -#if defined(ENOSYS) - REASON(ENOSYS); -#endif -#if defined(ENOTBLK) - REASON(ENOTBLK); -#endif -#if defined(ENOTCONN) - REASON(ENOTCONN); -#endif -#if defined(ENOTDIR) - REASON(ENOTDIR); -#endif -#if defined(ENOTEMPTY) - REASON(ENOTEMPTY); -#endif -#if defined(ENOTNAM) - REASON(ENOTNAM); -#endif -#if defined(ENOTRECOVERABLE) - REASON(ENOTRECOVERABLE); -#endif -#if defined(ENOTSOCK) - REASON(ENOTSOCK); -#endif -#if defined(ENOTTY) - REASON(ENOTTY); -#endif -#if defined(ENOTUNIQ) - REASON(ENOTUNIQ); -#endif -#if defined(ENXIO) - REASON(ENXIO); -#endif -#if defined(EOPNOTSUPP) - REASON(EOPNOTSUPP); -#endif -#if defined(EOVERFLOW) - REASON(EOVERFLOW); -#endif -#if defined(EOWNERDEAD) - REASON(EOWNERDEAD); -#endif -#if defined(EPERM) - REASON(EPERM); -#endif -#if defined(EPFNOSUPPORT) - REASON(EPFNOSUPPORT); -#endif -#if defined(EPIPE) - REASON(EPIPE); -#endif -#if defined(EPROTO) - REASON(EPROTO); -#endif -#if defined(EPROTONOSUPPORT) - REASON(EPROTONOSUPPORT); -#endif -#if defined(EPROTOTYPE) - REASON(EPROTOTYPE); -#endif -#if defined(ERANGE) - REASON(ERANGE); -#endif -#if defined(EREMCHG) - REASON(EREMCHG); -#endif -#if defined(EREMOTE) - REASON(EREMOTE); -#endif -#if defined(EREMOTEIO) - REASON(EREMOTEIO); -#endif -#if defined(ERESTART) - REASON(ERESTART); -#endif -#if defined(ERFKILL) - REASON(ERFKILL); -#endif -#if defined(EROFS) - REASON(EROFS); -#endif -#if defined(ESHUTDOWN) - REASON(ESHUTDOWN); -#endif -#if defined(ESOCKTNOSUPPORT) - REASON(ESOCKTNOSUPPORT); -#endif -#if defined(ESPIPE) - REASON(ESPIPE); -#endif -#if defined(ESRCH) - REASON(ESRCH); -#endif -#if defined(ESRMNT) - REASON(ESRMNT); -#endif -#if defined(ESTALE) - REASON(ESTALE); -#endif -#if defined(ESTRPIPE) - REASON(ESTRPIPE); -#endif -#if defined(ETIME) - REASON(ETIME); -#endif -#if defined(ETIMEDOUT) - REASON(ETIMEDOUT); -#endif -#if defined(ETOOMANYREFS) - REASON(ETOOMANYREFS); -#endif -#if defined(ETXTBSY) - REASON(ETXTBSY); -#endif -#if defined(EUCLEAN) - REASON(EUCLEAN); -#endif -#if defined(EUNATCH) - REASON(EUNATCH); -#endif -#if defined(EUSERS) - REASON(EUSERS); -#endif -#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || EWOULDBLOCK != EAGAIN) - REASON(EWOULDBLOCK); -#endif -#if defined(EXDEV) - REASON(EXDEV); -#endif -#if defined(EXFULL) - REASON(EXFULL); -#endif - default: - return TDisconnectReason(Sprintf("errno=%d", errno)); - } - } - -} // NActors diff --git a/library/cpp/actors/interconnect/types.h b/library/cpp/actors/interconnect/types.h deleted file mode 100644 index 14b1a1c7a6..0000000000 --- a/library/cpp/actors/interconnect/types.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/defs.h> -#include <library/cpp/actors/core/actorid.h> -#include <library/cpp/actors/core/event.h> - -#include <util/generic/string.h> - -namespace NActors { - - class TDisconnectReason { - TString Text; - - private: - explicit TDisconnectReason(TString text) - : Text(std::move(text)) - {} - - public: - TDisconnectReason() = default; - TDisconnectReason(const TDisconnectReason&) = default; - TDisconnectReason(TDisconnectReason&&) = default; - - static TDisconnectReason FromErrno(int err); - - static TDisconnectReason EndOfStream() { return TDisconnectReason("EndOfStream"); } - static TDisconnectReason CloseOnIdle() { return TDisconnectReason("CloseOnIdle"); } - static TDisconnectReason LostConnection() { return TDisconnectReason("LostConnection"); } - static TDisconnectReason DeadPeer() { return TDisconnectReason("DeadPeer"); } - static TDisconnectReason NewSession() { return TDisconnectReason("NewSession"); } - static TDisconnectReason HandshakeFailTransient() { return TDisconnectReason("HandshakeFailTransient"); } - static TDisconnectReason HandshakeFailPermanent() { return TDisconnectReason("HandshakeFailPermanent"); } - static TDisconnectReason UserRequest() { return TDisconnectReason("UserRequest"); } - static TDisconnectReason Debug() { return TDisconnectReason("Debug"); } - static TDisconnectReason ChecksumError() { return TDisconnectReason("ChecksumError"); } - static TDisconnectReason FormatError() { return TDisconnectReason("FormatError"); } - static TDisconnectReason EventTooLarge() { return TDisconnectReason("EventTooLarge"); } - static TDisconnectReason QueueOverload() { return TDisconnectReason("QueueOverload"); } - - TString ToString() const { - return Text; - } - - friend bool operator ==(const TDisconnectReason& x, const TDisconnectReason& y) { return x.Text == y.Text; } - - static TVector<const char*> Reasons; - }; - - struct TProgramInfo { - ui64 PID = 0; - ui64 StartTime = 0; - ui64 Serial = 0; - }; - - struct TSessionParams { - bool Encryption = {}; - bool AuthOnly = {}; - bool UseExternalDataChannel = {}; - bool UseXxhash = {}; - bool UseXdcShuffle = {}; - TString AuthCN; - NActors::TScopeId PeerScopeId; - }; - -} // NActors - -using NActors::IEventBase; -using NActors::IEventHandle; -using NActors::TActorId; -using NActors::TConstIoVec; -using NActors::TEventSerializedData; -using NActors::TSessionParams; diff --git a/library/cpp/actors/interconnect/ut/CMakeLists.darwin-arm64.txt b/library/cpp/actors/interconnect/ut/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 0b2d5cfe5c..0000000000 --- a/library/cpp/actors/interconnect/ut/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,85 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(lib) -add_subdirectory(protos) - -add_executable(library-cpp-actors-interconnect-ut) -target_link_libraries(library-cpp-actors-interconnect-ut PUBLIC - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - interconnect-ut-lib - interconnect-ut-protos - cpp-actors-testlib - cpp-digest-md5 - cpp-testing-unittest -) -target_link_options(library-cpp-actors-interconnect-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-interconnect-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/channel_scheduler_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/event_holder_pool_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/interconnect_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/large.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/outgoing_stream_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/poller_actor_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/dynamic_proxy_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/sticking_ut.cpp -) -set_property( - TARGET - library-cpp-actors-interconnect-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-interconnect-ut - TEST_TARGET - library-cpp-actors-interconnect-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-interconnect-ut - system_allocator -) -vcs_info(library-cpp-actors-interconnect-ut) diff --git a/library/cpp/actors/interconnect/ut/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/interconnect/ut/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 7519ee7ba9..0000000000 --- a/library/cpp/actors/interconnect/ut/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,86 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(lib) -add_subdirectory(protos) - -add_executable(library-cpp-actors-interconnect-ut) -target_link_libraries(library-cpp-actors-interconnect-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - interconnect-ut-lib - interconnect-ut-protos - cpp-actors-testlib - cpp-digest-md5 - cpp-testing-unittest -) -target_link_options(library-cpp-actors-interconnect-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-interconnect-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/channel_scheduler_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/event_holder_pool_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/interconnect_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/large.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/outgoing_stream_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/poller_actor_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/dynamic_proxy_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/sticking_ut.cpp -) -set_property( - TARGET - library-cpp-actors-interconnect-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-interconnect-ut - TEST_TARGET - library-cpp-actors-interconnect-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-interconnect-ut - system_allocator -) -vcs_info(library-cpp-actors-interconnect-ut) diff --git a/library/cpp/actors/interconnect/ut/CMakeLists.linux-aarch64.txt b/library/cpp/actors/interconnect/ut/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 1d488c4550..0000000000 --- a/library/cpp/actors/interconnect/ut/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,89 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(lib) -add_subdirectory(protos) - -add_executable(library-cpp-actors-interconnect-ut) -target_link_libraries(library-cpp-actors-interconnect-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - interconnect-ut-lib - interconnect-ut-protos - cpp-actors-testlib - cpp-digest-md5 - cpp-testing-unittest -) -target_link_options(library-cpp-actors-interconnect-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-interconnect-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/channel_scheduler_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/event_holder_pool_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/interconnect_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/large.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/outgoing_stream_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/poller_actor_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/dynamic_proxy_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/sticking_ut.cpp -) -set_property( - TARGET - library-cpp-actors-interconnect-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-interconnect-ut - TEST_TARGET - library-cpp-actors-interconnect-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-interconnect-ut - cpp-malloc-jemalloc -) -vcs_info(library-cpp-actors-interconnect-ut) diff --git a/library/cpp/actors/interconnect/ut/CMakeLists.linux-x86_64.txt b/library/cpp/actors/interconnect/ut/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 3ee5b5f656..0000000000 --- a/library/cpp/actors/interconnect/ut/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,91 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(lib) -add_subdirectory(protos) - -add_executable(library-cpp-actors-interconnect-ut) -target_link_libraries(library-cpp-actors-interconnect-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - interconnect-ut-lib - interconnect-ut-protos - cpp-actors-testlib - cpp-digest-md5 - cpp-testing-unittest -) -target_link_options(library-cpp-actors-interconnect-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-interconnect-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/channel_scheduler_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/event_holder_pool_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/interconnect_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/large.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/outgoing_stream_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/poller_actor_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/dynamic_proxy_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/sticking_ut.cpp -) -set_property( - TARGET - library-cpp-actors-interconnect-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-interconnect-ut - TEST_TARGET - library-cpp-actors-interconnect-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-interconnect-ut - cpp-malloc-tcmalloc - libs-tcmalloc-no_percpu_cache -) -vcs_info(library-cpp-actors-interconnect-ut) diff --git a/library/cpp/actors/interconnect/ut/CMakeLists.txt b/library/cpp/actors/interconnect/ut/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/interconnect/ut/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/interconnect/ut/CMakeLists.windows-x86_64.txt b/library/cpp/actors/interconnect/ut/CMakeLists.windows-x86_64.txt deleted file mode 100644 index b928771974..0000000000 --- a/library/cpp/actors/interconnect/ut/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,79 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(lib) -add_subdirectory(protos) - -add_executable(library-cpp-actors-interconnect-ut) -target_link_libraries(library-cpp-actors-interconnect-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - interconnect-ut-lib - interconnect-ut-protos - cpp-actors-testlib - cpp-digest-md5 - cpp-testing-unittest -) -target_sources(library-cpp-actors-interconnect-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/channel_scheduler_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/event_holder_pool_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/interconnect_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/large.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/outgoing_stream_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/poller_actor_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/dynamic_proxy_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/sticking_ut.cpp -) -set_property( - TARGET - library-cpp-actors-interconnect-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-interconnect-ut - TEST_TARGET - library-cpp-actors-interconnect-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut - PROPERTY - PROCESSORS - 1 -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-interconnect-ut - system_allocator -) -vcs_info(library-cpp-actors-interconnect-ut) diff --git a/library/cpp/actors/interconnect/ut/channel_scheduler_ut.cpp b/library/cpp/actors/interconnect/ut/channel_scheduler_ut.cpp deleted file mode 100644 index 98e81d7781..0000000000 --- a/library/cpp/actors/interconnect/ut/channel_scheduler_ut.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include <library/cpp/actors/interconnect/channel_scheduler.h> -#include <library/cpp/actors/interconnect/events_local.h> -#include <library/cpp/testing/unittest/registar.h> - -using namespace NActors; - -Y_UNIT_TEST_SUITE(ChannelScheduler) { - - Y_UNIT_TEST(PriorityTraffic) { - auto common = MakeIntrusive<TInterconnectProxyCommon>(); - common->MonCounters = MakeIntrusive<NMonitoring::TDynamicCounters>(); - std::shared_ptr<IInterconnectMetrics> ctr = CreateInterconnectCounters(common); - ctr->SetPeerInfo("peer", "1"); - auto callback = [](THolder<IEventBase>) {}; - TEventHolderPool pool(common, callback); - TSessionParams p; - TChannelScheduler scheduler(1, {}, ctr, pool, 64 << 20, p); - - ui32 numEvents = 0; - - auto pushEvent = [&](size_t size, int channel) { - TString payload(size, 'X'); - auto ev = MakeHolder<IEventHandle>(1, 0, TActorId(), TActorId(), MakeIntrusive<TEventSerializedData>(payload, TEventSerializationInfo{}), 0); - auto& ch = scheduler.GetOutputChannel(channel); - const bool wasWorking = ch.IsWorking(); - ch.Push(*ev); - if (!wasWorking) { - scheduler.AddToHeap(ch, 0); - } - ++numEvents; - }; - - for (ui32 i = 0; i < 100; ++i) { - pushEvent(10000, 1); - } - - for (ui32 i = 0; i < 1000; ++i) { - pushEvent(1000, 2); - } - - std::map<ui16, ui32> run; - ui32 step = 0; - - std::deque<std::map<ui16, ui32>> window; - - NInterconnect::TOutgoingStream stream; - - for (; numEvents; ++step) { - TTcpPacketOutTask task(p, stream, stream); - - if (step == 100) { - for (ui32 i = 0; i < 200; ++i) { - pushEvent(1000, 3); - } - } - - std::map<ui16, ui32> ch; - - while (numEvents) { - TEventOutputChannel *channel = scheduler.PickChannelWithLeastConsumedWeight(); - ui32 before = task.GetDataSize(); - ui64 weightConsumed = 0; - numEvents -= channel->FeedBuf(task, 0, &weightConsumed); - ui32 after = task.GetDataSize(); - Y_ABORT_UNLESS(after >= before); - scheduler.FinishPick(weightConsumed, 0); - const ui32 bytesAdded = after - before; - if (!bytesAdded) { - break; - } - ch[channel->ChannelId] += bytesAdded; - } - - scheduler.Equalize(); - - for (const auto& [key, value] : ch) { - run[key] += value; - } - window.push_back(ch); - - if (window.size() == 32) { - for (const auto& [key, value] : window.front()) { - run[key] -= value; - if (!run[key]) { - run.erase(key); - } - } - window.pop_front(); - } - - double mean = 0.0; - for (const auto& [key, value] : run) { - mean += value; - } - mean /= run.size(); - - double dev = 0.0; - for (const auto& [key, value] : run) { - dev += (value - mean) * (value - mean); - } - dev = sqrt(dev / run.size()); - - double devToMean = dev / mean; - - Cerr << step << ": "; - for (const auto& [key, value] : run) { - Cerr << "ch" << key << "=" << value << " "; - } - Cerr << "mean# " << mean << " dev# " << dev << " part# " << devToMean; - - Cerr << Endl; - - UNIT_ASSERT(devToMean < 1); - } - } - -} diff --git a/library/cpp/actors/interconnect/ut/dynamic_proxy_ut.cpp b/library/cpp/actors/interconnect/ut/dynamic_proxy_ut.cpp deleted file mode 100644 index 4cc6a3cc99..0000000000 --- a/library/cpp/actors/interconnect/ut/dynamic_proxy_ut.cpp +++ /dev/null @@ -1,179 +0,0 @@ -#include <library/cpp/actors/interconnect/ut/lib/node.h> -#include <library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h> -#include <library/cpp/testing/unittest/registar.h> - -TActorId MakeResponderServiceId(ui32 nodeId) { - return TActorId(nodeId, TStringBuf("ResponderAct", 12)); -} - -class TArriveQueue { - struct TArrivedItem { - ui32 QueueId; - ui32 Index; - bool Success; - }; - - TMutex Lock; - std::size_t Counter = 0; - std::vector<TArrivedItem> Items; - -public: - TArriveQueue(size_t capacity) - : Items(capacity) - {} - - bool Done() const { - with_lock (Lock) { - return Counter == Items.size(); - } - } - - void Push(ui64 cookie, bool success) { - with_lock (Lock) { - const size_t pos = Counter++; - TArrivedItem item{.QueueId = static_cast<ui32>(cookie >> 32), .Index = static_cast<ui32>(cookie & 0xffff'ffff), - .Success = success}; - memcpy(&Items[pos], &item, sizeof(TArrivedItem)); - } - } - - void Check() { - struct TPerQueueState { - std::vector<ui32> Ok, Error; - }; - std::unordered_map<ui32, TPerQueueState> state; - for (const TArrivedItem& item : Items) { - auto& st = state[item.QueueId]; - auto& v = item.Success ? st.Ok : st.Error; - v.push_back(item.Index); - } - for (const auto& [queueId, st] : state) { - ui32 expected = 0; - for (const ui32 index : st.Ok) { - Y_ABORT_UNLESS(index == expected); - ++expected; - } - for (const ui32 index : st.Error) { - Y_ABORT_UNLESS(index == expected); - ++expected; - } - if (st.Error.size()) { - Cerr << "Error.size# " << st.Error.size() << Endl; - } - } - } -}; - -class TResponder : public TActor<TResponder> { - TArriveQueue& ArriveQueue; - -public: - TResponder(TArriveQueue& arriveQueue) - : TActor(&TResponder::StateFunc) - , ArriveQueue(arriveQueue) - {} - - STRICT_STFUNC(StateFunc, - hFunc(TEvents::TEvPing, Handle); - ) - - void Handle(TEvents::TEvPing::TPtr ev) { - ArriveQueue.Push(ev->Cookie, true); - } -}; - -class TSender : public TActor<TSender> { - TArriveQueue& ArriveQueue; - -public: - TSender(TArriveQueue& arriveQueue) - : TActor(&TThis::StateFunc) - , ArriveQueue(arriveQueue) - {} - - STRICT_STFUNC(StateFunc, - hFunc(TEvents::TEvUndelivered, Handle); - ) - - void Handle(TEvents::TEvUndelivered::TPtr ev) { - ArriveQueue.Push(ev->Cookie, false); - } -}; - -void SenderThread(TMutex& lock, TActorSystem *as, ui32 nodeId, ui32 queueId, ui32 count, TArriveQueue& arriveQueue) { - const TActorId sender = as->Register(new TSender(arriveQueue)); - with_lock(lock) {} - const TActorId target = MakeResponderServiceId(nodeId); - for (ui32 i = 0; i < count; ++i) { - const ui32 flags = IEventHandle::FlagTrackDelivery; - as->Send(new IEventHandle(TEvents::THelloWorld::Ping, flags, target, sender, nullptr, ((ui64)queueId << 32) | i)); - } -} - -void RaceTestIter(ui32 numThreads, ui32 count) { - TPortManager portman; - THashMap<ui32, ui16> nodeToPort; - const ui32 numNodes = 6; // total - const ui32 numDynamicNodes = 3; - for (ui32 i = 1; i <= numNodes; ++i) { - nodeToPort.emplace(i, portman.GetPort()); - } - - NMonitoring::TDynamicCounterPtr counters = new NMonitoring::TDynamicCounters; - std::list<TNode> nodes; - for (ui32 i = 1; i <= numNodes; ++i) { - nodes.emplace_back(i, numNodes, nodeToPort, "127.1.0.0", counters->GetSubgroup("nodeId", TStringBuilder() << i), - TDuration::Seconds(10), TChannelsConfig(), numDynamicNodes, numThreads); - } - - const ui32 numSenders = 10; - TArriveQueue arriveQueue(numSenders * numNodes * (numNodes - 1) * count); - for (TNode& node : nodes) { - node.RegisterServiceActor(MakeResponderServiceId(node.GetActorSystem()->NodeId), new TResponder(arriveQueue)); - } - - TMutex lock; - std::list<TThread> threads; - ui32 queueId = 0; - with_lock(lock) { - for (TNode& from : nodes) { - for (ui32 toId = 1; toId <= numNodes; ++toId) { - if (toId == from.GetActorSystem()->NodeId) { - continue; - } - for (ui32 i = 0; i < numSenders; ++i) { - threads.emplace_back([=, &lock, &from, &arriveQueue] { - SenderThread(lock, from.GetActorSystem(), toId, queueId, count, arriveQueue); - }); - ++queueId; - } - } - } - for (auto& thread : threads) { - thread.Start(); - } - } - for (auto& thread : threads) { - thread.Join(); - } - - for (THPTimer timer; !arriveQueue.Done(); TDuration::MilliSeconds(10)) { - Y_ABORT_UNLESS(timer.Passed() < 10); - } - - nodes.clear(); - arriveQueue.Check(); -} - -Y_UNIT_TEST_SUITE(DynamicProxy) { - Y_UNIT_TEST(RaceCheck1) { - for (ui32 iteration = 0; iteration < 100; ++iteration) { - RaceTestIter(1 + iteration % 5, 1); - } - } - Y_UNIT_TEST(RaceCheck10) { - for (ui32 iteration = 0; iteration < 100; ++iteration) { - RaceTestIter(1 + iteration % 5, 10); - } - } -} diff --git a/library/cpp/actors/interconnect/ut/event_holder_pool_ut.cpp b/library/cpp/actors/interconnect/ut/event_holder_pool_ut.cpp deleted file mode 100644 index 7b45793e26..0000000000 --- a/library/cpp/actors/interconnect/ut/event_holder_pool_ut.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include <library/cpp/testing/unittest/registar.h> -#include <library/cpp/actors/core/events.h> -#include <library/cpp/actors/core/event_local.h> -#include <library/cpp/actors/interconnect/interconnect_common.h> -#include <library/cpp/monlib/dynamic_counters/counters.h> -#include <library/cpp/actors/interconnect/event_holder_pool.h> - -#include <atomic> - -using namespace NActors; - -template<typename T> -TEventHolderPool Setup(T&& callback) { - auto common = MakeIntrusive<TInterconnectProxyCommon>(); - common->DestructorQueueSize = std::make_shared<std::atomic<TAtomicBase>>(); - common->MaxDestructorQueueSize = 1024 * 1024; - return TEventHolderPool(common, callback); -} - -Y_UNIT_TEST_SUITE(EventHolderPool) { - - Y_UNIT_TEST(Overflow) { - TDeque<THolder<IEventBase>> freeQ; - auto callback = [&](THolder<IEventBase> event) { - freeQ.push_back(std::move(event)); - }; - auto pool = Setup(std::move(callback)); - - std::list<TEventHolder> q; - - auto& ev1 = pool.Allocate(q); - ev1.Buffer = MakeIntrusive<TEventSerializedData>(TString::Uninitialized(512 * 1024), TEventSerializationInfo{}); - - auto& ev2 = pool.Allocate(q); - ev2.Buffer = MakeIntrusive<TEventSerializedData>(TString::Uninitialized(512 * 1024), TEventSerializationInfo{}); - - auto& ev3 = pool.Allocate(q); - ev3.Buffer = MakeIntrusive<TEventSerializedData>(TString::Uninitialized(512 * 1024), TEventSerializationInfo{}); - - auto& ev4 = pool.Allocate(q); - ev4.Buffer = MakeIntrusive<TEventSerializedData>(TString::Uninitialized(512 * 1024), TEventSerializationInfo{}); - - pool.Release(q, q.begin()); - pool.Release(q, q.begin()); - pool.Trim(); - UNIT_ASSERT_VALUES_EQUAL(freeQ.size(), 1); - - pool.Release(q, q.begin()); - UNIT_ASSERT_VALUES_EQUAL(freeQ.size(), 1); - - freeQ.clear(); - pool.Release(q, q.begin()); - pool.Trim(); - UNIT_ASSERT_VALUES_EQUAL(freeQ.size(), 1); - - freeQ.clear(); // if we don't this, we may probablty crash due to the order of object destruction - } - -} diff --git a/library/cpp/actors/interconnect/ut/interconnect_ut.cpp b/library/cpp/actors/interconnect/ut/interconnect_ut.cpp deleted file mode 100644 index bc9e86545a..0000000000 --- a/library/cpp/actors/interconnect/ut/interconnect_ut.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include <library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h> -#include <library/cpp/testing/unittest/registar.h> -#include <library/cpp/digest/md5/md5.h> -#include <util/random/fast.h> - -using namespace NActors; - -class TSenderActor : public TActorBootstrapped<TSenderActor> { - const TActorId Recipient; - using TSessionToCookie = std::unordered_multimap<TActorId, ui64, THash<TActorId>>; - TSessionToCookie SessionToCookie; - std::unordered_map<ui64, std::pair<TSessionToCookie::iterator, TString>> InFlight; - std::unordered_map<ui64, TString> Tentative; - ui64 NextCookie = 0; - TActorId SessionId; - bool SubscribeInFlight = false; - -public: - TSenderActor(TActorId recipient) - : Recipient(recipient) - {} - - void Bootstrap() { - Become(&TThis::StateFunc); - Subscribe(); - } - - void Subscribe() { - Cerr << (TStringBuilder() << "Subscribe" << Endl); - Y_ABORT_UNLESS(!SubscribeInFlight); - SubscribeInFlight = true; - Send(TActivationContext::InterconnectProxy(Recipient.NodeId()), new TEvents::TEvSubscribe); - } - - void IssueQueries() { - if (!SessionId) { - return; - } - while (InFlight.size() < 10) { - size_t len = RandomNumber<size_t>(65536) + 1; - TString data = TString::Uninitialized(len); - TReallyFastRng32 rng(RandomNumber<ui32>()); - char *p = data.Detach(); - for (size_t i = 0; i < len; ++i) { - p[i] = rng(); - } - const TSessionToCookie::iterator s2cIt = SessionToCookie.emplace(SessionId, NextCookie); - InFlight.emplace(NextCookie, std::make_tuple(s2cIt, MD5::CalcRaw(data))); - TActivationContext::Send(new IEventHandle(TEvents::THelloWorld::Ping, IEventHandle::FlagTrackDelivery, Recipient, - SelfId(), MakeIntrusive<TEventSerializedData>(std::move(data), TEventSerializationInfo{}), NextCookie)); -// Cerr << (TStringBuilder() << "Send# " << NextCookie << Endl); - ++NextCookie; - } - } - - void HandlePong(TAutoPtr<IEventHandle> ev) { -// Cerr << (TStringBuilder() << "Receive# " << ev->Cookie << Endl); - if (const auto it = InFlight.find(ev->Cookie); it != InFlight.end()) { - auto& [s2cIt, hash] = it->second; - Y_ABORT_UNLESS(hash == ev->GetChainBuffer()->GetString()); - SessionToCookie.erase(s2cIt); - InFlight.erase(it); - } else if (const auto it = Tentative.find(ev->Cookie); it != Tentative.end()) { - Y_ABORT_UNLESS(it->second == ev->GetChainBuffer()->GetString()); - Tentative.erase(it); - } else { - Y_ABORT("Cookie# %" PRIu64, ev->Cookie); - } - IssueQueries(); - } - - void Handle(TEvInterconnect::TEvNodeConnected::TPtr ev) { - Cerr << (TStringBuilder() << "TEvNodeConnected" << Endl); - Y_ABORT_UNLESS(SubscribeInFlight); - SubscribeInFlight = false; - Y_ABORT_UNLESS(!SessionId); - SessionId = ev->Sender; - IssueQueries(); - } - - void Handle(TEvInterconnect::TEvNodeDisconnected::TPtr ev) { - Cerr << (TStringBuilder() << "TEvNodeDisconnected" << Endl); - SubscribeInFlight = false; - if (SessionId) { - Y_ABORT_UNLESS(SessionId == ev->Sender); - auto r = SessionToCookie.equal_range(SessionId); - for (auto it = r.first; it != r.second; ++it) { - const auto inFlightIt = InFlight.find(it->second); - Y_ABORT_UNLESS(inFlightIt != InFlight.end()); - Tentative.emplace(inFlightIt->first, inFlightIt->second.second); - InFlight.erase(it->second); - } - SessionToCookie.erase(r.first, r.second); - SessionId = TActorId(); - } - Schedule(TDuration::MilliSeconds(100), new TEvents::TEvWakeup); - } - - void Handle(TEvents::TEvUndelivered::TPtr ev) { - Cerr << (TStringBuilder() << "TEvUndelivered Cookie# " << ev->Cookie << Endl); - if (const auto it = InFlight.find(ev->Cookie); it != InFlight.end()) { - auto& [s2cIt, hash] = it->second; - Tentative.emplace(it->first, hash); - SessionToCookie.erase(s2cIt); - InFlight.erase(it); - IssueQueries(); - } - } - - STRICT_STFUNC(StateFunc, - fFunc(TEvents::THelloWorld::Pong, HandlePong); - hFunc(TEvInterconnect::TEvNodeConnected, Handle); - hFunc(TEvInterconnect::TEvNodeDisconnected, Handle); - hFunc(TEvents::TEvUndelivered, Handle); - cFunc(TEvents::TSystem::Wakeup, Subscribe); - ) -}; - -class TRecipientActor : public TActor<TRecipientActor> { -public: - TRecipientActor() - : TActor(&TThis::StateFunc) - {} - - void HandlePing(TAutoPtr<IEventHandle>& ev) { - const TString& data = ev->GetChainBuffer()->GetString(); - const TString& response = MD5::CalcRaw(data); - TActivationContext::Send(new IEventHandle(TEvents::THelloWorld::Pong, 0, ev->Sender, SelfId(), - MakeIntrusive<TEventSerializedData>(response, TEventSerializationInfo{}), ev->Cookie)); - } - - STRICT_STFUNC(StateFunc, - fFunc(TEvents::THelloWorld::Ping, HandlePing); - ) -}; - -Y_UNIT_TEST_SUITE(Interconnect) { - - Y_UNIT_TEST(SessionContinuation) { - TTestICCluster cluster(2); - const TActorId recipient = cluster.RegisterActor(new TRecipientActor, 1); - cluster.RegisterActor(new TSenderActor(recipient), 2); - for (ui32 i = 0; i < 100; ++i) { - const ui32 nodeId = 1 + RandomNumber(2u); - const ui32 peerNodeId = 3 - nodeId; - const ui32 action = RandomNumber(3u); - auto *node = cluster.GetNode(nodeId); - TActorId proxyId = node->InterconnectProxy(peerNodeId); - - switch (action) { - case 0: - node->Send(proxyId, new TEvInterconnect::TEvClosePeerSocket); - Cerr << (TStringBuilder() << "nodeId# " << nodeId << " peerNodeId# " << peerNodeId - << " TEvClosePeerSocket" << Endl); - break; - - case 1: - node->Send(proxyId, new TEvInterconnect::TEvCloseInputSession); - Cerr << (TStringBuilder() << "nodeId# " << nodeId << " peerNodeId# " << peerNodeId - << " TEvCloseInputSession" << Endl); - break; - - case 2: - node->Send(proxyId, new TEvInterconnect::TEvPoisonSession); - Cerr << (TStringBuilder() << "nodeId# " << nodeId << " peerNodeId# " << peerNodeId - << " TEvPoisonSession" << Endl); - break; - - default: - Y_ABORT(); - } - - Sleep(TDuration::MilliSeconds(RandomNumber<ui32>(500) + 100)); - } - } - -} diff --git a/library/cpp/actors/interconnect/ut/large.cpp b/library/cpp/actors/interconnect/ut/large.cpp deleted file mode 100644 index 88207f816b..0000000000 --- a/library/cpp/actors/interconnect/ut/large.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "lib/ic_test_cluster.h" -#include "lib/test_events.h" -#include "lib/test_actors.h" - -#include <library/cpp/actors/interconnect/interconnect_tcp_proxy.h> - -#include <library/cpp/testing/unittest/tests_data.h> -#include <library/cpp/testing/unittest/registar.h> - -#include <util/system/event.h> -#include <util/system/sanitizers.h> - -Y_UNIT_TEST_SUITE(LargeMessage) { - using namespace NActors; - - class TProducer: public TActorBootstrapped<TProducer> { - const TActorId RecipientActorId; - - public: - TProducer(const TActorId& recipientActorId) - : RecipientActorId(recipientActorId) - {} - - void Bootstrap(const TActorContext& ctx) { - Become(&TThis::StateFunc); - ctx.Send(RecipientActorId, new TEvTest(1, "hello"), IEventHandle::FlagTrackDelivery, 1); - ctx.Send(RecipientActorId, new TEvTest(2, TString(150 * 1024 * 1024, 'X')), IEventHandle::FlagTrackDelivery, 2); - } - - void Handle(TEvents::TEvUndelivered::TPtr ev, const TActorContext& ctx) { - if (ev->Cookie == 2) { - Cerr << "TEvUndelivered\n"; - ctx.Send(RecipientActorId, new TEvTest(3, "hello"), IEventHandle::FlagTrackDelivery, 3); - } - } - - STRICT_STFUNC(StateFunc, - HFunc(TEvents::TEvUndelivered, Handle) - ) - }; - - class TConsumer : public TActorBootstrapped<TConsumer> { - TManualEvent& Done; - TActorId SessionId; - - public: - TConsumer(TManualEvent& done) - : Done(done) - { - } - - void Bootstrap(const TActorContext& /*ctx*/) { - Become(&TThis::StateFunc); - } - - void Handle(TEvTest::TPtr ev, const TActorContext& /*ctx*/) { - const auto& record = ev->Get()->Record; - Cerr << "RECEIVED TEvTest\n"; - if (record.GetSequenceNumber() == 1) { - Y_ABORT_UNLESS(!SessionId); - SessionId = ev->InterconnectSession; - } else if (record.GetSequenceNumber() == 3) { - Y_ABORT_UNLESS(SessionId != ev->InterconnectSession); - Done.Signal(); - } else { - Y_ABORT("incorrect sequence number"); - } - } - - STRICT_STFUNC(StateFunc, - HFunc(TEvTest, Handle) - ) - }; - - Y_UNIT_TEST(Test) { - TTestICCluster testCluster(2); - - TManualEvent done; - TConsumer* consumer = new TConsumer(done); - const TActorId recp = testCluster.RegisterActor(consumer, 1); - testCluster.RegisterActor(new TProducer(recp), 2); - done.WaitI(); - } - -} diff --git a/library/cpp/actors/interconnect/ut/lib/CMakeLists.darwin-arm64.txt b/library/cpp/actors/interconnect/ut/lib/CMakeLists.darwin-arm64.txt deleted file mode 100644 index a6a86ac09b..0000000000 --- a/library/cpp/actors/interconnect/ut/lib/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,14 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(interconnect-ut-lib INTERFACE) -target_link_libraries(interconnect-ut-lib INTERFACE - contrib-libs-cxxsupp - yutil -) diff --git a/library/cpp/actors/interconnect/ut/lib/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/interconnect/ut/lib/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index a6a86ac09b..0000000000 --- a/library/cpp/actors/interconnect/ut/lib/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,14 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(interconnect-ut-lib INTERFACE) -target_link_libraries(interconnect-ut-lib INTERFACE - contrib-libs-cxxsupp - yutil -) diff --git a/library/cpp/actors/interconnect/ut/lib/CMakeLists.linux-aarch64.txt b/library/cpp/actors/interconnect/ut/lib/CMakeLists.linux-aarch64.txt deleted file mode 100644 index b20c3b0de9..0000000000 --- a/library/cpp/actors/interconnect/ut/lib/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,15 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(interconnect-ut-lib INTERFACE) -target_link_libraries(interconnect-ut-lib INTERFACE - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil -) diff --git a/library/cpp/actors/interconnect/ut/lib/CMakeLists.linux-x86_64.txt b/library/cpp/actors/interconnect/ut/lib/CMakeLists.linux-x86_64.txt deleted file mode 100644 index b20c3b0de9..0000000000 --- a/library/cpp/actors/interconnect/ut/lib/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,15 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(interconnect-ut-lib INTERFACE) -target_link_libraries(interconnect-ut-lib INTERFACE - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil -) diff --git a/library/cpp/actors/interconnect/ut/lib/CMakeLists.txt b/library/cpp/actors/interconnect/ut/lib/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/interconnect/ut/lib/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/interconnect/ut/lib/CMakeLists.windows-x86_64.txt b/library/cpp/actors/interconnect/ut/lib/CMakeLists.windows-x86_64.txt deleted file mode 100644 index a6a86ac09b..0000000000 --- a/library/cpp/actors/interconnect/ut/lib/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,14 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(interconnect-ut-lib INTERFACE) -target_link_libraries(interconnect-ut-lib INTERFACE - contrib-libs-cxxsupp - yutil -) diff --git a/library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h b/library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h deleted file mode 100644 index dd2557e25e..0000000000 --- a/library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h +++ /dev/null @@ -1,87 +0,0 @@ -#pragma once - -#include "node.h" -#include "interrupter.h" - -#include <library/cpp/actors/interconnect/interconnect_tcp_proxy.h> -#include <library/cpp/actors/core/events.h> -#include <library/cpp/testing/unittest/tests_data.h> - -#include <util/generic/noncopyable.h> - -class TTestICCluster: public TNonCopyable { -public: - struct TTrafficInterrupterSettings { - TDuration RejectingTrafficTimeout; - double BandWidth; - bool Disconnect; - }; - -private: - const ui32 NumNodes; - const TString Address = "::1"; - TDuration DeadPeerTimeout = TDuration::Seconds(2); - NMonitoring::TDynamicCounterPtr Counters; - THashMap<ui32, THolder<TNode>> Nodes; - TList<TTrafficInterrupter> interrupters; - NActors::TChannelsConfig ChannelsConfig; - TPortManager PortManager; - TIntrusivePtr<NLog::TSettings> LoggerSettings; - -public: - TTestICCluster(ui32 numNodes = 1, NActors::TChannelsConfig channelsConfig = NActors::TChannelsConfig(), - TTrafficInterrupterSettings* tiSettings = nullptr, TIntrusivePtr<NLog::TSettings> loggerSettings = nullptr) - : NumNodes(numNodes) - , Counters(new NMonitoring::TDynamicCounters) - , ChannelsConfig(channelsConfig) - , LoggerSettings(loggerSettings) - { - THashMap<ui32, ui16> nodeToPortMap; - THashMap<ui32, THashMap<ui32, ui16>> specificNodePortMap; - - for (ui32 i = 1; i <= NumNodes; ++i) { - nodeToPortMap.emplace(i, PortManager.GetPort()); - } - - if (tiSettings) { - ui32 nodeId; - ui16 listenPort; - ui16 forwardPort; - for (auto& item : nodeToPortMap) { - nodeId = item.first; - listenPort = item.second; - forwardPort = PortManager.GetPort(); - - specificNodePortMap[nodeId] = nodeToPortMap; - specificNodePortMap[nodeId].at(nodeId) = forwardPort; - interrupters.emplace_back(Address, listenPort, forwardPort, tiSettings->RejectingTrafficTimeout, tiSettings->BandWidth, tiSettings->Disconnect); - interrupters.back().Start(); - } - } - - for (ui32 i = 1; i <= NumNodes; ++i) { - auto& portMap = tiSettings ? specificNodePortMap[i] : nodeToPortMap; - Nodes.emplace(i, MakeHolder<TNode>(i, NumNodes, portMap, Address, Counters, DeadPeerTimeout, ChannelsConfig, - /*numDynamicNodes=*/0, /*numThreads=*/1, LoggerSettings)); - } - } - - TNode* GetNode(ui32 id) { - return Nodes[id].Get(); - } - - ~TTestICCluster() { - } - - TActorId RegisterActor(NActors::IActor* actor, ui32 nodeId) { - return Nodes[nodeId]->RegisterActor(actor); - } - - TActorId InterconnectProxy(ui32 peerNodeId, ui32 nodeId) { - return Nodes[nodeId]->InterconnectProxy(peerNodeId); - } - - void KillActor(ui32 nodeId, const TActorId& id) { - Nodes[nodeId]->Send(id, new NActors::TEvents::TEvPoisonPill); - } -}; diff --git a/library/cpp/actors/interconnect/ut/lib/interrupter.h b/library/cpp/actors/interconnect/ut/lib/interrupter.h deleted file mode 100644 index b00985573a..0000000000 --- a/library/cpp/actors/interconnect/ut/lib/interrupter.h +++ /dev/null @@ -1,249 +0,0 @@ -#pragma once - -#include <library/cpp/testing/unittest/tests_data.h> - -#include <util/network/sock.h> -#include <util/network/poller.h> -#include <util/system/thread.h> -#include <util/system/hp_timer.h> -#include <util/generic/list.h> -#include <util/generic/set.h> -#include <util/generic/vector.h> -#include <util/generic/deque.h> -#include <util/random/random.h> - -#include <iterator> - -class TTrafficInterrupter - : public ISimpleThread { - const TString Address; - const ui16 ForwardPort; - TInet6StreamSocket ListenSocket; - - struct TConnectionDescriptor; - struct TDelayedPacket { - TInet6StreamSocket* ForwardSocket = nullptr; - TVector<char> Data; - }; - struct TCompare { - bool operator()(const std::pair<TInstant, TDelayedPacket>& x, const std::pair<TInstant, TDelayedPacket>& y) const { - return x.first > y.first; - }; - }; - - struct TDirectedConnection { - TInet6StreamSocket* Source = nullptr; - TInet6StreamSocket* Destination = nullptr; - TList<TConnectionDescriptor>::iterator ListIterator; - TInstant Timestamp; - TPriorityQueue<std::pair<TInstant, TDelayedPacket>, TVector<std::pair<TInstant, TDelayedPacket>>, TCompare> DelayedQueue; - - TDirectedConnection(TInet6StreamSocket* source, TInet6StreamSocket* destination) - : Source(source) - , Destination(destination) - { - } - }; - - struct TConnectionDescriptor { - std::unique_ptr<TInet6StreamSocket> FirstSocket; - std::unique_ptr<TInet6StreamSocket> SecondSocket; - TDirectedConnection ForwardConnection; - TDirectedConnection BackwardConnection; - - TConnectionDescriptor(std::unique_ptr<TInet6StreamSocket> firstSock, - std::unique_ptr<TInet6StreamSocket> secondSock) - : FirstSocket(std::move(firstSock)) - , SecondSocket(std::move(secondSock)) - , ForwardConnection(FirstSocket.get(), SecondSocket.get()) - , BackwardConnection(SecondSocket.get(), FirstSocket.get()) - { - } - }; - - template <class It = TList<TConnectionDescriptor>::iterator> - class TCustomListIteratorCompare { - public: - bool operator()(const It& it1, const It& it2) const { - return (&(*it1) < &(*it2)); - } - }; - - TList<TConnectionDescriptor> Connections; - TSet<TList<TConnectionDescriptor>::iterator, TCustomListIteratorCompare<>> DroppedConnections; - -public: - TTrafficInterrupter(TString address, ui16 listenPort, ui16 forwardPort, TDuration rejectingTrafficTimeout, double bandwidth, bool disconnect = true) - : Address(std::move(address)) - , ForwardPort(forwardPort) - , ListenSocket() - , RejectingTrafficTimeout(rejectingTrafficTimeout) - , CurrentRejectingTimeout(rejectingTrafficTimeout) - , RejectingStateTimer() - , Bandwidth(bandwidth) - , Disconnect(disconnect) - , RejectingTraffic(false) - { - SetReuseAddressAndPort(ListenSocket); - TSockAddrInet6 addr(Address.data(), listenPort); - Y_ABORT_UNLESS(ListenSocket.Bind(&addr) == 0); - Y_ABORT_UNLESS(ListenSocket.Listen(5) == 0); - - DelayTraffic = (Bandwidth == 0.0) ? false : true; - - ForwardAddrress.Reset(new TSockAddrInet6(Address.data(), ForwardPort)); - const ui32 BufSize = DelayTraffic ? 4096 : 65536 + 4096; - Buf.resize(BufSize); - } - - ~TTrafficInterrupter() { - AtomicSet(Running, 0); - this->Join(); - } - -private: - TAtomic Running = 1; - TVector<char> Buf; - TSocketPoller SocketPoller; - THolder<TSockAddrInet6> ForwardAddrress; - TVector<void*> Events; - TDuration RejectingTrafficTimeout; - TDuration CurrentRejectingTimeout; - TDuration DefaultPollTimeout = TDuration::MilliSeconds(100); - TDuration DisconnectTimeout = TDuration::MilliSeconds(100); - THPTimer RejectingStateTimer; - THPTimer DisconnectTimer; - double Bandwidth; - const bool Disconnect; - bool RejectingTraffic; - bool DelayTraffic; - - void UpdateRejectingState() { - if (TDuration::Seconds(std::abs(RejectingStateTimer.Passed())) > CurrentRejectingTimeout) { - RejectingStateTimer.Reset(); - CurrentRejectingTimeout = (RandomNumber<ui32>(1) ? RejectingTrafficTimeout + TDuration::Seconds(1.0) : RejectingTrafficTimeout - TDuration::Seconds(0.2)); - RejectingTraffic = !RejectingTraffic; - } - } - - void RandomlyDisconnect() { - if (TDuration::Seconds(std::abs(DisconnectTimer.Passed())) > DisconnectTimeout) { - DisconnectTimer.Reset(); - if (RandomNumber<ui32>(100) > 90) { - if (!Connections.empty()) { - auto it = Connections.begin(); - std::advance(it, RandomNumber<ui32>(Connections.size())); - SocketPoller.Unwait(static_cast<SOCKET>(*it->FirstSocket.get())); - SocketPoller.Unwait(static_cast<SOCKET>(*it->SecondSocket.get())); - Connections.erase(it); - } - } - } - } - - void* ThreadProc() override { - int pollReadyCount = 0; - SocketPoller.WaitRead(static_cast<SOCKET>(ListenSocket), &ListenSocket); - Events.resize(10); - - while (AtomicGet(Running)) { - if (RejectingTrafficTimeout != TDuration::Zero()) { - UpdateRejectingState(); - } - if (Disconnect) { - RandomlyDisconnect(); - } - if (!RejectingTraffic) { - TDuration timeout = DefaultPollTimeout; - auto updateTimout = [&timeout](TDirectedConnection& conn) { - if (conn.DelayedQueue) { - timeout = Min(timeout, conn.DelayedQueue.top().first - TInstant::Now()); - } - }; - for (auto& it : Connections) { - updateTimout(it.ForwardConnection); - updateTimout(it.BackwardConnection); - } - pollReadyCount = SocketPoller.WaitT(Events.data(), Events.size(), timeout); - if (pollReadyCount > 0) { - for (int i = 0; i < pollReadyCount; i++) { - HandleSocketPollEvent(Events[i]); - } - for (auto it : DroppedConnections) { - Connections.erase(it); - } - DroppedConnections.clear(); - } - } - if (DelayTraffic) { // process packets from DelayQueues - auto processDelayedPackages = [](TDirectedConnection& conn) { - while (!conn.DelayedQueue.empty()) { - auto& frontPackage = conn.DelayedQueue.top(); - if (TInstant::Now() >= frontPackage.first) { - TInet6StreamSocket* sock = frontPackage.second.ForwardSocket; - if (sock) { - sock->Send(frontPackage.second.Data.data(), frontPackage.second.Data.size()); - } - conn.DelayedQueue.pop(); - } else { - break; - } - } - }; - for (auto& it : Connections) { - processDelayedPackages(it.ForwardConnection); - processDelayedPackages(it.BackwardConnection); - } - } - } - ListenSocket.Close(); - return nullptr; - } - - void HandleSocketPollEvent(void* ev) { - if (ev == static_cast<void*>(&ListenSocket)) { - TSockAddrInet6 origin; - Connections.emplace_back(TConnectionDescriptor(std::unique_ptr<TInet6StreamSocket>(new TInet6StreamSocket), std::unique_ptr<TInet6StreamSocket>(new TInet6StreamSocket))); - int err = ListenSocket.Accept(Connections.back().FirstSocket.get(), &origin); - if (!err) { - err = Connections.back().SecondSocket->Connect(ForwardAddrress.Get()); - if (!err) { - Connections.back().ForwardConnection.ListIterator = --Connections.end(); - Connections.back().BackwardConnection.ListIterator = --Connections.end(); - SocketPoller.WaitRead(static_cast<SOCKET>(*Connections.back().FirstSocket), &Connections.back().ForwardConnection); - SocketPoller.WaitRead(static_cast<SOCKET>(*Connections.back().SecondSocket), &Connections.back().BackwardConnection); - } else { - Connections.back().FirstSocket->Close(); - } - } else { - Connections.pop_back(); - } - } else { - TDirectedConnection* directedConnection = static_cast<TDirectedConnection*>(ev); - int recvSize = 0; - do { - recvSize = directedConnection->Source->Recv(Buf.data(), Buf.size()); - } while (recvSize == -EINTR); - - if (recvSize > 0) { - if (DelayTraffic) { - // put packet into DelayQueue - const TDuration baseDelay = TDuration::MicroSeconds(recvSize * 1e6 / Bandwidth); - const TInstant now = TInstant::Now(); - directedConnection->Timestamp = Max(now, directedConnection->Timestamp) + baseDelay; - TDelayedPacket pkt; - pkt.ForwardSocket = directedConnection->Destination; - pkt.Data.resize(recvSize); - memcpy(pkt.Data.data(), Buf.data(), recvSize); - directedConnection->DelayedQueue.emplace(directedConnection->Timestamp, std::move(pkt)); - } else { - directedConnection->Destination->Send(Buf.data(), recvSize); - } - } else { - SocketPoller.Unwait(static_cast<SOCKET>(*directedConnection->Source)); - SocketPoller.Unwait(static_cast<SOCKET>(*directedConnection->Destination)); - DroppedConnections.emplace(directedConnection->ListIterator); - } - } - } -}; diff --git a/library/cpp/actors/interconnect/ut/lib/node.h b/library/cpp/actors/interconnect/ut/lib/node.h deleted file mode 100644 index e63a95c31b..0000000000 --- a/library/cpp/actors/interconnect/ut/lib/node.h +++ /dev/null @@ -1,149 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/actorsystem.h> -#include <library/cpp/actors/core/executor_pool_basic.h> -#include <library/cpp/actors/core/executor_pool_io.h> -#include <library/cpp/actors/core/scheduler_basic.h> -#include <library/cpp/actors/core/mailbox.h> -#include <library/cpp/actors/dnsresolver/dnsresolver.h> - -#include <library/cpp/actors/interconnect/handshake_broker.h> -#include <library/cpp/actors/interconnect/interconnect_tcp_server.h> -#include <library/cpp/actors/interconnect/interconnect_tcp_proxy.h> -#include <library/cpp/actors/interconnect/interconnect_proxy_wrapper.h> - -using namespace NActors; - -class TNode { - THolder<TActorSystem> ActorSystem; - -public: - TNode(ui32 nodeId, ui32 numNodes, const THashMap<ui32, ui16>& nodeToPort, const TString& address, - NMonitoring::TDynamicCounterPtr counters, TDuration deadPeerTimeout, - TChannelsConfig channelsSettings = TChannelsConfig(), - ui32 numDynamicNodes = 0, ui32 numThreads = 1, - TIntrusivePtr<NLog::TSettings> loggerSettings = nullptr, ui32 inflight = 512 * 1024) { - TActorSystemSetup setup; - setup.NodeId = nodeId; - setup.ExecutorsCount = 2; - setup.Executors.Reset(new TAutoPtr<IExecutorPool>[setup.ExecutorsCount]); - setup.Executors[0].Reset(new TBasicExecutorPool(0, numThreads, 20 /* magic number */)); - setup.Executors[1].Reset(new TIOExecutorPool(1, 1)); - setup.Scheduler.Reset(new TBasicSchedulerThread()); - const ui32 interconnectPoolId = 0; - - auto common = MakeIntrusive<TInterconnectProxyCommon>(); - common->NameserviceId = GetNameserviceActorId(); - common->MonCounters = counters->GetSubgroup("nodeId", ToString(nodeId)); - common->ChannelsConfig = channelsSettings; - common->ClusterUUID = "cluster"; - common->AcceptUUID = {common->ClusterUUID}; - common->TechnicalSelfHostName = address; - common->Settings.Handshake = TDuration::Seconds(1); - common->Settings.DeadPeer = deadPeerTimeout; - common->Settings.CloseOnIdle = TDuration::Minutes(1); - common->Settings.SendBufferDieLimitInMB = 512; - common->Settings.TotalInflightAmountOfData = inflight; - common->Settings.TCPSocketBufferSize = 2048 * 1024; - common->OutgoingHandshakeInflightLimit = 3; - - setup.Interconnect.ProxyActors.resize(numNodes + 1 - numDynamicNodes); - setup.Interconnect.ProxyWrapperFactory = CreateProxyWrapperFactory(common, interconnectPoolId); - - for (ui32 i = 1; i <= numNodes; ++i) { - if (i == nodeId) { - // create listener actor for local node "nodeId" - setup.LocalServices.emplace_back(TActorId(), TActorSetupCmd(new TInterconnectListenerTCP(address, - nodeToPort.at(nodeId), common), TMailboxType::ReadAsFilled, interconnectPoolId)); - } else if (i <= numNodes - numDynamicNodes) { - // create proxy actor to reach node "i" - setup.Interconnect.ProxyActors[i] = {new TInterconnectProxyTCP(i, common), - TMailboxType::ReadAsFilled, interconnectPoolId}; - } - } - - setup.LocalServices.emplace_back(MakePollerActorId(), TActorSetupCmd(CreatePollerActor(), - TMailboxType::ReadAsFilled, 0)); - - const TActorId loggerActorId = loggerSettings ? loggerSettings->LoggerActorId : TActorId(0, "logger"); - - if (!loggerSettings) { - constexpr ui32 LoggerComponentId = NActorsServices::LOGGER; - loggerSettings = MakeIntrusive<NLog::TSettings>( - loggerActorId, - (NLog::EComponent)LoggerComponentId, - NLog::PRI_INFO, - NLog::PRI_DEBUG, - 0U); - - loggerSettings->Append( - NActorsServices::EServiceCommon_MIN, - NActorsServices::EServiceCommon_MAX, - NActorsServices::EServiceCommon_Name - ); - - constexpr ui32 WilsonComponentId = 430; // NKikimrServices::WILSON - static const TString WilsonComponentName = "WILSON"; - - loggerSettings->Append( - (NLog::EComponent)WilsonComponentId, - (NLog::EComponent)WilsonComponentId + 1, - [](NLog::EComponent) -> const TString & { return WilsonComponentName; }); - } - - // register nameserver table - auto names = MakeIntrusive<TTableNameserverSetup>(); - for (ui32 i = 1; i <= numNodes; ++i) { - names->StaticNodeTable[i] = TTableNameserverSetup::TNodeInfo(address, address, nodeToPort.at(i)); - } - setup.LocalServices.emplace_back( - NDnsResolver::MakeDnsResolverActorId(), - TActorSetupCmd( - NDnsResolver::CreateOnDemandDnsResolver(), - TMailboxType::ReadAsFilled, interconnectPoolId)); - setup.LocalServices.emplace_back(GetNameserviceActorId(), TActorSetupCmd( - CreateNameserverTable(names, interconnectPoolId), TMailboxType::ReadAsFilled, - interconnectPoolId)); - - // register logger - setup.LocalServices.emplace_back(loggerActorId, TActorSetupCmd(new TLoggerActor(loggerSettings, - CreateStderrBackend(), counters->GetSubgroup("subsystem", "logger")), - TMailboxType::ReadAsFilled, 1)); - - if (common->OutgoingHandshakeInflightLimit) { - // create handshake broker actor - setup.LocalServices.emplace_back(MakeHandshakeBrokerOutId(), TActorSetupCmd( - CreateHandshakeBroker(*common->OutgoingHandshakeInflightLimit), - TMailboxType::ReadAsFilled, interconnectPoolId)); - } - - auto sp = MakeHolder<TActorSystemSetup>(std::move(setup)); - ActorSystem.Reset(new TActorSystem(sp, nullptr, loggerSettings)); - ActorSystem->Start(); - } - - ~TNode() { - ActorSystem->Stop(); - } - - bool Send(const TActorId& recipient, IEventBase* ev) { - return ActorSystem->Send(recipient, ev); - } - - TActorId RegisterActor(IActor* actor) { - return ActorSystem->Register(actor); - } - - TActorId InterconnectProxy(ui32 peerNodeId) { - return ActorSystem->InterconnectProxy(peerNodeId); - } - - void RegisterServiceActor(const TActorId& serviceId, IActor* actor) { - const TActorId actorId = ActorSystem->Register(actor); - ActorSystem->RegisterLocalService(serviceId, actorId); - } - - TActorSystem *GetActorSystem() const { - return ActorSystem.Get(); - } -}; diff --git a/library/cpp/actors/interconnect/ut/lib/test_actors.h b/library/cpp/actors/interconnect/ut/lib/test_actors.h deleted file mode 100644 index 7591200471..0000000000 --- a/library/cpp/actors/interconnect/ut/lib/test_actors.h +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once - -namespace NActors { - class TSenderBaseActor: public TActorBootstrapped<TSenderBaseActor> { - protected: - const TActorId RecipientActorId; - const ui32 Preload; - ui64 SequenceNumber = 0; - ui32 InFlySize = 0; - - public: - TSenderBaseActor(const TActorId& recipientActorId, ui32 preload = 1) - : RecipientActorId(recipientActorId) - , Preload(preload) - { - } - - virtual ~TSenderBaseActor() { - } - - virtual void Bootstrap(const TActorContext& ctx) { - Become(&TSenderBaseActor::StateFunc); - ctx.Send(ctx.ExecutorThread.ActorSystem->InterconnectProxy(RecipientActorId.NodeId()), new TEvInterconnect::TEvConnectNode); - } - - virtual void SendMessagesIfPossible(const TActorContext& ctx) { - while (InFlySize < Preload) { - SendMessage(ctx); - } - } - - virtual void SendMessage(const TActorContext& /*ctx*/) { - ++SequenceNumber; - } - - virtual void Handle(TEvents::TEvUndelivered::TPtr& /*ev*/, const TActorContext& ctx) { - SendMessage(ctx); - } - - virtual void Handle(TEvTestResponse::TPtr& /*ev*/, const TActorContext& ctx) { - SendMessagesIfPossible(ctx); - } - - void Handle(TEvInterconnect::TEvNodeConnected::TPtr& /*ev*/, const TActorContext& ctx) { - SendMessagesIfPossible(ctx); - } - - void Handle(TEvInterconnect::TEvNodeDisconnected::TPtr& /*ev*/, const TActorContext& /*ctx*/) { - } - - virtual void Handle(TEvents::TEvPoisonPill::TPtr& /*ev*/, const TActorContext& ctx) { - Die(ctx); - } - - virtual STRICT_STFUNC(StateFunc, - HFunc(TEvTestResponse, Handle) - HFunc(TEvents::TEvUndelivered, Handle) - HFunc(TEvents::TEvPoisonPill, Handle) - HFunc(TEvInterconnect::TEvNodeConnected, Handle) - HFunc(TEvInterconnect::TEvNodeDisconnected, Handle) - ) - }; - - class TReceiverBaseActor: public TActor<TReceiverBaseActor> { - protected: - ui64 ReceivedCount = 0; - - public: - TReceiverBaseActor() - : TActor(&TReceiverBaseActor::StateFunc) - { - } - - virtual ~TReceiverBaseActor() { - } - - virtual STRICT_STFUNC(StateFunc, - HFunc(TEvTest, Handle) - ) - - virtual void Handle(TEvTest::TPtr& /*ev*/, const TActorContext& /*ctx*/) {} - }; -} diff --git a/library/cpp/actors/interconnect/ut/lib/test_events.h b/library/cpp/actors/interconnect/ut/lib/test_events.h deleted file mode 100644 index 1bb5eb7d38..0000000000 --- a/library/cpp/actors/interconnect/ut/lib/test_events.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include <library/cpp/actors/interconnect/ut/protos/interconnect_test.pb.h> - -namespace NActors { - enum { - EvTest = EventSpaceBegin(TEvents::ES_PRIVATE), - EvTestChan, - EvTestSmall, - EvTestLarge, - EvTestResponse, - EvTestStartPolling, - }; - - struct TEvTest : TEventPB<TEvTest, NInterconnectTest::TEvTest, EvTest> { - TEvTest() = default; - - TEvTest(ui64 sequenceNumber, const TString& payload) { - Record.SetSequenceNumber(sequenceNumber); - Record.SetPayload(payload); - } - }; - - struct TEvTestLarge : TEventPB<TEvTestLarge, NInterconnectTest::TEvTestLarge, EvTestLarge> { - TEvTestLarge() = default; - - TEvTestLarge(ui64 sequenceNumber, const TString& payload) { - Record.SetSequenceNumber(sequenceNumber); - Record.SetPayload(payload); - } - }; - - struct TEvTestSmall : TEventPB<TEvTestSmall, NInterconnectTest::TEvTestSmall, EvTestSmall> { - TEvTestSmall() = default; - - TEvTestSmall(ui64 sequenceNumber, const TString& payload) { - Record.SetSequenceNumber(sequenceNumber); - Record.SetPayload(payload); - } - }; - - struct TEvTestResponse : TEventPB<TEvTestResponse, NInterconnectTest::TEvTestResponse, EvTestResponse> { - TEvTestResponse() = default; - - TEvTestResponse(ui64 confirmedSequenceNumber) { - Record.SetConfirmedSequenceNumber(confirmedSequenceNumber); - } - }; - - struct TEvTestStartPolling : TEventPB<TEvTestStartPolling, NInterconnectTest::TEvTestStartPolling, EvTestStartPolling> { - TEvTestStartPolling() = default; - }; - -} diff --git a/library/cpp/actors/interconnect/ut/lib/ya.make b/library/cpp/actors/interconnect/ut/lib/ya.make deleted file mode 100644 index 615c6a0e54..0000000000 --- a/library/cpp/actors/interconnect/ut/lib/ya.make +++ /dev/null @@ -1,10 +0,0 @@ -LIBRARY() - -SRCS( - node.h - test_events.h - test_actors.h - ic_test_cluster.h -) - -END() diff --git a/library/cpp/actors/interconnect/ut/outgoing_stream_ut.cpp b/library/cpp/actors/interconnect/ut/outgoing_stream_ut.cpp deleted file mode 100644 index 4834e48765..0000000000 --- a/library/cpp/actors/interconnect/ut/outgoing_stream_ut.cpp +++ /dev/null @@ -1,147 +0,0 @@ -#include <library/cpp/actors/interconnect/outgoing_stream.h> -#include <library/cpp/testing/unittest/registar.h> -#include <util/random/entropy.h> -#include <util/stream/null.h> - -#define Ctest Cnull - -Y_UNIT_TEST_SUITE(OutgoingStream) { - Y_UNIT_TEST(Basic) { - std::vector<char> buffer; - buffer.resize(4 << 20); - - TReallyFastRng32 rng(EntropyPool()); - for (char *p = buffer.data(); p != buffer.data() + buffer.size(); p += sizeof(ui32)) { - *reinterpret_cast<ui32*>(p) = rng(); - } - - for (ui32 nIter = 0; nIter < 10; ++nIter) { - Cerr << "nIter# " << nIter << Endl; - - size_t base = 0; // number of dropped bytes - size_t sendOffset = 0; // offset to base - size_t pending = 0; // number of bytes in queue - - NInterconnect::TOutgoingStreamT<4096> stream; - - size_t numRewindsRemain = 10; - - while (base != buffer.size()) { - const size_t bytesToEnd = buffer.size() - (base + sendOffset); - - Ctest << "base# " << base << " sendOffset# " << sendOffset << " pending# " << pending - << " bytesToEnd# " << bytesToEnd; - - UNIT_ASSERT_VALUES_EQUAL(stream.CalculateOutgoingSize(), pending + sendOffset); - UNIT_ASSERT_VALUES_EQUAL(stream.CalculateUnsentSize(), pending); - - const size_t maxBuffers = 128; - std::vector<NActors::TConstIoVec> iov; - stream.ProduceIoVec(iov, maxBuffers, Max<size_t>()); - size_t offset = base + sendOffset; - for (const auto& [ptr, len] : iov) { - UNIT_ASSERT(memcmp(buffer.data() + offset, ptr, len) == 0); - offset += len; - } - UNIT_ASSERT(iov.size() == maxBuffers || offset == base + sendOffset + pending); - - const char *nextData = buffer.data() + base + sendOffset + pending; - const size_t nextDataMaxLen = bytesToEnd - pending; - const size_t nextDataLen = nextDataMaxLen ? rng() % Min<size_t>(16384, nextDataMaxLen) + 1 : 0; - - if (size_t bytesToScan = sendOffset + pending) { - bytesToScan = rng() % bytesToScan + 1; - size_t offset = base + sendOffset + pending - bytesToScan; - stream.ScanLastBytes(bytesToScan, [&](TContiguousSpan span) { - UNIT_ASSERT(offset + span.size() <= base + sendOffset + pending); - UNIT_ASSERT(memcmp(buffer.data() + offset, span.data(), span.size()) == 0); - offset += span.size(); - }); - UNIT_ASSERT_VALUES_EQUAL(offset, base + sendOffset + pending); - } - - enum class EAction { - COPY_APPEND, - WRITE, - REF_APPEND, - ADVANCE, - REWIND, - DROP, - BOOKMARK - }; - - std::vector<EAction> actions; - if (nextDataLen) { - actions.push_back(EAction::COPY_APPEND); - actions.push_back(EAction::WRITE); - actions.push_back(EAction::REF_APPEND); - actions.push_back(EAction::BOOKMARK); - } - if (numRewindsRemain && sendOffset > 65536) { - actions.push_back(EAction::REWIND); - } - actions.push_back(EAction::ADVANCE); - actions.push_back(EAction::DROP); - - switch (actions[rng() % actions.size()]) { - case EAction::COPY_APPEND: { - Ctest << " COPY_APPEND nextDataLen# " << nextDataLen; - auto span = stream.AcquireSpanForWriting(nextDataLen); - UNIT_ASSERT(span.size() != 0); - memcpy(span.data(), nextData, span.size()); - stream.Append(span); - pending += span.size(); - break; - } - - case EAction::WRITE: - Ctest << " WRITE nextDataLen# " << nextDataLen; - stream.Write({nextData, nextDataLen}); - pending += nextDataLen; - break; - - case EAction::REF_APPEND: - Ctest << " REF_APPEND nextDataLen# " << nextDataLen; - stream.Append({nextData, nextDataLen}); - pending += nextDataLen; - break; - - case EAction::ADVANCE: { - const size_t advance = rng() % Min<size_t>(4096, pending + 1); - Ctest << " ADVANCE advance# " << advance; - stream.Advance(advance); - sendOffset += advance; - pending -= advance; - break; - } - - case EAction::REWIND: - Ctest << " REWIND"; - stream.Rewind(); - pending += sendOffset; - sendOffset = 0; - --numRewindsRemain; - break; - - case EAction::DROP: { - const size_t drop = rng() % Min<size_t>(65536, sendOffset + 1); - Ctest << " DROP drop# " << drop; - stream.DropFront(drop); - base += drop; - sendOffset -= drop; - break; - } - - case EAction::BOOKMARK: - Ctest << " BOOKMARK nextDataLen# " << nextDataLen; - auto bookmark = stream.Bookmark(nextDataLen); - stream.WriteBookmark(std::move(bookmark), {nextData, nextDataLen}); - pending += nextDataLen; - break; - } - - Ctest << Endl; - } - } - } -} diff --git a/library/cpp/actors/interconnect/ut/poller_actor_ut.cpp b/library/cpp/actors/interconnect/ut/poller_actor_ut.cpp deleted file mode 100644 index 38b9b5a0b6..0000000000 --- a/library/cpp/actors/interconnect/ut/poller_actor_ut.cpp +++ /dev/null @@ -1,264 +0,0 @@ -#include <library/cpp/actors/interconnect/poller_actor.h> -#include <library/cpp/actors/testlib/test_runtime.h> - -#include <library/cpp/testing/unittest/registar.h> - -#include <util/network/pair.h> -#include <util/network/socket.h> - -using namespace NActors; - -class TTestSocket: public TSharedDescriptor { -public: - explicit TTestSocket(SOCKET fd) - : Fd_(fd) - { - } - - int GetDescriptor() override { - return Fd_; - } - -private: - SOCKET Fd_; -}; -using TTestSocketPtr = TIntrusivePtr<TTestSocket>; - -// create pair of connected, non-blocking sockets -std::pair<TTestSocketPtr, TTestSocketPtr> NonBlockSockets() { - SOCKET fds[2]; - SocketPair(fds); - SetNonBlock(fds[0]); - SetNonBlock(fds[1]); - return {MakeIntrusive<TTestSocket>(fds[0]), MakeIntrusive<TTestSocket>(fds[1])}; -} - -std::pair<TTestSocketPtr, TTestSocketPtr> TcpSockets() { - // create server (listening) socket - SOCKET server = socket(AF_INET, SOCK_STREAM, 0); - Y_ABORT_UNLESS(server != -1, "socket() failed with %s", strerror(errno)); - - // bind it to local address with automatically picked port - sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = 0; - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - if (bind(server, (sockaddr*)&addr, sizeof(addr)) == -1) { - Y_ABORT("bind() failed with %s", strerror(errno)); - } else if (listen(server, 1) == -1) { - Y_ABORT("listen() failed with %s", strerror(errno)); - } - - // obtain local address for client - socklen_t len = sizeof(addr); - if (getsockname(server, (sockaddr*)&addr, &len) == -1) { - Y_ABORT("getsockname() failed with %s", strerror(errno)); - } - - // create client socket - SOCKET client = socket(AF_INET, SOCK_STREAM, 0); - Y_ABORT_UNLESS(client != -1, "socket() failed with %s", strerror(errno)); - - // connect to server - if (connect(client, (sockaddr*)&addr, len) == -1) { - Y_ABORT("connect() failed with %s", strerror(errno)); - } - - // accept connection from the other side - SOCKET accepted = accept(server, nullptr, nullptr); - Y_ABORT_UNLESS(accepted != -1, "accept() failed with %s", strerror(errno)); - - // close server socket - closesocket(server); - - return std::make_pair(MakeIntrusive<TTestSocket>(client), MakeIntrusive<TTestSocket>(accepted)); -} - -class TPollerActorTest: public TTestBase { - UNIT_TEST_SUITE(TPollerActorTest); - UNIT_TEST(Registration) - UNIT_TEST(ReadNotification) - UNIT_TEST(WriteNotification) - UNIT_TEST(HangupNotification) - UNIT_TEST_SUITE_END(); - -public: - void SetUp() override { - ActorSystem_ = MakeHolder<TTestActorRuntimeBase>(); - ActorSystem_->Initialize(); - - PollerId_ = ActorSystem_->Register(CreatePollerActor()); - - TDispatchOptions opts; - opts.FinalEvents.emplace_back(TEvents::TSystem::Bootstrap, 1); - ActorSystem_->DispatchEvents(opts); - } - - void Registration() { - auto [s1, s2] = NonBlockSockets(); - auto readerId = ActorSystem_->AllocateEdgeActor(); - auto writerId = ActorSystem_->AllocateEdgeActor(); - - RegisterSocket(s1, readerId, writerId); - - // reader should receive event after socket registration - TPollerToken::TPtr token; - { - auto ev = ActorSystem_->GrabEdgeEvent<TEvPollerRegisterResult>(readerId); - token = ev->Get()->PollerToken; - } - - // writer should receive event after socket registration - { - auto ev = ActorSystem_->GrabEdgeEvent<TEvPollerRegisterResult>(writerId); - UNIT_ASSERT_EQUAL(token, ev->Get()->PollerToken); - } - } - - void ReadNotification() { - auto [r, w] = NonBlockSockets(); - auto clientId = ActorSystem_->AllocateEdgeActor(); - RegisterSocket(r, clientId, {}); - - // notification after registration - TPollerToken::TPtr token; - { - auto ev = ActorSystem_->GrabEdgeEvent<TEvPollerRegisterResult>(clientId); - token = ev->Get()->PollerToken; - } - - char buf; - - // data not ready yet for read - UNIT_ASSERT(read(r->GetDescriptor(), &buf, sizeof(buf)) == -1); - UNIT_ASSERT(errno == EWOULDBLOCK); - - // request read poll - token->Request(true, false); - - // write data - UNIT_ASSERT(write(w->GetDescriptor(), "x", 1) == 1); - - // notification after socket become readable - { - auto ev = ActorSystem_->GrabEdgeEvent<TEvPollerReady>(clientId); - UNIT_ASSERT_EQUAL(ev->Get()->Socket, r); - UNIT_ASSERT(ev->Get()->Read); - UNIT_ASSERT(!ev->Get()->Write); - } - - // read data - UNIT_ASSERT(read(r->GetDescriptor(), &buf, sizeof(buf)) == 1); - UNIT_ASSERT_EQUAL('x', buf); - - // no more data to read - UNIT_ASSERT(read(r->GetDescriptor(), &buf, sizeof(buf)) == -1); - UNIT_ASSERT(errno == EWOULDBLOCK); - } - - void WriteNotification() { - auto [r, w] = TcpSockets(); - auto clientId = ActorSystem_->AllocateEdgeActor(); - SetNonBlock(w->GetDescriptor()); - RegisterSocket(w, TActorId{}, clientId); - - // notification after registration - TPollerToken::TPtr token; - { - auto ev = ActorSystem_->GrabEdgeEvent<TEvPollerRegisterResult>(clientId); - token = ev->Get()->PollerToken; - } - - char buffer[4096]; - memset(buffer, 'x', sizeof(buffer)); - - for (int i = 0; i < 1000; ++i) { - // write as much as possible to send buffer - ssize_t written = 0; - for (;;) { - ssize_t res = send(w->GetDescriptor(), buffer, sizeof(buffer), 0); - if (res > 0) { - written += res; - } else if (res == 0) { - UNIT_FAIL("unexpected zero return from send()"); - } else { - UNIT_ASSERT(res == -1); - if (errno == EINTR) { - continue; - } else if (errno == EWOULDBLOCK || errno == EAGAIN) { - token->Request(false, true); - break; - } else { - UNIT_FAIL("unexpected error from send()"); - } - } - } - Cerr << "written " << written << " bytes" << Endl; - - // read all written data from the read end - for (;;) { - char buffer[4096]; - ssize_t res = recv(r->GetDescriptor(), buffer, sizeof(buffer), 0); - if (res > 0) { - UNIT_ASSERT(written >= res); - written -= res; - if (!written) { - break; - } - } else if (res == 0) { - UNIT_FAIL("unexpected zero return from recv()"); - } else { - UNIT_ASSERT(res == -1); - if (errno == EINTR) { - continue; - } else { - UNIT_FAIL("unexpected error from recv()"); - } - } - } - - // wait for notification after socket becomes writable again - { - auto ev = ActorSystem_->GrabEdgeEvent<TEvPollerReady>(clientId); - UNIT_ASSERT_EQUAL(ev->Get()->Socket, w); - UNIT_ASSERT(!ev->Get()->Read); - UNIT_ASSERT(ev->Get()->Write); - } - } - } - - void HangupNotification() { - auto [r, w] = NonBlockSockets(); - auto clientId = ActorSystem_->AllocateEdgeActor(); - RegisterSocket(r, clientId, TActorId{}); - - // notification after registration - TPollerToken::TPtr token; - { - auto ev = ActorSystem_->GrabEdgeEvent<TEvPollerRegisterResult>(clientId); - token = ev->Get()->PollerToken; - } - - token->Request(true, false); - ShutDown(w->GetDescriptor(), SHUT_RDWR); - - // notification after peer shuts down its socket - { - auto ev = ActorSystem_->GrabEdgeEvent<TEvPollerReady>(clientId); - UNIT_ASSERT_EQUAL(ev->Get()->Socket, r); - UNIT_ASSERT(ev->Get()->Read); - } - } - -private: - void RegisterSocket(TTestSocketPtr socket, TActorId readActorId, TActorId writeActorId) { - auto ev = new TEvPollerRegister{socket, readActorId, writeActorId}; - ActorSystem_->Send(new IEventHandle(PollerId_, TActorId{}, ev)); - } - -private: - THolder<TTestActorRuntimeBase> ActorSystem_; - TActorId PollerId_; -}; - -UNIT_TEST_SUITE_REGISTRATION(TPollerActorTest); diff --git a/library/cpp/actors/interconnect/ut/protos/CMakeLists.darwin-arm64.txt b/library/cpp/actors/interconnect/ut/protos/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 01f1765c08..0000000000 --- a/library/cpp/actors/interconnect/ut/protos/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,43 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) - -add_library(interconnect-ut-protos) -target_link_libraries(interconnect-ut-protos PUBLIC - contrib-libs-cxxsupp - yutil - contrib-libs-protobuf -) -target_proto_messages(interconnect-ut-protos PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/protos/interconnect_test.proto -) -target_proto_addincls(interconnect-ut-protos - ./ - ${CMAKE_SOURCE_DIR}/ - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src -) -target_proto_outs(interconnect-ut-protos - --cpp_out=${CMAKE_BINARY_DIR}/ - --cpp_styleguide_out=${CMAKE_BINARY_DIR}/ -) diff --git a/library/cpp/actors/interconnect/ut/protos/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/interconnect/ut/protos/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 01f1765c08..0000000000 --- a/library/cpp/actors/interconnect/ut/protos/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,43 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) - -add_library(interconnect-ut-protos) -target_link_libraries(interconnect-ut-protos PUBLIC - contrib-libs-cxxsupp - yutil - contrib-libs-protobuf -) -target_proto_messages(interconnect-ut-protos PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/protos/interconnect_test.proto -) -target_proto_addincls(interconnect-ut-protos - ./ - ${CMAKE_SOURCE_DIR}/ - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src -) -target_proto_outs(interconnect-ut-protos - --cpp_out=${CMAKE_BINARY_DIR}/ - --cpp_styleguide_out=${CMAKE_BINARY_DIR}/ -) diff --git a/library/cpp/actors/interconnect/ut/protos/CMakeLists.linux-aarch64.txt b/library/cpp/actors/interconnect/ut/protos/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 10cf33244c..0000000000 --- a/library/cpp/actors/interconnect/ut/protos/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,44 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) - -add_library(interconnect-ut-protos) -target_link_libraries(interconnect-ut-protos PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - contrib-libs-protobuf -) -target_proto_messages(interconnect-ut-protos PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/protos/interconnect_test.proto -) -target_proto_addincls(interconnect-ut-protos - ./ - ${CMAKE_SOURCE_DIR}/ - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src -) -target_proto_outs(interconnect-ut-protos - --cpp_out=${CMAKE_BINARY_DIR}/ - --cpp_styleguide_out=${CMAKE_BINARY_DIR}/ -) diff --git a/library/cpp/actors/interconnect/ut/protos/CMakeLists.linux-x86_64.txt b/library/cpp/actors/interconnect/ut/protos/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 10cf33244c..0000000000 --- a/library/cpp/actors/interconnect/ut/protos/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,44 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) - -add_library(interconnect-ut-protos) -target_link_libraries(interconnect-ut-protos PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - contrib-libs-protobuf -) -target_proto_messages(interconnect-ut-protos PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/protos/interconnect_test.proto -) -target_proto_addincls(interconnect-ut-protos - ./ - ${CMAKE_SOURCE_DIR}/ - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src -) -target_proto_outs(interconnect-ut-protos - --cpp_out=${CMAKE_BINARY_DIR}/ - --cpp_styleguide_out=${CMAKE_BINARY_DIR}/ -) diff --git a/library/cpp/actors/interconnect/ut/protos/CMakeLists.txt b/library/cpp/actors/interconnect/ut/protos/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/interconnect/ut/protos/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/interconnect/ut/protos/CMakeLists.windows-x86_64.txt b/library/cpp/actors/interconnect/ut/protos/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 01f1765c08..0000000000 --- a/library/cpp/actors/interconnect/ut/protos/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,43 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) - -add_library(interconnect-ut-protos) -target_link_libraries(interconnect-ut-protos PUBLIC - contrib-libs-cxxsupp - yutil - contrib-libs-protobuf -) -target_proto_messages(interconnect-ut-protos PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut/protos/interconnect_test.proto -) -target_proto_addincls(interconnect-ut-protos - ./ - ${CMAKE_SOURCE_DIR}/ - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src -) -target_proto_outs(interconnect-ut-protos - --cpp_out=${CMAKE_BINARY_DIR}/ - --cpp_styleguide_out=${CMAKE_BINARY_DIR}/ -) diff --git a/library/cpp/actors/interconnect/ut/protos/interconnect_test.proto b/library/cpp/actors/interconnect/ut/protos/interconnect_test.proto deleted file mode 100644 index b74d068a8b..0000000000 --- a/library/cpp/actors/interconnect/ut/protos/interconnect_test.proto +++ /dev/null @@ -1,28 +0,0 @@ -package NInterconnectTest; - -message TEvTest { - optional uint64 SequenceNumber = 1; - optional bytes Payload = 2; -} - -message TEvTestChan { - optional uint64 SequenceNumber = 1; - optional uint64 Payload = 2; -} - -message TEvTestLarge { - optional uint64 SequenceNumber = 1; - optional bytes Payload = 2; -} - -message TEvTestSmall { - optional uint64 SequenceNumber = 1; - optional bytes Payload = 2; -} - -message TEvTestResponse { - optional uint64 ConfirmedSequenceNumber = 1; -} - -message TEvTestStartPolling { -} diff --git a/library/cpp/actors/interconnect/ut/protos/ya.make b/library/cpp/actors/interconnect/ut/protos/ya.make deleted file mode 100644 index a7ffcd6bd0..0000000000 --- a/library/cpp/actors/interconnect/ut/protos/ya.make +++ /dev/null @@ -1,9 +0,0 @@ -PROTO_LIBRARY() - -SRCS( - interconnect_test.proto -) - -EXCLUDE_TAGS(GO_PROTO) - -END() diff --git a/library/cpp/actors/interconnect/ut/sticking_ut.cpp b/library/cpp/actors/interconnect/ut/sticking_ut.cpp deleted file mode 100644 index 2fa3d0933e..0000000000 --- a/library/cpp/actors/interconnect/ut/sticking_ut.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include <library/cpp/actors/interconnect/ut/lib/node.h> -#include <library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h> -#include <library/cpp/testing/unittest/registar.h> - -using namespace NActors; - -struct TEvPing : TEventBase<TEvPing, TEvents::THelloWorld::Ping> { - TString Data; - - TEvPing(TString data) - : Data(data) - {} - - TEvPing() = default; - - ui32 CalculateSerializedSize() const override { return Data.size(); } - bool IsSerializable() const override { return true; } - bool SerializeToArcadiaStream(TChunkSerializer *serializer) const override { serializer->WriteAliasedRaw(Data.data(), Data.size()); return true; } - TString ToStringHeader() const override { return {}; } -}; - -class TPonger : public TActor<TPonger> { -public: - TPonger() - : TActor(&TThis::StateFunc) - {} - - void Handle(TEvPing::TPtr ev) { - Send(ev->Sender, new TEvents::TEvPong(), 0, ev->Cookie); - } - - STRICT_STFUNC(StateFunc, - hFunc(TEvPing, Handle); - ) -}; - -class TPinger : public TActorBootstrapped<TPinger> { - ui32 PingInFlight = 0; - TActorId PongerId; - TDuration MaxRTT; - -public: - TPinger(TActorId pongerId) - : PongerId(pongerId) - {} - - void Bootstrap() { - Become(&TThis::StateFunc); - Action(); - } - - void Action() { - if (PingInFlight) { - return; - } - const ui32 max = 1 + RandomNumber(10u); - while (PingInFlight < max) { - IssuePing(); - } - } - - void IssuePing() { - TString data = TString::Uninitialized(RandomNumber<size_t>(256 * 1024) + 1); - memset(data.Detach(), 0, data.size()); - Send(PongerId, new TEvPing(data), 0, GetCycleCountFast()); - ++PingInFlight; - } - - void Handle(TEvents::TEvPong::TPtr ev) { - const TDuration rtt = CyclesToDuration(GetCycleCountFast() - ev->Cookie); - if (MaxRTT < rtt) { - MaxRTT = rtt; - Cerr << "Updated MaxRTT# " << MaxRTT << Endl; - Y_ABORT_UNLESS(MaxRTT <= TDuration::MilliSeconds(500)); - } - --PingInFlight; - Action(); - } - - STRICT_STFUNC(StateFunc, - hFunc(TEvents::TEvPong, Handle); - ) -}; - -Y_UNIT_TEST_SUITE(Sticking) { - Y_UNIT_TEST(Check) { - TPortManager portman; - THashMap<ui32, ui16> nodeToPort; - nodeToPort.emplace(1, portman.GetPort()); - nodeToPort.emplace(2, portman.GetPort()); - - NMonitoring::TDynamicCounterPtr counters = new NMonitoring::TDynamicCounters; - std::list<TNode> nodes; - for (auto [nodeId, _] : nodeToPort) { - nodes.emplace_back(nodeId, nodeToPort.size(), nodeToPort, "127.1.0.0", - counters->GetSubgroup("nodeId", TStringBuilder() << nodeId), TDuration::Seconds(10), - TChannelsConfig(), 0, 1, nullptr, 40 << 20); - } - - auto& node1 = *nodes.begin(); - auto& node2 = *++nodes.begin(); - - const TActorId ponger = node2.RegisterActor(new TPonger()); - node1.RegisterActor(new TPinger(ponger)); - - Sleep(TDuration::Seconds(10)); - } -} diff --git a/library/cpp/actors/interconnect/ut/ya.make b/library/cpp/actors/interconnect/ut/ya.make deleted file mode 100644 index e5b838635f..0000000000 --- a/library/cpp/actors/interconnect/ut/ya.make +++ /dev/null @@ -1,33 +0,0 @@ -UNITTEST() - -IF (SANITIZER_TYPE == "thread") - TIMEOUT(1200) - SIZE(LARGE) - TAG(ya:fat) -ELSE() - TIMEOUT(600) - SIZE(MEDIUM) -ENDIF() - -SRCS( - channel_scheduler_ut.cpp - event_holder_pool_ut.cpp - interconnect_ut.cpp - large.cpp - outgoing_stream_ut.cpp - poller_actor_ut.cpp - dynamic_proxy_ut.cpp - sticking_ut.cpp -) - -PEERDIR( - library/cpp/actors/core - library/cpp/actors/interconnect - library/cpp/actors/interconnect/ut/lib - library/cpp/actors/interconnect/ut/protos - library/cpp/actors/testlib - library/cpp/digest/md5 - library/cpp/testing/unittest -) - -END() diff --git a/library/cpp/actors/interconnect/ut_fat/CMakeLists.darwin-arm64.txt b/library/cpp/actors/interconnect/ut_fat/CMakeLists.darwin-arm64.txt deleted file mode 100644 index ad106fc729..0000000000 --- a/library/cpp/actors/interconnect/ut_fat/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,69 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-interconnect-ut_fat) -target_link_libraries(library-cpp-actors-interconnect-ut_fat PUBLIC - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - actors-interconnect-mock - interconnect-ut-lib - interconnect-ut-protos - cpp-testing-unittest - cpp-deprecated-atomic -) -target_link_options(library-cpp-actors-interconnect-ut_fat PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-interconnect-ut_fat PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut_fat/main.cpp -) -set_property( - TARGET - library-cpp-actors-interconnect-ut_fat - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-interconnect-ut_fat - TEST_TARGET - library-cpp-actors-interconnect-ut_fat - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_fat - PROPERTY - LABELS - LARGE -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_fat - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-interconnect-ut_fat - system_allocator -) -vcs_info(library-cpp-actors-interconnect-ut_fat) diff --git a/library/cpp/actors/interconnect/ut_fat/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/interconnect/ut_fat/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 4285513499..0000000000 --- a/library/cpp/actors/interconnect/ut_fat/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,70 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-interconnect-ut_fat) -target_link_libraries(library-cpp-actors-interconnect-ut_fat PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - actors-interconnect-mock - interconnect-ut-lib - interconnect-ut-protos - cpp-testing-unittest - cpp-deprecated-atomic -) -target_link_options(library-cpp-actors-interconnect-ut_fat PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-interconnect-ut_fat PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut_fat/main.cpp -) -set_property( - TARGET - library-cpp-actors-interconnect-ut_fat - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-interconnect-ut_fat - TEST_TARGET - library-cpp-actors-interconnect-ut_fat - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_fat - PROPERTY - LABELS - LARGE -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_fat - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-interconnect-ut_fat - system_allocator -) -vcs_info(library-cpp-actors-interconnect-ut_fat) diff --git a/library/cpp/actors/interconnect/ut_fat/CMakeLists.linux-aarch64.txt b/library/cpp/actors/interconnect/ut_fat/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 5365ba4e24..0000000000 --- a/library/cpp/actors/interconnect/ut_fat/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,73 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-interconnect-ut_fat) -target_link_libraries(library-cpp-actors-interconnect-ut_fat PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - actors-interconnect-mock - interconnect-ut-lib - interconnect-ut-protos - cpp-testing-unittest - cpp-deprecated-atomic -) -target_link_options(library-cpp-actors-interconnect-ut_fat PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-interconnect-ut_fat PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut_fat/main.cpp -) -set_property( - TARGET - library-cpp-actors-interconnect-ut_fat - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-interconnect-ut_fat - TEST_TARGET - library-cpp-actors-interconnect-ut_fat - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_fat - PROPERTY - LABELS - LARGE -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_fat - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-interconnect-ut_fat - cpp-malloc-jemalloc -) -vcs_info(library-cpp-actors-interconnect-ut_fat) diff --git a/library/cpp/actors/interconnect/ut_fat/CMakeLists.linux-x86_64.txt b/library/cpp/actors/interconnect/ut_fat/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 86ef393bab..0000000000 --- a/library/cpp/actors/interconnect/ut_fat/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,75 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-interconnect-ut_fat) -target_link_libraries(library-cpp-actors-interconnect-ut_fat PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - actors-interconnect-mock - interconnect-ut-lib - interconnect-ut-protos - cpp-testing-unittest - cpp-deprecated-atomic -) -target_link_options(library-cpp-actors-interconnect-ut_fat PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-interconnect-ut_fat PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut_fat/main.cpp -) -set_property( - TARGET - library-cpp-actors-interconnect-ut_fat - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-interconnect-ut_fat - TEST_TARGET - library-cpp-actors-interconnect-ut_fat - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_fat - PROPERTY - LABELS - LARGE -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_fat - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-interconnect-ut_fat - cpp-malloc-tcmalloc - libs-tcmalloc-no_percpu_cache -) -vcs_info(library-cpp-actors-interconnect-ut_fat) diff --git a/library/cpp/actors/interconnect/ut_fat/CMakeLists.txt b/library/cpp/actors/interconnect/ut_fat/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/interconnect/ut_fat/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/interconnect/ut_fat/CMakeLists.windows-x86_64.txt b/library/cpp/actors/interconnect/ut_fat/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 3841949a28..0000000000 --- a/library/cpp/actors/interconnect/ut_fat/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,63 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-interconnect-ut_fat) -target_link_libraries(library-cpp-actors-interconnect-ut_fat PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - actors-interconnect-mock - interconnect-ut-lib - interconnect-ut-protos - cpp-testing-unittest - cpp-deprecated-atomic -) -target_sources(library-cpp-actors-interconnect-ut_fat PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut_fat/main.cpp -) -set_property( - TARGET - library-cpp-actors-interconnect-ut_fat - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-interconnect-ut_fat - TEST_TARGET - library-cpp-actors-interconnect-ut_fat - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_fat - PROPERTY - LABELS - LARGE -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_fat - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-interconnect-ut_fat - system_allocator -) -vcs_info(library-cpp-actors-interconnect-ut_fat) diff --git a/library/cpp/actors/interconnect/ut_fat/main.cpp b/library/cpp/actors/interconnect/ut_fat/main.cpp deleted file mode 100644 index abd1cd289a..0000000000 --- a/library/cpp/actors/interconnect/ut_fat/main.cpp +++ /dev/null @@ -1,133 +0,0 @@ - -#include <library/cpp/actors/interconnect/interconnect_tcp_proxy.h> -#include <library/cpp/actors/interconnect/ut/protos/interconnect_test.pb.h> -#include <library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h> -#include <library/cpp/actors/interconnect/ut/lib/interrupter.h> -#include <library/cpp/actors/interconnect/ut/lib/test_events.h> -#include <library/cpp/actors/interconnect/ut/lib/test_actors.h> -#include <library/cpp/actors/interconnect/ut/lib/node.h> - -#include <library/cpp/testing/unittest/tests_data.h> -#include <library/cpp/testing/unittest/registar.h> - -#include <util/network/sock.h> -#include <util/network/poller.h> -#include <library/cpp/deprecated/atomic/atomic.h> -#include <util/generic/set.h> - -Y_UNIT_TEST_SUITE(InterconnectUnstableConnection) { - using namespace NActors; - - class TSenderActor: public TSenderBaseActor { - TDeque<ui64> InFly; - ui16 SendFlags; - - public: - TSenderActor(const TActorId& recipientActorId, ui16 sendFlags) - : TSenderBaseActor(recipientActorId, 32) - , SendFlags(sendFlags) - { - } - - ~TSenderActor() override { - Cerr << "Sent " << SequenceNumber << " messages\n"; - } - - void SendMessage(const TActorContext& ctx) override { - const ui32 flags = IEventHandle::MakeFlags(0, SendFlags); - const ui64 cookie = SequenceNumber; - const TString payload('@', RandomNumber<size_t>(65536) + 4096); - ctx.Send(RecipientActorId, new TEvTest(SequenceNumber, payload), flags, cookie); - InFly.push_back(SequenceNumber); - ++InFlySize; - ++SequenceNumber; - } - - void Handle(TEvents::TEvUndelivered::TPtr& ev, const TActorContext& ctx) override { - auto record = std::find(InFly.begin(), InFly.end(), ev->Cookie); - if (SendFlags & IEventHandle::FlagGenerateUnsureUndelivered) { - if (record != InFly.end()) { - InFly.erase(record); - --InFlySize; - SendMessage(ctx); - } - } else { - Y_ABORT_UNLESS(record != InFly.end()); - } - } - - void Handle(TEvTestResponse::TPtr& ev, const TActorContext& ctx) override { - Y_ABORT_UNLESS(InFly); - const NInterconnectTest::TEvTestResponse& record = ev->Get()->Record; - Y_ABORT_UNLESS(record.HasConfirmedSequenceNumber()); - if (!(SendFlags & IEventHandle::FlagGenerateUnsureUndelivered)) { - while (record.GetConfirmedSequenceNumber() != InFly.front()) { - InFly.pop_front(); - --InFlySize; - } - } - Y_ABORT_UNLESS(record.GetConfirmedSequenceNumber() == InFly.front(), "got# %" PRIu64 " expected# %" PRIu64, - record.GetConfirmedSequenceNumber(), InFly.front()); - InFly.pop_front(); - --InFlySize; - SendMessagesIfPossible(ctx); - } - }; - - class TReceiverActor: public TReceiverBaseActor { - ui64 ReceivedCount = 0; - TNode* SenderNode = nullptr; - - public: - TReceiverActor(TNode* senderNode) - : TReceiverBaseActor() - , SenderNode(senderNode) - { - } - - void Handle(TEvTest::TPtr& ev, const TActorContext& /*ctx*/) override { - const NInterconnectTest::TEvTest& m = ev->Get()->Record; - Y_ABORT_UNLESS(m.HasSequenceNumber()); - Y_ABORT_UNLESS(m.GetSequenceNumber() >= ReceivedCount, "got #%" PRIu64 " expected at least #%" PRIu64, - m.GetSequenceNumber(), ReceivedCount); - ++ReceivedCount; - SenderNode->Send(ev->Sender, new TEvTestResponse(m.GetSequenceNumber())); - } - - ~TReceiverActor() override { - Cerr << "Received " << ReceivedCount << " messages\n"; - } - }; - - Y_UNIT_TEST(InterconnectTestWithProxyUnsureUndelivered) { - ui32 numNodes = 2; - double bandWidth = 1000000; - ui16 flags = IEventHandle::FlagTrackDelivery | IEventHandle::FlagGenerateUnsureUndelivered; - TTestICCluster::TTrafficInterrupterSettings interrupterSettings{TDuration::Seconds(2), bandWidth, true}; - - TTestICCluster testCluster(numNodes, TChannelsConfig(), &interrupterSettings); - - TReceiverActor* receiverActor = new TReceiverActor(testCluster.GetNode(1)); - const TActorId recipient = testCluster.RegisterActor(receiverActor, 2); - TSenderActor* senderActor = new TSenderActor(recipient, flags); - testCluster.RegisterActor(senderActor, 1); - - NanoSleep(30ULL * 1000 * 1000 * 1000); - } - - Y_UNIT_TEST(InterconnectTestWithProxy) { - ui32 numNodes = 2; - double bandWidth = 1000000; - ui16 flags = IEventHandle::FlagTrackDelivery; - TTestICCluster::TTrafficInterrupterSettings interrupterSettings{TDuration::Seconds(2), bandWidth, true}; - - TTestICCluster testCluster(numNodes, TChannelsConfig(), &interrupterSettings); - - TReceiverActor* receiverActor = new TReceiverActor(testCluster.GetNode(1)); - const TActorId recipient = testCluster.RegisterActor(receiverActor, 2); - TSenderActor* senderActor = new TSenderActor(recipient, flags); - testCluster.RegisterActor(senderActor, 1); - - NanoSleep(30ULL * 1000 * 1000 * 1000); - } -} diff --git a/library/cpp/actors/interconnect/ut_fat/ya.make b/library/cpp/actors/interconnect/ut_fat/ya.make deleted file mode 100644 index 8361c5d9f7..0000000000 --- a/library/cpp/actors/interconnect/ut_fat/ya.make +++ /dev/null @@ -1,21 +0,0 @@ -UNITTEST() - -SIZE(LARGE) - -TAG(ya:fat) - -SRCS( - main.cpp -) - -PEERDIR( - library/cpp/actors/core - library/cpp/actors/interconnect - library/cpp/actors/interconnect/mock - library/cpp/actors/interconnect/ut/lib - library/cpp/actors/interconnect/ut/protos - library/cpp/testing/unittest - library/cpp/deprecated/atomic -) - -END() diff --git a/library/cpp/actors/interconnect/ut_huge_cluster/CMakeLists.darwin-arm64.txt b/library/cpp/actors/interconnect/ut_huge_cluster/CMakeLists.darwin-arm64.txt deleted file mode 100644 index b91e1530bb..0000000000 --- a/library/cpp/actors/interconnect/ut_huge_cluster/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,75 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-interconnect-ut_huge_cluster) -target_link_libraries(library-cpp-actors-interconnect-ut_huge_cluster PUBLIC - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - interconnect-ut-lib - interconnect-ut-protos - cpp-testing-unittest - cpp-actors-testlib -) -target_link_options(library-cpp-actors-interconnect-ut_huge_cluster PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-interconnect-ut_huge_cluster PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut_huge_cluster/huge_cluster.cpp -) -set_property( - TARGET - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-interconnect-ut_huge_cluster - TEST_TARGET - library-cpp-actors-interconnect-ut_huge_cluster - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - PROCESSORS - 4 -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-interconnect-ut_huge_cluster - system_allocator -) -vcs_info(library-cpp-actors-interconnect-ut_huge_cluster) diff --git a/library/cpp/actors/interconnect/ut_huge_cluster/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/interconnect/ut_huge_cluster/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 45fd7e2060..0000000000 --- a/library/cpp/actors/interconnect/ut_huge_cluster/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,76 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-interconnect-ut_huge_cluster) -target_link_libraries(library-cpp-actors-interconnect-ut_huge_cluster PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - interconnect-ut-lib - interconnect-ut-protos - cpp-testing-unittest - cpp-actors-testlib -) -target_link_options(library-cpp-actors-interconnect-ut_huge_cluster PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-interconnect-ut_huge_cluster PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut_huge_cluster/huge_cluster.cpp -) -set_property( - TARGET - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-interconnect-ut_huge_cluster - TEST_TARGET - library-cpp-actors-interconnect-ut_huge_cluster - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - PROCESSORS - 4 -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-interconnect-ut_huge_cluster - system_allocator -) -vcs_info(library-cpp-actors-interconnect-ut_huge_cluster) diff --git a/library/cpp/actors/interconnect/ut_huge_cluster/CMakeLists.linux-aarch64.txt b/library/cpp/actors/interconnect/ut_huge_cluster/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 51c8af6a26..0000000000 --- a/library/cpp/actors/interconnect/ut_huge_cluster/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,79 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-interconnect-ut_huge_cluster) -target_link_libraries(library-cpp-actors-interconnect-ut_huge_cluster PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - interconnect-ut-lib - interconnect-ut-protos - cpp-testing-unittest - cpp-actors-testlib -) -target_link_options(library-cpp-actors-interconnect-ut_huge_cluster PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-interconnect-ut_huge_cluster PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut_huge_cluster/huge_cluster.cpp -) -set_property( - TARGET - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-interconnect-ut_huge_cluster - TEST_TARGET - library-cpp-actors-interconnect-ut_huge_cluster - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - PROCESSORS - 4 -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-interconnect-ut_huge_cluster - cpp-malloc-jemalloc -) -vcs_info(library-cpp-actors-interconnect-ut_huge_cluster) diff --git a/library/cpp/actors/interconnect/ut_huge_cluster/CMakeLists.linux-x86_64.txt b/library/cpp/actors/interconnect/ut_huge_cluster/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 97a04cc102..0000000000 --- a/library/cpp/actors/interconnect/ut_huge_cluster/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,81 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-interconnect-ut_huge_cluster) -target_link_libraries(library-cpp-actors-interconnect-ut_huge_cluster PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - interconnect-ut-lib - interconnect-ut-protos - cpp-testing-unittest - cpp-actors-testlib -) -target_link_options(library-cpp-actors-interconnect-ut_huge_cluster PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-interconnect-ut_huge_cluster PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut_huge_cluster/huge_cluster.cpp -) -set_property( - TARGET - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-interconnect-ut_huge_cluster - TEST_TARGET - library-cpp-actors-interconnect-ut_huge_cluster - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - PROCESSORS - 4 -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-interconnect-ut_huge_cluster - cpp-malloc-tcmalloc - libs-tcmalloc-no_percpu_cache -) -vcs_info(library-cpp-actors-interconnect-ut_huge_cluster) diff --git a/library/cpp/actors/interconnect/ut_huge_cluster/CMakeLists.txt b/library/cpp/actors/interconnect/ut_huge_cluster/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/interconnect/ut_huge_cluster/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/interconnect/ut_huge_cluster/CMakeLists.windows-x86_64.txt b/library/cpp/actors/interconnect/ut_huge_cluster/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 7155e17cd5..0000000000 --- a/library/cpp/actors/interconnect/ut_huge_cluster/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,69 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-interconnect-ut_huge_cluster) -target_link_libraries(library-cpp-actors-interconnect-ut_huge_cluster PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-core - cpp-actors-interconnect - interconnect-ut-lib - interconnect-ut-protos - cpp-testing-unittest - cpp-actors-testlib -) -target_sources(library-cpp-actors-interconnect-ut_huge_cluster PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/interconnect/ut_huge_cluster/huge_cluster.cpp -) -set_property( - TARGET - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-interconnect-ut_huge_cluster - TEST_TARGET - library-cpp-actors-interconnect-ut_huge_cluster - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - LABELS - MEDIUM -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - PROCESSORS - 4 -) -set_yunittest_property( - TEST - library-cpp-actors-interconnect-ut_huge_cluster - PROPERTY - TIMEOUT - 600 -) -target_allocator(library-cpp-actors-interconnect-ut_huge_cluster - system_allocator -) -vcs_info(library-cpp-actors-interconnect-ut_huge_cluster) diff --git a/library/cpp/actors/interconnect/ut_huge_cluster/huge_cluster.cpp b/library/cpp/actors/interconnect/ut_huge_cluster/huge_cluster.cpp deleted file mode 100644 index cb46a62ed9..0000000000 --- a/library/cpp/actors/interconnect/ut_huge_cluster/huge_cluster.cpp +++ /dev/null @@ -1,167 +0,0 @@ -#include <library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h> -#include <library/cpp/actors/interconnect/ut/lib/test_events.h> -#include <library/cpp/actors/interconnect/ut/lib/test_actors.h> - -#include <library/cpp/testing/unittest/registar.h> - -#include <vector> - -Y_UNIT_TEST_SUITE(HugeCluster) { - using namespace NActors; - - class TPoller: public TActor<TPoller> { - const std::vector<TActorId>& Targets; - std::unordered_map<TActorId, TManualEvent>& Connected; - - public: - TPoller(const std::vector<TActorId>& targets, std::unordered_map<TActorId, TManualEvent>& events) - : TActor(&TPoller::StateFunc) - , Targets(targets) - , Connected(events) - {} - - void Handle(TEvTestStartPolling::TPtr /*ev*/, const TActorContext& ctx) { - for (ui32 i = 0; i < Targets.size(); ++i) { - ctx.Send(Targets[i], new TEvTest(), IEventHandle::FlagTrackDelivery, i); - } - } - - void Handle(TEvents::TEvUndelivered::TPtr ev, const TActorContext& ctx) { - const ui32 cookie = ev->Cookie; - // Cerr << "TEvUndelivered ping from node# " << SelfId().NodeId() << " to node# " << cookie + 1 << Endl; - ctx.Send(Targets[cookie], new TEvTest(), IEventHandle::FlagTrackDelivery, cookie); - } - - void Handle(TEvTest::TPtr ev, const TActorContext& /*ctx*/) { - // Cerr << "Polled from " << ev->Sender.ToString() << Endl; - Connected[ev->Sender].Signal(); - } - - void Handle(TEvents::TEvPoisonPill::TPtr& /*ev*/, const TActorContext& ctx) { - Die(ctx); - } - - STRICT_STFUNC(StateFunc, - HFunc(TEvents::TEvUndelivered, Handle) - HFunc(TEvTestStartPolling, Handle) - HFunc(TEvTest, Handle) - HFunc(TEvents::TEvPoisonPill, Handle) - ) - }; - - class TStartPollers : public TActorBootstrapped<TStartPollers> { - const std::vector<TActorId>& Pollers; - - public: - TStartPollers(const std::vector<TActorId>& pollers) - : Pollers(pollers) - {} - - void Bootstrap(const TActorContext& ctx) { - Become(&TThis::StateFunc); - for (ui32 i = 0; i < Pollers.size(); ++i) { - ctx.Send(Pollers[i], new TEvTestStartPolling(), IEventHandle::FlagTrackDelivery, i); - } - } - - void Handle(TEvents::TEvUndelivered::TPtr ev, const TActorContext& ctx) { - const ui32 cookie = ev->Cookie; - // Cerr << "TEvUndelivered start poller message to node# " << cookie + 1 << Endl; - ctx.Send(Pollers[cookie], new TEvTestStartPolling(), IEventHandle::FlagTrackDelivery, cookie); - } - - void Handle(TEvents::TEvPoisonPill::TPtr& /*ev*/, const TActorContext& ctx) { - Die(ctx); - } - - STRICT_STFUNC(StateFunc, - HFunc(TEvents::TEvUndelivered, Handle) - HFunc(TEvents::TEvPoisonPill, Handle) - ) - }; - - TIntrusivePtr<NLog::TSettings> MakeLogConfigs(NLog::EPriority priority) { - // custom logger settings - auto loggerSettings = MakeIntrusive<NLog::TSettings>( - TActorId(0, "logger"), - NActorsServices::LOGGER, - priority, - priority, - 0U); - - loggerSettings->Append( - NActorsServices::EServiceCommon_MIN, - NActorsServices::EServiceCommon_MAX, - NActorsServices::EServiceCommon_Name - ); - - constexpr ui32 WilsonComponentId = 430; // NKikimrServices::WILSON - static const TString WilsonComponentName = "WILSON"; - - loggerSettings->Append( - (NLog::EComponent)WilsonComponentId, - (NLog::EComponent)WilsonComponentId + 1, - [](NLog::EComponent) -> const TString & { return WilsonComponentName; }); - - return loggerSettings; - } - - Y_UNIT_TEST(AllToAll) { - ui32 nodesNum = 120; - std::vector<TActorId> pollers(nodesNum); - std::vector<std::unordered_map<TActorId, TManualEvent>> events(nodesNum); - - // Must destroy actor system before shared arrays - { - TTestICCluster testCluster(nodesNum, NActors::TChannelsConfig(), nullptr, MakeLogConfigs(NLog::PRI_EMERG)); - - for (ui32 i = 0; i < nodesNum; ++i) { - pollers[i] = testCluster.RegisterActor(new TPoller(pollers, events[i]), i + 1); - } - - for (ui32 i = 0; i < nodesNum; ++i) { - for (const auto& actor : pollers) { - events[i][actor] = TManualEvent(); - } - } - - testCluster.RegisterActor(new TStartPollers(pollers), 1); - - for (ui32 i = 0; i < nodesNum; ++i) { - for (auto& [_, ev] : events[i]) { - ev.WaitI(); - } - } - } - } - - - Y_UNIT_TEST(AllToOne) { - ui32 nodesNum = 500; - std::vector<TActorId> listeners; - std::vector<TActorId> pollers(nodesNum - 1); - std::unordered_map<TActorId, TManualEvent> events; - std::unordered_map<TActorId, TManualEvent> emptyEventList; - - // Must destroy actor system before shared arrays - { - TTestICCluster testCluster(nodesNum, NActors::TChannelsConfig(), nullptr, MakeLogConfigs(NLog::PRI_EMERG)); - - const TActorId listener = testCluster.RegisterActor(new TPoller({}, events), nodesNum); - listeners = { listener }; - for (ui32 i = 0; i < nodesNum - 1; ++i) { - pollers[i] = testCluster.RegisterActor(new TPoller(listeners, emptyEventList), i + 1); - } - - for (const auto& actor : pollers) { - events[actor] = TManualEvent(); - } - - testCluster.RegisterActor(new TStartPollers(pollers), 1); - - for (auto& [_, ev] : events) { - ev.WaitI(); - } - } - } -} diff --git a/library/cpp/actors/interconnect/ut_huge_cluster/ya.make b/library/cpp/actors/interconnect/ut_huge_cluster/ya.make deleted file mode 100644 index 828783323d..0000000000 --- a/library/cpp/actors/interconnect/ut_huge_cluster/ya.make +++ /dev/null @@ -1,34 +0,0 @@ -UNITTEST() - -IF (SANITIZER_TYPE OR WITH_VALGRIND) - TIMEOUT(3600) - SIZE(LARGE) - TAG(ya:fat) -ELSE() - TIMEOUT(600) - SIZE(MEDIUM) -ENDIF() - -IF (BUILD_TYPE == "RELEASE" OR BUILD_TYPE == "RELWITHDEBINFO") - SRCS( - huge_cluster.cpp - ) -ELSE () - MESSAGE(WARNING "It takes too much time to run test in DEBUG mode, some tests are skipped") -ENDIF () - -PEERDIR( - library/cpp/actors/core - library/cpp/actors/interconnect - library/cpp/actors/interconnect/ut/lib - library/cpp/actors/interconnect/ut/protos - library/cpp/testing/unittest - library/cpp/actors/testlib -) - -REQUIREMENTS( - cpu:4 - ram:32 -) - -END() diff --git a/library/cpp/actors/interconnect/watchdog_timer.h b/library/cpp/actors/interconnect/watchdog_timer.h deleted file mode 100644 index 2a5860f84c..0000000000 --- a/library/cpp/actors/interconnect/watchdog_timer.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -namespace NActors { - template<typename TEvent> - class TWatchdogTimer { - using TCallback = std::function<void()>; - - const TDuration Timeout; - const TCallback Callback; - - TMonotonic TriggerTimestamp = TMonotonic::Max(); - bool EventScheduled = false; - ui32 Iteration; - - static constexpr ui32 NumIterationsBeforeFiring = 2; - - public: - TWatchdogTimer(TDuration timeout, TCallback callback) - : Timeout(timeout) - , Callback(std::move(callback)) - {} - - void Rearm(const TActorIdentity& actor) { - if (Timeout != TDuration::Zero() && Timeout != TDuration::Max()) { - TriggerTimestamp = TActivationContext::Monotonic() + Timeout; - Iteration = 0; - Schedule(actor); - } - } - - void Disarm() { - TriggerTimestamp = TMonotonic::Max(); - } - - bool Armed() const { - return TriggerTimestamp != TMonotonic::Max(); - } - - void operator()(typename TEvent::TPtr& ev) { - Y_DEBUG_ABORT_UNLESS(EventScheduled); - EventScheduled = false; - if (!Armed()) { - // just do nothing - } else if (TActivationContext::Monotonic() < TriggerTimestamp) { - // the time hasn't come yet - Schedule(TActorIdentity(ev->Recipient)); - } else if (Iteration < NumIterationsBeforeFiring) { - // time has come, but we will still give actor a chance to process some messages and rearm timer - ++Iteration; - TActivationContext::Send(ev.Release()); // send this event into queue once more - EventScheduled = true; - } else { - // no chance to disarm, fire callback - Disarm(); - Callback(); - } - } - - private: - void Schedule(const TActorIdentity& actor) { - Y_DEBUG_ABORT_UNLESS(Armed()); - if (!EventScheduled) { - actor.Schedule(TriggerTimestamp, new TEvent); - EventScheduled = true; - } - } - }; - -} diff --git a/library/cpp/actors/interconnect/ya.make b/library/cpp/actors/interconnect/ya.make deleted file mode 100644 index 9cb5bc7d8c..0000000000 --- a/library/cpp/actors/interconnect/ya.make +++ /dev/null @@ -1,97 +0,0 @@ -LIBRARY() - -NO_WSHADOW() - -IF (PROFILE_MEMORY_ALLOCATIONS) - CFLAGS(-DPROFILE_MEMORY_ALLOCATIONS) -ENDIF() - -SRCS( - channel_scheduler.h - event_filter.h - event_holder_pool.h - events_local.h - interconnect_address.cpp - interconnect_address.h - interconnect_channel.cpp - interconnect_channel.h - interconnect_common.h - interconnect_counters.cpp - interconnect.h - interconnect_handshake.cpp - interconnect_handshake.h - interconnect_impl.h - interconnect_mon.cpp - interconnect_mon.h - interconnect_nameserver_dynamic.cpp - interconnect_nameserver_table.cpp - interconnect_proxy_wrapper.cpp - interconnect_proxy_wrapper.h - interconnect_resolve.cpp - interconnect_stream.cpp - interconnect_stream.h - interconnect_tcp_input_session.cpp - interconnect_tcp_proxy.cpp - interconnect_tcp_proxy.h - interconnect_tcp_server.cpp - interconnect_tcp_server.h - interconnect_tcp_session.cpp - interconnect_tcp_session.h - load.cpp - load.h - logging.h - packet.cpp - packet.h - poller_actor.cpp - poller_actor.h - poller.h - poller_tcp.cpp - poller_tcp.h - poller_tcp_unit.cpp - poller_tcp_unit.h - poller_tcp_unit_select.cpp - poller_tcp_unit_select.h - profiler.h - slowpoke_actor.h - types.cpp - types.h - watchdog_timer.h -) - -IF (OS_LINUX) - SRCS( - poller_tcp_unit_epoll.cpp - poller_tcp_unit_epoll.h - ) -ENDIF() - -PEERDIR( - contrib/libs/libc_compat - contrib/libs/openssl - contrib/libs/xxhash - library/cpp/actors/core - library/cpp/actors/dnscachelib - library/cpp/actors/dnsresolver - library/cpp/actors/helpers - library/cpp/actors/prof - library/cpp/actors/protos - library/cpp/actors/util - library/cpp/actors/wilson - library/cpp/digest/crc32c - library/cpp/json - library/cpp/lwtrace - library/cpp/monlib/dynamic_counters - library/cpp/monlib/metrics - library/cpp/monlib/service/pages/resources - library/cpp/monlib/service/pages/tablesorter - library/cpp/openssl/init - library/cpp/packedtypes -) - -END() - -RECURSE_FOR_TESTS( - ut - ut_fat - ut_huge_cluster -) diff --git a/library/cpp/actors/log_backend/CMakeLists.darwin-arm64.txt b/library/cpp/actors/log_backend/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 2845e78e35..0000000000 --- a/library/cpp/actors/log_backend/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(cpp-actors-log_backend) -target_link_libraries(cpp-actors-log_backend PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core - library-cpp-logger -) -target_sources(cpp-actors-log_backend PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/log_backend/actor_log_backend.cpp -) diff --git a/library/cpp/actors/log_backend/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/log_backend/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 2845e78e35..0000000000 --- a/library/cpp/actors/log_backend/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(cpp-actors-log_backend) -target_link_libraries(cpp-actors-log_backend PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core - library-cpp-logger -) -target_sources(cpp-actors-log_backend PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/log_backend/actor_log_backend.cpp -) diff --git a/library/cpp/actors/log_backend/CMakeLists.linux-aarch64.txt b/library/cpp/actors/log_backend/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 15786d6c74..0000000000 --- a/library/cpp/actors/log_backend/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,20 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(cpp-actors-log_backend) -target_link_libraries(cpp-actors-log_backend PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-actors-core - library-cpp-logger -) -target_sources(cpp-actors-log_backend PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/log_backend/actor_log_backend.cpp -) diff --git a/library/cpp/actors/log_backend/CMakeLists.linux-x86_64.txt b/library/cpp/actors/log_backend/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 15786d6c74..0000000000 --- a/library/cpp/actors/log_backend/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,20 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(cpp-actors-log_backend) -target_link_libraries(cpp-actors-log_backend PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-actors-core - library-cpp-logger -) -target_sources(cpp-actors-log_backend PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/log_backend/actor_log_backend.cpp -) diff --git a/library/cpp/actors/log_backend/CMakeLists.txt b/library/cpp/actors/log_backend/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/log_backend/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/log_backend/CMakeLists.windows-x86_64.txt b/library/cpp/actors/log_backend/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 2845e78e35..0000000000 --- a/library/cpp/actors/log_backend/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(cpp-actors-log_backend) -target_link_libraries(cpp-actors-log_backend PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core - library-cpp-logger -) -target_sources(cpp-actors-log_backend PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/log_backend/actor_log_backend.cpp -) diff --git a/library/cpp/actors/log_backend/actor_log_backend.cpp b/library/cpp/actors/log_backend/actor_log_backend.cpp deleted file mode 100644 index a6fdd20c7b..0000000000 --- a/library/cpp/actors/log_backend/actor_log_backend.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "actor_log_backend.h" - -#include <library/cpp/actors/core/actorsystem.h> -#include <library/cpp/actors/core/log.h> -#include <library/cpp/logger/record.h> - -namespace { - -NActors::NLog::EPriority GetActorLogPriority(ELogPriority priority) { - switch (priority) { - case TLOG_EMERG: - return NActors::NLog::PRI_EMERG; - case TLOG_ALERT: - return NActors::NLog::PRI_ALERT; - case TLOG_CRIT: - return NActors::NLog::PRI_CRIT; - case TLOG_ERR: - return NActors::NLog::PRI_ERROR; - case TLOG_WARNING: - return NActors::NLog::PRI_WARN; - case TLOG_NOTICE: - return NActors::NLog::PRI_NOTICE; - case TLOG_INFO: - return NActors::NLog::PRI_INFO; - case TLOG_DEBUG: - return NActors::NLog::PRI_DEBUG; - default: - return NActors::NLog::PRI_TRACE; - } -} - -} - -TActorLogBackend::TActorLogBackend(NActors::TActorSystem* actorSystem, int logComponent) - : ActorSystem(actorSystem) - , LogComponent(logComponent) -{ -} - -void TActorLogBackend::WriteData(const TLogRecord& rec) { - LOG_LOG(*ActorSystem, GetActorLogPriority(rec.Priority), LogComponent, TString(rec.Data, rec.Len)); -} diff --git a/library/cpp/actors/log_backend/actor_log_backend.h b/library/cpp/actors/log_backend/actor_log_backend.h deleted file mode 100644 index a51427d498..0000000000 --- a/library/cpp/actors/log_backend/actor_log_backend.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include <library/cpp/logger/backend.h> - -namespace NActors { -class TActorSystem; -} // namespace NActors - -class TActorLogBackend : public TLogBackend { -public: - TActorLogBackend(NActors::TActorSystem* actorSystem, int logComponent); - - void WriteData(const TLogRecord& rec) override; - - void ReopenLog() override { - } - -private: - NActors::TActorSystem* const ActorSystem; - const int LogComponent; -}; diff --git a/library/cpp/actors/log_backend/ya.make b/library/cpp/actors/log_backend/ya.make deleted file mode 100644 index ce9f049e9a..0000000000 --- a/library/cpp/actors/log_backend/ya.make +++ /dev/null @@ -1,12 +0,0 @@ -LIBRARY() - -PEERDIR( - library/cpp/actors/core - library/cpp/logger -) - -SRCS( - actor_log_backend.cpp -) - -END() diff --git a/library/cpp/actors/memory_log/CMakeLists.darwin-arm64.txt b/library/cpp/actors/memory_log/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 5109f0fcce..0000000000 --- a/library/cpp/actors/memory_log/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,21 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(cpp-actors-memory_log) -target_link_libraries(cpp-actors-memory_log PUBLIC - contrib-libs-cxxsupp - yutil - cpp-threading-queue - contrib-libs-linuxvdso - cpp-deprecated-atomic -) -target_sources(cpp-actors-memory_log PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/memory_log/memlog.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/memory_log/mmap.cpp -) diff --git a/library/cpp/actors/memory_log/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/memory_log/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 5109f0fcce..0000000000 --- a/library/cpp/actors/memory_log/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,21 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(cpp-actors-memory_log) -target_link_libraries(cpp-actors-memory_log PUBLIC - contrib-libs-cxxsupp - yutil - cpp-threading-queue - contrib-libs-linuxvdso - cpp-deprecated-atomic -) -target_sources(cpp-actors-memory_log PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/memory_log/memlog.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/memory_log/mmap.cpp -) diff --git a/library/cpp/actors/memory_log/CMakeLists.linux-aarch64.txt b/library/cpp/actors/memory_log/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 1fa79db3ff..0000000000 --- a/library/cpp/actors/memory_log/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,22 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(cpp-actors-memory_log) -target_link_libraries(cpp-actors-memory_log PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-threading-queue - contrib-libs-linuxvdso - cpp-deprecated-atomic -) -target_sources(cpp-actors-memory_log PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/memory_log/memlog.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/memory_log/mmap.cpp -) diff --git a/library/cpp/actors/memory_log/CMakeLists.linux-x86_64.txt b/library/cpp/actors/memory_log/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 1fa79db3ff..0000000000 --- a/library/cpp/actors/memory_log/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,22 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(cpp-actors-memory_log) -target_link_libraries(cpp-actors-memory_log PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-threading-queue - contrib-libs-linuxvdso - cpp-deprecated-atomic -) -target_sources(cpp-actors-memory_log PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/memory_log/memlog.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/memory_log/mmap.cpp -) diff --git a/library/cpp/actors/memory_log/CMakeLists.txt b/library/cpp/actors/memory_log/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/memory_log/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/memory_log/CMakeLists.windows-x86_64.txt b/library/cpp/actors/memory_log/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 5109f0fcce..0000000000 --- a/library/cpp/actors/memory_log/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,21 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(cpp-actors-memory_log) -target_link_libraries(cpp-actors-memory_log PUBLIC - contrib-libs-cxxsupp - yutil - cpp-threading-queue - contrib-libs-linuxvdso - cpp-deprecated-atomic -) -target_sources(cpp-actors-memory_log PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/memory_log/memlog.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/memory_log/mmap.cpp -) diff --git a/library/cpp/actors/memory_log/memlog.cpp b/library/cpp/actors/memory_log/memlog.cpp deleted file mode 100644 index 263c5c5079..0000000000 --- a/library/cpp/actors/memory_log/memlog.cpp +++ /dev/null @@ -1,367 +0,0 @@ -#include "memlog.h" - -#include <library/cpp/actors/util/datetime.h> - -#include <util/system/info.h> -#include <library/cpp/deprecated/atomic/atomic.h> -#include <util/system/align.h> - -#include <contrib/libs/linuxvdso/interface.h> - -#if (defined(_i386_) || defined(_x86_64_)) && defined(_linux_) -#define HAVE_VDSO_GETCPU 1 -#include <contrib/libs/linuxvdso/interface.h> -static int (*FastGetCpu)(unsigned* cpu, unsigned* node, void* unused); -#endif - -#if defined(_unix_) -#include <sched.h> -#elif defined(_win_) -#include <WinBase.h> -#else -#error NO IMPLEMENTATION FOR THE PLATFORM -#endif - -const char TMemoryLog::DEFAULT_LAST_MARK[16] = { - 'c', - 'b', - '7', - 'B', - '6', - '8', - 'a', - '8', - 'A', - '5', - '6', - '1', - '6', - '4', - '5', - '\n', -}; - -const char TMemoryLog::CLEAR_MARK[16] = { - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - '\n', -}; - -unsigned TMemoryLog::GetSelfCpu() noexcept { -#if defined(_unix_) -#if HAVE_VDSO_GETCPU - unsigned cpu; - if (Y_LIKELY(FastGetCpu != nullptr)) { - auto result = FastGetCpu(&cpu, nullptr, nullptr); - Y_ABORT_UNLESS(result == 0); - return cpu; - } else { - return 0; - } - -#elif defined(_x86_64_) || defined(_i386_) - -#define CPUID(func, eax, ebx, ecx, edx) \ - __asm__ __volatile__( \ - "cpuid" \ - : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) \ - : "a"(func)); - - int a = 0, b = 0, c = 0, d = 0; - CPUID(0x1, a, b, c, d); - int acpiID = (b >> 24); - return acpiID; - -#elif defined(__CNUC__) - return sched_getcpu(); -#else - return 0; -#endif - -#elif defined(_win_) - return GetCurrentProcessorNumber(); -#else - return 0; -#endif -} - -TMemoryLog* TMemoryLog::MemLogBuffer = nullptr; -Y_POD_THREAD(TThread::TId) -TMemoryLog::LogThreadId; -char* TMemoryLog::LastMarkIsHere = nullptr; - -std::atomic<bool> TMemoryLog::PrintLastMark(true); - -TMemoryLog::TMemoryLog(size_t totalSize, size_t grainSize) - : GrainSize(grainSize) - , FreeGrains(DEFAULT_TOTAL_SIZE / DEFAULT_GRAIN_SIZE * 2) - , Buf(totalSize) -{ - Y_ABORT_UNLESS(DEFAULT_TOTAL_SIZE % DEFAULT_GRAIN_SIZE == 0); - NumberOfGrains = DEFAULT_TOTAL_SIZE / DEFAULT_GRAIN_SIZE; - - for (size_t i = 0; i < NumberOfGrains; ++i) { - new (GetGrain(i)) TGrain; - } - - NumberOfCpus = NSystemInfo::NumberOfCpus(); - Y_ABORT_UNLESS(NumberOfGrains > NumberOfCpus); - ActiveGrains.Reset(new TGrain*[NumberOfCpus]); - for (size_t i = 0; i < NumberOfCpus; ++i) { - ActiveGrains[i] = GetGrain(i); - } - - for (size_t i = NumberOfCpus; i < NumberOfGrains; ++i) { - FreeGrains.StubbornPush(GetGrain(i)); - } - -#if HAVE_VDSO_GETCPU - auto vdsoFunc = (decltype(FastGetCpu)) - NVdso::Function("__vdso_getcpu", "LINUX_2.6"); - AtomicSet(FastGetCpu, vdsoFunc); -#endif -} - -void* TMemoryLog::GetWriteBuffer(size_t amount) noexcept { - // alignment required by NoCacheMemcpy - amount = AlignUp<size_t>(amount, MemcpyAlignment); - - for (ui16 tries = MAX_GET_BUFFER_TRIES; tries-- > 0;) { - auto myCpu = GetSelfCpu(); - - TGrain* grain = AtomicGet(ActiveGrains[myCpu]); - - if (grain != nullptr) { - auto mine = AtomicGetAndAdd(grain->WritePointer, amount); - if (mine + amount <= GrainSize - sizeof(TGrain)) { - return &grain->Data[mine]; - } - - if (!AtomicCas(&ActiveGrains[myCpu], 0, grain)) { - continue; - } - - FreeGrains.StubbornPush(grain); - } - - grain = (TGrain*)FreeGrains.Pop(); - - if (grain == nullptr) { - return nullptr; - } - - grain->WritePointer = 0; - - if (!AtomicCas(&ActiveGrains[myCpu], grain, 0)) { - FreeGrains.StubbornPush(grain); - continue; - } - } - - return nullptr; -} - -void ClearAlignedTail(char* tail) noexcept { - auto aligned = AlignUp(tail, TMemoryLog::MemcpyAlignment); - if (aligned > tail) { - memset(tail, 0, aligned - tail); - } -} - -#if defined(_x86_64_) || defined(_i386_) -#include <xmmintrin.h> -// the main motivation is not poluting CPU cache -NO_SANITIZE_THREAD -void NoCacheMemcpy(char* dst, const char* src, size_t size) noexcept { - while (size >= sizeof(__m128) * 2) { - __m128 a = _mm_load_ps((float*)(src + 0 * sizeof(__m128))); - __m128 b = _mm_load_ps((float*)(src + 1 * sizeof(__m128))); - _mm_stream_ps((float*)(dst + 0 * sizeof(__m128)), a); - _mm_stream_ps((float*)(dst + 1 * sizeof(__m128)), b); - - size -= sizeof(__m128) * 2; - src += sizeof(__m128) * 2; - dst += sizeof(__m128) * 2; - } - memcpy(dst, src, size); -} - -NO_SANITIZE_THREAD -void NoWCacheMemcpy(char* dst, const char* src, size_t size) noexcept { - constexpr ui16 ITEMS_COUNT = 1024; - alignas(TMemoryLog::MemcpyAlignment) __m128 buf[ITEMS_COUNT]; - while (size >= sizeof(buf)) { - memcpy(&buf, src, sizeof(buf)); - - for (ui16 i = 0; i < ITEMS_COUNT; ++i) { - _mm_stream_ps((float*)dst, buf[i]); - dst += sizeof(__m128); - } - - size -= sizeof(buf); - src += sizeof(buf); - } - - memcpy(&buf, src, size); - // no problem to copy few bytes more - size = AlignUp(size, sizeof(__m128)); - for (ui16 i = 0; i < size / sizeof(__m128); ++i) { - _mm_stream_ps((float*)dst, buf[i]); - dst += sizeof(__m128); - } -} - -#endif - -NO_SANITIZE_THREAD -char* BareMemLogWrite(const char* begin, size_t msgSize, bool isLast) noexcept { - bool lastMark = - isLast && TMemoryLog::PrintLastMark.load(std::memory_order_acquire); - size_t amount = lastMark ? msgSize + TMemoryLog::LAST_MARK_SIZE : msgSize; - - char* buffer = (char*)TMemoryLog::GetWriteBufferStatic(amount); - if (buffer == nullptr) { - return nullptr; - } - -#if defined(_x86_64_) || defined(_i386_) - if (AlignDown(begin, TMemoryLog::MemcpyAlignment) == begin) { - NoCacheMemcpy(buffer, begin, msgSize); - } else { - NoWCacheMemcpy(buffer, begin, msgSize); - } -#else - memcpy(buffer, begin, msgSize); -#endif - - if (lastMark) { - TMemoryLog::ChangeLastMark(buffer + msgSize); - } - - ClearAlignedTail(buffer + amount); - return buffer; -} - -NO_SANITIZE_THREAD -bool MemLogWrite(const char* begin, size_t msgSize, bool addLF) noexcept { - bool lastMark = TMemoryLog::PrintLastMark.load(std::memory_order_acquire); - size_t amount = lastMark ? msgSize + TMemoryLog::LAST_MARK_SIZE : msgSize; - - // Let's construct prolog with timestamp and thread id - auto threadId = TMemoryLog::GetTheadId(); - - // alignment required by NoCacheMemcpy - // check for format for snprintf - constexpr size_t prologSize = 48; - alignas(TMemoryLog::MemcpyAlignment) char prolog[prologSize + 1]; - Y_ABORT_UNLESS(AlignDown(&prolog, TMemoryLog::MemcpyAlignment) == &prolog); - - int snprintfResult = snprintf(prolog, prologSize + 1, - "TS %020" PRIu64 " TI %020" PRIu64 " ", GetCycleCountFast(), threadId); - - if (snprintfResult < 0) { - return false; - } - Y_ABORT_UNLESS(snprintfResult == prologSize); - - amount += prologSize; - if (addLF) { - ++amount; // add 1 byte for \n at the end of the message - } - - char* buffer = (char*)TMemoryLog::GetWriteBufferStatic(amount); - if (buffer == nullptr) { - return false; - } - -#if defined(_x86_64_) || defined(_i386_) - // warning: copy prolog first to avoid corruption of the message - // by prolog tail - NoCacheMemcpy(buffer, prolog, prologSize); - if (AlignDown(begin + prologSize, TMemoryLog::MemcpyAlignment) == begin + prologSize) { - NoCacheMemcpy(buffer + prologSize, begin, msgSize); - } else { - NoWCacheMemcpy(buffer + prologSize, begin, msgSize); - } -#else - memcpy(buffer, prolog, prologSize); - memcpy(buffer + prologSize, begin, msgSize); -#endif - - if (addLF) { - buffer[prologSize + msgSize] = '\n'; - } - - if (lastMark) { - TMemoryLog::ChangeLastMark(buffer + prologSize + msgSize + (int)addLF); - } - - ClearAlignedTail(buffer + amount); - return true; -} - -NO_SANITIZE_THREAD -void TMemoryLog::ChangeLastMark(char* buffer) noexcept { - memcpy(buffer, DEFAULT_LAST_MARK, LAST_MARK_SIZE); - auto oldMark = AtomicSwap(&LastMarkIsHere, buffer); - if (Y_LIKELY(oldMark != nullptr)) { - memcpy(oldMark, CLEAR_MARK, LAST_MARK_SIZE); - } - if (AtomicGet(LastMarkIsHere) != buffer) { - memcpy(buffer, CLEAR_MARK, LAST_MARK_SIZE); - AtomicBarrier(); - } -} - -bool MemLogVPrintF(const char* format, va_list params) noexcept { - auto logger = TMemoryLog::GetMemoryLogger(); - if (logger == nullptr) { - return false; - } - - auto threadId = TMemoryLog::GetTheadId(); - - // alignment required by NoCacheMemcpy - alignas(TMemoryLog::MemcpyAlignment) char buf[TMemoryLog::MAX_MESSAGE_SIZE]; - Y_ABORT_UNLESS(AlignDown(&buf, TMemoryLog::MemcpyAlignment) == &buf); - - int prologSize = snprintf(buf, - TMemoryLog::MAX_MESSAGE_SIZE - 2, - "TS %020" PRIu64 " TI %020" PRIu64 " ", - GetCycleCountFast(), - threadId); - - if (Y_UNLIKELY(prologSize < 0)) { - return false; - } - Y_ABORT_UNLESS((ui32)prologSize <= TMemoryLog::MAX_MESSAGE_SIZE); - - int add = vsnprintf( - &buf[prologSize], - TMemoryLog::MAX_MESSAGE_SIZE - prologSize - 2, - format, params); - - if (Y_UNLIKELY(add < 0)) { - return false; - } - Y_ABORT_UNLESS(add >= 0); - auto totalSize = prologSize + add; - - buf[totalSize++] = '\n'; - Y_ABORT_UNLESS((ui32)totalSize <= TMemoryLog::MAX_MESSAGE_SIZE); - - return BareMemLogWrite(buf, totalSize) != nullptr; -} diff --git a/library/cpp/actors/memory_log/memlog.h b/library/cpp/actors/memory_log/memlog.h deleted file mode 100644 index bf4e115c49..0000000000 --- a/library/cpp/actors/memory_log/memlog.h +++ /dev/null @@ -1,211 +0,0 @@ -#pragma once - -#include <library/cpp/threading/queue/mpmc_unordered_ring.h> -#include <util/generic/string.h> -#include <util/string/printf.h> -#include <util/system/datetime.h> -#include <util/system/thread.h> -#include <util/system/types.h> -#include <library/cpp/deprecated/atomic/atomic.h> -#include <util/system/align.h> -#include <util/system/tls.h> - -#include <atomic> -#include <cstdio> - -#ifdef _win_ -#include <util/system/winint.h> -#endif - -#ifndef NO_SANITIZE_THREAD -#define NO_SANITIZE_THREAD -#if defined(__has_feature) -#if __has_feature(thread_sanitizer) -#undef NO_SANITIZE_THREAD -#define NO_SANITIZE_THREAD __attribute__((no_sanitize_thread)) -#endif -#endif -#endif - -class TMemoryLog { -public: - static constexpr size_t DEFAULT_TOTAL_SIZE = 10 * 1024 * 1024; - static constexpr size_t DEFAULT_GRAIN_SIZE = 1024 * 64; - static constexpr size_t MAX_MESSAGE_SIZE = 1024; - static constexpr ui16 MAX_GET_BUFFER_TRIES = 4; - static constexpr ui16 MemcpyAlignment = 16; - - // search for cb7B68a8A561645 - static const char DEFAULT_LAST_MARK[16]; - static const char CLEAR_MARK[16]; - - static constexpr size_t LAST_MARK_SIZE = sizeof(DEFAULT_LAST_MARK); - - inline static TMemoryLog* GetMemoryLogger() noexcept { - return AtomicGet(MemLogBuffer); - } - - void* GetWriteBuffer(size_t amount) noexcept; - - inline static void* GetWriteBufferStatic(size_t amount) noexcept { - auto logger = GetMemoryLogger(); - if (logger == nullptr) { - return nullptr; - } - return logger->GetWriteBuffer(amount); - } - - size_t GetGlobalBufferSize() const noexcept { - return Buf.GetSize(); - } - - inline static void CreateMemoryLogBuffer( - size_t totalSize = DEFAULT_TOTAL_SIZE, - size_t grainSize = DEFAULT_GRAIN_SIZE) - Y_COLD { - if (AtomicGet(MemLogBuffer) != nullptr) { - return; - } - - AtomicSet(MemLogBuffer, new TMemoryLog(totalSize, grainSize)); - } - - static std::atomic<bool> PrintLastMark; - - // buffer must be at least 16 bytes - static void ChangeLastMark(char* buffer) noexcept; - - inline static TThread::TId GetTheadId() noexcept { - if (LogThreadId == 0) { - LogThreadId = TThread::CurrentThreadId(); - } - return LogThreadId; - } - -private: - TMemoryLog(size_t totalSize, size_t grainSize) Y_COLD; - - struct TGrain { - TAtomic WritePointer = 0; - char Padding[MemcpyAlignment - sizeof(TAtomic)]; - char Data[]; - }; - - size_t NumberOfCpus; - size_t GrainSize; - size_t NumberOfGrains; - TArrayPtr<TGrain*> ActiveGrains; - NThreading::TMPMCUnorderedRing FreeGrains; - - TGrain* GetGrain(size_t grainIndex) const noexcept { - return (TGrain*)((char*)GetGlobalBuffer() + GrainSize * grainIndex); - } - - class TMMapArea { - public: - TMMapArea(size_t amount) Y_COLD { - MMap(amount); - } - - TMMapArea(const TMMapArea&) = delete; - TMMapArea& operator=(const TMMapArea& copy) = delete; - - TMMapArea(TMMapArea&& move) Y_COLD { - BufPtr = move.BufPtr; - Size = move.Size; - - move.BufPtr = nullptr; - move.Size = 0; - } - - TMMapArea& operator=(TMMapArea&& move) Y_COLD { - BufPtr = move.BufPtr; - Size = move.Size; - - move.BufPtr = nullptr; - move.Size = 0; - return *this; - } - - void Reset(size_t amount) Y_COLD { - MUnmap(); - MMap(amount); - } - - ~TMMapArea() noexcept Y_COLD { - MUnmap(); - } - - size_t GetSize() const noexcept { - return Size; - } - - void* GetPtr() const noexcept { - return BufPtr; - } - - private: - void* BufPtr; - size_t Size; -#ifdef _win_ - HANDLE Mapping; -#endif - - void MMap(size_t amount); - void MUnmap(); - }; - - TMMapArea Buf; - - void* GetGlobalBuffer() const noexcept { - return Buf.GetPtr(); - } - - static unsigned GetSelfCpu() noexcept; - - static TMemoryLog* MemLogBuffer; - static Y_POD_THREAD(TThread::TId) LogThreadId; - static char* LastMarkIsHere; -}; - -// it's no use of sanitizing this function -NO_SANITIZE_THREAD -char* BareMemLogWrite( - const char* begin, size_t msgSize, bool isLast = true) noexcept; - -// it's no use of sanitizing this function -NO_SANITIZE_THREAD -bool MemLogWrite( - const char* begin, size_t msgSize, bool addLF = false) noexcept; - -Y_WRAPPER inline bool MemLogWrite(const char* begin, const char* end) noexcept { - if (end <= begin) { - return false; - } - - size_t msgSize = end - begin; - return MemLogWrite(begin, msgSize); -} - -template <typename TObj> -bool MemLogWriteStruct(const TObj* obj) noexcept { - auto begin = (const char*)(const void*)obj; - return MemLogWrite(begin, begin + sizeof(TObj)); -} - -Y_PRINTF_FORMAT(1, 0) -bool MemLogVPrintF(const char* format, va_list params) noexcept; - -Y_PRINTF_FORMAT(1, 2) -Y_WRAPPER -inline bool MemLogPrintF(const char* format, ...) noexcept { - va_list params; - va_start(params, format); - auto result = MemLogVPrintF(format, params); - va_end(params); - return result; -} - -Y_WRAPPER inline bool MemLogWriteNullTerm(const char* str) noexcept { - return MemLogWrite(str, strlen(str)); -} diff --git a/library/cpp/actors/memory_log/mmap.cpp b/library/cpp/actors/memory_log/mmap.cpp deleted file mode 100644 index 1fe734235e..0000000000 --- a/library/cpp/actors/memory_log/mmap.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "memlog.h" - -#if defined(_unix_) -#include <sys/mman.h> -#elif defined(_win_) -#include <util/system/winint.h> -#else -#error NO IMPLEMENTATION FOR THE PLATFORM -#endif - -void TMemoryLog::TMMapArea::MMap(size_t amount) { - Y_ABORT_UNLESS(amount > 0); - -#if defined(_unix_) - constexpr int mmapProt = PROT_READ | PROT_WRITE; -#if defined(_linux_) - constexpr int mmapFlags = MAP_PRIVATE | MAP_ANON | MAP_POPULATE; -#else - constexpr int mmapFlags = MAP_PRIVATE | MAP_ANON; -#endif - - BufPtr = ::mmap(nullptr, amount, mmapProt, mmapFlags, -1, 0); - if (BufPtr == MAP_FAILED) { - throw std::bad_alloc(); - } - -#elif defined(_win_) - Mapping = ::CreateFileMapping( - (HANDLE)-1, nullptr, PAGE_READWRITE, 0, amount, nullptr); - if (Mapping == NULL) { - throw std::bad_alloc(); - } - BufPtr = ::MapViewOfFile(Mapping, FILE_MAP_WRITE, 0, 0, amount); - if (BufPtr == NULL) { - throw std::bad_alloc(); - } -#endif - - Size = amount; -} - -void TMemoryLog::TMMapArea::MUnmap() { - if (BufPtr == nullptr) { - return; - } - -#if defined(_unix_) - int result = ::munmap(BufPtr, Size); - Y_ABORT_UNLESS(result == 0); - -#elif defined(_win_) - BOOL result = ::UnmapViewOfFile(BufPtr); - Y_ABORT_UNLESS(result != 0); - - result = ::CloseHandle(Mapping); - Y_ABORT_UNLESS(result != 0); - - Mapping = 0; -#endif - - BufPtr = nullptr; - Size = 0; -} diff --git a/library/cpp/actors/memory_log/ya.make b/library/cpp/actors/memory_log/ya.make deleted file mode 100644 index ae766a5464..0000000000 --- a/library/cpp/actors/memory_log/ya.make +++ /dev/null @@ -1,15 +0,0 @@ -LIBRARY() - -SRCS( - memlog.cpp - memlog.h - mmap.cpp -) - -PEERDIR( - library/cpp/threading/queue - contrib/libs/linuxvdso - library/cpp/deprecated/atomic -) - -END() diff --git a/library/cpp/actors/prof/CMakeLists.darwin-arm64.txt b/library/cpp/actors/prof/CMakeLists.darwin-arm64.txt deleted file mode 100644 index c641cf5a52..0000000000 --- a/library/cpp/actors/prof/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,22 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-prof) -target_link_libraries(cpp-actors-prof PUBLIC - contrib-libs-cxxsupp - yutil - libs-tcmalloc-malloc_extension - library-cpp-charset - cpp-containers-atomizer -) -target_sources(cpp-actors-prof PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof/tag.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof/tcmalloc.cpp -) diff --git a/library/cpp/actors/prof/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/prof/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index c641cf5a52..0000000000 --- a/library/cpp/actors/prof/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,22 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-prof) -target_link_libraries(cpp-actors-prof PUBLIC - contrib-libs-cxxsupp - yutil - libs-tcmalloc-malloc_extension - library-cpp-charset - cpp-containers-atomizer -) -target_sources(cpp-actors-prof PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof/tag.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof/tcmalloc.cpp -) diff --git a/library/cpp/actors/prof/CMakeLists.linux-aarch64.txt b/library/cpp/actors/prof/CMakeLists.linux-aarch64.txt deleted file mode 100644 index fa76970f57..0000000000 --- a/library/cpp/actors/prof/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,23 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-prof) -target_link_libraries(cpp-actors-prof PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - libs-tcmalloc-malloc_extension - library-cpp-charset - cpp-containers-atomizer -) -target_sources(cpp-actors-prof PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof/tag.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof/tcmalloc.cpp -) diff --git a/library/cpp/actors/prof/CMakeLists.linux-x86_64.txt b/library/cpp/actors/prof/CMakeLists.linux-x86_64.txt deleted file mode 100644 index fa76970f57..0000000000 --- a/library/cpp/actors/prof/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,23 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-prof) -target_link_libraries(cpp-actors-prof PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - libs-tcmalloc-malloc_extension - library-cpp-charset - cpp-containers-atomizer -) -target_sources(cpp-actors-prof PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof/tag.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof/tcmalloc.cpp -) diff --git a/library/cpp/actors/prof/CMakeLists.txt b/library/cpp/actors/prof/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/prof/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/prof/CMakeLists.windows-x86_64.txt b/library/cpp/actors/prof/CMakeLists.windows-x86_64.txt deleted file mode 100644 index c641cf5a52..0000000000 --- a/library/cpp/actors/prof/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,22 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-prof) -target_link_libraries(cpp-actors-prof PUBLIC - contrib-libs-cxxsupp - yutil - libs-tcmalloc-malloc_extension - library-cpp-charset - cpp-containers-atomizer -) -target_sources(cpp-actors-prof PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof/tag.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof/tcmalloc.cpp -) diff --git a/library/cpp/actors/prof/tag.cpp b/library/cpp/actors/prof/tag.cpp deleted file mode 100644 index 99248a135f..0000000000 --- a/library/cpp/actors/prof/tag.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include "tag.h" -#include "tcmalloc.h" - -#include <library/cpp/charset/ci_string.h> -#include <library/cpp/containers/atomizer/atomizer.h> -#include <library/cpp/malloc/api/malloc.h> - -#if defined(PROFILE_MEMORY_ALLOCATIONS) -#include <library/cpp/lfalloc/dbg_info/dbg_info.h> -#include <library/cpp/ytalloc/api/ytalloc.h> -#include <library/cpp/yt/memory/memory_tag.h> -#endif - -#include <util/generic/singleton.h> -#include <util/generic/string.h> -#include <util/generic/vector.h> -#include <util/system/mutex.h> -#include <library/cpp/actors/util/local_process_key.h> -#include <library/cpp/actors/actor_type/index_constructor.h> - -namespace NProfiling { - class TStringAtoms { - private: - TMutex Mutex; - atomizer<ci_hash, ci_equal_to> Tags; - - public: - static TStringAtoms& Instance() { - return *Singleton<TStringAtoms>(); - } - - ui32 MakeTag(const char* s) { - Y_ABORT_UNLESS(s); - with_lock (Mutex) { - return Tags.string_to_atom(s); - } - } - - ui32 MakeTags(const TVector<const char*>& ss) { - Y_ABORT_UNLESS(ss); - with_lock (Mutex) { - ui32 baseTag = Tags.string_to_atom(ss[0]); - ui32 nextTag = baseTag + 1; - for (auto i = ss.begin() + 1; i != ss.end(); ++i, ++nextTag) { - Y_ABORT_UNLESS(*i); - ui32 ctag = Tags.string_to_atom(*i); - Y_ABORT_UNLESS(ctag == nextTag); - } - return baseTag; - } - } - - const char* GetTag(ui32 tag) const { - with_lock (Mutex) { - return Tags.get_atom_name(tag); - } - } - - size_t GetTagsCount() const { - with_lock (Mutex) { - return Tags.size(); - } - } - }; - - ui32 MakeTag(const char* s) { - return TStringAtoms::Instance().MakeTag(s); - } - - ui32 MakeTags(const TVector<const char*>& ss) { - return TStringAtoms::Instance().MakeTags(ss); - } - - const char* GetTag(ui32 tag) { - return TStringAtoms::Instance().GetTag(tag); - } - - size_t GetTagsCount() { - return TStringAtoms::Instance().GetTagsCount(); - } - - static ui32 SetThreadAllocTag_Default(ui32 tag) { - Y_UNUSED(tag); - return 0; - } - -#if defined(PROFILE_MEMORY_ALLOCATIONS) - static ui32 SetThreadAllocTag_YT(ui32 tag) { - auto prev = NYT::GetCurrentMemoryTag(); - NYT::SetCurrentMemoryTag(tag); - return prev; - } - - static TSetThreadAllocTag* SetThreadAllocTagFn() { - const auto& info = NMalloc::MallocInfo(); - - TStringBuf name(info.Name); - if (name.StartsWith("lf")) { - return (TSetThreadAllocTag*)NAllocDbg::SetThreadAllocTag; - } else if (name.StartsWith("yt")) { - return SetThreadAllocTag_YT; - } else if (name.StartsWith("tc")) { - return SetTCMallocThreadAllocTag; - } else { - return SetThreadAllocTag_Default; - } - } -#else - static TSetThreadAllocTag* SetThreadAllocTagFn() { - const auto& info = NMalloc::MallocInfo(); - - TStringBuf name(info.Name); - if (name.StartsWith("tc")) { - return SetTCMallocThreadAllocTag; - } else { - return SetThreadAllocTag_Default; - } - } -#endif - - TSetThreadAllocTag* SetThreadAllocTag = SetThreadAllocTagFn(); -} - -TMemoryProfileGuard::TMemoryProfileGuard(const TString& id) - : Id(id) -{ - NProfiling::TMemoryTagScope::Reset(TLocalProcessKeyState<NActors::TActorActivityTag>::GetInstance().Register(Id + "-Start")); -} - -TMemoryProfileGuard::~TMemoryProfileGuard() { - NProfiling::TMemoryTagScope::Reset(TLocalProcessKeyState<NActors::TActorActivityTag>::GetInstance().Register(Id + "-Finish")); -} diff --git a/library/cpp/actors/prof/tag.h b/library/cpp/actors/prof/tag.h deleted file mode 100644 index 1624d9d1e0..0000000000 --- a/library/cpp/actors/prof/tag.h +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once - -#include <util/generic/string.h> -#include <util/generic/noncopyable.h> -#include <util/generic/vector.h> - -/* - Common registry for tagging memory profiler. - Register a new tag with MakeTag using a unique string. - Use registered tags with SetThreadAllocTag function in allocator API. -*/ - -namespace NProfiling { - ui32 MakeTag(const char* s); - - // Make only unique tags. Y_ABORT_UNLESS inside. - ui32 MakeTags(const TVector<const char*>& ss); - - const char* GetTag(ui32 tag); - size_t GetTagsCount(); - - using TSetThreadAllocTag = ui32(ui32 tag); - extern TSetThreadAllocTag* SetThreadAllocTag; - - class TMemoryTagScope { - public: - explicit TMemoryTagScope(ui32 tag) - : RestoreTag(SetThreadAllocTag(tag)) - { - } - - explicit TMemoryTagScope(const char* tagName) { - ui32 newTag = MakeTag(tagName); - RestoreTag = SetThreadAllocTag(newTag); - } - - TMemoryTagScope(TMemoryTagScope&& move) - : RestoreTag(move.RestoreTag) - , Released(move.Released) - { - move.Released = true; - } - - TMemoryTagScope& operator=(TMemoryTagScope&& move) { - RestoreTag = move.RestoreTag; - Released = move.Released; - move.Released = true; - return *this; - } - - static void Reset(ui32 tag) { - SetThreadAllocTag(tag); - } - - void Release() { - if (!Released) { - SetThreadAllocTag(RestoreTag); - Released = true; - } - } - - ~TMemoryTagScope() { - if (!Released) { - SetThreadAllocTag(RestoreTag); - } - } - - protected: - TMemoryTagScope(const TMemoryTagScope&) = delete; - void operator=(const TMemoryTagScope&) = delete; - - ui32 RestoreTag = 0; - bool Released = false; - }; -} - -class TMemoryProfileGuard: TNonCopyable { -private: - const TString Id; -public: - TMemoryProfileGuard(const TString& id); - ~TMemoryProfileGuard(); - -}; diff --git a/library/cpp/actors/prof/tcmalloc.cpp b/library/cpp/actors/prof/tcmalloc.cpp deleted file mode 100644 index 3d4f203dbb..0000000000 --- a/library/cpp/actors/prof/tcmalloc.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "tcmalloc.h" - -#include <contrib/libs/tcmalloc/tcmalloc/malloc_extension.h> - -namespace NProfiling { - -static thread_local ui32 AllocationTag = 0; - -static struct TInitTCMallocCallbacks { - static void* CreateTag() { - return reinterpret_cast<void*>(AllocationTag); - } - static void* CopyTag(void* tag) { - return tag; - } - static void DestroyTag(void* tag) { - Y_UNUSED(tag); - } - - TInitTCMallocCallbacks() { - tcmalloc::MallocExtension::SetSampleUserDataCallbacks( - CreateTag, CopyTag, DestroyTag); - } -} InitTCMallocCallbacks; - -ui32 SetTCMallocThreadAllocTag(ui32 tag) { - ui32 prev = AllocationTag; - AllocationTag = tag; - return prev; -} - -} diff --git a/library/cpp/actors/prof/tcmalloc.h b/library/cpp/actors/prof/tcmalloc.h deleted file mode 100644 index 659fb4eaf3..0000000000 --- a/library/cpp/actors/prof/tcmalloc.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include <util/generic/fwd.h> - -namespace NProfiling { - -ui32 SetTCMallocThreadAllocTag(ui32 tag); - -} diff --git a/library/cpp/actors/prof/ut/CMakeLists.darwin-arm64.txt b/library/cpp/actors/prof/ut/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 44995c4d4b..0000000000 --- a/library/cpp/actors/prof/ut/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,66 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-prof-ut) -target_include_directories(library-cpp-actors-prof-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof -) -target_link_libraries(library-cpp-actors-prof-ut PUBLIC - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-prof -) -target_link_options(library-cpp-actors-prof-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-prof-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof/ut/tag_ut.cpp -) -set_property( - TARGET - library-cpp-actors-prof-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-prof-ut - TEST_TARGET - library-cpp-actors-prof-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-prof-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-prof-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-prof-ut - system_allocator -) -vcs_info(library-cpp-actors-prof-ut) diff --git a/library/cpp/actors/prof/ut/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/prof/ut/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 0ec56d8762..0000000000 --- a/library/cpp/actors/prof/ut/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,67 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-prof-ut) -target_include_directories(library-cpp-actors-prof-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof -) -target_link_libraries(library-cpp-actors-prof-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-prof -) -target_link_options(library-cpp-actors-prof-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-prof-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof/ut/tag_ut.cpp -) -set_property( - TARGET - library-cpp-actors-prof-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-prof-ut - TEST_TARGET - library-cpp-actors-prof-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-prof-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-prof-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-prof-ut - system_allocator -) -vcs_info(library-cpp-actors-prof-ut) diff --git a/library/cpp/actors/prof/ut/CMakeLists.linux-aarch64.txt b/library/cpp/actors/prof/ut/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 591055b744..0000000000 --- a/library/cpp/actors/prof/ut/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,70 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-prof-ut) -target_include_directories(library-cpp-actors-prof-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof -) -target_link_libraries(library-cpp-actors-prof-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-prof -) -target_link_options(library-cpp-actors-prof-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-prof-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof/ut/tag_ut.cpp -) -set_property( - TARGET - library-cpp-actors-prof-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-prof-ut - TEST_TARGET - library-cpp-actors-prof-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-prof-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-prof-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-prof-ut - cpp-malloc-jemalloc -) -vcs_info(library-cpp-actors-prof-ut) diff --git a/library/cpp/actors/prof/ut/CMakeLists.linux-x86_64.txt b/library/cpp/actors/prof/ut/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 7c84eda1b0..0000000000 --- a/library/cpp/actors/prof/ut/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,72 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-prof-ut) -target_include_directories(library-cpp-actors-prof-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof -) -target_link_libraries(library-cpp-actors-prof-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-prof -) -target_link_options(library-cpp-actors-prof-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-prof-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof/ut/tag_ut.cpp -) -set_property( - TARGET - library-cpp-actors-prof-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-prof-ut - TEST_TARGET - library-cpp-actors-prof-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-prof-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-prof-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-prof-ut - cpp-malloc-tcmalloc - libs-tcmalloc-no_percpu_cache -) -vcs_info(library-cpp-actors-prof-ut) diff --git a/library/cpp/actors/prof/ut/CMakeLists.txt b/library/cpp/actors/prof/ut/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/prof/ut/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/prof/ut/CMakeLists.windows-x86_64.txt b/library/cpp/actors/prof/ut/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 3165130380..0000000000 --- a/library/cpp/actors/prof/ut/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,60 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-prof-ut) -target_include_directories(library-cpp-actors-prof-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof -) -target_link_libraries(library-cpp-actors-prof-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-prof -) -target_sources(library-cpp-actors-prof-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/prof/ut/tag_ut.cpp -) -set_property( - TARGET - library-cpp-actors-prof-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-prof-ut - TEST_TARGET - library-cpp-actors-prof-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-prof-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-prof-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-prof-ut - system_allocator -) -vcs_info(library-cpp-actors-prof-ut) diff --git a/library/cpp/actors/prof/ut/tag_ut.cpp b/library/cpp/actors/prof/ut/tag_ut.cpp deleted file mode 100644 index accf3921ab..0000000000 --- a/library/cpp/actors/prof/ut/tag_ut.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "tag.h" - -#include <library/cpp/testing/unittest/registar.h> - -using namespace NProfiling; - -class TAtomTagsTest: public TTestBase { -private: - UNIT_TEST_SUITE(TAtomTagsTest); - UNIT_TEST(Test_MakeTag); - UNIT_TEST(Test_Make2Tags); - UNIT_TEST(Test_MakeTagTwice); - - UNIT_TEST(Test_MakeAndGetTag); - - UNIT_TEST(Test_MakeVector); - UNIT_TEST_SUITE_END(); - -public: - void Test_MakeTag(); - void Test_Make2Tags(); - void Test_MakeTagTwice(); - void Test_MakeAndGetTag(); - void Test_MakeVector(); -}; - -UNIT_TEST_SUITE_REGISTRATION(TAtomTagsTest); - -void TAtomTagsTest::Test_MakeTag() { - ui32 tag = MakeTag("a tag"); - UNIT_ASSERT(tag != 0); -} - -void TAtomTagsTest::Test_Make2Tags() { - ui32 tag1 = MakeTag("a tag 1"); - ui32 tag2 = MakeTag("a tag 2"); - UNIT_ASSERT(tag1 != 0); - UNIT_ASSERT(tag2 != 0); - UNIT_ASSERT(tag1 != tag2); -} - -void TAtomTagsTest::Test_MakeTagTwice() { - ui32 tag1 = MakeTag("a tag twice"); - ui32 tag2 = MakeTag("a tag twice"); - UNIT_ASSERT(tag1 != 0); - UNIT_ASSERT(tag1 == tag2); -} - -void TAtomTagsTest::Test_MakeAndGetTag() { - const char* makeStr = "tag to get"; - ui32 tag = MakeTag(makeStr); - const char* tagStr = GetTag(tag); - UNIT_ASSERT_STRINGS_EQUAL(makeStr, tagStr); -} - -void TAtomTagsTest::Test_MakeVector() { - TVector<const char*> strs = { - "vector tag 0", - "vector tag 1", - "vector tag 3", - "vector tag 4"}; - ui32 baseTag = MakeTags(strs); - UNIT_ASSERT(baseTag != 0); - for (ui32 i = 0; i < strs.size(); ++i) { - const char* str = GetTag(baseTag + i); - UNIT_ASSERT_STRINGS_EQUAL(str, strs[i]); - } -} diff --git a/library/cpp/actors/prof/ut/ya.make b/library/cpp/actors/prof/ut/ya.make deleted file mode 100644 index e439856698..0000000000 --- a/library/cpp/actors/prof/ut/ya.make +++ /dev/null @@ -1,7 +0,0 @@ -UNITTEST_FOR(library/cpp/actors/prof) - -SRCS( - tag_ut.cpp -) - -END() diff --git a/library/cpp/actors/prof/ya.make b/library/cpp/actors/prof/ya.make deleted file mode 100644 index 4bae10a443..0000000000 --- a/library/cpp/actors/prof/ya.make +++ /dev/null @@ -1,28 +0,0 @@ -LIBRARY() - -SRCS( - tag.cpp - tcmalloc.cpp -) - -PEERDIR( - contrib/libs/tcmalloc/malloc_extension - library/cpp/charset - library/cpp/containers/atomizer -) - -IF (PROFILE_MEMORY_ALLOCATIONS) - CFLAGS(-DPROFILE_MEMORY_ALLOCATIONS) - PEERDIR( - library/cpp/malloc/api - library/cpp/lfalloc/dbg_info - library/cpp/ytalloc/api - library/cpp/yt/memory - ) -ENDIF() - -END() - -RECURSE_FOR_TESTS( - ut -) diff --git a/library/cpp/actors/protos/CMakeLists.darwin-arm64.txt b/library/cpp/actors/protos/CMakeLists.darwin-arm64.txt deleted file mode 100644 index be3257b127..0000000000 --- a/library/cpp/actors/protos/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,82 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) - -add_library(cpp-actors-protos) -target_link_libraries(cpp-actors-protos PUBLIC - contrib-libs-cxxsupp - yutil - contrib-libs-protobuf -) -target_proto_messages(cpp-actors-protos PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/actors.proto - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/interconnect.proto - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/services_common.proto - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/unittests.proto -) -target_proto_addincls(cpp-actors-protos - ./ - ${CMAKE_SOURCE_DIR}/ - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src -) -target_proto_outs(cpp-actors-protos - --cpp_out=${CMAKE_BINARY_DIR}/ - --cpp_styleguide_out=${CMAKE_BINARY_DIR}/ -) diff --git a/library/cpp/actors/protos/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/protos/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index be3257b127..0000000000 --- a/library/cpp/actors/protos/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,82 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) - -add_library(cpp-actors-protos) -target_link_libraries(cpp-actors-protos PUBLIC - contrib-libs-cxxsupp - yutil - contrib-libs-protobuf -) -target_proto_messages(cpp-actors-protos PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/actors.proto - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/interconnect.proto - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/services_common.proto - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/unittests.proto -) -target_proto_addincls(cpp-actors-protos - ./ - ${CMAKE_SOURCE_DIR}/ - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src -) -target_proto_outs(cpp-actors-protos - --cpp_out=${CMAKE_BINARY_DIR}/ - --cpp_styleguide_out=${CMAKE_BINARY_DIR}/ -) diff --git a/library/cpp/actors/protos/CMakeLists.linux-aarch64.txt b/library/cpp/actors/protos/CMakeLists.linux-aarch64.txt deleted file mode 100644 index a9da706400..0000000000 --- a/library/cpp/actors/protos/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,83 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) - -add_library(cpp-actors-protos) -target_link_libraries(cpp-actors-protos PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - contrib-libs-protobuf -) -target_proto_messages(cpp-actors-protos PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/actors.proto - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/interconnect.proto - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/services_common.proto - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/unittests.proto -) -target_proto_addincls(cpp-actors-protos - ./ - ${CMAKE_SOURCE_DIR}/ - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src -) -target_proto_outs(cpp-actors-protos - --cpp_out=${CMAKE_BINARY_DIR}/ - --cpp_styleguide_out=${CMAKE_BINARY_DIR}/ -) diff --git a/library/cpp/actors/protos/CMakeLists.linux-x86_64.txt b/library/cpp/actors/protos/CMakeLists.linux-x86_64.txt deleted file mode 100644 index a9da706400..0000000000 --- a/library/cpp/actors/protos/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,83 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) - -add_library(cpp-actors-protos) -target_link_libraries(cpp-actors-protos PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - contrib-libs-protobuf -) -target_proto_messages(cpp-actors-protos PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/actors.proto - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/interconnect.proto - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/services_common.proto - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/unittests.proto -) -target_proto_addincls(cpp-actors-protos - ./ - ${CMAKE_SOURCE_DIR}/ - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src -) -target_proto_outs(cpp-actors-protos - --cpp_out=${CMAKE_BINARY_DIR}/ - --cpp_styleguide_out=${CMAKE_BINARY_DIR}/ -) diff --git a/library/cpp/actors/protos/CMakeLists.txt b/library/cpp/actors/protos/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/protos/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/protos/CMakeLists.windows-x86_64.txt b/library/cpp/actors/protos/CMakeLists.windows-x86_64.txt deleted file mode 100644 index be3257b127..0000000000 --- a/library/cpp/actors/protos/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,82 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) -get_built_tool_path( - TOOL_protoc_bin - TOOL_protoc_dependency - contrib/tools/protoc/bin - protoc -) -get_built_tool_path( - TOOL_cpp_styleguide_bin - TOOL_cpp_styleguide_dependency - contrib/tools/protoc/plugins/cpp_styleguide - cpp_styleguide -) - -add_library(cpp-actors-protos) -target_link_libraries(cpp-actors-protos PUBLIC - contrib-libs-cxxsupp - yutil - contrib-libs-protobuf -) -target_proto_messages(cpp-actors-protos PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/actors.proto - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/interconnect.proto - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/services_common.proto - ${CMAKE_SOURCE_DIR}/library/cpp/actors/protos/unittests.proto -) -target_proto_addincls(cpp-actors-protos - ./ - ${CMAKE_SOURCE_DIR}/ - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src - ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/contrib/libs/protobuf/src -) -target_proto_outs(cpp-actors-protos - --cpp_out=${CMAKE_BINARY_DIR}/ - --cpp_styleguide_out=${CMAKE_BINARY_DIR}/ -) diff --git a/library/cpp/actors/protos/actors.proto b/library/cpp/actors/protos/actors.proto deleted file mode 100644 index 329eb998df..0000000000 --- a/library/cpp/actors/protos/actors.proto +++ /dev/null @@ -1,41 +0,0 @@ -package NActorsProto; -option java_package = "ru.yandex.kikimr.proto"; -option java_outer_classname = "NActorsBaseProto"; - -message TActorId { - required fixed64 RawX1 = 1; - required fixed64 RawX2 = 2; -} - -message TTraceId { - optional bytes Data = 1; -} - -message TCallbackException { - required TActorId ActorId = 1; - required string ExceptionMessage = 2; -} - -message TRemoteHttpInfo { - message TQueryParam { - optional string Key = 1; - optional string Value = 2; - } - - message THeader { - optional string Name = 1; - optional string Value = 2; - } - - optional uint32 Method = 1; // HTTP_METHOD enum - optional string Path = 2; - repeated TQueryParam QueryParams = 3; - repeated TQueryParam PostParams = 4; - optional bytes PostContent = 8; - repeated THeader Headers = 9; - optional string RemoteAddr = 7; - - // for compatibility reasons (incorrect field types merged in 21-4) - reserved 5; - reserved 6; -} diff --git a/library/cpp/actors/protos/interconnect.proto b/library/cpp/actors/protos/interconnect.proto deleted file mode 100644 index 0e88f3bce5..0000000000 --- a/library/cpp/actors/protos/interconnect.proto +++ /dev/null @@ -1,133 +0,0 @@ -import "library/cpp/actors/protos/actors.proto"; -import "google/protobuf/descriptor.proto"; - -package NActorsInterconnect; -option java_package = "ru.yandex.kikimr.proto"; - -message TEvResolveNode { - optional uint32 NodeId = 1; - optional uint64 Deadline = 2; -} - -message TEvNodeInfo { - optional uint32 NodeId = 1; - optional string Address = 2; - optional uint32 Port = 3; -} - -extend google.protobuf.FieldOptions { - optional string PrintName = 50376; -} - -message TNodeLocation { - // compatibility section -- will be removed in future versions - optional uint32 DataCenterNum = 1 [deprecated=true]; - optional uint32 RoomNum = 2 [deprecated=true]; - optional uint32 RackNum = 3 [deprecated=true]; - optional uint32 BodyNum = 4 [deprecated=true]; - optional uint32 Body = 100500 [deprecated=true]; // for compatibility with WalleLocation - - optional string DataCenter = 10 [(PrintName) = "DC"]; - optional string Module = 20 [(PrintName) = "M"]; - optional string Rack = 30 [(PrintName) = "R"]; - optional string Unit = 40 [(PrintName) = "U"]; -} - -message TClusterUUIDs { - optional string ClusterUUID = 1; - repeated string AcceptUUID = 2; -} - -message TScopeId { - optional fixed64 X1 = 1; - optional fixed64 X2 = 2; -} - -message THandshakeRequest { - required uint64 Protocol = 1; - - required uint64 ProgramPID = 2; - required uint64 ProgramStartTime = 3; - required uint64 Serial = 4; - - required uint32 ReceiverNodeId = 5; - required string SenderActorId = 6; - - optional string SenderHostName = 7; - optional string ReceiverHostName = 8; - optional string UUID = 9; - optional TClusterUUIDs ClusterUUIDs = 13; - - optional bytes Ballast = 10; - - optional string VersionTag = 11; - repeated string AcceptedVersionTags = 12; - - optional bool RequireEncryption = 14; - optional TScopeId ClientScopeId = 15; - - optional string Cookie = 16; - optional bool DoCheckCookie = 17; - - optional bool RequestModernFrame = 18; - optional bool RequestAuthOnly = 19; - optional bool RequestExtendedTraceFmt = 20; - optional bool RequestExternalDataChannel = 21; - optional bool RequestXxhash = 24; - optional bool RequestXdcShuffle = 25; - - optional bytes CompatibilityInfo = 22; - - optional bytes HandshakeId = 23; -} - -message THandshakeSuccess { - required uint64 Protocol = 1; - - required uint64 ProgramPID = 2; - required uint64 ProgramStartTime = 3; - required uint64 Serial = 4; - - required string SenderActorId = 5; - - optional string VersionTag = 6; - repeated string AcceptedVersionTags = 7; - - optional TClusterUUIDs ClusterUUIDs = 8; - - optional bool StartEncryption = 9; - optional TScopeId ServerScopeId = 10; - - optional bool UseModernFrame = 11; - optional bool AuthOnly = 12; - optional bool UseExtendedTraceFmt = 13; - optional bool UseExternalDataChannel = 14; - optional bool UseXxhash = 16; - optional bool UseXdcShuffle = 17; - - optional bytes CompatibilityInfo = 15; -} - -message THandshakeReply { - optional THandshakeSuccess Success = 1; - optional string ErrorExplaination = 2; - optional bool CookieCheckResult = 3; -} - -message TEvLoadMessage { - message THop { - optional NActorsProto.TActorId NextHop = 1; // if zero, then the payload is trimmed out of the message - } - - repeated THop Hops = 1; // the route for the message - optional string Id = 3; // message identifier - optional bytes Payload = 4; // data payload -} - -message TContinuationParams { - optional bytes HandshakeId = 1; -} - -message TExternalDataChannelParams { - optional bytes HandshakeId = 1; -} diff --git a/library/cpp/actors/protos/services_common.proto b/library/cpp/actors/protos/services_common.proto deleted file mode 100644 index 1191859f03..0000000000 --- a/library/cpp/actors/protos/services_common.proto +++ /dev/null @@ -1,22 +0,0 @@ -package NActorsServices; -option java_package = "ru.yandex.kikimr.proto"; - -// 0-255 range -enum EServiceCommon { - // WARN: This must be the smallest value in the enumeration - - GLOBAL = 0; - INTERCONNECT = 1; - TEST = 2; - PROTOCOLS = 3; - INTERCONNECT_SPEED_TEST = 4; - INTERCONNECT_STATUS = 5; - INTERCONNECT_NETWORK = 6; - INTERCONNECT_SESSION = 7; - HTTP = 8; - LOGGER = 9; - - // This value is reserved boundary. Is must not be aliased with any values - // TODO: use reseved values upon protobuf update - // COMMON_END = 256; -}; diff --git a/library/cpp/actors/protos/unittests.proto b/library/cpp/actors/protos/unittests.proto deleted file mode 100644 index 4b1af85e01..0000000000 --- a/library/cpp/actors/protos/unittests.proto +++ /dev/null @@ -1,20 +0,0 @@ -option cc_enable_arenas = true; - -message TSimple { - required string Str1 = 1; - optional string Str2 = 2; - optional uint64 Number1 = 3; -} - -message TBigMessage { - repeated TSimple Simples = 1; - repeated string ManyStr = 2; - optional string OneMoreStr = 3; - optional uint64 YANumber = 4; -} - -message TMessageWithPayload { - optional string Meta = 1; - repeated uint32 PayloadId = 2; - repeated bytes SomeData = 3; -} diff --git a/library/cpp/actors/protos/ya.make b/library/cpp/actors/protos/ya.make deleted file mode 100644 index c9139191ec..0000000000 --- a/library/cpp/actors/protos/ya.make +++ /dev/null @@ -1,12 +0,0 @@ -PROTO_LIBRARY() - -SRCS( - actors.proto - interconnect.proto - services_common.proto - unittests.proto -) - -EXCLUDE_TAGS(GO_PROTO) - -END() diff --git a/library/cpp/actors/testlib/CMakeLists.darwin-arm64.txt b/library/cpp/actors/testlib/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 4f1c8d01a2..0000000000 --- a/library/cpp/actors/testlib/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,23 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-testlib) -target_link_libraries(cpp-actors-testlib PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core - actors-interconnect-mock - cpp-actors-protos - library-cpp-random_provider - library-cpp-time_provider -) -target_sources(cpp-actors-testlib PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/testlib/test_runtime.cpp -) diff --git a/library/cpp/actors/testlib/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/testlib/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 4f1c8d01a2..0000000000 --- a/library/cpp/actors/testlib/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,23 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-testlib) -target_link_libraries(cpp-actors-testlib PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core - actors-interconnect-mock - cpp-actors-protos - library-cpp-random_provider - library-cpp-time_provider -) -target_sources(cpp-actors-testlib PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/testlib/test_runtime.cpp -) diff --git a/library/cpp/actors/testlib/CMakeLists.linux-aarch64.txt b/library/cpp/actors/testlib/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 40a5c9c26f..0000000000 --- a/library/cpp/actors/testlib/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,24 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-testlib) -target_link_libraries(cpp-actors-testlib PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-actors-core - actors-interconnect-mock - cpp-actors-protos - library-cpp-random_provider - library-cpp-time_provider -) -target_sources(cpp-actors-testlib PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/testlib/test_runtime.cpp -) diff --git a/library/cpp/actors/testlib/CMakeLists.linux-x86_64.txt b/library/cpp/actors/testlib/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 40a5c9c26f..0000000000 --- a/library/cpp/actors/testlib/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,24 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-testlib) -target_link_libraries(cpp-actors-testlib PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-actors-core - actors-interconnect-mock - cpp-actors-protos - library-cpp-random_provider - library-cpp-time_provider -) -target_sources(cpp-actors-testlib PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/testlib/test_runtime.cpp -) diff --git a/library/cpp/actors/testlib/CMakeLists.txt b/library/cpp/actors/testlib/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/testlib/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/testlib/CMakeLists.windows-x86_64.txt b/library/cpp/actors/testlib/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 4f1c8d01a2..0000000000 --- a/library/cpp/actors/testlib/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,23 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-testlib) -target_link_libraries(cpp-actors-testlib PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core - actors-interconnect-mock - cpp-actors-protos - library-cpp-random_provider - library-cpp-time_provider -) -target_sources(cpp-actors-testlib PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/testlib/test_runtime.cpp -) diff --git a/library/cpp/actors/testlib/decorator_ut.cpp b/library/cpp/actors/testlib/decorator_ut.cpp deleted file mode 100644 index fe5c769290..0000000000 --- a/library/cpp/actors/testlib/decorator_ut.cpp +++ /dev/null @@ -1,327 +0,0 @@ -#include "test_runtime.h" - -#include <library/cpp/actors/core/actor_bootstrapped.h> -#include <library/cpp/testing/unittest/registar.h> - - -using namespace NActors; - - -Y_UNIT_TEST_SUITE(TesTTestDecorator) { - - bool IsVerbose = false; - void Write(TString msg) { - if (IsVerbose) { - Cerr << (TStringBuilder() << msg << Endl); - } - } - - struct TDyingChecker : TTestDecorator { - TActorId MasterId; - - TDyingChecker(THolder<IActor> &&actor, TActorId masterId) - : TTestDecorator(std::move(actor)) - , MasterId(masterId) - { - Write("TDyingChecker::Construct\n"); - } - - virtual ~TDyingChecker() { - Write("TDyingChecker::~TDyingChecker"); - TActivationContext::Send(new IEventHandle(MasterId, SelfId(), new TEvents::TEvPing())); - } - - bool DoBeforeReceiving(TAutoPtr<IEventHandle> &/*ev*/, const TActorContext &/*ctx*/) override { - Write("TDyingChecker::DoBeforeReceiving"); - return true; - } - - void DoAfterReceiving(const TActorContext &/*ctx*/) override { - Write("TDyingChecker::DoAfterReceiving"); - } - }; - - struct TTestMasterActor : TActorBootstrapped<TTestMasterActor> { - friend TActorBootstrapped<TTestMasterActor>; - - TSet<TActorId> ActorIds; - TVector<THolder<IActor>> Actors; - TActorId EdgeActor; - - TTestMasterActor(TVector<THolder<IActor>> &&actors, TActorId edgeActor) - : TActorBootstrapped() - , Actors(std::move(actors)) - , EdgeActor(edgeActor) - { - } - - void Bootstrap() - { - Write("Start master actor"); - for (auto &actor : Actors) { - THolder<IActor> decaratedActor = MakeHolder<TDyingChecker>(std::move(actor), SelfId()); - TActorId id = Register(decaratedActor.Release()); - Write("Register test actor"); - UNIT_ASSERT(ActorIds.insert(id).second); - } - Become(&TTestMasterActor::State); - } - - STATEFN(State) { - auto it = ActorIds.find(ev->Sender); - UNIT_ASSERT(it != ActorIds.end()); - Write("End test actor"); - ActorIds.erase(it); - if (!ActorIds) { - Send(EdgeActor, new TEvents::TEvPing()); - PassAway(); - } - } - }; - - enum { - Begin = EventSpaceBegin(TEvents::ES_USERSPACE), - EvWords - }; - - struct TEvWords : TEventLocal<TEvWords, EvWords> { - TVector<TString> Words; - - TEvWords() - : TEventLocal() - { - } - }; - - struct TFizzBuzzToFooBar : TTestDecorator { - TFizzBuzzToFooBar(THolder<IActor> &&actor) - : TTestDecorator(std::move(actor)) - { - } - - bool DoBeforeSending(TAutoPtr<IEventHandle> &ev) override { - if (ev->Type == TEvents::TSystem::Bootstrap) { - return true; - } - Write("TFizzBuzzToFooBar::DoBeforeSending"); - TEventHandle<TEvWords> *handle = reinterpret_cast<TEventHandle<TEvWords>*>(ev.Get()); - UNIT_ASSERT(handle); - TEvWords *event = handle->Get(); - TVector<TString> &words = event->Words; - TStringBuilder wordsMsg; - for (auto &word : words) { - wordsMsg << word << ';'; - } - Write(TStringBuilder() << "Send# " << wordsMsg); - if (words.size() == 2 && words[0] == "Fizz" && words[1] == "Buzz") { - words[0] = "Foo"; - words[1] = "Bar"; - } - return true; - } - - bool DoBeforeReceiving(TAutoPtr<IEventHandle> &/*ev*/, const TActorContext &/*ctx*/) override { - Write("TFizzBuzzToFooBar::DoBeforeReceiving"); - return true; - } - - void DoAfterReceiving(const TActorContext &/*ctx*/) override { - Write("TFizzBuzzToFooBar::DoAfterReceiving"); - } - }; - - struct TWordEraser : TTestDecorator { - TString ErasingWord; - - TWordEraser(THolder<IActor> &&actor, TString word) - : TTestDecorator(std::move(actor)) - , ErasingWord(word) - { - } - - bool DoBeforeSending(TAutoPtr<IEventHandle> &ev) override { - if (ev->Type == TEvents::TSystem::Bootstrap) { - return true; - } - Write("TWordEraser::DoBeforeSending"); - TEventHandle<TEvWords> *handle = reinterpret_cast<TEventHandle<TEvWords>*>(ev.Get()); - UNIT_ASSERT(handle); - TEvWords *event = handle->Get(); - TVector<TString> &words = event->Words; - auto it = Find(words.begin(), words.end(), ErasingWord); - if (it != words.end()) { - words.erase(it); - } - return true; - } - - bool DoBeforeReceiving(TAutoPtr<IEventHandle> &/*ev*/, const TActorContext &/*ctx*/) override { - Write("TWordEraser::DoBeforeReceiving"); - return true; - } - - void DoAfterReceiving(const TActorContext &/*ctx*/) override { - Write("TWordEraser::DoAfterReceiving"); - } - }; - - struct TWithoutWordsDroper : TTestDecorator { - TWithoutWordsDroper(THolder<IActor> &&actor) - : TTestDecorator(std::move(actor)) - { - } - - bool DoBeforeSending(TAutoPtr<IEventHandle> &ev) override { - if (ev->Type == TEvents::TSystem::Bootstrap) { - return true; - } - Write("TWithoutWordsDroper::DoBeforeSending"); - TEventHandle<TEvWords> *handle = reinterpret_cast<TEventHandle<TEvWords>*>(ev.Get()); - UNIT_ASSERT(handle); - TEvWords *event = handle->Get(); - return bool(event->Words); - } - - bool DoBeforeReceiving(TAutoPtr<IEventHandle> &/*ev*/, const TActorContext &/*ctx*/) override { - Write("TWithoutWordsDroper::DoBeforeReceiving"); - return true; - } - - void DoAfterReceiving(const TActorContext &/*ctx*/) override { - Write("TWithoutWordsDroper::DoAfterReceiving"); - } - }; - - struct TFooBarReceiver : TActorBootstrapped<TFooBarReceiver> { - TActorId MasterId; - ui64 Counter = 0; - - TFooBarReceiver(TActorId masterId) - : TActorBootstrapped() - , MasterId(masterId) - { - } - - void Bootstrap() - { - Become(&TFooBarReceiver::State); - } - - STATEFN(State) { - TEventHandle<TEvWords> *handle = reinterpret_cast<TEventHandle<TEvWords>*>(ev.Get()); - UNIT_ASSERT(handle); - UNIT_ASSERT(handle->Sender == MasterId); - TEvWords *event = handle->Get(); - TVector<TString> &words = event->Words; - UNIT_ASSERT(words.size() == 2 && words[0] == "Foo" && words[1] == "Bar"); - Write(TStringBuilder() << "Receive# " << Counter + 1 << '/' << 2); - if (++Counter == 2) { - PassAway(); - } - } - }; - - struct TFizzBuzzSender : TActorBootstrapped<TFizzBuzzSender> { - TActorId SlaveId; - - TFizzBuzzSender() - : TActorBootstrapped() - { - Write("TFizzBuzzSender::Construct"); - } - - void Bootstrap() { - Write("TFizzBuzzSender::Bootstrap"); - THolder<IActor> actor = MakeHolder<TFooBarReceiver>(SelfId()); - THolder<IActor> decoratedActor = MakeHolder<TDyingChecker>(std::move(actor), SelfId()); - SlaveId = Register(decoratedActor.Release()); - for (ui64 idx = 1; idx <= 30; ++idx) { - THolder<TEvWords> ev = MakeHolder<TEvWords>(); - if (idx % 3 == 0) { - ev->Words.push_back("Fizz"); - } - if (idx % 5 == 0) { - ev->Words.push_back("Buzz"); - } - Send(SlaveId, ev.Release()); - Write("TFizzBuzzSender::Send words"); - } - Become(&TFizzBuzzSender::State); - } - - STATEFN(State) { - UNIT_ASSERT(ev->Sender == SlaveId); - PassAway(); - } - }; - - struct TCounters { - ui64 SendedCount = 0; - ui64 RecievedCount = 0; - }; - - struct TCountingDecorator : TTestDecorator { - TCounters *Counters; - - TCountingDecorator(THolder<IActor> &&actor, TCounters *counters) - : TTestDecorator(std::move(actor)) - , Counters(counters) - { - } - - bool DoBeforeSending(TAutoPtr<IEventHandle> &ev) override { - if (ev->Type == TEvents::TSystem::Bootstrap) { - return true; - } - Write("TCountingDecorator::DoBeforeSending"); - Counters->SendedCount++; - return true; - } - - bool DoBeforeReceiving(TAutoPtr<IEventHandle> &/*ev*/, const TActorContext &/*ctx*/) override { - Write("TCountingDecorator::DoBeforeReceiving"); - Counters->RecievedCount++; - return true; - } - }; - - bool ScheduledFilterFunc(NActors::TTestActorRuntimeBase& runtime, TAutoPtr<NActors::IEventHandle>& event, - TDuration delay, TInstant& deadline) { - if (runtime.IsScheduleForActorEnabled(event->GetRecipientRewrite())) { - deadline = runtime.GetTimeProvider()->Now() + delay; - return false; - } - return true; - } - - THolder<IActor> CreateFizzBuzzSender() { - THolder<IActor> actor = MakeHolder<TFizzBuzzSender>(); - THolder<IActor> foobar = MakeHolder<TFizzBuzzToFooBar>(std::move(actor)); - THolder<IActor> fizzEraser = MakeHolder<TWordEraser>(std::move(foobar), "Fizz"); - THolder<IActor> buzzEraser = MakeHolder<TWordEraser>(std::move(fizzEraser), "Buzz"); - return MakeHolder<TWithoutWordsDroper>(std::move(buzzEraser)); - } - - Y_UNIT_TEST(Basic) { - TTestActorRuntimeBase runtime(1, false); - - runtime.SetScheduledEventFilter(&ScheduledFilterFunc); - runtime.SetEventFilter([](NActors::TTestActorRuntimeBase&, TAutoPtr<NActors::IEventHandle>&) { - return false; - }); - runtime.Initialize(); - - TActorId edgeActor = runtime.AllocateEdgeActor(); - TVector<THolder<IActor>> actors(1); - actors[0] = CreateFizzBuzzSender(); - //actors[1] = CreateFizzBuzzSender(); - THolder<IActor> testActor = MakeHolder<TTestMasterActor>(std::move(actors), edgeActor); - Write("Start test"); - runtime.Register(testActor.Release()); - - TAutoPtr<IEventHandle> handle; - auto ev = runtime.GrabEdgeEventRethrow<TEvents::TEvPing>(handle); - UNIT_ASSERT(ev); - Write("Stop test"); - } -} diff --git a/library/cpp/actors/testlib/test_runtime.cpp b/library/cpp/actors/testlib/test_runtime.cpp deleted file mode 100644 index 18e58c21de..0000000000 --- a/library/cpp/actors/testlib/test_runtime.cpp +++ /dev/null @@ -1,1968 +0,0 @@ -#include "test_runtime.h" - -#include <library/cpp/actors/core/actor_bootstrapped.h> -#include <library/cpp/actors/core/callstack.h> -#include <library/cpp/actors/core/executor_pool_basic.h> -#include <library/cpp/actors/core/executor_pool_io.h> -#include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/core/scheduler_basic.h> -#include <library/cpp/actors/util/datetime.h> -#include <library/cpp/actors/protos/services_common.pb.h> -#include <library/cpp/random_provider/random_provider.h> -#include <library/cpp/actors/interconnect/interconnect.h> -#include <library/cpp/actors/interconnect/interconnect_tcp_proxy.h> -#include <library/cpp/actors/interconnect/interconnect_proxy_wrapper.h> - -#include <util/generic/maybe.h> -#include <util/generic/bt_exception.h> -#include <util/random/mersenne.h> -#include <util/string/printf.h> -#include <typeinfo> - -bool VERBOSE = false; -const bool PRINT_EVENT_BODY = false; - -namespace { - - TString MakeClusterId() { - pid_t pid = getpid(); - TStringBuilder uuid; - uuid << "Cluster for process with id: " << pid; - return uuid; - } -} - -namespace NActors { - ui64 TScheduledEventQueueItem::NextUniqueId = 0; - - void PrintEvent(TAutoPtr<IEventHandle>& ev, const TTestActorRuntimeBase* runtime) { - Cerr << "mailbox: " << ev->GetRecipientRewrite().Hint() << ", type: " << Sprintf("%08x", ev->GetTypeRewrite()) - << ", from " << ev->Sender.LocalId(); - TString name = runtime->GetActorName(ev->Sender); - if (!name.empty()) - Cerr << " \"" << name << "\""; - Cerr << ", to " << ev->GetRecipientRewrite().LocalId(); - name = runtime->GetActorName(ev->GetRecipientRewrite()); - if (!name.empty()) - Cerr << " \"" << name << "\""; - Cerr << ", "; - if (ev->HasEvent()) - Cerr << " : " << (PRINT_EVENT_BODY ? ev->ToString() : ev->GetTypeName()); - else if (ev->HasBuffer()) - Cerr << " : BUFFER"; - else - Cerr << " : EMPTY"; - - Cerr << "\n"; - } - - TTestActorRuntimeBase::TNodeDataBase::TNodeDataBase() { - ActorSystemTimestamp = nullptr; - ActorSystemMonotonic = nullptr; - } - - void TTestActorRuntimeBase::TNodeDataBase::Stop() { - if (Poller) - Poller->Stop(); - - if (MailboxTable) { - for (ui32 round = 0; !MailboxTable->Cleanup(); ++round) - Y_ABORT_UNLESS(round < 10, "cyclic event/actor spawn while trying to shutdown actorsystem stub"); - } - - if (ActorSystem) - ActorSystem->Stop(); - - ActorSystem.Destroy(); - Poller.Reset(); - } - - TTestActorRuntimeBase::TNodeDataBase::~TNodeDataBase() { - Stop(); - } - - - class TTestActorRuntimeBase::TEdgeActor : public TActor<TEdgeActor> { - public: - static constexpr EActivityType ActorActivityType() { - return EActivityType::TEST_ACTOR_RUNTIME; - } - - TEdgeActor(TTestActorRuntimeBase* runtime) - : TActor(&TEdgeActor::StateFunc) - , Runtime(runtime) - { - } - - STFUNC(StateFunc) { - TGuard<TMutex> guard(Runtime->Mutex); - bool verbose = (Runtime->CurrentDispatchContext ? !Runtime->CurrentDispatchContext->Options->Quiet : true) && VERBOSE; - if (Runtime->BlockedOutput.find(ev->Sender) != Runtime->BlockedOutput.end()) { - verbose = false; - } - - if (verbose) { - Cerr << "Got event at " << TInstant::MicroSeconds(Runtime->CurrentTimestamp) << ", "; - PrintEvent(ev, Runtime); - } - - if (!Runtime->EventFilterFunc(*Runtime, ev)) { - ui32 nodeId = ev->GetRecipientRewrite().NodeId(); - Y_ABORT_UNLESS(nodeId != 0); - ui32 mailboxHint = ev->GetRecipientRewrite().Hint(); - Runtime->GetMailbox(nodeId, mailboxHint).Send(ev); - Runtime->MailboxesHasEvents.Signal(); - if (verbose) - Cerr << "Event was added to sent queue\n"; - } - else { - if (verbose) - Cerr << "Event was dropped\n"; - } - } - - private: - TTestActorRuntimeBase* Runtime; - }; - - void TEventMailBox::Send(TAutoPtr<IEventHandle> ev) { - IEventHandle* ptr = ev.Get(); - Y_ABORT_UNLESS(ptr); -#ifdef DEBUG_ORDER_EVENTS - ui64 counter = NextToSend++; - TrackSent[ptr] = counter; -#endif - Sent.push_back(ev); - } - - TAutoPtr<IEventHandle> TEventMailBox::Pop() { - TAutoPtr<IEventHandle> result = Sent.front(); - Sent.pop_front(); -#ifdef DEBUG_ORDER_EVENTS - auto it = TrackSent.find(result.Get()); - if (it != TrackSent.end()) { - Y_ABORT_UNLESS(ExpectedReceive == it->second); - TrackSent.erase(result.Get()); - ++ExpectedReceive; - } -#endif - return result; - } - - bool TEventMailBox::IsEmpty() const { - return Sent.empty(); - } - - void TEventMailBox::Capture(TEventsList& evList) { - evList.insert(evList.end(), Sent.begin(), Sent.end()); - Sent.clear(); - } - - void TEventMailBox::PushFront(TAutoPtr<IEventHandle>& ev) { - Sent.push_front(ev); - } - - void TEventMailBox::PushFront(TEventsList& evList) { - for (auto rit = evList.rbegin(); rit != evList.rend(); ++rit) { - if (*rit) { - Sent.push_front(*rit); - } - } - } - - void TEventMailBox::CaptureScheduled(TScheduledEventsList& evList) { - for (auto it = Scheduled.begin(); it != Scheduled.end(); ++it) { - evList.insert(*it); - } - - Scheduled.clear(); - } - - void TEventMailBox::PushScheduled(TScheduledEventsList& evList) { - for (auto it = evList.begin(); it != evList.end(); ++it) { - if (it->Event) { - Scheduled.insert(*it); - } - } - - evList.clear(); - } - - bool TEventMailBox::IsActive(const TInstant& currentTime) const { - return currentTime >= InactiveUntil; - } - - void TEventMailBox::Freeze(const TInstant& deadline) { - if (deadline > InactiveUntil) - InactiveUntil = deadline; - } - - TInstant TEventMailBox::GetInactiveUntil() const { - return InactiveUntil; - } - - void TEventMailBox::Schedule(const TScheduledEventQueueItem& item) { - Scheduled.insert(item); - } - - bool TEventMailBox::IsScheduledEmpty() const { - return Scheduled.empty(); - } - - TInstant TEventMailBox::GetFirstScheduleDeadline() const { - return Scheduled.begin()->Deadline; - } - - ui64 TEventMailBox::GetSentEventCount() const { - return Sent.size(); - } - - class TTestActorRuntimeBase::TTimeProvider : public ITimeProvider { - public: - TTimeProvider(TTestActorRuntimeBase& runtime) - : Runtime(runtime) - { - } - - TInstant Now() override { - return Runtime.GetCurrentTime(); - } - - private: - TTestActorRuntimeBase& Runtime; - }; - - class TTestActorRuntimeBase::TMonotonicTimeProvider : public IMonotonicTimeProvider { - public: - TMonotonicTimeProvider(TTestActorRuntimeBase& runtime) - : Runtime(runtime) - { } - - TMonotonic Now() override { - return Runtime.GetCurrentMonotonicTime(); - } - - private: - TTestActorRuntimeBase& Runtime; - }; - - class TTestActorRuntimeBase::TSchedulerThreadStub : public ISchedulerThread { - public: - TSchedulerThreadStub(TTestActorRuntimeBase* runtime, TTestActorRuntimeBase::TNodeDataBase* node) - : Runtime(runtime) - , Node(node) - { - Y_UNUSED(Runtime); - } - - void Prepare(TActorSystem *actorSystem, volatile ui64 *currentTimestamp, volatile ui64 *currentMonotonic) override { - Y_UNUSED(actorSystem); - Node->ActorSystemTimestamp = currentTimestamp; - Node->ActorSystemMonotonic = currentMonotonic; - } - - void PrepareSchedules(NSchedulerQueue::TReader **readers, ui32 scheduleReadersCount) override { - Y_UNUSED(readers); - Y_UNUSED(scheduleReadersCount); - } - - void Start() override { - } - - void PrepareStop() override { - } - - void Stop() override { - } - - private: - TTestActorRuntimeBase* Runtime; - TTestActorRuntimeBase::TNodeDataBase* Node; - }; - - class TTestActorRuntimeBase::TExecutorPoolStub : public IExecutorPool { - public: - TExecutorPoolStub(TTestActorRuntimeBase* runtime, ui32 nodeIndex, TTestActorRuntimeBase::TNodeDataBase* node, ui32 poolId) - : IExecutorPool(poolId) - , Runtime(runtime) - , NodeIndex(nodeIndex) - , Node(node) - { - } - - TTestActorRuntimeBase* GetRuntime() { - return Runtime; - } - - // for threads - ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) override { - Y_UNUSED(wctx); - Y_UNUSED(revolvingCounter); - Y_ABORT(); - } - - void ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingCounter) override { - Y_UNUSED(workerId); - Node->MailboxTable->ReclaimMailbox(mailboxType, hint, revolvingCounter); - } - - TMailboxHeader *ResolveMailbox(ui32 hint) override { - return Node->MailboxTable->Get(hint); - } - - void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie *cookie, TWorkerId workerId) override { - DoSchedule(deadline, ev, cookie, workerId); - } - - void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie *cookie, TWorkerId workerId) override { - DoSchedule(TInstant::FromValue(deadline.GetValue()), ev, cookie, workerId); - } - - void Schedule(TDuration delay, TAutoPtr<IEventHandle> ev, ISchedulerCookie *cookie, TWorkerId workerId) override { - TInstant deadline = Runtime->GetTimeProvider()->Now() + delay; - DoSchedule(deadline, ev, cookie, workerId); - } - - void DoSchedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie *cookie, TWorkerId workerId) { - Y_UNUSED(workerId); - - TGuard<TMutex> guard(Runtime->Mutex); - bool verbose = (Runtime->CurrentDispatchContext ? !Runtime->CurrentDispatchContext->Options->Quiet : true) && VERBOSE; - if (Runtime->BlockedOutput.find(ev->Sender) != Runtime->BlockedOutput.end()) { - verbose = false; - } - - if (verbose) { - Cerr << "Got scheduled event at " << TInstant::MicroSeconds(Runtime->CurrentTimestamp) << ", "; - PrintEvent(ev, Runtime); - } - - auto now = Runtime->GetTimeProvider()->Now(); - if (deadline < now) { - deadline = now; // avoid going backwards in time - } - TDuration delay = (deadline - now); - - if (Runtime->SingleSysEnv || !Runtime->ScheduledEventFilterFunc(*Runtime, ev, delay, deadline)) { - ui32 mailboxHint = ev->GetRecipientRewrite().Hint(); - Runtime->GetMailbox(Runtime->FirstNodeId + NodeIndex, mailboxHint).Schedule(TScheduledEventQueueItem(deadline, ev, cookie)); - Runtime->MailboxesHasEvents.Signal(); - if (verbose) - Cerr << "Event was added to scheduled queue\n"; - } else { - if (cookie) { - cookie->Detach(); - } - if (verbose) { - Cerr << "Scheduled event for " << ev->GetRecipientRewrite().ToString() << " was dropped\n"; - } - } - } - - // for actorsystem - bool SpecificSend(TAutoPtr<IEventHandle>& ev) override { - return Send(ev); - } - - bool Send(TAutoPtr<IEventHandle>& ev) override { - TGuard<TMutex> guard(Runtime->Mutex); - bool verbose = (Runtime->CurrentDispatchContext ? !Runtime->CurrentDispatchContext->Options->Quiet : true) && VERBOSE; - if (Runtime->BlockedOutput.find(ev->Sender) != Runtime->BlockedOutput.end()) { - verbose = false; - } - - if (verbose) { - Cerr << "Got event at " << TInstant::MicroSeconds(Runtime->CurrentTimestamp) << ", "; - PrintEvent(ev, Runtime); - } - - if (!Runtime->EventFilterFunc(*Runtime, ev)) { - ui32 nodeId = ev->GetRecipientRewrite().NodeId(); - Y_ABORT_UNLESS(nodeId != 0); - TNodeDataBase* node = Runtime->Nodes[nodeId].Get(); - - if (!AllowSendFrom(node, ev)) { - return true; - } - - ui32 mailboxHint = ev->GetRecipientRewrite().Hint(); - if (ev->GetTypeRewrite() == ui32(NActors::NLog::EEv::Log)) { - const NActors::TActorId loggerActorId = NActors::TActorId(nodeId, "logger"); - TActorId logger = node->ActorSystem->LookupLocalService(loggerActorId); - if (ev->GetRecipientRewrite() == logger) { - TMailboxHeader* mailbox = node->MailboxTable->Get(mailboxHint); - IActor* recipientActor = mailbox->FindActor(ev->GetRecipientRewrite().LocalId()); - if (recipientActor) { - TActorContext ctx(*mailbox, *node->ExecutorThread, GetCycleCountFast(), ev->GetRecipientRewrite()); - TActivationContext *prevTlsActivationContext = TlsActivationContext; - TlsActivationContext = &ctx; - recipientActor->Receive(ev); - TlsActivationContext = prevTlsActivationContext; - // we expect the logger to never die in tests - } - } - } else { - Runtime->GetMailbox(nodeId, mailboxHint).Send(ev); - Runtime->MailboxesHasEvents.Signal(); - } - if (verbose) - Cerr << "Event was added to sent queue\n"; - } else { - if (verbose) - Cerr << "Event was dropped\n"; - } - return true; - } - - void ScheduleActivation(ui32 activation) override { - Y_UNUSED(activation); - } - - void SpecificScheduleActivation(ui32 activation) override { - Y_UNUSED(activation); - } - - void ScheduleActivationEx(ui32 activation, ui64 revolvingCounter) override { - Y_UNUSED(activation); - Y_UNUSED(revolvingCounter); - } - - TActorId Register(IActor *actor, TMailboxType::EType mailboxType, ui64 revolvingCounter, - const TActorId& parentId) override { - return Runtime->Register(actor, NodeIndex, PoolId, mailboxType, revolvingCounter, parentId); - } - - TActorId Register(IActor *actor, TMailboxHeader *mailbox, ui32 hint, const TActorId& parentId) override { - return Runtime->Register(actor, NodeIndex, PoolId, mailbox, hint, parentId); - } - - // lifecycle stuff - void Prepare(TActorSystem *actorSystem, NSchedulerQueue::TReader **scheduleReaders, ui32 *scheduleSz) override { - Y_UNUSED(actorSystem); - Y_UNUSED(scheduleReaders); - Y_UNUSED(scheduleSz); - } - - void Start() override { - } - - void PrepareStop() override { - } - - void Shutdown() override { - } - - bool Cleanup() override { - return true; - } - - // generic - TAffinity* Affinity() const override { - Y_ABORT(); - } - - private: - TTestActorRuntimeBase* const Runtime; - const ui32 NodeIndex; - TTestActorRuntimeBase::TNodeDataBase* const Node; - }; - - IExecutorPool* TTestActorRuntimeBase::CreateExecutorPoolStub(TTestActorRuntimeBase* runtime, ui32 nodeIndex, TTestActorRuntimeBase::TNodeDataBase* node, ui32 poolId) { - return new TExecutorPoolStub{runtime, nodeIndex, node, poolId}; - } - - - ui32 TTestActorRuntimeBase::NextNodeId = 1; - - TTestActorRuntimeBase::TTestActorRuntimeBase(THeSingleSystemEnv) - : TTestActorRuntimeBase(1, 1, false) - { - SingleSysEnv = true; - } - - TTestActorRuntimeBase::TTestActorRuntimeBase(ui32 nodeCount, ui32 dataCenterCount, bool useRealThreads) - : ScheduledCount(0) - , ScheduledLimit(100000) - , MainThreadId(TThread::CurrentThreadId()) - , ClusterUUID(MakeClusterId()) - , FirstNodeId(NextNodeId) - , NodeCount(nodeCount) - , DataCenterCount(dataCenterCount) - , UseRealThreads(useRealThreads) - , LocalId(0) - , DispatchCyclesCount(0) - , DispatchedEventsCount(0) - , NeedMonitoring(false) - , RandomProvider(CreateDeterministicRandomProvider(DefaultRandomSeed)) - , TimeProvider(new TTimeProvider(*this)) - , MonotonicTimeProvider(new TMonotonicTimeProvider(*this)) - , ShouldContinue() - , CurrentTimestamp(0) - , DispatchTimeout(DEFAULT_DISPATCH_TIMEOUT) - , ReschedulingDelay(TDuration::MicroSeconds(0)) - , ObserverFunc(&TTestActorRuntimeBase::DefaultObserverFunc) - , ScheduledEventsSelectorFunc(&CollapsedTimeScheduledEventsSelector) - , EventFilterFunc(&TTestActorRuntimeBase::DefaultFilterFunc) - , ScheduledEventFilterFunc(&TTestActorRuntimeBase::NopFilterFunc) - , RegistrationObserver(&TTestActorRuntimeBase::DefaultRegistrationObserver) - , CurrentDispatchContext(nullptr) - { - SetDispatcherRandomSeed(TInstant::Now(), 0); - EnableActorCallstack(); - } - - void TTestActorRuntimeBase::InitNode(TNodeDataBase* node, size_t nodeIndex) { - const NActors::TActorId loggerActorId = NActors::TActorId(FirstNodeId + nodeIndex, "logger"); - node->LogSettings = new NActors::NLog::TSettings(loggerActorId, NActorsServices::LOGGER, - NActors::NLog::PRI_WARN, NActors::NLog::PRI_WARN, 0); - node->LogSettings->SetAllowDrop(false); - node->LogSettings->SetThrottleDelay(TDuration::Zero()); - node->DynamicCounters = new NMonitoring::TDynamicCounters; - - InitNodeImpl(node, nodeIndex); - } - - void TTestActorRuntimeBase::InitNodeImpl(TNodeDataBase* node, size_t nodeIndex) { - node->LogSettings->Append( - NActorsServices::EServiceCommon_MIN, - NActorsServices::EServiceCommon_MAX, - NActorsServices::EServiceCommon_Name - ); - - if (!UseRealThreads) { - node->SchedulerPool.Reset(CreateExecutorPoolStub(this, nodeIndex, node, 0)); - node->MailboxTable.Reset(new TMailboxTable()); - node->ActorSystem = MakeActorSystem(nodeIndex, node); - node->ExecutorThread.Reset(new TExecutorThread(0, 0, node->ActorSystem.Get(), node->SchedulerPool.Get(), node->MailboxTable.Get(), "TestExecutor")); - } else { - node->ActorSystem = MakeActorSystem(nodeIndex, node); - } - - node->ActorSystem->Start(); - } - - bool TTestActorRuntimeBase::AllowSendFrom(TNodeDataBase* node, TAutoPtr<IEventHandle>& ev) { - ui64 senderLocalId = ev->Sender.LocalId(); - ui64 senderMailboxHint = ev->Sender.Hint(); - TMailboxHeader* senderMailbox = node->MailboxTable->Get(senderMailboxHint); - if (senderMailbox) { - IActor* senderActor = senderMailbox->FindActor(senderLocalId); - TTestDecorator *decorator = dynamic_cast<TTestDecorator*>(senderActor); - return !decorator || decorator->BeforeSending(ev); - } - return true; - } - - TTestActorRuntimeBase::TTestActorRuntimeBase(ui32 nodeCount, ui32 dataCenterCount) - : TTestActorRuntimeBase(nodeCount, dataCenterCount, false) { - } - - TTestActorRuntimeBase::TTestActorRuntimeBase(ui32 nodeCount, bool useRealThreads) - : TTestActorRuntimeBase(nodeCount, nodeCount, useRealThreads) { - } - - TTestActorRuntimeBase::~TTestActorRuntimeBase() { - CleanupNodes(); - Cerr.Flush(); - Cerr.Flush(); - Clog.Flush(); - - DisableActorCallstack(); - } - - void TTestActorRuntimeBase::CleanupNodes() { - Nodes.clear(); - } - - bool TTestActorRuntimeBase::IsRealThreads() const { - return UseRealThreads; - } - - TTestActorRuntimeBase::EEventAction TTestActorRuntimeBase::DefaultObserverFunc(TAutoPtr<IEventHandle>& event) { - Y_UNUSED(event); - return EEventAction::PROCESS; - } - - void TTestActorRuntimeBase::DroppingScheduledEventsSelector(TTestActorRuntimeBase& runtime, TScheduledEventsList& scheduledEvents, TEventsList& queue) { - Y_UNUSED(runtime); - Y_UNUSED(queue); - scheduledEvents.clear(); - } - - bool TTestActorRuntimeBase::DefaultFilterFunc(TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event) { - Y_UNUSED(runtime); - Y_UNUSED(event); - return false; - } - - bool TTestActorRuntimeBase::NopFilterFunc(TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event, TDuration delay, TInstant& deadline) { - Y_UNUSED(runtime); - Y_UNUSED(delay); - Y_UNUSED(event); - Y_UNUSED(deadline); - return true; - } - - - void TTestActorRuntimeBase::DefaultRegistrationObserver(TTestActorRuntimeBase& runtime, const TActorId& parentId, const TActorId& actorId) { - if (runtime.ScheduleWhiteList.find(parentId) != runtime.ScheduleWhiteList.end()) { - runtime.ScheduleWhiteList.insert(actorId); - runtime.ScheduleWhiteListParent[actorId] = parentId; - } - } - - class TScheduledTreeItem { - public: - TString Name; - ui64 Count; - TVector<TScheduledTreeItem> Children; - - TScheduledTreeItem(const TString& name) - : Name(name) - , Count(0) - {} - - TScheduledTreeItem* GetItem(const TString& name) { - TScheduledTreeItem* item = nullptr; - for (TScheduledTreeItem& i : Children) { - if (i.Name == name) { - item = &i; - break; - } - } - if (item != nullptr) - return item; - Children.emplace_back(name); - return &Children.back(); - } - - void RecursiveSort() { - Sort(Children, [](const TScheduledTreeItem& a, const TScheduledTreeItem& b) -> bool { return a.Count > b.Count; }); - for (TScheduledTreeItem& item : Children) { - item.RecursiveSort(); - } - } - - void Print(IOutputStream& stream, const TString& prefix) { - for (auto it = Children.begin(); it != Children.end(); ++it) { - bool lastChild = (std::next(it) == Children.end()); - TString connectionPrefix = lastChild ? "└─ " : "├─ "; - TString subChildPrefix = lastChild ? " " : "│ "; - stream << prefix << connectionPrefix << it->Name << " (" << it->Count << ")\n"; - it->Print(stream, prefix + subChildPrefix); - } - } - - void Print(IOutputStream& stream) { - stream << Name << " (" << Count << ")\n"; - Print(stream, TString()); - } - }; - - void TTestActorRuntimeBase::CollapsedTimeScheduledEventsSelector(TTestActorRuntimeBase& runtime, TScheduledEventsList& scheduledEvents, TEventsList& queue) { - if (scheduledEvents.empty()) - return; - - TInstant time = scheduledEvents.begin()->Deadline; - while (!scheduledEvents.empty() && scheduledEvents.begin()->Deadline == time) { -// static THashMap<std::pair<TActorId, TString>, ui64> eventTypes; - auto& item = *scheduledEvents.begin(); - TString name = item.Event->GetTypeName(); -// eventTypes[std::make_pair(item.Event->Recipient, name)]++; - runtime.ScheduledCount++; - if (runtime.ScheduledCount > runtime.ScheduledLimit) { -// TScheduledTreeItem root("Root"); -// TVector<TString> path; -// for (const auto& pr : eventTypes) { -// path.clear(); -// path.push_back(runtime.GetActorName(pr.first.first)); -// for (auto it = runtime.ScheduleWhiteListParent.find(pr.first.first); it != runtime.ScheduleWhiteListParent.end(); it = runtime.ScheduleWhiteListParent.find(it->second)) { -// path.insert(path.begin(), runtime.GetActorName(it->second)); -// } -// path.push_back("<" + pr.first.second + ">"); // event name; -// ui64 count = pr.second; -// TScheduledTreeItem* item = &root; -// item->Count += count; -// for (TString name : path) { -// item = item->GetItem(name); -// item->Count += count; -// } -// } -// root.RecursiveSort(); -// root.Print(Cerr); - - ythrow TSchedulingLimitReachedException(runtime.ScheduledLimit); - } - if (item.Cookie->Get()) { - if (item.Cookie->Detach()) { - queue.push_back(item.Event); - } - } else { - queue.push_back(item.Event); - } - - scheduledEvents.erase(scheduledEvents.begin()); - } - - runtime.UpdateCurrentTime(time); - } - - TTestActorRuntimeBase::TEventObserver TTestActorRuntimeBase::SetObserverFunc(TEventObserver observerFunc) { - TGuard<TMutex> guard(Mutex); - auto result = ObserverFunc; - ObserverFunc = observerFunc; - return result; - } - - TTestActorRuntimeBase::TScheduledEventsSelector TTestActorRuntimeBase::SetScheduledEventsSelectorFunc(TScheduledEventsSelector scheduledEventsSelectorFunc) { - TGuard<TMutex> guard(Mutex); - auto result = ScheduledEventsSelectorFunc; - ScheduledEventsSelectorFunc = scheduledEventsSelectorFunc; - return result; - } - - TTestActorRuntimeBase::TEventFilter TTestActorRuntimeBase::SetEventFilter(TEventFilter filterFunc) { - TGuard<TMutex> guard(Mutex); - auto result = EventFilterFunc; - EventFilterFunc = filterFunc; - return result; - } - - TTestActorRuntimeBase::TScheduledEventFilter TTestActorRuntimeBase::SetScheduledEventFilter(TScheduledEventFilter filterFunc) { - TGuard<TMutex> guard(Mutex); - auto result = ScheduledEventFilterFunc; - ScheduledEventFilterFunc = filterFunc; - return result; - } - - TTestActorRuntimeBase::TRegistrationObserver TTestActorRuntimeBase::SetRegistrationObserverFunc(TRegistrationObserver observerFunc) { - TGuard<TMutex> guard(Mutex); - auto result = RegistrationObserver; - RegistrationObserver = observerFunc; - return result; - } - - bool TTestActorRuntimeBase::IsVerbose() { - return VERBOSE; - } - - void TTestActorRuntimeBase::SetVerbose(bool verbose) { - VERBOSE = verbose; - } - - void TTestActorRuntimeBase::AddLocalService(const TActorId& actorId, TActorSetupCmd cmd, ui32 nodeIndex) { - Y_ABORT_UNLESS(!IsInitialized); - Y_ABORT_UNLESS(nodeIndex < NodeCount); - auto node = Nodes[nodeIndex + FirstNodeId]; - if (!node) { - node = GetNodeFactory().CreateNode(); - Nodes[nodeIndex + FirstNodeId] = node; - } - - node->LocalServicesActors[actorId] = cmd.Actor.get(); - node->LocalServices.push_back(std::make_pair(actorId, TTestActorSetupCmd(std::move(cmd)))); - } - - void TTestActorRuntimeBase::InitNodes() { - NextNodeId += NodeCount; - Y_ABORT_UNLESS(NodeCount > 0); - - for (ui32 nodeIndex = 0; nodeIndex < NodeCount; ++nodeIndex) { - auto nodeIt = Nodes.emplace(FirstNodeId + nodeIndex, GetNodeFactory().CreateNode()).first; - TNodeDataBase* node = nodeIt->second.Get(); - InitNode(node, nodeIndex); - } - - } - - void TTestActorRuntimeBase::Initialize() { - InitNodes(); - IsInitialized = true; - } - - void SetupCrossDC() { - - } - - TDuration TTestActorRuntimeBase::SetDispatchTimeout(TDuration timeout) { - TGuard<TMutex> guard(Mutex); - TDuration oldTimeout = DispatchTimeout; - DispatchTimeout = timeout; - return oldTimeout; - } - - TDuration TTestActorRuntimeBase::SetReschedulingDelay(TDuration delay) { - TGuard<TMutex> guard(Mutex); - TDuration oldDelay = ReschedulingDelay; - ReschedulingDelay = delay; - return oldDelay; - } - - void TTestActorRuntimeBase::SetLogBackend(const TAutoPtr<TLogBackend> logBackend) { - Y_ABORT_UNLESS(!IsInitialized); - TGuard<TMutex> guard(Mutex); - LogBackend = logBackend; - } - - void TTestActorRuntimeBase::SetLogPriority(NActors::NLog::EComponent component, NActors::NLog::EPriority priority) { - TGuard<TMutex> guard(Mutex); - for (ui32 nodeIndex = 0; nodeIndex < NodeCount; ++nodeIndex) { - TNodeDataBase* node = Nodes[FirstNodeId + nodeIndex].Get(); - TString explanation; - auto status = node->LogSettings->SetLevel(priority, component, explanation); - if (status) { - Y_ABORT("SetLogPriority failed: %s", explanation.c_str()); - } - } - } - - TInstant TTestActorRuntimeBase::GetCurrentTime() const { - TGuard<TMutex> guard(Mutex); - Y_ABORT_UNLESS(!UseRealThreads); - return TInstant::MicroSeconds(CurrentTimestamp); - } - - TMonotonic TTestActorRuntimeBase::GetCurrentMonotonicTime() const { - TGuard<TMutex> guard(Mutex); - Y_ABORT_UNLESS(!UseRealThreads); - return TMonotonic::MicroSeconds(CurrentTimestamp); - } - - void TTestActorRuntimeBase::UpdateCurrentTime(TInstant newTime) { - static int counter = 0; - ++counter; - if (VERBOSE) { - Cerr << "UpdateCurrentTime(" << counter << "," << newTime << ")\n"; - } - TGuard<TMutex> guard(Mutex); - Y_ABORT_UNLESS(!UseRealThreads); - if (newTime.MicroSeconds() > CurrentTimestamp) { - CurrentTimestamp = newTime.MicroSeconds(); - for (auto& kv : Nodes) { - AtomicStore(kv.second->ActorSystemTimestamp, CurrentTimestamp); - AtomicStore(kv.second->ActorSystemMonotonic, CurrentTimestamp); - } - } - } - - void TTestActorRuntimeBase::AdvanceCurrentTime(TDuration duration) { - UpdateCurrentTime(GetCurrentTime() + duration); - } - - TIntrusivePtr<ITimeProvider> TTestActorRuntimeBase::GetTimeProvider() { - Y_ABORT_UNLESS(!UseRealThreads); - return TimeProvider; - } - - TIntrusivePtr<IMonotonicTimeProvider> TTestActorRuntimeBase::GetMonotonicTimeProvider() { - Y_ABORT_UNLESS(!UseRealThreads); - return MonotonicTimeProvider; - } - - ui32 TTestActorRuntimeBase::GetNodeId(ui32 index) const { - Y_ABORT_UNLESS(index < NodeCount); - return FirstNodeId + index; - } - - ui32 TTestActorRuntimeBase::GetNodeCount() const { - return NodeCount; - } - - ui64 TTestActorRuntimeBase::AllocateLocalId() { - TGuard<TMutex> guard(Mutex); - ui64 nextId = ++LocalId; - if (VERBOSE) { - Cerr << "Allocated id: " << nextId << "\n"; - } - - return nextId; - } - - ui32 TTestActorRuntimeBase::InterconnectPoolId() const { - if (UseRealThreads && NSan::TSanIsOn()) { - // Interconnect coroutines may move across threads - // Use a special single-threaded pool to avoid that - return 4; - } - return 0; - } - - TString TTestActorRuntimeBase::GetTempDir() { - if (!TmpDir) - TmpDir.Reset(new TTempDir()); - return (*TmpDir)(); - } - - TActorId TTestActorRuntimeBase::Register(IActor* actor, ui32 nodeIndex, ui32 poolId, TMailboxType::EType mailboxType, - ui64 revolvingCounter, const TActorId& parentId) { - Y_ABORT_UNLESS(nodeIndex < NodeCount); - TGuard<TMutex> guard(Mutex); - TNodeDataBase* node = Nodes[FirstNodeId + nodeIndex].Get(); - if (UseRealThreads) { - Y_ABORT_UNLESS(poolId < node->ExecutorPools.size()); - return node->ExecutorPools[poolId]->Register(actor, mailboxType, revolvingCounter, parentId); - } - - // first step - find good enough mailbox - ui32 hint = 0; - TMailboxHeader *mailbox = nullptr; - - { - ui32 hintBackoff = 0; - - while (hint == 0) { - hint = node->MailboxTable->AllocateMailbox(mailboxType, ++revolvingCounter); - mailbox = node->MailboxTable->Get(hint); - - if (!mailbox->LockFromFree()) { - node->MailboxTable->ReclaimMailbox(mailboxType, hintBackoff, ++revolvingCounter); - hintBackoff = hint; - hint = 0; - } - } - - node->MailboxTable->ReclaimMailbox(mailboxType, hintBackoff, ++revolvingCounter); - } - - const ui64 localActorId = AllocateLocalId(); - if (VERBOSE) { - Cerr << "Register actor " << TypeName(*actor) << " as " << localActorId << ", mailbox: " << hint << "\n"; - } - - // ok, got mailbox - mailbox->AttachActor(localActorId, actor); - - // do init - const TActorId actorId(FirstNodeId + nodeIndex, poolId, localActorId, hint); - ActorNames[actorId] = TypeName(*actor); - RegistrationObserver(*this, parentId ? parentId : CurrentRecipient, actorId); - DoActorInit(node->ActorSystem.Get(), actor, actorId, parentId ? parentId : CurrentRecipient); - - switch (mailboxType) { - case TMailboxType::Simple: - UnlockFromExecution((TMailboxTable::TSimpleMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter); - break; - case TMailboxType::Revolving: - UnlockFromExecution((TMailboxTable::TRevolvingMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter); - break; - case TMailboxType::HTSwap: - UnlockFromExecution((TMailboxTable::THTSwapMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter); - break; - case TMailboxType::ReadAsFilled: - UnlockFromExecution((TMailboxTable::TReadAsFilledMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter); - break; - case TMailboxType::TinyReadAsFilled: - UnlockFromExecution((TMailboxTable::TTinyReadAsFilledMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter); - break; - default: - Y_ABORT("Unsupported mailbox type"); - } - - return actorId; - } - - TActorId TTestActorRuntimeBase::Register(IActor *actor, ui32 nodeIndex, ui32 poolId, TMailboxHeader *mailbox, ui32 hint, - const TActorId& parentId) { - Y_ABORT_UNLESS(nodeIndex < NodeCount); - TGuard<TMutex> guard(Mutex); - TNodeDataBase* node = Nodes[FirstNodeId + nodeIndex].Get(); - if (UseRealThreads) { - Y_ABORT_UNLESS(poolId < node->ExecutorPools.size()); - return node->ExecutorPools[poolId]->Register(actor, mailbox, hint, parentId); - } - - const ui64 localActorId = AllocateLocalId(); - if (VERBOSE) { - Cerr << "Register actor " << TypeName(*actor) << " as " << localActorId << "\n"; - } - - mailbox->AttachActor(localActorId, actor); - const TActorId actorId(FirstNodeId + nodeIndex, poolId, localActorId, hint); - ActorNames[actorId] = TypeName(*actor); - RegistrationObserver(*this, parentId ? parentId : CurrentRecipient, actorId); - DoActorInit(node->ActorSystem.Get(), actor, actorId, parentId ? parentId : CurrentRecipient); - - return actorId; - } - - TActorId TTestActorRuntimeBase::RegisterService(const TActorId& serviceId, const TActorId& actorId, ui32 nodeIndex) { - TGuard<TMutex> guard(Mutex); - Y_ABORT_UNLESS(nodeIndex < NodeCount); - TNodeDataBase* node = Nodes[FirstNodeId + nodeIndex].Get(); - if (!UseRealThreads) { - IActor* actor = FindActor(actorId, node); - node->LocalServicesActors[serviceId] = actor; - node->ActorToActorId[actor] = actorId; - } - - return node->ActorSystem->RegisterLocalService(serviceId, actorId); - } - - TActorId TTestActorRuntimeBase::AllocateEdgeActor(ui32 nodeIndex) { - TGuard<TMutex> guard(Mutex); - Y_ABORT_UNLESS(nodeIndex < NodeCount); - TActorId edgeActor = Register(new TEdgeActor(this), nodeIndex); - EdgeActors.insert(edgeActor); - EdgeActorByMailbox[TEventMailboxId(edgeActor.NodeId(), edgeActor.Hint())] = edgeActor; - return edgeActor; - } - - TEventsList TTestActorRuntimeBase::CaptureEvents() { - TGuard<TMutex> guard(Mutex); - TEventsList result; - for (auto& mbox : Mailboxes) { - mbox.second->Capture(result); - } - - return result; - } - - TEventsList TTestActorRuntimeBase::CaptureMailboxEvents(ui32 hint, ui32 nodeId) { - TGuard<TMutex> guard(Mutex); - Y_ABORT_UNLESS(nodeId >= FirstNodeId && nodeId < FirstNodeId + NodeCount); - TEventsList result; - GetMailbox(nodeId, hint).Capture(result); - return result; - } - - void TTestActorRuntimeBase::PushFront(TAutoPtr<IEventHandle>& ev) { - TGuard<TMutex> guard(Mutex); - ui32 nodeId = ev->GetRecipientRewrite().NodeId(); - Y_ABORT_UNLESS(nodeId != 0); - GetMailbox(nodeId, ev->GetRecipientRewrite().Hint()).PushFront(ev); - } - - void TTestActorRuntimeBase::PushEventsFront(TEventsList& events) { - TGuard<TMutex> guard(Mutex); - for (auto rit = events.rbegin(); rit != events.rend(); ++rit) { - if (*rit) { - auto& ev = *rit; - ui32 nodeId = ev->GetRecipientRewrite().NodeId(); - Y_ABORT_UNLESS(nodeId != 0); - GetMailbox(nodeId, ev->GetRecipientRewrite().Hint()).PushFront(ev); - } - } - - events.clear(); - } - - void TTestActorRuntimeBase::PushMailboxEventsFront(ui32 hint, ui32 nodeId, TEventsList& events) { - TGuard<TMutex> guard(Mutex); - Y_ABORT_UNLESS(nodeId >= FirstNodeId && nodeId < FirstNodeId + NodeCount); - TEventsList result; - GetMailbox(nodeId, hint).PushFront(events); - events.clear(); - } - - TScheduledEventsList TTestActorRuntimeBase::CaptureScheduledEvents() { - TGuard<TMutex> guard(Mutex); - TScheduledEventsList result; - for (auto& mbox : Mailboxes) { - mbox.second->CaptureScheduled(result); - } - - return result; - } - - bool TTestActorRuntimeBase::DispatchEvents(const TDispatchOptions& options) { - return DispatchEvents(options, TInstant::Max()); - } - - bool TTestActorRuntimeBase::DispatchEvents(const TDispatchOptions& options, TDuration simTimeout) { - return DispatchEvents(options, TInstant::MicroSeconds(CurrentTimestamp) + simTimeout); - } - - bool TTestActorRuntimeBase::DispatchEvents(const TDispatchOptions& options, TInstant simDeadline) { - TGuard<TMutex> guard(Mutex); - return DispatchEventsInternal(options, simDeadline); - } - - // Mutex must be locked by caller! - bool TTestActorRuntimeBase::DispatchEventsInternal(const TDispatchOptions& options, TInstant simDeadline) { - TDispatchContext localContext; - localContext.Options = &options; - localContext.PrevContext = nullptr; - bool verbose = !options.Quiet && VERBOSE; - - struct TDispatchContextSetter { - TDispatchContextSetter(TTestActorRuntimeBase& runtime, TDispatchContext& lastContext) - : Runtime(runtime) - { - lastContext.PrevContext = Runtime.CurrentDispatchContext; - Runtime.CurrentDispatchContext = &lastContext; - } - - ~TDispatchContextSetter() { - Runtime.CurrentDispatchContext = Runtime.CurrentDispatchContext->PrevContext; - } - - TTestActorRuntimeBase& Runtime; - } DispatchContextSetter(*this, localContext); - - TInstant dispatchTime = TInstant::MicroSeconds(0); - TInstant deadline = dispatchTime + DispatchTimeout; - const TDuration scheduledEventsInspectInterval = TDuration::MilliSeconds(10); - TInstant inspectScheduledEventsAt = dispatchTime + scheduledEventsInspectInterval; - if (verbose) { - Cerr << "Start dispatch at " << TInstant::MicroSeconds(CurrentTimestamp) << ", deadline is " << deadline << "\n"; - } - - struct TTempEdgeEventsCaptor { - TTempEdgeEventsCaptor(TTestActorRuntimeBase& runtime) - : Runtime(runtime) - , HasEvents(false) - { - for (auto edgeActor : Runtime.EdgeActors) { - TEventsList events; - Runtime.GetMailbox(edgeActor.NodeId(), edgeActor.Hint()).Capture(events); - auto mboxId = TEventMailboxId(edgeActor.NodeId(), edgeActor.Hint()); - auto storeIt = Store.find(mboxId); - Y_ABORT_UNLESS(storeIt == Store.end()); - storeIt = Store.insert(std::make_pair(mboxId, new TEventMailBox)).first; - storeIt->second->PushFront(events); - if (!events.empty()) - HasEvents = true; - } - } - - ~TTempEdgeEventsCaptor() { - for (auto edgeActor : Runtime.EdgeActors) { - auto mboxId = TEventMailboxId(edgeActor.NodeId(), edgeActor.Hint()); - auto storeIt = Store.find(mboxId); - if (storeIt == Store.end()) { - continue; - } - - TEventsList events; - storeIt->second->Capture(events); - Runtime.GetMailbox(edgeActor.NodeId(), edgeActor.Hint()).PushFront(events); - } - } - - TTestActorRuntimeBase& Runtime; - TEventMailBoxList Store; - bool HasEvents; - }; - - TEventMailBoxList restrictedMailboxes; - const bool useRestrictedMailboxes = !options.OnlyMailboxes.empty(); - for (auto mailboxId : options.OnlyMailboxes) { - auto it = Mailboxes.find(mailboxId); - if (it == Mailboxes.end()) { - it = Mailboxes.insert(std::make_pair(mailboxId, new TEventMailBox())).first; - } - - restrictedMailboxes.insert(std::make_pair(mailboxId, it->second)); - } - - TAutoPtr<TTempEdgeEventsCaptor> tempEdgeEventsCaptor; - if (!restrictedMailboxes) { - tempEdgeEventsCaptor.Reset(new TTempEdgeEventsCaptor(*this)); - } - - TEventMailBoxList& currentMailboxes = useRestrictedMailboxes ? restrictedMailboxes : Mailboxes; - while (!currentMailboxes.empty()) { - bool hasProgress = true; - while (hasProgress) { - ++DispatchCyclesCount; - hasProgress = false; - - ui64 eventsToDispatch = 0; - for (auto mboxIt = currentMailboxes.begin(); mboxIt != currentMailboxes.end(); ++mboxIt) { - if (mboxIt->second->IsActive(TInstant::MicroSeconds(CurrentTimestamp))) { - eventsToDispatch += mboxIt->second->GetSentEventCount(); - } - } - ui32 eventsDispatched = 0; - - //TODO: count events before each cycle, break after dispatching that much events - bool isEmpty = false; - while (!isEmpty && eventsDispatched < eventsToDispatch) { - ui64 mailboxCount = currentMailboxes.size(); - ui64 startWith = mailboxCount ? DispatcherRandomProvider->GenRand64() % mailboxCount : 0ull; - auto startWithMboxIt = currentMailboxes.begin(); - for (ui64 i = 0; i < startWith; ++i) { - ++startWithMboxIt; - } - auto endWithMboxIt = startWithMboxIt; - - isEmpty = true; - auto mboxIt = startWithMboxIt; - TDeque<TEventMailboxId> suspectedBoxes; - while (true) { - auto& mbox = *mboxIt; - bool isIgnored = true; - if (!mbox.second->IsEmpty()) { - HandleNonEmptyMailboxesForEachContext(mbox.first); - if (mbox.second->IsActive(TInstant::MicroSeconds(CurrentTimestamp))) { - - bool isEdgeMailbox = false; - if (EdgeActorByMailbox.FindPtr(TEventMailboxId(mbox.first.NodeId, mbox.first.Hint))) { - isEdgeMailbox = true; - TEventsList events; - mbox.second->Capture(events); - - TEventsList eventsToPush; - for (auto& ev : events) { - TInverseGuard<TMutex> inverseGuard(Mutex); - - for (auto observer : ObserverFuncs) { - observer(ev); - if (!ev) break; - } - - if(ev && ObserverFunc(ev) != EEventAction::DROP && ev) - eventsToPush.push_back(ev); - } - mbox.second->PushFront(eventsToPush); - } - - if (!isEdgeMailbox) { - isEmpty = false; - isIgnored = false; - ++eventsDispatched; - ++DispatchedEventsCount; - if (DispatchedEventsCount > DispatchedEventsLimit) { - ythrow TWithBackTrace<yexception>() << "Dispatched " - << DispatchedEventsLimit << " events, limit reached."; - } - - auto ev = mbox.second->Pop(); - if (BlockedOutput.find(ev->Sender) == BlockedOutput.end()) { - //UpdateCurrentTime(TInstant::MicroSeconds(CurrentTimestamp + 10)); - if (verbose) { - Cerr << "Process event at " << TInstant::MicroSeconds(CurrentTimestamp) << ", "; - PrintEvent(ev, this); - } - } - - hasProgress = true; - EEventAction action = EEventAction::PROCESS; - { - TInverseGuard<TMutex> inverseGuard(Mutex); - - for (auto observer : ObserverFuncs) { - observer(ev); - if(!ev) break; - } - - if (ev) - action = ObserverFunc(ev); - } - - if (ev) { - switch (action) { - case EEventAction::PROCESS: - UpdateFinalEventsStatsForEachContext(*ev); - SendInternal(ev.Release(), mbox.first.NodeId - FirstNodeId, false); - break; - case EEventAction::DROP: - // do nothing - break; - case EEventAction::RESCHEDULE: { - TInstant deadline = TInstant::MicroSeconds(CurrentTimestamp) + ReschedulingDelay; - mbox.second->Freeze(deadline); - mbox.second->PushFront(ev); - break; - } - default: - Y_ABORT("Unknown action"); - } - } - } - } - - } - Y_ABORT_UNLESS(mboxIt != currentMailboxes.end()); - if (!isIgnored && !CurrentDispatchContext->PrevContext && !restrictedMailboxes && - mboxIt->second->IsEmpty() && - mboxIt->second->IsScheduledEmpty() && - mboxIt->second->IsActive(TInstant::MicroSeconds(CurrentTimestamp))) { - suspectedBoxes.push_back(mboxIt->first); - } - ++mboxIt; - if (mboxIt == currentMailboxes.end()) { - mboxIt = currentMailboxes.begin(); - } - Y_ABORT_UNLESS(endWithMboxIt != currentMailboxes.end()); - if (mboxIt == endWithMboxIt) { - break; - } - } - - for (auto id : suspectedBoxes) { - auto it = currentMailboxes.find(id); - if (it != currentMailboxes.end() && it->second->IsEmpty() && it->second->IsScheduledEmpty() && - it->second->IsActive(TInstant::MicroSeconds(CurrentTimestamp))) { - currentMailboxes.erase(it); - } - } - } - } - - if (localContext.FinalEventFound) { - return true; - } - - if (!localContext.FoundNonEmptyMailboxes.empty()) - return true; - - if (options.CustomFinalCondition && options.CustomFinalCondition()) - return true; - - if (options.FinalEvents.empty()) { - for (auto& mbox : currentMailboxes) { - if (!mbox.second->IsActive(TInstant::MicroSeconds(CurrentTimestamp))) - continue; - - if (!mbox.second->IsEmpty()) { - if (verbose) { - Cerr << "Dispatch complete with non-empty queue at " << TInstant::MicroSeconds(CurrentTimestamp) << "\n"; - } - - return true; - } - } - } - - if (TInstant::MicroSeconds(CurrentTimestamp) > simDeadline) { - return false; - } - - if (dispatchTime >= deadline) { - if (verbose) { - Cerr << "Reach deadline at " << TInstant::MicroSeconds(CurrentTimestamp) << "\n"; - } - - ythrow TWithBackTrace<TEmptyEventQueueException>(); - } - - if (!options.Quiet && dispatchTime >= inspectScheduledEventsAt) { - inspectScheduledEventsAt = dispatchTime + scheduledEventsInspectInterval; - bool isEmpty = true; - TMaybe<TInstant> nearestMailboxDeadline; - TVector<TIntrusivePtr<TEventMailBox>> nextScheduleMboxes; - TMaybe<TInstant> nextScheduleDeadline; - for (auto& mbox : currentMailboxes) { - if (!mbox.second->IsActive(TInstant::MicroSeconds(CurrentTimestamp))) { - if (!nearestMailboxDeadline.Defined() || *nearestMailboxDeadline.Get() > mbox.second->GetInactiveUntil()) { - nearestMailboxDeadline = mbox.second->GetInactiveUntil(); - } - - continue; - } - - if (mbox.second->IsScheduledEmpty()) - continue; - - auto firstScheduleDeadline = mbox.second->GetFirstScheduleDeadline(); - if (!nextScheduleDeadline || firstScheduleDeadline < *nextScheduleDeadline) { - nextScheduleMboxes.clear(); - nextScheduleMboxes.emplace_back(mbox.second); - nextScheduleDeadline = firstScheduleDeadline; - } else if (firstScheduleDeadline == *nextScheduleDeadline) { - nextScheduleMboxes.emplace_back(mbox.second); - } - } - - for (const auto& nextScheduleMbox : nextScheduleMboxes) { - TEventsList selectedEvents; - TScheduledEventsList capturedScheduledEvents; - nextScheduleMbox->CaptureScheduled(capturedScheduledEvents); - ScheduledEventsSelectorFunc(*this, capturedScheduledEvents, selectedEvents); - nextScheduleMbox->PushScheduled(capturedScheduledEvents); - for (auto& event : selectedEvents) { - if (verbose && (BlockedOutput.find(event->Sender) == BlockedOutput.end())) { - Cerr << "Selected scheduled event at " << TInstant::MicroSeconds(CurrentTimestamp) << ", "; - PrintEvent(event, this); - } - - nextScheduleMbox->Send(event); - isEmpty = false; - } - } - - if (!isEmpty) { - if (verbose) { - Cerr << "Process selected events at " << TInstant::MicroSeconds(CurrentTimestamp) << "\n"; - } - - deadline = dispatchTime + DispatchTimeout; - continue; - } - - if (nearestMailboxDeadline.Defined()) { - if (verbose) { - Cerr << "Forward time to " << *nearestMailboxDeadline.Get() << "\n"; - } - - UpdateCurrentTime(*nearestMailboxDeadline.Get()); - continue; - } - } - - TDuration waitDelay = TDuration::MilliSeconds(10); - dispatchTime += waitDelay; - MailboxesHasEvents.WaitT(Mutex, waitDelay); - } - return false; - } - - void TTestActorRuntimeBase::HandleNonEmptyMailboxesForEachContext(TEventMailboxId mboxId) { - TDispatchContext* context = CurrentDispatchContext; - while (context) { - const auto& nonEmptyMailboxes = context->Options->NonEmptyMailboxes; - if (Find(nonEmptyMailboxes.begin(), nonEmptyMailboxes.end(), mboxId) != nonEmptyMailboxes.end()) { - context->FoundNonEmptyMailboxes.insert(mboxId); - } - - context = context->PrevContext; - } - } - - void TTestActorRuntimeBase::UpdateFinalEventsStatsForEachContext(IEventHandle& ev) { - TDispatchContext* context = CurrentDispatchContext; - while (context) { - for (const auto& finalEvent : context->Options->FinalEvents) { - if (finalEvent.EventCheck(ev)) { - auto& freq = context->FinalEventFrequency[&finalEvent]; - if (++freq >= finalEvent.RequiredCount) { - context->FinalEventFound = true; - } - } - } - - context = context->PrevContext; - } - } - - void TTestActorRuntimeBase::Send(const TActorId& recipient, const TActorId& sender, TAutoPtr<IEventBase> ev, ui32 senderNodeIndex, bool viaActorSystem) { - Send(new IEventHandle(recipient, sender, ev.Release()), senderNodeIndex, viaActorSystem); - } - - void TTestActorRuntimeBase::Send(TAutoPtr<IEventHandle> ev, ui32 senderNodeIndex, bool viaActorSystem) { - TGuard<TMutex> guard(Mutex); - Y_ABORT_UNLESS(senderNodeIndex < NodeCount, "senderNodeIndex# %" PRIu32 " < NodeCount# %" PRIu32, - senderNodeIndex, NodeCount); - SendInternal(ev, senderNodeIndex, viaActorSystem); - } - - void TTestActorRuntimeBase::SendAsync(TAutoPtr<IEventHandle> ev, ui32 senderNodeIndex) { - Send(ev, senderNodeIndex, true); - } - - void TTestActorRuntimeBase::Schedule(TAutoPtr<IEventHandle> ev, const TDuration& duration, ui32 nodeIndex) { - TGuard<TMutex> guard(Mutex); - Y_ABORT_UNLESS(nodeIndex < NodeCount); - ui32 nodeId = FirstNodeId + nodeIndex; - ui32 mailboxHint = ev->GetRecipientRewrite().Hint(); - TInstant deadline = TInstant::MicroSeconds(CurrentTimestamp) + duration; - GetMailbox(nodeId, mailboxHint).Schedule(TScheduledEventQueueItem(deadline, ev, nullptr)); - if (VERBOSE) - Cerr << "Event was added to scheduled queue\n"; - } - - void TTestActorRuntimeBase::ClearCounters() { - TGuard<TMutex> guard(Mutex); - EvCounters.clear(); - } - - ui64 TTestActorRuntimeBase::GetCounter(ui32 evType) const { - TGuard<TMutex> guard(Mutex); - auto it = EvCounters.find(evType); - if (it == EvCounters.end()) - return 0; - - return it->second; - } - - TActorId TTestActorRuntimeBase::GetLocalServiceId(const TActorId& serviceId, ui32 nodeIndex) { - TGuard<TMutex> guard(Mutex); - Y_ABORT_UNLESS(nodeIndex < NodeCount); - TNodeDataBase* node = Nodes[FirstNodeId + nodeIndex].Get(); - return node->ActorSystem->LookupLocalService(serviceId); - } - - void TTestActorRuntimeBase::WaitForEdgeEvents(TEventFilter filter, const TSet<TActorId>& edgeFilter, TDuration simTimeout) { - TGuard<TMutex> guard(Mutex); - ui32 dispatchCount = 0; - if (!edgeFilter.empty()) { - for (auto edgeActor : edgeFilter) { - Y_ABORT_UNLESS(EdgeActors.contains(edgeActor), "%s is not an edge actor", ToString(edgeActor).data()); - } - } - const TSet<TActorId>& edgeActors = edgeFilter.empty() ? EdgeActors : edgeFilter; - TInstant deadline = TInstant::MicroSeconds(CurrentTimestamp) + simTimeout; - for (;;) { - for (auto edgeActor : edgeActors) { - TEventsList events; - auto& mbox = GetMailbox(edgeActor.NodeId(), edgeActor.Hint()); - bool foundEvent = false; - mbox.Capture(events); - for (auto& ev : events) { - if (filter(*this, ev)) { - foundEvent = true; - break; - } - } - - mbox.PushFront(events); - if (foundEvent) - return; - } - - ++dispatchCount; - { - if (!DispatchEventsInternal(TDispatchOptions(), deadline)) { - return; // Timed out; event was not found - } - } - - Y_ABORT_UNLESS(dispatchCount < 1000, "Hard limit to prevent endless loop"); - } - } - - TActorId TTestActorRuntimeBase::GetInterconnectProxy(ui32 nodeIndexFrom, ui32 nodeIndexTo) { - TGuard<TMutex> guard(Mutex); - Y_ABORT_UNLESS(nodeIndexFrom < NodeCount); - Y_ABORT_UNLESS(nodeIndexTo < NodeCount); - Y_ABORT_UNLESS(nodeIndexFrom != nodeIndexTo); - TNodeDataBase* node = Nodes[FirstNodeId + nodeIndexFrom].Get(); - return node->ActorSystem->InterconnectProxy(FirstNodeId + nodeIndexTo); - } - - void TTestActorRuntimeBase::BlockOutputForActor(const TActorId& actorId) { - TGuard<TMutex> guard(Mutex); - BlockedOutput.insert(actorId); - } - - void TTestActorRuntimeBase::SetDispatcherRandomSeed(TInstant time, ui64 iteration) { - ui64 days = (time.Hours() / 24); - DispatcherRandomSeed = (days << 32) ^ iteration; - DispatcherRandomProvider = CreateDeterministicRandomProvider(DispatcherRandomSeed); - } - - IActor* TTestActorRuntimeBase::FindActor(const TActorId& actorId, ui32 nodeIndex) const { - TGuard<TMutex> guard(Mutex); - if (nodeIndex == Max<ui32>()) { - Y_ABORT_UNLESS(actorId.NodeId()); - nodeIndex = actorId.NodeId() - FirstNodeId; - } - - Y_ABORT_UNLESS(nodeIndex < NodeCount); - auto nodeIt = Nodes.find(FirstNodeId + nodeIndex); - Y_ABORT_UNLESS(nodeIt != Nodes.end()); - TNodeDataBase* node = nodeIt->second.Get(); - return FindActor(actorId, node); - } - - void TTestActorRuntimeBase::EnableScheduleForActor(const TActorId& actorId, bool allow) { - TGuard<TMutex> guard(Mutex); - if (allow) { - if (VERBOSE) { - Cerr << "Actor " << actorId << " added to schedule whitelist"; - } - ScheduleWhiteList.insert(actorId); - } else { - if (VERBOSE) { - Cerr << "Actor " << actorId << " removed from schedule whitelist"; - } - ScheduleWhiteList.erase(actorId); - } - } - - bool TTestActorRuntimeBase::IsScheduleForActorEnabled(const TActorId& actorId) const { - TGuard<TMutex> guard(Mutex); - return ScheduleWhiteList.find(actorId) != ScheduleWhiteList.end(); - } - - TIntrusivePtr<NMonitoring::TDynamicCounters> TTestActorRuntimeBase::GetDynamicCounters(ui32 nodeIndex) { - TGuard<TMutex> guard(Mutex); - Y_ABORT_UNLESS(nodeIndex < NodeCount); - ui32 nodeId = FirstNodeId + nodeIndex; - TNodeDataBase* node = Nodes[nodeId].Get(); - return node->DynamicCounters; - } - - void TTestActorRuntimeBase::SetupMonitoring() { - NeedMonitoring = true; - } - - void TTestActorRuntimeBase::SendInternal(TAutoPtr<IEventHandle> ev, ui32 nodeIndex, bool viaActorSystem) { - Y_ABORT_UNLESS(nodeIndex < NodeCount); - ui32 nodeId = FirstNodeId + nodeIndex; - TNodeDataBase* node = Nodes[nodeId].Get(); - ui32 targetNode = ev->GetRecipientRewrite().NodeId(); - ui32 targetNodeIndex; - if (targetNode == 0) { - targetNodeIndex = nodeIndex; - } else { - targetNodeIndex = targetNode - FirstNodeId; - Y_ABORT_UNLESS(targetNodeIndex < NodeCount); - } - - if (viaActorSystem || UseRealThreads || ev->GetRecipientRewrite().IsService() || (targetNodeIndex != nodeIndex)) { - node->ActorSystem->Send(ev); - return; - } - - Y_ABORT_UNLESS(!ev->GetRecipientRewrite().IsService() && (targetNodeIndex == nodeIndex)); - - if (!AllowSendFrom(node, ev)) { - return; - } - - ui32 mailboxHint = ev->GetRecipientRewrite().Hint(); - TEventMailBox& mbox = GetMailbox(nodeId, mailboxHint); - if (!mbox.IsActive(TInstant::MicroSeconds(CurrentTimestamp))) { - mbox.PushFront(ev); - return; - } - - ui64 recipientLocalId = ev->GetRecipientRewrite().LocalId(); - if ((BlockedOutput.find(ev->Sender) == BlockedOutput.end()) && VERBOSE) { - Cerr << "Send event, "; - PrintEvent(ev, this); - } - - EvCounters[ev->GetTypeRewrite()]++; - - TMailboxHeader* mailbox = node->MailboxTable->Get(mailboxHint); - IActor* recipientActor = mailbox->FindActor(recipientLocalId); - if (recipientActor) { - // Save actorId by value in order to prevent ctx from being invalidated during another Send call. - TActorId actorId = ev->GetRecipientRewrite(); - node->ActorToActorId[recipientActor] = ev->GetRecipientRewrite(); - TActorContext ctx(*mailbox, *node->ExecutorThread, GetCycleCountFast(), actorId); - TActivationContext *prevTlsActivationContext = TlsActivationContext; - TlsActivationContext = &ctx; - CurrentRecipient = actorId; - { - TInverseGuard<TMutex> inverseGuard(Mutex); -#ifdef USE_ACTOR_CALLSTACK - TCallstack::GetTlsCallstack() = ev->Callstack; - TCallstack::GetTlsCallstack().SetLinesToSkip(); -#endif - recipientActor->Receive(ev); - node->ExecutorThread->DropUnregistered(); - } - CurrentRecipient = TActorId(); - TlsActivationContext = prevTlsActivationContext; - } else { - if (VERBOSE) { - Cerr << "Failed to find actor with local id: " << recipientLocalId << "\n"; - } - - auto fw = IEventHandle::ForwardOnNondelivery(ev, TEvents::TEvUndelivered::ReasonActorUnknown); - node->ActorSystem->Send(fw); - } - } - - IActor* TTestActorRuntimeBase::FindActor(const TActorId& actorId, TNodeDataBase* node) const { - ui32 mailboxHint = actorId.Hint(); - ui64 localId = actorId.LocalId(); - TMailboxHeader* mailbox = node->MailboxTable->Get(mailboxHint); - IActor* actor = mailbox->FindActor(localId); - return actor; - } - - THolder<TActorSystemSetup> TTestActorRuntimeBase::MakeActorSystemSetup(ui32 nodeIndex, TNodeDataBase* node) { - THolder<TActorSystemSetup> setup(new TActorSystemSetup); - setup->NodeId = FirstNodeId + nodeIndex; - - if (UseRealThreads) { - setup->ExecutorsCount = 5; - setup->Executors.Reset(new TAutoPtr<IExecutorPool>[5]); - setup->Executors[0].Reset(new TBasicExecutorPool(0, 2, 20)); - setup->Executors[1].Reset(new TBasicExecutorPool(1, 2, 20)); - setup->Executors[2].Reset(new TIOExecutorPool(2, 1)); - setup->Executors[3].Reset(new TBasicExecutorPool(3, 2, 20)); - setup->Executors[4].Reset(new TBasicExecutorPool(4, 1, 20)); - setup->Scheduler.Reset(new TBasicSchedulerThread(TSchedulerConfig(512, 100))); - } else { - setup->ExecutorsCount = 1; - setup->Scheduler.Reset(new TSchedulerThreadStub(this, node)); - setup->Executors.Reset(new TAutoPtr<IExecutorPool>[1]); - setup->Executors[0].Reset(new TExecutorPoolStub(this, nodeIndex, node, 0)); - } - - InitActorSystemSetup(*setup); - - return setup; - } - - THolder<TActorSystem> TTestActorRuntimeBase::MakeActorSystem(ui32 nodeIndex, TNodeDataBase* node) { - auto setup = MakeActorSystemSetup(nodeIndex, node); - - node->ExecutorPools.resize(setup->ExecutorsCount); - for (ui32 i = 0; i < setup->ExecutorsCount; ++i) { - node->ExecutorPools[i] = setup->Executors[i].Get(); - } - - const auto& interconnectCounters = GetCountersForComponent(node->DynamicCounters, "interconnect"); - - for (const auto& cmd : node->LocalServices) { - setup->LocalServices.emplace_back(cmd.first, TActorSetupCmd(cmd.second.Actor, cmd.second.MailboxType, cmd.second.PoolId)); - } - setup->Interconnect.ProxyActors.resize(FirstNodeId + NodeCount); - const TActorId nameserviceId = GetNameserviceActorId(); - - TIntrusivePtr<TInterconnectProxyCommon> common; - common.Reset(new TInterconnectProxyCommon); - common->NameserviceId = nameserviceId; - common->MonCounters = interconnectCounters; - common->TechnicalSelfHostName = "::1"; - - if (!UseRealThreads) { - common->Settings.DeadPeer = TDuration::Max(); - common->Settings.CloseOnIdle = TDuration::Max(); - common->Settings.PingPeriod = TDuration::Max(); - common->Settings.ForceConfirmPeriod = TDuration::Max(); - common->Settings.Handshake = TDuration::Max(); - } - - common->ClusterUUID = ClusterUUID; - common->AcceptUUID = {ClusterUUID}; - - if (ICCommonSetupper) { - ICCommonSetupper(nodeIndex, common); - } - - for (ui32 proxyNodeIndex = 0; proxyNodeIndex < NodeCount; ++proxyNodeIndex) { - if (proxyNodeIndex == nodeIndex) - continue; - - const ui32 peerNodeId = FirstNodeId + proxyNodeIndex; - - IActor *proxyActor = UseRealInterconnect - ? new TInterconnectProxyTCP(peerNodeId, common) - : InterconnectMock.CreateProxyMock(setup->NodeId, peerNodeId, common); - - setup->Interconnect.ProxyActors[peerNodeId] = {proxyActor, TMailboxType::ReadAsFilled, InterconnectPoolId()}; - } - - setup->Interconnect.ProxyWrapperFactory = CreateProxyWrapperFactory(common, InterconnectPoolId(), &InterconnectMock); - - if (UseRealInterconnect) { - setup->LocalServices.emplace_back(MakePollerActorId(), NActors::TActorSetupCmd(CreatePollerActor(), - NActors::TMailboxType::Simple, InterconnectPoolId())); - } - - if (!SingleSysEnv) { // Single system env should do this self - TAutoPtr<TLogBackend> logBackend = LogBackend ? LogBackend : NActors::CreateStderrBackend(); - NActors::TLoggerActor *loggerActor = new NActors::TLoggerActor(node->LogSettings, - logBackend, GetCountersForComponent(node->DynamicCounters, "utils")); - NActors::TActorSetupCmd loggerActorCmd(loggerActor, NActors::TMailboxType::Simple, node->GetLoggerPoolId()); - std::pair<NActors::TActorId, NActors::TActorSetupCmd> loggerActorPair(node->LogSettings->LoggerActorId, std::move(loggerActorCmd)); - setup->LocalServices.push_back(std::move(loggerActorPair)); - } - - return THolder<TActorSystem>(new TActorSystem(setup, node->GetAppData(), node->LogSettings)); - } - - TActorSystem* TTestActorRuntimeBase::SingleSys() const { - Y_ABORT_UNLESS(Nodes.size() == 1, "Works only for single system env"); - - return Nodes.begin()->second->ActorSystem.Get(); - } - - TActorSystem* TTestActorRuntimeBase::GetAnyNodeActorSystem() { - for (auto& x : Nodes) { - return x.second->ActorSystem.Get(); - } - Y_ABORT("Don't use this method."); - } - - TActorSystem* TTestActorRuntimeBase::GetActorSystem(ui32 nodeId) { - auto it = Nodes.find(GetNodeId(nodeId)); - Y_ABORT_UNLESS(it != Nodes.end()); - return it->second->ActorSystem.Get(); - } - - - TEventMailBox& TTestActorRuntimeBase::GetMailbox(ui32 nodeId, ui32 hint) { - TGuard<TMutex> guard(Mutex); - auto mboxId = TEventMailboxId(nodeId, hint); - auto it = Mailboxes.find(mboxId); - if (it == Mailboxes.end()) { - it = Mailboxes.insert(std::make_pair(mboxId, new TEventMailBox())).first; - } - - return *it->second; - } - - void TTestActorRuntimeBase::ClearMailbox(ui32 nodeId, ui32 hint) { - TGuard<TMutex> guard(Mutex); - auto mboxId = TEventMailboxId(nodeId, hint); - Mailboxes.erase(mboxId); - } - - TString TTestActorRuntimeBase::GetActorName(const TActorId& actorId) const { - auto it = ActorNames.find(actorId); - if (it != ActorNames.end()) - return it->second; - return actorId.ToString(); - } - - struct TStrandingActorDecoratorContext : public TThrRefBase { - TStrandingActorDecoratorContext() - : Queue(new TQueueType) - { - } - - typedef TOneOneQueueInplace<IEventHandle*, 32> TQueueType; - TAutoPtr<TQueueType, TQueueType::TPtrCleanDestructor> Queue; - }; - - class TStrandingActorDecorator : public TActorBootstrapped<TStrandingActorDecorator> { - public: - class TReplyActor : public TActor<TReplyActor> { - public: - static constexpr EActivityType ActorActivityType() { - return EActivityType::TEST_ACTOR_RUNTIME; - } - - TReplyActor(TStrandingActorDecorator* owner) - : TActor(&TReplyActor::StateFunc) - , Owner(owner) - { - } - - STFUNC(StateFunc); - - private: - TStrandingActorDecorator* const Owner; - }; - - static constexpr EActivityType ActorActivityType() { - return EActivityType::TEST_ACTOR_RUNTIME; - } - - TStrandingActorDecorator(const TActorId& delegatee, bool isSync, const TVector<TActorId>& additionalActors, - TSimpleSharedPtr<TStrandingActorDecoratorContext> context, TTestActorRuntimeBase* runtime, - TReplyCheckerCreator createReplyChecker) - : Delegatee(delegatee) - , IsSync(isSync) - , AdditionalActors(additionalActors) - , Context(context) - , HasReply(false) - , Runtime(runtime) - , ReplyChecker(createReplyChecker()) - { - if (IsSync) { - Y_ABORT_UNLESS(!runtime->IsRealThreads()); - } - } - - void Bootstrap(const TActorContext& ctx) { - Become(&TStrandingActorDecorator::StateFunc); - ReplyId = ctx.RegisterWithSameMailbox(new TReplyActor(this)); - DelegateeOptions.OnlyMailboxes.push_back(TEventMailboxId(Delegatee.NodeId(), Delegatee.Hint())); - for (const auto& actor : AdditionalActors) { - DelegateeOptions.OnlyMailboxes.push_back(TEventMailboxId(actor.NodeId(), actor.Hint())); - } - - DelegateeOptions.OnlyMailboxes.push_back(TEventMailboxId(ReplyId.NodeId(), ReplyId.Hint())); - DelegateeOptions.NonEmptyMailboxes.push_back(TEventMailboxId(ReplyId.NodeId(), ReplyId.Hint())); - DelegateeOptions.Quiet = true; - } - - STFUNC(StateFunc) { - bool wasEmpty = !Context->Queue->Head(); - Context->Queue->Push(ev.Release()); - if (wasEmpty) { - SendHead(ActorContext()); - } - } - - STFUNC(Reply) { - Y_ABORT_UNLESS(!HasReply); - IEventHandle *requestEv = Context->Queue->Head(); - TActorId originalSender = requestEv->Sender; - HasReply = !ReplyChecker->IsWaitingForMoreResponses(ev.Get()); - if (HasReply) { - delete Context->Queue->Pop(); - } - auto ctx(ActorContext()); - ctx.ExecutorThread.Send(IEventHandle::Forward(ev, originalSender)); - if (!IsSync && Context->Queue->Head()) { - SendHead(ctx); - } - } - - private: - void SendHead(const TActorContext& ctx) { - if (!IsSync) { - ctx.ExecutorThread.Send(GetForwardedEvent().Release()); - } else { - while (Context->Queue->Head()) { - HasReply = false; - ctx.ExecutorThread.Send(GetForwardedEvent().Release()); - int count = 100; - while (!HasReply && count > 0) { - try { - Runtime->DispatchEvents(DelegateeOptions); - } catch (TEmptyEventQueueException&) { - count--; - Cerr << "No reply" << Endl; - } - } - - Runtime->UpdateCurrentTime(Runtime->GetCurrentTime() + TDuration::MicroSeconds(1000)); - } - } - } - - TAutoPtr<IEventHandle> GetForwardedEvent() { - IEventHandle* ev = Context->Queue->Head(); - ReplyChecker->OnRequest(ev); - TAutoPtr<IEventHandle> forwardedEv = ev->HasEvent() - ? new IEventHandle(Delegatee, ReplyId, ev->ReleaseBase().Release(), ev->Flags, ev->Cookie) - : new IEventHandle(ev->GetTypeRewrite(), ev->Flags, Delegatee, ReplyId, ev->ReleaseChainBuffer(), ev->Cookie); - - return forwardedEv; - } - private: - const TActorId Delegatee; - const bool IsSync; - const TVector<TActorId> AdditionalActors; - TSimpleSharedPtr<TStrandingActorDecoratorContext> Context; - TActorId ReplyId; - bool HasReply; - TDispatchOptions DelegateeOptions; - TTestActorRuntimeBase* Runtime; - THolder<IReplyChecker> ReplyChecker; - }; - - void TStrandingActorDecorator::TReplyActor::StateFunc(STFUNC_SIG) { - Owner->Reply(ev); - } - - class TStrandingDecoratorFactory : public IStrandingDecoratorFactory { - public: - TStrandingDecoratorFactory(TTestActorRuntimeBase* runtime, - TReplyCheckerCreator createReplyChecker) - : Context(new TStrandingActorDecoratorContext()) - , Runtime(runtime) - , CreateReplyChecker(createReplyChecker) - { - } - - IActor* Wrap(const TActorId& delegatee, bool isSync, const TVector<TActorId>& additionalActors) override { - return new TStrandingActorDecorator(delegatee, isSync, additionalActors, Context, Runtime, - CreateReplyChecker); - } - - private: - TSimpleSharedPtr<TStrandingActorDecoratorContext> Context; - TTestActorRuntimeBase* Runtime; - TReplyCheckerCreator CreateReplyChecker; - }; - - TAutoPtr<IStrandingDecoratorFactory> CreateStrandingDecoratorFactory(TTestActorRuntimeBase* runtime, - TReplyCheckerCreator createReplyChecker) { - return TAutoPtr<IStrandingDecoratorFactory>(new TStrandingDecoratorFactory(runtime, createReplyChecker)); - } - - ui64 DefaultRandomSeed = 9999; -} diff --git a/library/cpp/actors/testlib/test_runtime.h b/library/cpp/actors/testlib/test_runtime.h deleted file mode 100644 index f46d3906e4..0000000000 --- a/library/cpp/actors/testlib/test_runtime.h +++ /dev/null @@ -1,814 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/actor.h> -#include <library/cpp/actors/core/actorsystem.h> -#include <library/cpp/actors/core/log.h> -#include <library/cpp/actors/core/events.h> -#include <library/cpp/actors/core/executor_thread.h> -#include <library/cpp/actors/core/mailbox.h> -#include <library/cpp/actors/core/monotonic_provider.h> -#include <library/cpp/actors/util/should_continue.h> -#include <library/cpp/actors/interconnect/poller_tcp.h> -#include <library/cpp/actors/interconnect/mock/ic_mock.h> -#include <library/cpp/random_provider/random_provider.h> -#include <library/cpp/time_provider/time_provider.h> -#include <library/cpp/testing/unittest/tests_data.h> - -#include <util/datetime/base.h> -#include <util/folder/tempdir.h> -#include <util/generic/deque.h> -#include <util/generic/hash.h> -#include <util/generic/noncopyable.h> -#include <util/generic/ptr.h> -#include <util/generic/queue.h> -#include <util/generic/set.h> -#include <util/generic/vector.h> -#include <util/system/defaults.h> -#include <util/system/mutex.h> -#include <util/system/condvar.h> -#include <util/system/thread.h> -#include <util/system/sanitizers.h> -#include <util/system/valgrind.h> -#include <utility> - -#include <functional> - -const TDuration DEFAULT_DISPATCH_TIMEOUT = NSan::PlainOrUnderSanitizer( - NValgrind::PlainOrUnderValgrind(TDuration::Seconds(60), TDuration::Seconds(120)), - TDuration::Seconds(120) -); - - -namespace NActors { - struct THeSingleSystemEnv { }; - - struct TTestActorSetupCmd { // like TActorSetupCmd, but not owning the Actor - TTestActorSetupCmd(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId) - : MailboxType(mailboxType) - , PoolId(poolId) - , Actor(actor) - { - } - - TTestActorSetupCmd(TActorSetupCmd cmd) - : MailboxType(cmd.MailboxType) - , PoolId(cmd.PoolId) - , Actor(cmd.Actor.release()) - { - } - - TMailboxType::EType MailboxType; - ui32 PoolId; - IActor* Actor; - }; - - struct TEventMailboxId { - TEventMailboxId() - : NodeId(0) - , Hint(0) - { - } - - TEventMailboxId(ui32 nodeId, ui32 hint) - : NodeId(nodeId) - , Hint(hint) - { - } - - bool operator<(const TEventMailboxId& other) const { - return (NodeId < other.NodeId) || (NodeId == other.NodeId) && (Hint < other.Hint); - } - - bool operator==(const TEventMailboxId& other) const { - return (NodeId == other.NodeId) && (Hint == other.Hint); - } - - struct THash { - ui64 operator()(const TEventMailboxId& mboxId) const noexcept { - return mboxId.NodeId * 31ULL + mboxId.Hint; - } - }; - - ui32 NodeId; - ui32 Hint; - }; - - struct TDispatchOptions { - struct TFinalEventCondition { - std::function<bool(IEventHandle& ev)> EventCheck; - ui32 RequiredCount; - - TFinalEventCondition(ui32 eventType, ui32 requiredCount = 1) - : EventCheck([eventType](IEventHandle& ev) -> bool { return ev.GetTypeRewrite() == eventType; }) - , RequiredCount(requiredCount) - { - } - - TFinalEventCondition(std::function<bool(IEventHandle& ev)> eventCheck, ui32 requiredCount = 1) - : EventCheck(eventCheck) - , RequiredCount(requiredCount) - { - } - }; - - TVector<TFinalEventCondition> FinalEvents; - TVector<TEventMailboxId> NonEmptyMailboxes; - TVector<TEventMailboxId> OnlyMailboxes; - std::function<bool()> CustomFinalCondition; - bool Quiet = false; - }; - - struct TScheduledEventQueueItem { - TInstant Deadline; - TAutoPtr<IEventHandle> Event; - TAutoPtr<TSchedulerCookieHolder> Cookie; - ui64 UniqueId; - - TScheduledEventQueueItem(TInstant deadline, TAutoPtr<IEventHandle> event, ISchedulerCookie* cookie) - : Deadline(deadline) - , Event(event) - , Cookie(new TSchedulerCookieHolder(cookie)) - , UniqueId(++NextUniqueId) - {} - - bool operator<(const TScheduledEventQueueItem& other) const { - if (Deadline < other.Deadline) - return true; - - if (Deadline > other.Deadline) - return false; - - return UniqueId < other.UniqueId; - } - - static ui64 NextUniqueId; - }; - - typedef TDeque<TAutoPtr<IEventHandle>> TEventsList; - typedef TSet<TScheduledEventQueueItem> TScheduledEventsList; - - class TEventMailBox : public TThrRefBase { - public: - TEventMailBox() - : InactiveUntil(TInstant::MicroSeconds(0)) -#ifdef DEBUG_ORDER_EVENTS - , ExpectedReceive(0) - , NextToSend(0) -#endif - { - } - - void Send(TAutoPtr<IEventHandle> ev); - bool IsEmpty() const; - TAutoPtr<IEventHandle> Pop(); - void Capture(TEventsList& evList); - void PushFront(TAutoPtr<IEventHandle>& ev); - void PushFront(TEventsList& evList); - void CaptureScheduled(TScheduledEventsList& evList); - void PushScheduled(TScheduledEventsList& evList); - bool IsActive(const TInstant& currentTime) const; - void Freeze(const TInstant& deadline); - TInstant GetInactiveUntil() const; - void Schedule(const TScheduledEventQueueItem& item); - bool IsScheduledEmpty() const; - TInstant GetFirstScheduleDeadline() const; - ui64 GetSentEventCount() const; - - private: - TScheduledEventsList Scheduled; - TInstant InactiveUntil; - TEventsList Sent; -#ifdef DEBUG_ORDER_EVENTS - TMap<IEventHandle*, ui64> TrackSent; - ui64 ExpectedReceive; - ui64 NextToSend; -#endif - }; - - typedef THashMap<TEventMailboxId, TIntrusivePtr<TEventMailBox>, TEventMailboxId::THash> TEventMailBoxList; - - class TEmptyEventQueueException : public yexception { - public: - TEmptyEventQueueException() { - Append("Event queue is still empty."); - } - }; - - class TSchedulingLimitReachedException : public yexception { - public: - TSchedulingLimitReachedException(ui64 limit) { - TStringStream str; - str << "TestActorRuntime Processed over " << limit << " events."; - Append(str.Str()); - } - }; - - class TTestActorRuntimeBase: public TNonCopyable { - public: - class TEdgeActor; - class TSchedulerThreadStub; - class TExecutorPoolStub; - class TTimeProvider; - class TMonotonicTimeProvider; - - enum class EEventAction { - PROCESS, - DROP, - RESCHEDULE - }; - - typedef std::function<EEventAction(TAutoPtr<IEventHandle>& event)> TEventObserver; - typedef std::function<void(TTestActorRuntimeBase& runtime, TScheduledEventsList& scheduledEvents, TEventsList& queue)> TScheduledEventsSelector; - typedef std::function<bool(TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event)> TEventFilter; - typedef std::function<bool(TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event, TDuration delay, TInstant& deadline)> TScheduledEventFilter; - typedef std::function<void(TTestActorRuntimeBase& runtime, const TActorId& parentId, const TActorId& actorId)> TRegistrationObserver; - - - TTestActorRuntimeBase(THeSingleSystemEnv); - TTestActorRuntimeBase(ui32 nodeCount, ui32 dataCenterCount, bool UseRealThreads); - TTestActorRuntimeBase(ui32 nodeCount, ui32 dataCenterCount); - TTestActorRuntimeBase(ui32 nodeCount = 1, bool useRealThreads = false); - virtual ~TTestActorRuntimeBase(); - bool IsRealThreads() const; - static EEventAction DefaultObserverFunc(TAutoPtr<IEventHandle>& event); - static void DroppingScheduledEventsSelector(TTestActorRuntimeBase& runtime, TScheduledEventsList& scheduledEvents, TEventsList& queue); - static void CollapsedTimeScheduledEventsSelector(TTestActorRuntimeBase& runtime, TScheduledEventsList& scheduledEvents, TEventsList& queue); - static bool DefaultFilterFunc(TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event); - static bool NopFilterFunc(TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event, TDuration delay, TInstant& deadline); - static void DefaultRegistrationObserver(TTestActorRuntimeBase& runtime, const TActorId& parentId, const TActorId& actorId); - TEventObserver SetObserverFunc(TEventObserver observerFunc); // deprecated, use AddObserver - TScheduledEventsSelector SetScheduledEventsSelectorFunc(TScheduledEventsSelector scheduledEventsSelectorFunc); - TEventFilter SetEventFilter(TEventFilter filterFunc); - TScheduledEventFilter SetScheduledEventFilter(TScheduledEventFilter filterFunc); - TRegistrationObserver SetRegistrationObserverFunc(TRegistrationObserver observerFunc); - static bool IsVerbose(); - static void SetVerbose(bool verbose); - TDuration SetDispatchTimeout(TDuration timeout); - void SetDispatchedEventsLimit(ui64 limit) { - DispatchedEventsLimit = limit; - } - TDuration SetReschedulingDelay(TDuration delay); - void SetLogBackend(const TAutoPtr<TLogBackend> logBackend); - void SetLogPriority(NActors::NLog::EComponent component, NActors::NLog::EPriority priority); - TIntrusivePtr<ITimeProvider> GetTimeProvider(); - TIntrusivePtr<IMonotonicTimeProvider> GetMonotonicTimeProvider(); - TInstant GetCurrentTime() const; - TMonotonic GetCurrentMonotonicTime() const; - void UpdateCurrentTime(TInstant newTime); - void AdvanceCurrentTime(TDuration duration); - void AddLocalService(const TActorId& actorId, TActorSetupCmd cmd, ui32 nodeIndex = 0); - virtual void Initialize(); - ui32 GetNodeId(ui32 index = 0) const; - ui32 GetNodeCount() const; - ui64 AllocateLocalId(); - ui32 InterconnectPoolId() const; - TString GetTempDir(); - TActorId Register(IActor* actor, ui32 nodeIndex = 0, ui32 poolId = 0, - TMailboxType::EType mailboxType = TMailboxType::Simple, ui64 revolvingCounter = 0, - const TActorId& parentid = TActorId()); - TActorId Register(IActor *actor, ui32 nodeIndex, ui32 poolId, TMailboxHeader *mailbox, ui32 hint, - const TActorId& parentid = TActorId()); - TActorId RegisterService(const TActorId& serviceId, const TActorId& actorId, ui32 nodeIndex = 0); - TActorId AllocateEdgeActor(ui32 nodeIndex = 0); - TEventsList CaptureEvents(); - TEventsList CaptureMailboxEvents(ui32 hint, ui32 nodeId); - TScheduledEventsList CaptureScheduledEvents(); - void PushFront(TAutoPtr<IEventHandle>& ev); - void PushEventsFront(TEventsList& events); - void PushMailboxEventsFront(ui32 hint, ui32 nodeId, TEventsList& events); - // doesn't dispatch events for edge actors - bool DispatchEvents(const TDispatchOptions& options = TDispatchOptions()); - bool DispatchEvents(const TDispatchOptions& options, TDuration simTimeout); - bool DispatchEvents(const TDispatchOptions& options, TInstant simDeadline); - void Send(const TActorId& recipient, const TActorId& sender, TAutoPtr<IEventBase> ev, ui32 senderNodeIndex = 0, bool viaActorSystem = false); - void Send(TAutoPtr<IEventHandle> ev, ui32 senderNodeIndex = 0, bool viaActorSystem = false); - void SendAsync(TAutoPtr<IEventHandle> ev, ui32 senderNodeIndex = 0); - void Schedule(TAutoPtr<IEventHandle> ev, const TDuration& duration, ui32 nodeIndex = 0); - void ClearCounters(); - ui64 GetCounter(ui32 evType) const; - TActorId GetLocalServiceId(const TActorId& serviceId, ui32 nodeIndex = 0); - void WaitForEdgeEvents(TEventFilter filter, const TSet<TActorId>& edgeFilter = {}, TDuration simTimeout = TDuration::Max()); - TActorId GetInterconnectProxy(ui32 nodeIndexFrom, ui32 nodeIndexTo); - void BlockOutputForActor(const TActorId& actorId); - IActor* FindActor(const TActorId& actorId, ui32 nodeIndex = Max<ui32>()) const; - void EnableScheduleForActor(const TActorId& actorId, bool allow = true); - bool IsScheduleForActorEnabled(const TActorId& actorId) const; - TIntrusivePtr<NMonitoring::TDynamicCounters> GetDynamicCounters(ui32 nodeIndex = 0); - void SetupMonitoring(); - - using TEventObserverCollection = std::list<std::function<void(TAutoPtr<IEventHandle>& event)>>; - class TEventObserverHolder { - public: - TEventObserverHolder(TEventObserverCollection& list, TEventObserverCollection::iterator&& iter) - : List(list) - , Iter(iter) - { - } - - ~TEventObserverHolder() - { - Remove(); - } - - void Remove() - { - if (Iter == List.end()) { - return; - } - - List.erase(Iter); - Iter = List.end(); - } - private: - TEventObserverCollection& List; - TEventObserverCollection::iterator Iter; - }; - - // An example of using AddObserver in unit tests - /* - auto observerHolder = runtime.AddObserver<TEvDataShard::TEvRead>([&](TEvDataShard::TEvRead::TPtr& event) { - // Do something with the event inside the calback - Cout << "An event is observed " << ev->Get()->Record.ShortDebugString() << Endl; - - // Optionally reset the event, all subsequent handlers of this event will not be called - event.Reset(); - }); - - // Do something inside the main code of the unit test - - // Optionally remove the observer, otherwise it will be destroyed in its destructor - observerHolder.Remove(); - */ - - template <typename TEvType> - TEventObserverHolder AddObserver(std::function<void(typename TEvType::TPtr&)> observerFunc) - { - auto baseFunc = [observerFunc](TAutoPtr<IEventHandle>& event) { - if (event && event->GetTypeRewrite() == TEvType::EventType) - observerFunc(*(reinterpret_cast<typename TEvType::TPtr*>(&event))); - }; - - auto iter = ObserverFuncs.insert(ObserverFuncs.end(), baseFunc); - return TEventObserverHolder(ObserverFuncs, std::move(iter)); - } - - TEventObserverHolder AddObserver(std::function<void(TAutoPtr<IEventHandle>&)> observerFunc) - { - auto iter = ObserverFuncs.insert(ObserverFuncs.end(), observerFunc); - return TEventObserverHolder(ObserverFuncs, std::move(iter)); - } - - template<typename T> - void AppendToLogSettings(NLog::EComponent minVal, NLog::EComponent maxVal, T func) { - Y_ABORT_UNLESS(!IsInitialized); - - for (const auto& pair : Nodes) { - pair.second->LogSettings->Append(minVal, maxVal, func); - } - } - - TIntrusivePtr<NLog::TSettings> GetLogSettings(ui32 nodeIdx) - { - return Nodes[FirstNodeId + nodeIdx]->LogSettings; - } - - TActorSystem* SingleSys() const; - TActorSystem* GetAnyNodeActorSystem(); - TActorSystem* GetActorSystem(ui32 nodeId); - template <typename TEvent> - TEvent* GrabEdgeEventIf(TAutoPtr<IEventHandle>& handle, std::function<bool(const TEvent&)> predicate, TDuration simTimeout = TDuration::Max()) { - handle.Destroy(); - const ui32 eventType = TEvent::EventType; - WaitForEdgeEvents([&](TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event) { - Y_UNUSED(runtime); - if (event->GetTypeRewrite() != eventType) - return false; - - TEvent* typedEvent = event->Get<TEvent>(); - if (predicate(*typedEvent)) { - handle = event; - return true; - } - - return false; - }, {}, simTimeout); - - if (simTimeout == TDuration::Max()) - Y_ABORT_UNLESS(handle); - - if (handle) { - return handle->Get<TEvent>(); - } else { - return nullptr; - } - } - - template<class TEvent> - typename TEvent::TPtr GrabEdgeEventIf( - const TSet<TActorId>& edgeFilter, - const std::function<bool(const typename TEvent::TPtr&)>& predicate, - TDuration simTimeout = TDuration::Max()) - { - typename TEvent::TPtr handle; - const ui32 eventType = TEvent::EventType; - WaitForEdgeEvents([&](TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event) { - Y_UNUSED(runtime); - if (event->GetTypeRewrite() != eventType) - return false; - - typename TEvent::TPtr* typedEvent = reinterpret_cast<typename TEvent::TPtr*>(&event); - if (predicate(*typedEvent)) { - handle = *typedEvent; - return true; - } - - return false; - }, edgeFilter, simTimeout); - - if (simTimeout == TDuration::Max()) - Y_ABORT_UNLESS(handle); - - return handle; - } - - template<class TEvent> - typename TEvent::TPtr GrabEdgeEventIf( - const TActorId& edgeActor, - const std::function<bool(const typename TEvent::TPtr&)>& predicate, - TDuration simTimeout = TDuration::Max()) - { - TSet<TActorId> edgeFilter{edgeActor}; - return GrabEdgeEventIf<TEvent>(edgeFilter, predicate, simTimeout); - } - - template <typename TEvent> - TEvent* GrabEdgeEvent(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) { - std::function<bool(const TEvent&)> truth = [](const TEvent&) { return true; }; - return GrabEdgeEventIf(handle, truth, simTimeout); - } - - template <typename TEvent> - THolder<TEvent> GrabEdgeEvent(TDuration simTimeout = TDuration::Max()) { - TAutoPtr<IEventHandle> handle; - std::function<bool(const TEvent&)> truth = [](const TEvent&) { return true; }; - GrabEdgeEventIf(handle, truth, simTimeout); - if (handle) { - return THolder<TEvent>(handle->Release<TEvent>()); - } - return {}; - } - - template<class TEvent> - typename TEvent::TPtr GrabEdgeEvent(const TSet<TActorId>& edgeFilter, TDuration simTimeout = TDuration::Max()) { - return GrabEdgeEventIf<TEvent>(edgeFilter, [](const typename TEvent::TPtr&) { return true; }, simTimeout); - } - - template<class TEvent> - typename TEvent::TPtr GrabEdgeEvent(const TActorId& edgeActor, TDuration simTimeout = TDuration::Max()) { - TSet<TActorId> edgeFilter{edgeActor}; - return GrabEdgeEvent<TEvent>(edgeFilter, simTimeout); - } - - // replace with std::variant<> - template <typename... TEvents> - std::tuple<TEvents*...> GrabEdgeEvents(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) { - handle.Destroy(); - auto eventTypes = { TEvents::EventType... }; - WaitForEdgeEvents([&](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& event) { - if (std::find(std::begin(eventTypes), std::end(eventTypes), event->GetTypeRewrite()) == std::end(eventTypes)) - return false; - handle = event; - return true; - }, {}, simTimeout); - if (simTimeout == TDuration::Max()) - Y_ABORT_UNLESS(handle); - if (handle) { - return std::make_tuple(handle->Type == TEvents::EventType - ? handle->Get<TEvents>() - : static_cast<TEvents*>(nullptr)...); - } - return {}; - } - - template <typename TEvent> - TEvent* GrabEdgeEventRethrow(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) { - try { - return GrabEdgeEvent<TEvent>(handle, simTimeout); - } catch (...) { - ythrow TWithBackTrace<yexception>() << "Exception occured while waiting for " << TypeName<TEvent>() << ": " << CurrentExceptionMessage(); - } - } - - template<class TEvent> - typename TEvent::TPtr GrabEdgeEventRethrow(const TSet<TActorId>& edgeFilter, TDuration simTimeout = TDuration::Max()) { - try { - return GrabEdgeEvent<TEvent>(edgeFilter, simTimeout); - } catch (...) { - ythrow TWithBackTrace<yexception>() << "Exception occured while waiting for " << TypeName<TEvent>() << ": " << CurrentExceptionMessage(); - } - } - - template<class TEvent> - typename TEvent::TPtr GrabEdgeEventRethrow(const TActorId& edgeActor, TDuration simTimeout = TDuration::Max()) { - try { - return GrabEdgeEvent<TEvent>(edgeActor, simTimeout); - } catch (...) { - ythrow TWithBackTrace<yexception>() << "Exception occured while waiting for " << TypeName<TEvent>() << ": " << CurrentExceptionMessage(); - } - } - - template <typename... TEvents> - static TString TypeNames() { - static TString names[] = { TypeName<TEvents>()... }; - TString result; - for (const TString& s : names) { - if (result.empty()) { - result += '<'; - } else { - result += ','; - } - result += s; - } - if (!result.empty()) { - result += '>'; - } - return result; - } - - template <typename... TEvents> - std::tuple<TEvents*...> GrabEdgeEventsRethrow(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) { - try { - return GrabEdgeEvents<TEvents...>(handle, simTimeout); - } catch (...) { - ythrow TWithBackTrace<yexception>() << "Exception occured while waiting for " << TypeNames<TEvents...>() << ": " << CurrentExceptionMessage(); - } - } - - void ResetScheduledCount() { - ScheduledCount = 0; - } - - void SetScheduledLimit(ui64 limit) { - ScheduledLimit = limit; - } - - void SetDispatcherRandomSeed(TInstant time, ui64 iteration); - TString GetActorName(const TActorId& actorId) const; - - const TVector<ui64>& GetTxAllocatorTabletIds() const { return TxAllocatorTabletIds; } - void SetTxAllocatorTabletIds(const TVector<ui64>& ids) { TxAllocatorTabletIds = ids; } - - void SetUseRealInterconnect() { - UseRealInterconnect = true; - } - - void SetICCommonSetupper(std::function<void(ui32, TIntrusivePtr<TInterconnectProxyCommon>)>&& icCommonSetupper) { - ICCommonSetupper = std::move(icCommonSetupper); - } - - protected: - struct TNodeDataBase; - TNodeDataBase* GetRawNode(ui32 node) const { - return Nodes.at(FirstNodeId + node).Get(); - } - - static IExecutorPool* CreateExecutorPoolStub(TTestActorRuntimeBase* runtime, ui32 nodeIndex, TNodeDataBase* node, ui32 poolId); - virtual TIntrusivePtr<NMonitoring::TDynamicCounters> GetCountersForComponent(TIntrusivePtr<NMonitoring::TDynamicCounters> counters, const char* component) { - Y_UNUSED(counters); - Y_UNUSED(component); - - // do nothing, just return the existing counters - return counters; - } - - THolder<TActorSystemSetup> MakeActorSystemSetup(ui32 nodeIndex, TNodeDataBase* node); - THolder<TActorSystem> MakeActorSystem(ui32 nodeIndex, TNodeDataBase* node); - virtual void InitActorSystemSetup(TActorSystemSetup& setup) { - Y_UNUSED(setup); - } - - private: - IActor* FindActor(const TActorId& actorId, TNodeDataBase* node) const; - void SendInternal(TAutoPtr<IEventHandle> ev, ui32 nodeIndex, bool viaActorSystem); - TEventMailBox& GetMailbox(ui32 nodeId, ui32 hint); - void ClearMailbox(ui32 nodeId, ui32 hint); - void HandleNonEmptyMailboxesForEachContext(TEventMailboxId mboxId); - void UpdateFinalEventsStatsForEachContext(IEventHandle& ev); - bool DispatchEventsInternal(const TDispatchOptions& options, TInstant simDeadline); - - private: - ui64 ScheduledCount; - ui64 ScheduledLimit; - THolder<TTempDir> TmpDir; - const TThread::TId MainThreadId; - - protected: - bool UseRealInterconnect = false; - TInterconnectMock InterconnectMock; - bool IsInitialized = false; - bool SingleSysEnv = false; - const TString ClusterUUID; - const ui32 FirstNodeId; - const ui32 NodeCount; - const ui32 DataCenterCount; - const bool UseRealThreads; - std::function<void(ui32, TIntrusivePtr<TInterconnectProxyCommon>)> ICCommonSetupper; - - ui64 LocalId; - TMutex Mutex; - TCondVar MailboxesHasEvents; - TEventMailBoxList Mailboxes; - TMap<ui32, ui64> EvCounters; - ui64 DispatchCyclesCount; - ui64 DispatchedEventsCount; - ui64 DispatchedEventsLimit = 2'500'000; - TActorId CurrentRecipient; - ui64 DispatcherRandomSeed; - TIntrusivePtr<IRandomProvider> DispatcherRandomProvider; - TAutoPtr<TLogBackend> LogBackend; - bool NeedMonitoring; - - TIntrusivePtr<IRandomProvider> RandomProvider; - TIntrusivePtr<ITimeProvider> TimeProvider; - TIntrusivePtr<IMonotonicTimeProvider> MonotonicTimeProvider; - - protected: - struct TNodeDataBase: public TThrRefBase { - TNodeDataBase(); - void Stop(); - virtual ~TNodeDataBase(); - virtual ui64 GetLoggerPoolId() const { - return 0; - } - - template <typename T = void> - T* GetAppData() { - return static_cast<T*>(AppData0.get()); - } - - template <typename T = void> - const T* GetAppData() const { - return static_cast<T*>(AppData0.get()); - } - - TIntrusivePtr<NMonitoring::TDynamicCounters> DynamicCounters; - TIntrusivePtr<NActors::NLog::TSettings> LogSettings; - TIntrusivePtr<NInterconnect::TPollerThreads> Poller; - volatile ui64* ActorSystemTimestamp; - volatile ui64* ActorSystemMonotonic; - TVector<std::pair<TActorId, TTestActorSetupCmd>> LocalServices; - TMap<TActorId, IActor*> LocalServicesActors; - TMap<IActor*, TActorId> ActorToActorId; - THolder<TMailboxTable> MailboxTable; - std::shared_ptr<void> AppData0; - THolder<TActorSystem> ActorSystem; - THolder<IExecutorPool> SchedulerPool; - TVector<IExecutorPool*> ExecutorPools; - THolder<TExecutorThread> ExecutorThread; - }; - - struct INodeFactory { - virtual ~INodeFactory() = default; - virtual TIntrusivePtr<TNodeDataBase> CreateNode() = 0; - }; - - struct TDefaultNodeFactory final: INodeFactory { - virtual TIntrusivePtr<TNodeDataBase> CreateNode() override { - return new TNodeDataBase(); - } - }; - - INodeFactory& GetNodeFactory() { - return *NodeFactory; - } - - virtual TNodeDataBase* GetNodeById(size_t idx) { - return Nodes[idx].Get(); - } - - void InitNodes(); - void CleanupNodes(); - virtual void InitNodeImpl(TNodeDataBase*, size_t); - - static bool AllowSendFrom(TNodeDataBase* node, TAutoPtr<IEventHandle>& ev); - - protected: - THolder<INodeFactory> NodeFactory{new TDefaultNodeFactory}; - - private: - void InitNode(TNodeDataBase* node, size_t idx); - - struct TDispatchContext { - const TDispatchOptions* Options; - TDispatchContext* PrevContext; - - TMap<const TDispatchOptions::TFinalEventCondition*, ui32> FinalEventFrequency; - TSet<TEventMailboxId> FoundNonEmptyMailboxes; - bool FinalEventFound = false; - }; - - TProgramShouldContinue ShouldContinue; - TMap<ui32, TIntrusivePtr<TNodeDataBase>> Nodes; - ui64 CurrentTimestamp; - TSet<TActorId> EdgeActors; - THashMap<TEventMailboxId, TActorId, TEventMailboxId::THash> EdgeActorByMailbox; - TDuration DispatchTimeout; - TDuration ReschedulingDelay; - TEventObserver ObserverFunc; - TEventObserverCollection ObserverFuncs; - TScheduledEventsSelector ScheduledEventsSelectorFunc; - TEventFilter EventFilterFunc; - TScheduledEventFilter ScheduledEventFilterFunc; - TRegistrationObserver RegistrationObserver; - TSet<TActorId> BlockedOutput; - TSet<TActorId> ScheduleWhiteList; - THashMap<TActorId, TActorId> ScheduleWhiteListParent; - THashMap<TActorId, TString> ActorNames; - TDispatchContext* CurrentDispatchContext; - TVector<ui64> TxAllocatorTabletIds; - - static ui32 NextNodeId; - }; - - template <typename TEvent> - TEvent* FindEvent(TEventsList& events) { - for (auto& event : events) { - if (event && event->GetTypeRewrite() == TEvent::EventType) { - return event->CastAsLocal<TEvent>(); - } - } - - return nullptr; - } - - template <typename TEvent> - TEvent* FindEvent(TEventsList& events, const std::function<bool(const TEvent&)>& predicate) { - for (auto& event : events) { - if (event && event->GetTypeRewrite() == TEvent::EventType && predicate(*event->CastAsLocal<TEvent>())) { - return event->CastAsLocal<TEvent>(); - } - } - - return nullptr; - } - - template <typename TEvent> - TEvent* GrabEvent(TEventsList& events, TAutoPtr<IEventHandle>& ev) { - ev.Destroy(); - for (auto& event : events) { - if (event && event->GetTypeRewrite() == TEvent::EventType) { - ev = event; - return ev->CastAsLocal<TEvent>(); - } - } - - return nullptr; - } - - template <typename TEvent> - TEvent* GrabEvent(TEventsList& events, TAutoPtr<IEventHandle>& ev, - const std::function<bool(const typename TEvent::TPtr&)>& predicate) { - ev.Destroy(); - for (auto& event : events) { - if (event && event->GetTypeRewrite() == TEvent::EventType) { - if (predicate(reinterpret_cast<const typename TEvent::TPtr&>(event))) { - ev = event; - return ev->CastAsLocal<TEvent>(); - } - } - } - - return nullptr; - } - - class IStrandingDecoratorFactory { - public: - virtual ~IStrandingDecoratorFactory() {} - virtual IActor* Wrap(const TActorId& delegatee, bool isSync, const TVector<TActorId>& additionalActors) = 0; - }; - - struct IReplyChecker { - virtual ~IReplyChecker() {} - virtual void OnRequest(IEventHandle *request) = 0; - virtual bool IsWaitingForMoreResponses(IEventHandle *response) = 0; - }; - - struct TNoneReplyChecker : IReplyChecker { - void OnRequest(IEventHandle*) override { - } - - bool IsWaitingForMoreResponses(IEventHandle*) override { - return false; - } - }; - - using TReplyCheckerCreator = std::function<THolder<IReplyChecker>(void)>; - - inline THolder<IReplyChecker> CreateNoneReplyChecker() { - return MakeHolder<TNoneReplyChecker>(); - } - - TAutoPtr<IStrandingDecoratorFactory> CreateStrandingDecoratorFactory(TTestActorRuntimeBase* runtime, - TReplyCheckerCreator createReplyChecker = CreateNoneReplyChecker); - extern ui64 DefaultRandomSeed; -} diff --git a/library/cpp/actors/testlib/ut/CMakeLists.darwin-arm64.txt b/library/cpp/actors/testlib/ut/CMakeLists.darwin-arm64.txt deleted file mode 100644 index ae1df12ed6..0000000000 --- a/library/cpp/actors/testlib/ut/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,67 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-testlib-ut) -target_include_directories(library-cpp-actors-testlib-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/testlib -) -target_link_libraries(library-cpp-actors-testlib-ut PUBLIC - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-testlib - cpp-actors-core -) -target_link_options(library-cpp-actors-testlib-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-testlib-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/testlib/decorator_ut.cpp -) -set_property( - TARGET - library-cpp-actors-testlib-ut - PROPERTY - SPLIT_FACTOR - 10 -) -add_yunittest( - NAME - library-cpp-actors-testlib-ut - TEST_TARGET - library-cpp-actors-testlib-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-testlib-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-testlib-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-testlib-ut - system_allocator -) -vcs_info(library-cpp-actors-testlib-ut) diff --git a/library/cpp/actors/testlib/ut/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/testlib/ut/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 03d106c63f..0000000000 --- a/library/cpp/actors/testlib/ut/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,68 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-testlib-ut) -target_include_directories(library-cpp-actors-testlib-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/testlib -) -target_link_libraries(library-cpp-actors-testlib-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-testlib - cpp-actors-core -) -target_link_options(library-cpp-actors-testlib-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-testlib-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/testlib/decorator_ut.cpp -) -set_property( - TARGET - library-cpp-actors-testlib-ut - PROPERTY - SPLIT_FACTOR - 10 -) -add_yunittest( - NAME - library-cpp-actors-testlib-ut - TEST_TARGET - library-cpp-actors-testlib-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-testlib-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-testlib-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-testlib-ut - system_allocator -) -vcs_info(library-cpp-actors-testlib-ut) diff --git a/library/cpp/actors/testlib/ut/CMakeLists.linux-aarch64.txt b/library/cpp/actors/testlib/ut/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 598b6e53de..0000000000 --- a/library/cpp/actors/testlib/ut/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,71 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-testlib-ut) -target_include_directories(library-cpp-actors-testlib-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/testlib -) -target_link_libraries(library-cpp-actors-testlib-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-testlib - cpp-actors-core -) -target_link_options(library-cpp-actors-testlib-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-testlib-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/testlib/decorator_ut.cpp -) -set_property( - TARGET - library-cpp-actors-testlib-ut - PROPERTY - SPLIT_FACTOR - 10 -) -add_yunittest( - NAME - library-cpp-actors-testlib-ut - TEST_TARGET - library-cpp-actors-testlib-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-testlib-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-testlib-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-testlib-ut - cpp-malloc-jemalloc -) -vcs_info(library-cpp-actors-testlib-ut) diff --git a/library/cpp/actors/testlib/ut/CMakeLists.linux-x86_64.txt b/library/cpp/actors/testlib/ut/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 42713842da..0000000000 --- a/library/cpp/actors/testlib/ut/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,73 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-testlib-ut) -target_include_directories(library-cpp-actors-testlib-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/testlib -) -target_link_libraries(library-cpp-actors-testlib-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-testlib - cpp-actors-core -) -target_link_options(library-cpp-actors-testlib-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-testlib-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/testlib/decorator_ut.cpp -) -set_property( - TARGET - library-cpp-actors-testlib-ut - PROPERTY - SPLIT_FACTOR - 10 -) -add_yunittest( - NAME - library-cpp-actors-testlib-ut - TEST_TARGET - library-cpp-actors-testlib-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-testlib-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-testlib-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-testlib-ut - cpp-malloc-tcmalloc - libs-tcmalloc-no_percpu_cache -) -vcs_info(library-cpp-actors-testlib-ut) diff --git a/library/cpp/actors/testlib/ut/CMakeLists.txt b/library/cpp/actors/testlib/ut/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/testlib/ut/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/testlib/ut/CMakeLists.windows-x86_64.txt b/library/cpp/actors/testlib/ut/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 077ccae7fb..0000000000 --- a/library/cpp/actors/testlib/ut/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,61 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-testlib-ut) -target_include_directories(library-cpp-actors-testlib-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/testlib -) -target_link_libraries(library-cpp-actors-testlib-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-testlib - cpp-actors-core -) -target_sources(library-cpp-actors-testlib-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/testlib/decorator_ut.cpp -) -set_property( - TARGET - library-cpp-actors-testlib-ut - PROPERTY - SPLIT_FACTOR - 10 -) -add_yunittest( - NAME - library-cpp-actors-testlib-ut - TEST_TARGET - library-cpp-actors-testlib-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-testlib-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-testlib-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-testlib-ut - system_allocator -) -vcs_info(library-cpp-actors-testlib-ut) diff --git a/library/cpp/actors/testlib/ut/ya.make b/library/cpp/actors/testlib/ut/ya.make deleted file mode 100644 index ea6aef37a6..0000000000 --- a/library/cpp/actors/testlib/ut/ya.make +++ /dev/null @@ -1,15 +0,0 @@ -UNITTEST_FOR(library/cpp/actors/testlib) - -FORK_SUBTESTS() -SIZE(SMALL) - - -PEERDIR( - library/cpp/actors/core -) - -SRCS( - decorator_ut.cpp -) - -END() diff --git a/library/cpp/actors/testlib/ya.make b/library/cpp/actors/testlib/ya.make deleted file mode 100644 index 0bd44ddd57..0000000000 --- a/library/cpp/actors/testlib/ya.make +++ /dev/null @@ -1,23 +0,0 @@ -LIBRARY() - -SRCS( - test_runtime.cpp -) - -PEERDIR( - library/cpp/actors/core - library/cpp/actors/interconnect/mock - library/cpp/actors/protos - library/cpp/random_provider - library/cpp/time_provider -) - -IF (GCC) - CFLAGS(-fno-devirtualize-speculatively) -ENDIF() - -END() - -RECURSE_FOR_TESTS( - ut -) diff --git a/library/cpp/actors/util/CMakeLists.darwin-arm64.txt b/library/cpp/actors/util/CMakeLists.darwin-arm64.txt deleted file mode 100644 index be68d418f7..0000000000 --- a/library/cpp/actors/util/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,28 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-util) -target_link_libraries(cpp-actors-util PUBLIC - contrib-libs-cxxsupp - yutil - cpp-containers-absl_flat_hash - cpp-deprecated-atomic - library-cpp-pop_count -) -target_sources(cpp-actors-util PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/affinity.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_track.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/should_continue.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/threadparkpad.cpp -) diff --git a/library/cpp/actors/util/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/util/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index be68d418f7..0000000000 --- a/library/cpp/actors/util/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,28 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-util) -target_link_libraries(cpp-actors-util PUBLIC - contrib-libs-cxxsupp - yutil - cpp-containers-absl_flat_hash - cpp-deprecated-atomic - library-cpp-pop_count -) -target_sources(cpp-actors-util PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/affinity.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_track.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/should_continue.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/threadparkpad.cpp -) diff --git a/library/cpp/actors/util/CMakeLists.linux-aarch64.txt b/library/cpp/actors/util/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 9c5183c2bd..0000000000 --- a/library/cpp/actors/util/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,29 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-util) -target_link_libraries(cpp-actors-util PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-containers-absl_flat_hash - cpp-deprecated-atomic - library-cpp-pop_count -) -target_sources(cpp-actors-util PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/affinity.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_track.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/should_continue.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/threadparkpad.cpp -) diff --git a/library/cpp/actors/util/CMakeLists.linux-x86_64.txt b/library/cpp/actors/util/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 9c5183c2bd..0000000000 --- a/library/cpp/actors/util/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,29 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-util) -target_link_libraries(cpp-actors-util PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-containers-absl_flat_hash - cpp-deprecated-atomic - library-cpp-pop_count -) -target_sources(cpp-actors-util PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/affinity.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_track.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/should_continue.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/threadparkpad.cpp -) diff --git a/library/cpp/actors/util/CMakeLists.txt b/library/cpp/actors/util/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/util/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/util/CMakeLists.windows-x86_64.txt b/library/cpp/actors/util/CMakeLists.windows-x86_64.txt deleted file mode 100644 index be68d418f7..0000000000 --- a/library/cpp/actors/util/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,28 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-util) -target_link_libraries(cpp-actors-util PUBLIC - contrib-libs-cxxsupp - yutil - cpp-containers-absl_flat_hash - cpp-deprecated-atomic - library-cpp-pop_count -) -target_sources(cpp-actors-util PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/affinity.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_track.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/should_continue.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/threadparkpad.cpp -) diff --git a/library/cpp/actors/util/README.md b/library/cpp/actors/util/README.md deleted file mode 100644 index ff2d573fe8..0000000000 --- a/library/cpp/actors/util/README.md +++ /dev/null @@ -1,99 +0,0 @@ -## Memory tracker - -https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/actors/util/memory_track.h - -Использование: - -* отслеживание аллокаций экземпляров конкретного класса через new/delete и new[]/delete[] -* отслеживание аллокаций в контейнерах -* ручное отслеживание моментов аллокации/деаллокации - ----- - -### Отслеживание аллокаций класса через new/delete - -Использование с автоматически генерируемой меткой: - -```cpp -#include <library/cpp/actors/util/memory_track.h> - -struct TTypeLabeled - : public NActors::NMemory::TTrack<TTypeLabeled> -{ - char payload[16]; -}; -``` - -Использование с пользовательским именем метки: - -```cpp -#include <library/cpp/actors/util/memory_track.h> - -static const char NamedLabel[] = "NamedLabel"; - -struct TNameLabeled - : public NActors::NMemory::TTrack<TNameLabeled, NamedLabel> -{ - char payload[32]; -}; -``` - ----- - -### Отслеживание аллокаций в контейнерах - -```cpp -#include <library/cpp/actors/util/memory_track.h> - -static const char InContainerLabel[] = "InContainerLabel"; - -struct TInContainer { - char payload[16]; -}; - -std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer>> vecT; - -std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer, InContainerLabel>> vecN; - -using TKey = int; - -std::map<TKey, TInContainer, std::less<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> mapT; - -std::map<TKey, TInContainer, std::less<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> mapN; - -std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> umapT; - -std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> umapN; -``` - ----- - -### Ручное отслеживание аллокаций/деаллокаций - -```cpp -#include <library/cpp/actors/util/memory_track.h> - -static const char ManualLabel[] = "ManualLabel"; - -... -NActors::NMemory::TLabel<ManualLabel>::Add(size); - -... -NActors::NMemory::TLabel<ManualLabel>::Sub(size); -``` - ----- - -### Собираемые метрики - -Сервис **utils**, пользовательская метка **label**, сенсоры: - -- MT/Count: количество аллокаций в моменте -- MT/Memory: аллоцированная память в моменте -- MT/PeakCount: пиковое значение количества аллокаций (сэмплится с фиксированной частотой) -- MT/PeakMemory: пиковое значение аллоцированной памяти - diff --git a/library/cpp/actors/util/affinity.cpp b/library/cpp/actors/util/affinity.cpp deleted file mode 100644 index 5851105ae7..0000000000 --- a/library/cpp/actors/util/affinity.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "affinity.h" - -#ifdef _linux_ -#include <sched.h> -#endif - -class TAffinity::TImpl { -#ifdef _linux_ - cpu_set_t Mask; -#endif -public: - TImpl() { -#ifdef _linux_ - int ar = sched_getaffinity(0, sizeof(cpu_set_t), &Mask); - Y_DEBUG_ABORT_UNLESS(ar == 0); -#endif - } - - explicit TImpl(const ui8* cpus, ui32 size) { -#ifdef _linux_ - CPU_ZERO(&Mask); - for (ui32 i = 0; i != size; ++i) { - if (cpus[i]) { - CPU_SET(i, &Mask); - } - } -#else - Y_UNUSED(cpus); - Y_UNUSED(size); -#endif - } - - void Set() const { -#ifdef _linux_ - int ar = sched_setaffinity(0, sizeof(cpu_set_t), &Mask); - Y_DEBUG_ABORT_UNLESS(ar == 0); -#endif - } - - operator TCpuMask() const { - TCpuMask result; -#ifdef _linux_ - for (ui32 i = 0; i != CPU_SETSIZE; ++i) { - result.Cpus.emplace_back(CPU_ISSET(i, &Mask)); - } - result.RemoveTrailingZeros(); -#endif - return result; - } - -}; - -TAffinity::TAffinity() { -} - -TAffinity::~TAffinity() { -} - -TAffinity::TAffinity(const ui8* x, ui32 sz) { - if (x && sz) { - Impl.Reset(new TImpl(x, sz)); - } -} - -TAffinity::TAffinity(const TCpuMask& mask) { - if (!mask.IsEmpty()) { - static_assert(sizeof(ui8) == sizeof(mask.Cpus[0])); - const ui8* x = reinterpret_cast<const ui8*>(&mask.Cpus[0]); - const ui32 sz = mask.Size(); - Impl.Reset(new TImpl(x, sz)); - } -} - -void TAffinity::Current() { - Impl.Reset(new TImpl()); -} - -void TAffinity::Set() const { - if (!!Impl) { - Impl->Set(); - } -} - -bool TAffinity::Empty() const { - return !Impl; -} - -TAffinity::operator TCpuMask() const { - if (!!Impl) { - return *Impl; - } - return TCpuMask(); -} diff --git a/library/cpp/actors/util/affinity.h b/library/cpp/actors/util/affinity.h deleted file mode 100644 index ae106ed180..0000000000 --- a/library/cpp/actors/util/affinity.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include "defs.h" -#include "cpumask.h" - -// Platform-specific class to set or get thread affinity -class TAffinity: public TThrRefBase, TNonCopyable { - class TImpl; - THolder<TImpl> Impl; - -public: - TAffinity(); - TAffinity(const ui8* cpus, ui32 size); - explicit TAffinity(const TCpuMask& mask); - ~TAffinity(); - - void Current(); - void Set() const; - bool Empty() const; - - operator TCpuMask() const; -}; - -// Scoped affinity setter -class TAffinityGuard : TNonCopyable { - bool Stacked; - TAffinity OldAffinity; - -public: - TAffinityGuard(const TAffinity* affinity) { - Stacked = false; - if (affinity && !affinity->Empty()) { - OldAffinity.Current(); - affinity->Set(); - Stacked = true; - } - } - - ~TAffinityGuard() { - Release(); - } - - void Release() { - if (Stacked) { - OldAffinity.Set(); - Stacked = false; - } - } -}; diff --git a/library/cpp/actors/util/cpu_load_log.h b/library/cpp/actors/util/cpu_load_log.h deleted file mode 100644 index 225f7148da..0000000000 --- a/library/cpp/actors/util/cpu_load_log.h +++ /dev/null @@ -1,227 +0,0 @@ -#pragma once - -#include "defs.h" -#include <library/cpp/deprecated/atomic/atomic.h> -#include <library/cpp/pop_count/popcount.h> - -static constexpr ui64 BitDurationNs = 131'072; // A power of 2 - -template <ui64 DataSize> -struct TCpuLoadLog { - static constexpr ui64 BitsSize = DataSize * 64; - TAtomic LastTimeNs = 0; - ui64 Data[DataSize]; - - TCpuLoadLog() { - LastTimeNs = 0; - for (size_t i = 0; i < DataSize; ++i) { - Data[i] = 0; - } - } - - TCpuLoadLog(ui64 timeNs) { - LastTimeNs = timeNs; - for (size_t i = 0; i < DataSize; ++i) { - Data[i] = 0; - } - } - - void RegisterBusyPeriod(ui64 timeNs) { - RegisterBusyPeriod<true>(timeNs, AtomicGet(LastTimeNs)); - } - - template <bool ModifyLastTime> - void RegisterBusyPeriod(ui64 timeNs, ui64 lastTimeNs) { - timeNs |= 1ull; - if (timeNs < lastTimeNs) { - for (ui64 i = 0; i < DataSize; ++i) { - AtomicSet(Data[i], ~0ull); - } - if (ModifyLastTime) { - AtomicSet(LastTimeNs, timeNs); - } - return; - } - const ui64 lastIdx = timeNs / BitDurationNs; - const ui64 curIdx = lastTimeNs / BitDurationNs; - ui64 firstElementIdx = curIdx / 64; - const ui64 firstBitIdx = curIdx % 64; - const ui64 lastElementIdx = lastIdx / 64; - const ui64 lastBitIdx = lastIdx % 64; - if (firstElementIdx == lastElementIdx) { - ui64 prevValue = 0; - if (firstBitIdx != 0) { - prevValue = AtomicGet(Data[firstElementIdx % DataSize]); - } - const ui64 bits = (((~0ull) << (firstBitIdx + (63-lastBitIdx))) >> (63-lastBitIdx)); - const ui64 newValue = prevValue | bits; - AtomicSet(Data[firstElementIdx % DataSize], newValue); - if (ModifyLastTime) { - AtomicSet(LastTimeNs, timeNs); - } - return; - } - // process the first element - ui64 prevValue = 0; - if (firstBitIdx != 0) { - prevValue = AtomicGet(Data[firstElementIdx % DataSize]); - } - const ui64 bits = ((~0ull) << firstBitIdx); - const ui64 newValue = (prevValue | bits); - AtomicSet(Data[firstElementIdx % DataSize], newValue); - ++firstElementIdx; - // process the fully filled elements - const ui64 firstLoop = firstElementIdx / DataSize; - const ui64 lastLoop = lastElementIdx / DataSize; - const ui64 lastOffset = lastElementIdx % DataSize; - if (firstLoop < lastLoop) { - for (ui64 i = firstElementIdx % DataSize; i < DataSize; ++i) { - AtomicSet(Data[i], ~0ull); - } - for (ui64 i = 0; i < lastOffset; ++i) { - AtomicSet(Data[i], ~0ull); - } - } else { - for (ui64 i = firstElementIdx % DataSize; i < lastOffset; ++i) { - AtomicSet(Data[i], ~0ull); - } - } - // process the last element - const ui64 newValue2 = ((~0ull) >> (63-lastBitIdx)); - AtomicSet(Data[lastOffset], newValue2); - if (ModifyLastTime) { - AtomicSet(LastTimeNs, timeNs); - } - } - - void RegisterIdlePeriod(ui64 timeNs) { - timeNs &= ~1ull; - ui64 lastTimeNs = AtomicGet(LastTimeNs); - if (timeNs < lastTimeNs) { - // Fast check first, slower chec later - if ((timeNs | 1ull) < lastTimeNs) { - // Time goes back, dont panic, just mark the whole array 'busy' - for (ui64 i = 0; i < DataSize; ++i) { - AtomicSet(Data[i], ~0ull); - } - AtomicSet(LastTimeNs, timeNs); - return; - } - } - const ui64 curIdx = lastTimeNs / BitDurationNs; - const ui64 lastIdx = timeNs / BitDurationNs; - ui64 firstElementIdx = curIdx / 64; - const ui64 lastElementIdx = lastIdx / 64; - if (firstElementIdx >= lastElementIdx) { - AtomicSet(LastTimeNs, timeNs); - return; - } - // process the first partially filled element - ++firstElementIdx; - // process all other elements - const ui64 firstLoop = firstElementIdx / DataSize; - const ui64 lastLoop = lastElementIdx / DataSize; - const ui64 lastOffset = lastElementIdx % DataSize; - if (firstLoop < lastLoop) { - for (ui64 i = firstElementIdx % DataSize; i < DataSize; ++i) { - AtomicSet(Data[i], 0); - } - for (ui64 i = 0; i <= lastOffset; ++i) { - AtomicSet(Data[i], 0); - } - } else { - for (ui64 i = firstElementIdx % DataSize; i <= lastOffset; ++i) { - AtomicSet(Data[i], 0); - } - } - AtomicSet(LastTimeNs, timeNs); - } -}; - -template <ui64 DataSize> -struct TMinusOneCpuEstimator { - static constexpr ui64 BitsSize = DataSize * 64; - ui64 BeginDelayIdx; - ui64 EndDelayIdx; - ui64 Idle; - ui64 Delay[BitsSize]; - - ui64 MaxLatencyIncreaseWithOneLessCpu(TCpuLoadLog<DataSize>** logs, i64 logCount, ui64 timeNs, ui64 periodNs) { - Y_ABORT_UNLESS(logCount > 0); - ui64 endTimeNs = timeNs; - - ui64 lastTimeNs = timeNs; - for (i64 log_idx = 0; log_idx < logCount; ++log_idx) { - ui64 x = AtomicGet(logs[log_idx]->LastTimeNs); - if ((x & 1) == 1) { - lastTimeNs = Min(lastTimeNs, x); - } else { - logs[log_idx]->template RegisterBusyPeriod<false>(endTimeNs, x); - } - } - const ui64 beginTimeNs = periodNs < timeNs ? timeNs - periodNs : 0; - - ui64 beginIdx = beginTimeNs / BitDurationNs; - ui64 lastIdx = lastTimeNs / BitDurationNs; - ui64 beginElementIdx = beginIdx / 64; - ui64 lastElementIdx = lastIdx / 64; - - BeginDelayIdx = 0; - EndDelayIdx = 0; - Idle = 0; - ui64 maxDelay = 0; - ui64 bucket = 0; - for (ui64 idx = beginElementIdx; idx <= lastElementIdx; ++idx) { - ui64 i = idx % DataSize; - ui64 input = AtomicGet(logs[0]->Data[i]); - ui64 all_busy = ~0ull; - for (i64 log_idx = 1; log_idx < logCount; ++log_idx) { - ui64 x = AtomicGet(logs[log_idx]->Data[i]); - all_busy &= x; - } - if (!input) { - if (!bucket) { - Idle += 64 - PopCount(all_busy); - continue; - } - } - for (i64 bit_idx = 0; bit_idx < 64; ++bit_idx) { - ui64 x = (1ull << bit_idx); - if (all_busy & x) { - if (input & x) { - // Push into the queue - bucket++; - Delay[EndDelayIdx] = EndDelayIdx; - ++EndDelayIdx; - } else { - // All busy - } - } else { - if (input & x) { - // Move success - } else { - if (bucket) { - // Remove from the queue - bucket--; - ui64 stored = Delay[BeginDelayIdx]; - ++BeginDelayIdx; - ui64 delay = EndDelayIdx - stored; - maxDelay = Max(maxDelay, delay); - //Cerr << "bit_idx: " << bit_idx << " stored: " << stored << " delay: " << delay << Endl; - } else { - Idle++; - } - } - } - } - } - if (bucket) { - ui64 stored = Delay[BeginDelayIdx]; - ui64 delay = EndDelayIdx - stored; - maxDelay = Max(maxDelay, delay); - //Cerr << "last stored: " << stored << " delay: " << delay << Endl; - } - return maxDelay * BitDurationNs; - } -}; - diff --git a/library/cpp/actors/util/cpu_load_log_ut.cpp b/library/cpp/actors/util/cpu_load_log_ut.cpp deleted file mode 100644 index 7109123c6e..0000000000 --- a/library/cpp/actors/util/cpu_load_log_ut.cpp +++ /dev/null @@ -1,275 +0,0 @@ -#include "cpu_load_log.h" - -#include <library/cpp/testing/unittest/registar.h> -#include <util/random/random.h> -#include <util/system/hp_timer.h> -#include <util/system/sanitizers.h> -#include <util/system/thread.h> - -Y_UNIT_TEST_SUITE(CpuLoadLog) { - - TString PrintBits(ui64 x) { - TStringStream str; - for (ui64 i = 0; i < 64; ++i) { - if (x & (1ull << i)) { - str << "1"; - } else { - str << "0"; - } - } - return str.Str(); - } - - Y_UNIT_TEST(FillAll) { - TCpuLoadLog<5> log(100*BitDurationNs); - log.RegisterBusyPeriod(101*BitDurationNs); - log.RegisterBusyPeriod(163*BitDurationNs); - log.RegisterBusyPeriod(164*BitDurationNs); - log.RegisterBusyPeriod(165*BitDurationNs); - log.RegisterBusyPeriod(331*BitDurationNs); - log.RegisterBusyPeriod(340*BitDurationNs); - log.RegisterBusyPeriod(420*BitDurationNs); - log.RegisterBusyPeriod(511*BitDurationNs); - //for (ui64 i = 0; i < 5; ++i) { - // Cerr << "i: " << i << " bits: " << PrintBits(log.Data[i]) << Endl; - //} - for (ui64 i = 0; i < 5; ++i) { - UNIT_ASSERT_C((ui64(log.Data[i]) == ~ui64(0)), "Unequal at " << i << "\n got: " << PrintBits(log.Data[i]) - << "\n expected: " << PrintBits(~ui64(0))); - } - } - - Y_UNIT_TEST(PartialFill) { - TCpuLoadLog<5> log(0*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(0b0ull)); - log.RegisterBusyPeriod(0*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(0b1ull)); - log.RegisterBusyPeriod(0*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(0b1ull)); - log.RegisterBusyPeriod(1*BitDurationNs/2); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(0b1ull)); - log.RegisterBusyPeriod(1*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(0b11ull)); - log.RegisterIdlePeriod(3*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(0b11ull)); - log.RegisterBusyPeriod(3*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(0b1011ull)); - log.RegisterBusyPeriod(63*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits((~0ull)^0b0100ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(0b0ull)); - log.RegisterBusyPeriod(128*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits((~0ull)^0b0100ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[2]), PrintBits(0b1ull)); - log.RegisterBusyPeriod(1*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[2]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[3]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[4]), PrintBits(~0ull)); - log.RegisterBusyPeriod(2*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[2]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[3]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[4]), PrintBits(~0ull)); - log.RegisterBusyPeriod(64*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(0b1ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[2]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[3]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[4]), PrintBits(~0ull)); - log.RegisterIdlePeriod(128*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(0b1ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[2]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[3]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[4]), PrintBits(~0ull)); - log.RegisterIdlePeriod(192*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(0b1ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[2]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[3]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[4]), PrintBits(~0ull)); - log.RegisterBusyPeriod(192*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(0b1ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[2]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[3]), PrintBits(0b1ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[4]), PrintBits(~0ull)); - log.RegisterIdlePeriod((192+5*64-1)*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[2]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[3]), PrintBits(0b1ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[4]), PrintBits(0ull)); - log.RegisterIdlePeriod((192+15*64)*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[2]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[3]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[4]), PrintBits(0ull)); - } - - Y_UNIT_TEST(Estimator) { - TCpuLoadLog<5> *log[10]; - log[0] = new TCpuLoadLog<5>(0*BitDurationNs); - log[1] = new TCpuLoadLog<5>(0*BitDurationNs); - TMinusOneCpuEstimator<5> estimator; - - - for (ui64 i = 0; i < 5*64; i+=2) { - log[0]->RegisterIdlePeriod(i*BitDurationNs); - log[0]->RegisterBusyPeriod(i*BitDurationNs); - } - log[0]->RegisterIdlePeriod((5*64-2)*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log[0]->Data[0]), - PrintBits(0b0101010101010101010101010101010101010101010101010101010101010101ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log[0]->Data[4]), - PrintBits(0b0101010101010101010101010101010101010101010101010101010101010101ull)); - for (ui64 i = 0; i < 5*64-1; i+=2) { - log[1]->RegisterIdlePeriod((i+1)*BitDurationNs); - log[1]->RegisterBusyPeriod((i+1)*BitDurationNs); - } - log[1]->RegisterIdlePeriod((5*64-2+1)*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log[1]->Data[0]), - PrintBits(0b1010101010101010101010101010101010101010101010101010101010101010ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log[1]->Data[4]), - PrintBits(0b1010101010101010101010101010101010101010101010101010101010101010ull)); - - ui64 value = estimator.MaxLatencyIncreaseWithOneLessCpu(log, 2, (5*64)*BitDurationNs-1, 3*64*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(value/BitDurationNs, 1); - - value = estimator.MaxLatencyIncreaseWithOneLessCpu(log, 2, (5*64+10)*BitDurationNs, 3*64*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(value/BitDurationNs, 12); - - delete log[0]; - delete log[1]; - } - - Y_UNIT_TEST(Estimator2) { - TCpuLoadLog<5> *log[2]; - log[0] = new TCpuLoadLog<5>(0*BitDurationNs); - log[1] = new TCpuLoadLog<5>(0*BitDurationNs); - TMinusOneCpuEstimator<5> estimator; - - for (ui64 i = 0; i < 5*64; i+=2) { - log[0]->RegisterIdlePeriod(i*BitDurationNs); - log[0]->RegisterBusyPeriod(i*BitDurationNs); - } - for (ui64 i = 0; i < 5; ++i) { - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log[0]->Data[i]), - PrintBits(0b0101010101010101010101010101010101010101010101010101010101010101ull)); - } - for (ui64 i = 0; i < 5*64-1; i+=2) { - log[1]->RegisterIdlePeriod((i+1)*BitDurationNs); - log[1]->RegisterBusyPeriod((i+1)*BitDurationNs); - } - for (ui64 i = 0; i < 5; ++i) { - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log[1]->Data[i]), - PrintBits(0b1010101010101010101010101010101010101010101010101010101010101010ull)); - } - - log[0]->Data[2] = ~0ull; - ui64 value = estimator.MaxLatencyIncreaseWithOneLessCpu(log, 2, (5*64-1)*BitDurationNs, 3*64*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(value/BitDurationNs, 32); - - delete log[0]; - delete log[1]; - } - - Y_UNIT_TEST(Estimator3) { - TCpuLoadLog<5> *log[3]; - log[0] = new TCpuLoadLog<5>(0*BitDurationNs); - log[1] = new TCpuLoadLog<5>(0*BitDurationNs); - log[2] = new TCpuLoadLog<5>(0*BitDurationNs); - TMinusOneCpuEstimator<5> estimator; - - for (ui64 i = 0; i < 5*64; i+=8) { - log[0]->RegisterIdlePeriod(i*BitDurationNs); - log[0]->RegisterBusyPeriod((i+3)*BitDurationNs); - log[1]->RegisterIdlePeriod(i*BitDurationNs); - log[1]->RegisterBusyPeriod((i+3)*BitDurationNs); - log[2]->RegisterIdlePeriod(i*BitDurationNs); - log[2]->RegisterBusyPeriod((i+3)*BitDurationNs); - } - for (ui64 i = 0; i < 5; ++i) { - for (ui64 n = 0; n < 3; ++n) { - UNIT_ASSERT_VALUES_EQUAL_C(PrintBits(log[n]->Data[i]), - PrintBits(0b0000111100001111000011110000111100001111000011110000111100001111ull), - " i: " << i << " n: " << n); - } - } - - ui64 value = estimator.MaxLatencyIncreaseWithOneLessCpu(log, 3, (5*64-5)*BitDurationNs, 3*64*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(value/BitDurationNs, 4); - - delete log[0]; - delete log[1]; - delete log[2]; - } - /* - class TWorkerThread : public ISimpleThread { - private: - std::function<void()> Func; - double Time = 0.0; - - public: - TWorkerThread(std::function<void()> func) - : Func(std::move(func)) - { } - - double GetTime() const { - return Time; - } - - static THolder<TWorkerThread> Spawn(std::function<void()> func) { - THolder<TWorkerThread> thread = MakeHolder<TWorkerThread>(std::move(func)); - thread->Start(); - return thread; - } - - private: - void* ThreadProc() noexcept override { - THPTimer timer; - Func(); - Time = timer.Passed(); - return nullptr; - } - }; - - void DoConcurrentPushPop(size_t threads, ui64 perThreadCount) { - // Concurrency factor 4 is up to 16 threads - - auto workerFunc = [&](size_t threadIndex) { - }; - - TVector<THolder<TWorkerThread>> workers(threads); - for (size_t i = 0; i < threads; ++i) { - workers[i] = TWorkerThread::Spawn([workerFunc, i]() { - workerFunc(i); - }); - } - - double maxTime = 0; - for (size_t i = 0; i < threads; ++i) { - workers[i]->Join(); - maxTime = Max(maxTime, workers[i]->GetTime()); - } - - UNIT_ASSERT_VALUES_EQUAL(popped, 0u); - - Cerr << "Concurrent with " << threads << " threads: " << maxTime << " seconds" << Endl; - } - - void DoConcurrentPushPop_3times(size_t threads, ui64 perThreadCount) { - for (size_t i = 0; i < 3; ++i) { - DoConcurrentPushPop(threads, perThreadCount); - } - } - - static constexpr ui64 PER_THREAD_COUNT = NSan::PlainOrUnderSanitizer(1000000, 100000); - - Y_UNIT_TEST(ConcurrentPushPop_1thread) { DoConcurrentPushPop_3times(1, PER_THREAD_COUNT); } - */ -} diff --git a/library/cpp/actors/util/cpumask.h b/library/cpp/actors/util/cpumask.h deleted file mode 100644 index 29741aa1d6..0000000000 --- a/library/cpp/actors/util/cpumask.h +++ /dev/null @@ -1,133 +0,0 @@ -#pragma once - -#include "defs.h" - -#include <library/cpp/containers/stack_vector/stack_vec.h> - -#include <util/string/split.h> -#include <util/generic/yexception.h> - -using TCpuId = ui32; - -// Simple data structure to operate with set of cpus -struct TCpuMask { - TStackVec<bool, 1024> Cpus; - - // Creates empty mask - TCpuMask() {} - - // Creates mask with single cpu set - explicit TCpuMask(TCpuId cpuId) { - Set(cpuId); - } - - // Initialize mask from raw boolean array - template <class T> - TCpuMask(const T* cpus, TCpuId size) { - Cpus.reserve(size); - for (TCpuId i = 0; i != size; ++i) { - Cpus.emplace_back(bool(cpus[i])); - } - } - - // Parse a numerical list of processors. The numbers are separated by commas and may include ranges. For example: 0,5,7,9-11 - explicit TCpuMask(const TString& cpuList) { - try { - for (TStringBuf s : StringSplitter(cpuList).Split(',')) { - TCpuId l, r; - if (s.find('-') != TString::npos) { - StringSplitter(s).Split('-').CollectInto(&l, &r); - } else { - l = r = FromString<TCpuId>(s); - } - if (r >= Cpus.size()) { - Cpus.resize(r + 1, false); - } - for (TCpuId cpu = l; cpu <= r; cpu++) { - Cpus[cpu] = true; - } - } - } catch (...) { - ythrow TWithBackTrace<yexception>() << "Exception occured while parsing cpu list '" << cpuList << "': " << CurrentExceptionMessage(); - } - } - - // Returns size of underlying vector - TCpuId Size() const { - return Cpus.size(); - } - - // Returns number of set bits in mask - TCpuId CpuCount() const { - TCpuId result = 0; - for (bool value : Cpus) { - result += value; - } - return result; - } - - bool IsEmpty() const { - for (bool value : Cpus) { - if (value) { - return false; - } - } - return true; - } - - bool IsSet(TCpuId cpu) const { - return cpu < Cpus.size() && Cpus[cpu]; - } - - void Set(TCpuId cpu) { - if (cpu >= Cpus.size()) { - Cpus.resize(cpu + 1, false); - } - Cpus[cpu] = true; - } - - void Reset(TCpuId cpu) { - if (cpu < Cpus.size()) { - Cpus[cpu] = false; - } - } - - void RemoveTrailingZeros() { - while (!Cpus.empty() && !Cpus.back()) { - Cpus.pop_back(); - } - } - - explicit operator bool() const { - return !IsEmpty(); - } - - TCpuMask operator &(const TCpuMask& rhs) const { - TCpuMask result; - TCpuId size = Max(Size(), rhs.Size()); - result.Cpus.reserve(size); - for (TCpuId cpu = 0; cpu < size; cpu++) { - result.Cpus.emplace_back(IsSet(cpu) && rhs.IsSet(cpu)); - } - return result; - } - - TCpuMask operator |(const TCpuMask& rhs) const { - TCpuMask result; - TCpuId size = Max(Size(), rhs.Size()); - result.Cpus.reserve(size); - for (TCpuId cpu = 0; cpu < size; cpu++) { - result.Cpus.emplace_back(IsSet(cpu) || rhs.IsSet(cpu)); - } - return result; - } - - TCpuMask operator -(const TCpuMask& rhs) const { - TCpuMask result; - result.Cpus.reserve(Size()); - for (TCpuId cpu = 0; cpu < Size(); cpu++) { - result.Cpus.emplace_back(IsSet(cpu) && !rhs.IsSet(cpu)); - } - return result; - } -}; diff --git a/library/cpp/actors/util/datetime.h b/library/cpp/actors/util/datetime.h deleted file mode 100644 index cbec5965d6..0000000000 --- a/library/cpp/actors/util/datetime.h +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include <util/system/defaults.h> -#include <util/system/hp_timer.h> -#include <util/system/platform.h> - -#if defined(_win_) -#include <intrin.h> -#pragma intrinsic(__rdtsc) -#endif // _win_ - -#if defined(_darwin_) && !defined(_x86_) -#include <mach/mach_time.h> -#endif - -// GetCycleCount() from util/system/datetime.h uses rdtscp, which is more accurate than rdtsc, -// but rdtscp disables processor's out-of-order execution, so it can be slow -Y_FORCE_INLINE ui64 GetCycleCountFast() { -#if defined(_MSC_VER) - // Generates the rdtsc instruction, which returns the processor time stamp. - // The processor time stamp records the number of clock cycles since the last reset. - return __rdtsc(); -#elif defined(__clang__) && !defined(_arm64_) - return __builtin_readcyclecounter(); -#elif defined(_x86_64_) - unsigned hi, lo; - __asm__ __volatile__("rdtsc" - : "=a"(lo), "=d"(hi)); - return ((unsigned long long)lo) | (((unsigned long long)hi) << 32); -#elif defined(_i386_) - ui64 x; - __asm__ volatile("rdtsc\n\t" - : "=A"(x)); - return x; -#elif defined(_darwin_) - return mach_absolute_time(); -#elif defined(_arm32_) - return MicroSeconds(); -#elif defined(_arm64_) - ui64 x; - - __asm__ __volatile__("isb; mrs %0, cntvct_el0" - : "=r"(x)); - - return x; -#else -#error "unsupported arch" -#endif -} - -// NHPTimer::GetTime fast analog -Y_FORCE_INLINE void GetTimeFast(NHPTimer::STime* pTime) noexcept { - *pTime = GetCycleCountFast(); -} - -namespace NActors { - inline double Ts2Ns(ui64 ts) { - return NHPTimer::GetSeconds(ts) * 1e9; - } - - inline double Ts2Us(ui64 ts) { - return NHPTimer::GetSeconds(ts) * 1e6; - } - - inline double Ts2Ms(ui64 ts) { - return NHPTimer::GetSeconds(ts) * 1e3; - } - - inline ui64 Us2Ts(double us) { - return ui64(NHPTimer::GetClockRate() * us / 1e6); - } - - struct TTimeTracker { - ui64 Ts; - TTimeTracker(): Ts(GetCycleCountFast()) {} - ui64 Elapsed() { - ui64 ts = GetCycleCountFast(); - std::swap(Ts, ts); - return Ts - ts; - } - }; -} diff --git a/library/cpp/actors/util/defs.h b/library/cpp/actors/util/defs.h deleted file mode 100644 index 70f969753e..0000000000 --- a/library/cpp/actors/util/defs.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -// unique tag to fix pragma once gcc glueing: ./library/actors/util/defs.h - -#include <util/system/defaults.h> -#include <util/generic/bt_exception.h> -#include <util/generic/noncopyable.h> -#include <util/generic/ptr.h> -#include <util/generic/string.h> -#include <util/generic/yexception.h> -#include <library/cpp/deprecated/atomic/atomic.h> -#include <util/system/align.h> -#include <util/generic/vector.h> -#include <util/datetime/base.h> -#include <util/generic/ylimits.h> -#include "intrinsics.h" diff --git a/library/cpp/actors/util/funnel_queue.h b/library/cpp/actors/util/funnel_queue.h deleted file mode 100644 index 15af57b121..0000000000 --- a/library/cpp/actors/util/funnel_queue.h +++ /dev/null @@ -1,240 +0,0 @@ -#pragma once - -#include <library/cpp/deprecated/atomic/atomic.h> -#include <util/generic/noncopyable.h> - -template <typename ElementType> -class TFunnelQueue: private TNonCopyable { -public: - TFunnelQueue() noexcept - : Front(nullptr) - , Back(nullptr) - { - } - - virtual ~TFunnelQueue() noexcept { - for (auto entry = Front; entry; entry = DeleteEntry(entry)) - continue; - } - - /// Push element. Can be used from many threads. Return true if is first element. - bool - Push(ElementType&& element) noexcept { - TEntry* const next = NewEntry(static_cast<ElementType&&>(element)); - TEntry* const prev = AtomicSwap(&Back, next); - AtomicSet(prev ? prev->Next : Front, next); - return !prev; - } - - /// Extract top element. Must be used only from one thread. Return true if have more. - bool - Pop() noexcept { - if (TEntry* const top = AtomicGet(Front)) { - const auto last = AtomicCas(&Back, nullptr, top); - if (last) // This is last element in queue. Queue is empty now. - AtomicCas(&Front, nullptr, top); - else // This element is not last. - for (;;) { - if (const auto next = AtomicGet(top->Next)) { - AtomicSet(Front, next); - break; - } - // But Next is null. Wait next assignment in spin lock. - } - - DeleteEntry(top); - return !last; - } - - return false; - } - - /// Peek top element. Must be used only from one thread. - ElementType& - Top() const noexcept { - return AtomicGet(Front)->Data; - } - - bool - IsEmpty() const noexcept { - return !AtomicGet(Front); - } - -protected: - class TEntry: private TNonCopyable { - friend class TFunnelQueue; - - private: - explicit TEntry(ElementType&& element) noexcept - : Data(static_cast<ElementType&&>(element)) - , Next(nullptr) - { - } - - ~TEntry() noexcept { - } - - public: - ElementType Data; - TEntry* volatile Next; - }; - - TEntry* volatile Front; - TEntry* volatile Back; - - virtual TEntry* NewEntry(ElementType&& element) noexcept { - return new TEntry(static_cast<ElementType&&>(element)); - } - - virtual TEntry* DeleteEntry(TEntry* entry) noexcept { - const auto next = entry->Next; - delete entry; - return next; - } - -protected: - struct TEntryIter { - TEntry* ptr; - - ElementType& operator*() { - return ptr->Data; - } - - ElementType* operator->() { - return &ptr->Data; - } - - TEntryIter& operator++() { - ptr = AtomicGet(ptr->Next); - return *this; - } - - bool operator!=(const TEntryIter& other) const { - return ptr != other.ptr; - } - - bool operator==(const TEntryIter& other) const { - return ptr == other.ptr; - } - }; - - struct TConstEntryIter { - const TEntry* ptr; - - const ElementType& operator*() { - return ptr->Data; - } - - const ElementType* operator->() { - return &ptr->Data; - } - - TEntryIter& operator++() { - ptr = AtomicGet(ptr->Next); - return *this; - } - - bool operator!=(const TConstEntryIter& other) const { - return ptr != other.ptr; - } - - bool operator==(const TConstEntryIter& other) const { - return ptr == other.ptr; - } - }; - -public: - using const_iterator = TConstEntryIter; - using iterator = TEntryIter; - - iterator begin() { - return {AtomicGet(Front)}; - } - const_iterator cbegin() { - return {AtomicGet(Front)}; - } - const_iterator begin() const { - return {AtomicGet(Front)}; - } - - iterator end() { - return {nullptr}; - } - const_iterator cend() { - return {nullptr}; - } - const_iterator end() const { - return {nullptr}; - } -}; - -template <typename ElementType> -class TPooledFunnelQueue: public TFunnelQueue<ElementType> { -public: - TPooledFunnelQueue() noexcept - : Stack(nullptr) - { - } - - virtual ~TPooledFunnelQueue() noexcept override { - for (auto entry = TBase::Front; entry; entry = TBase::DeleteEntry(entry)) - continue; - for (auto entry = Stack; entry; entry = TBase::DeleteEntry(entry)) - continue; - TBase::Back = TBase::Front = Stack = nullptr; - } - -private: - typedef TFunnelQueue<ElementType> TBase; - - typename TBase::TEntry* volatile Stack; - -protected: - virtual typename TBase::TEntry* NewEntry(ElementType&& element) noexcept override { - while (const auto top = AtomicGet(Stack)) - if (AtomicCas(&Stack, top->Next, top)) { - top->Data = static_cast<ElementType&&>(element); - AtomicSet(top->Next, nullptr); - return top; - } - - return TBase::NewEntry(static_cast<ElementType&&>(element)); - } - - virtual typename TBase::TEntry* DeleteEntry(typename TBase::TEntry* entry) noexcept override { - entry->Data = ElementType(); - const auto next = entry->Next; - do - AtomicSet(entry->Next, AtomicGet(Stack)); - while (!AtomicCas(&Stack, entry, entry->Next)); - return next; - } -}; - -template <typename ElementType, template <typename T> class TQueueType = TFunnelQueue> -class TCountedFunnelQueue: public TQueueType<ElementType> { -public: - TCountedFunnelQueue() noexcept - : Count(0) - { - } - - TAtomicBase GetSize() const noexcept { - return AtomicGet(Count); - } - -private: - typedef TQueueType<ElementType> TBase; - - virtual typename TBase::TEntry* NewEntry(ElementType&& element) noexcept override { - AtomicAdd(Count, 1); - return TBase::NewEntry(static_cast<ElementType&&>(element)); - } - - virtual typename TBase::TEntry* DeleteEntry(typename TBase::TEntry* entry) noexcept override { - AtomicSub(Count, 1); - return TBase::DeleteEntry(entry); - } - - TAtomic Count; -}; diff --git a/library/cpp/actors/util/futex.h b/library/cpp/actors/util/futex.h deleted file mode 100644 index c193f8d128..0000000000 --- a/library/cpp/actors/util/futex.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#ifdef _linux_ - -#include <linux/futex.h> -#include <unistd.h> -#include <sys/syscall.h> - -static long SysFutex(void* addr1, int op, int val1, struct timespec* timeout, void* addr2, int val3) { - return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3); -} - -#endif diff --git a/library/cpp/actors/util/intrinsics.h b/library/cpp/actors/util/intrinsics.h deleted file mode 100644 index c02b633b70..0000000000 --- a/library/cpp/actors/util/intrinsics.h +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once - -#include <util/system/defaults.h> -#include <library/cpp/deprecated/atomic/atomic.h> -#include <util/system/spinlock.h> - -#include <library/cpp/sse/sse.h> // The header chooses appropriate SSE support - -static_assert(sizeof(TAtomic) == 8, "expect sizeof(TAtomic) == 8"); - -// we need explicit 32 bit operations to keep cache-line friendly packs -// so have to define some atomics additionaly to arcadia one -#ifdef _win_ -#pragma intrinsic(_InterlockedCompareExchange) -#pragma intrinsic(_InterlockedExchangeAdd) -#pragma intrinsic(_InterlockedIncrement) -#pragma intrinsic(_InterlockedDecrement) -#endif - -inline bool AtomicUi32Cas(volatile ui32* a, ui32 exchange, ui32 compare) { -#ifdef _win_ - return _InterlockedCompareExchange((volatile long*)a, exchange, compare) == (long)compare; -#else - ui32 expected = compare; - return __atomic_compare_exchange_n(a, &expected, exchange, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); -#endif -} - -inline ui32 AtomicUi32Add(volatile ui32* a, ui32 add) { -#ifdef _win_ - return _InterlockedExchangeAdd((volatile long*)a, add) + add; -#else - return __atomic_add_fetch(a, add, __ATOMIC_SEQ_CST); -#endif -} - -inline ui32 AtomicUi32Sub(volatile ui32* a, ui32 sub) { -#ifdef _win_ - return _InterlockedExchangeAdd((volatile long*)a, -(long)sub) - sub; -#else - return __atomic_sub_fetch(a, sub, __ATOMIC_SEQ_CST); -#endif -} - -inline ui32 AtomicUi32Increment(volatile ui32* a) { -#ifdef _win_ - return _InterlockedIncrement((volatile long*)a); -#else - return __atomic_add_fetch(a, 1, __ATOMIC_SEQ_CST); -#endif -} - -inline ui32 AtomicUi32Decrement(volatile ui32* a) { -#ifdef _win_ - return _InterlockedDecrement((volatile long*)a); -#else - return __atomic_sub_fetch(a, 1, __ATOMIC_SEQ_CST); -#endif -} - -template <typename T> -inline void AtomicStore(volatile T* a, T x) { - static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value"); -#ifdef _win_ - *a = x; -#else - __atomic_store_n(a, x, __ATOMIC_RELEASE); -#endif -} - -template <typename T> -inline void RelaxedStore(volatile T* a, T x) { - static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value"); -#ifdef _win_ - *a = x; -#else - __atomic_store_n(a, x, __ATOMIC_RELAXED); -#endif -} - -template <typename T> -inline T AtomicLoad(volatile T* a) { -#ifdef _win_ - return *a; -#else - return __atomic_load_n(a, __ATOMIC_ACQUIRE); -#endif -} - -template <typename T> -inline T RelaxedLoad(volatile T* a) { -#ifdef _win_ - return *a; -#else - return __atomic_load_n(a, __ATOMIC_RELAXED); -#endif -} diff --git a/library/cpp/actors/util/local_process_key.h b/library/cpp/actors/util/local_process_key.h deleted file mode 100644 index bff8bef81b..0000000000 --- a/library/cpp/actors/util/local_process_key.h +++ /dev/null @@ -1,157 +0,0 @@ -#pragma once - -#include <util/string/builder.h> -#include <util/system/mutex.h> -#include <util/generic/strbuf.h> -#include <util/generic/vector.h> -#include <util/generic/hash.h> -#include <util/generic/singleton.h> -#include <util/generic/serialized_enum.h> - -class TLocalProcessKeyStateIndexLimiter { -public: - static constexpr ui32 GetMaxKeysCount() { - return 10000; - } -}; - -template <class T> -class TLocalProcessKeyStateIndexConstructor { -public: -}; - -template <typename T> -class TLocalProcessKeyState { - -template <typename U, const char* Name> -friend class TLocalProcessKey; -template <typename U, class TClass, ui32 KeyLengthLimit> -friend class TLocalProcessExtKey; -template <typename U, typename EnumT> -friend class TEnumProcessKey; - -public: - static TLocalProcessKeyState& GetInstance() { - return *Singleton<TLocalProcessKeyState<T>>(); - } - - ui32 GetCount() const { - return MaxKeysCount; - } - - TStringBuf GetNameByIndex(size_t index) const { - Y_ABORT_UNLESS(index < Names.size()); - return Names[index]; - } - - size_t GetIndexByName(TStringBuf name) const { - TGuard<TMutex> g(Mutex); - auto it = Map.find(name); - Y_ENSURE(it != Map.end()); - return it->second; - } - - TLocalProcessKeyState() { - Names.resize(MaxKeysCount); - } - - size_t Register(TStringBuf name) { - TGuard<TMutex> g(Mutex); - auto it = Map.find(name); - if (it != Map.end()) { - return it->second; - } - const ui32 index = TLocalProcessKeyStateIndexConstructor<T>::BuildCurrentIndex(name, Names.size()); - auto x = Map.emplace(name, index); - if (x.second) { - Y_ABORT_UNLESS(index < Names.size(), "a lot of actors or tags for memory monitoring"); - Names[index] = name; - } - - return x.first->second; - } - -private: - - static constexpr ui32 MaxKeysCount = TLocalProcessKeyStateIndexLimiter::GetMaxKeysCount(); - -private: - TVector<TString> Names; - THashMap<TString, size_t> Map; - TMutex Mutex; -}; - -template <typename T, const char* Name> -class TLocalProcessKey { -public: - static TStringBuf GetName() { - return Name; - } - - static size_t GetIndex() { - return Index; - } - -private: - inline static size_t Index = TLocalProcessKeyState<T>::GetInstance().Register(Name); -}; - -template <typename T, class TClass, ui32 KeyLengthLimit = 0> -class TLocalProcessExtKey { -public: - static TStringBuf GetName() { - return Name; - } - - static size_t GetIndex() { - return Index; - } - -private: - - static TString TypeNameRobust() { - const TString className = TypeName<TClass>(); - if (KeyLengthLimit && className.size() > KeyLengthLimit) { - return className.substr(0, KeyLengthLimit - 3) + "..."; - } else { - return className; - } - } - - static const inline TString Name = TypeName<TClass>(); - inline static size_t Index = TLocalProcessKeyState<T>::GetInstance().Register(TypeNameRobust()); -}; - -template <typename T, typename EnumT> -class TEnumProcessKey { -public: - static TStringBuf GetName(const EnumT key) { - return TLocalProcessKeyState<T>::GetInstance().GetNameByIndex(GetIndex(key)); - } - - static size_t GetIndex(const EnumT key) { - ui32 index = static_cast<ui32>(key); - Y_ABORT_UNLESS(index < Enum2Index.size()); - return Enum2Index[index]; - } - -private: - inline static TVector<size_t> RegisterAll() { - static_assert(std::is_enum<EnumT>::value, "Enum is required"); - - TVector<size_t> enum2Index; - auto names = GetEnumNames<EnumT>(); - ui32 maxId = 0; - for (const auto& [k, v] : names) { - maxId = Max(maxId, static_cast<ui32>(k)); - } - enum2Index.resize(maxId + 1); - for (const auto& [k, v] : names) { - ui32 enumId = static_cast<ui32>(k); - enum2Index[enumId] = TLocalProcessKeyState<T>::GetInstance().Register(v); - } - return enum2Index; - } - - inline static TVector<size_t> Enum2Index = RegisterAll(); -}; diff --git a/library/cpp/actors/util/memory_track.cpp b/library/cpp/actors/util/memory_track.cpp deleted file mode 100644 index 5f422116be..0000000000 --- a/library/cpp/actors/util/memory_track.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "memory_track.h" -#include "memory_tracker.h" - -namespace NActors { -namespace NMemory { - -namespace NPrivate { - -TThreadLocalInfo::TThreadLocalInfo() - : Metrics(TMemoryTracker::Instance()->GetCount()) -{ - TMemoryTracker::Instance()->OnCreateThread(this); -} - -TThreadLocalInfo::~TThreadLocalInfo() { - TMemoryTracker::Instance()->OnDestroyThread(this); -} - -TMetric* TThreadLocalInfo::GetMetric(size_t index) { - if (Y_UNLIKELY(index >= Metrics.size())) { - return &Null; - } - return &Metrics[index]; -} - -const std::vector<TMetric>& TThreadLocalInfo::GetMetrics() const { - return Metrics; -} - -size_t TBaseLabel::RegisterStaticMemoryLabel(const char* name, bool hasSensor) { - return TMemoryTracker::Instance()->RegisterStaticMemoryLabel(name, hasSensor); -} - -} - -} -} - diff --git a/library/cpp/actors/util/memory_track.h b/library/cpp/actors/util/memory_track.h deleted file mode 100644 index 6035333eeb..0000000000 --- a/library/cpp/actors/util/memory_track.h +++ /dev/null @@ -1,293 +0,0 @@ -#pragma once - -#include <vector> - -#include <util/system/type_name.h> -#include <util/thread/singleton.h> - -#define ENABLE_MEMORY_TRACKING - -namespace NActors { -namespace NMemory { - -namespace NPrivate { - -class TMetric { - std::atomic<ssize_t> Memory; - std::atomic<ssize_t> Count; - - void Copy(const TMetric& other) { - Memory.store(other.GetMemory(), std::memory_order_relaxed); - Count.store(other.GetCount(), std::memory_order_relaxed); - } - -public: - TMetric() - : Memory(0) - , Count(0) - {} - - inline TMetric(const TMetric& other) { - Copy(other); - } - - inline TMetric(TMetric&& other) { - Copy(other); - } - - inline TMetric& operator=(const TMetric& other) { - Copy(other); - return *this; - } - - inline TMetric& operator=(TMetric&& other) { - Copy(other); - return *this; - } - - inline ssize_t GetMemory() const { - return Memory.load(std::memory_order_relaxed); - } - inline void SetMemory(ssize_t value) { - Memory.store(value, std::memory_order_relaxed); - } - - inline ssize_t GetCount() const { - return Count.load(std::memory_order_relaxed); - } - inline void SetCount(ssize_t value) { - Count.store(value, std::memory_order_relaxed); - } - - inline void operator+=(const TMetric& other) { - SetMemory(GetMemory() + other.GetMemory()); - SetCount(GetCount() + other.GetCount()); - } - - inline void CalculatePeak(const TMetric& other) { - SetMemory(Max(GetMemory(), other.GetMemory())); - SetCount(Max(GetCount(), other.GetCount())); - } - - inline void Add(size_t size) { - SetMemory(GetMemory() + size); - SetCount(GetCount() + 1); - } - - inline void Sub(size_t size) { - SetMemory(GetMemory() - size); - SetCount(GetCount() - 1); - } -}; - - -class TThreadLocalInfo { -public: - TThreadLocalInfo(); - ~TThreadLocalInfo(); - - TMetric* GetMetric(size_t index); - const std::vector<TMetric>& GetMetrics() const; - -private: - std::vector<TMetric> Metrics; - - inline static TMetric Null = {}; -}; - - -class TBaseLabel { -protected: - static size_t RegisterStaticMemoryLabel(const char* name, bool hasSensor); - - inline static TMetric* GetLocalMetric(size_t index) { - return FastTlsSingleton<TThreadLocalInfo>()->GetMetric(index); - } -}; - - -template <const char* Name> -class TNameLabel - : TBaseLabel -{ -public: - static void Add(size_t size) { -#if defined(ENABLE_MEMORY_TRACKING) - Y_UNUSED(MetricInit); - - if (Y_UNLIKELY(!Metric)) { - Metric = GetLocalMetric(Index); - } - - Metric->Add(size); -#else - Y_UNUSED(size); -#endif - } - - static void Sub(size_t size) { -#if defined(ENABLE_MEMORY_TRACKING) - Y_UNUSED(MetricInit); - - if (Y_UNLIKELY(!Metric)) { - Metric = GetLocalMetric(Index); - } - - Metric->Sub(size); -#else - Y_UNUSED(size); -#endif - } - -private: -#if defined(ENABLE_MEMORY_TRACKING) - inline static size_t Index = Max<size_t>(); - inline static struct TMetricInit { - TMetricInit() { - Index = RegisterStaticMemoryLabel(Name, true); - } - } MetricInit; - - inline static thread_local TMetric* Metric = nullptr; -#endif -}; - - -template <typename TType> -class TTypeLabel - : TBaseLabel -{ -public: - static void Add(size_t size) { -#if defined(ENABLE_MEMORY_TRACKING) - Y_UNUSED(MetricInit); - - if (Y_UNLIKELY(!Metric)) { - Metric = GetLocalMetric(Index); - } - - Metric->Add(size); -#else - Y_UNUSED(size); -#endif - } - - static void Sub(size_t size) { -#if defined(ENABLE_MEMORY_TRACKING) - Y_UNUSED(MetricInit); - - if (Y_UNLIKELY(!Metric)) { - Metric = GetLocalMetric(Index); - } - - Metric->Sub(size); -#else - Y_UNUSED(size); -#endif - } - -private: -#if defined(ENABLE_MEMORY_TRACKING) - inline static size_t Index = Max<size_t>(); - inline static struct TMetricInit { - TMetricInit() { - Index = RegisterStaticMemoryLabel(TypeName<TType>().c_str(), false); - } - } MetricInit; - - inline static thread_local TMetric* Metric = nullptr; -#endif -}; - - -template <typename T> -struct TTrackHelper { -#if defined(ENABLE_MEMORY_TRACKING) - void* operator new(size_t size) { - T::Add(size); - return malloc(size); - } - - void* operator new[](size_t size) { - T::Add(size); - return malloc(size); - } - - void operator delete(void* ptr, size_t size) { - T::Sub(size); - free(ptr); - } - - void operator delete[](void* ptr, size_t size) { - T::Sub(size); - free(ptr); - } -#endif -}; - -template <typename TType, typename T> -struct TAllocHelper { - typedef size_t size_type; - typedef TType value_type; - typedef TType* pointer; - typedef const TType* const_pointer; - - struct propagate_on_container_copy_assignment : public std::false_type {}; - struct propagate_on_container_move_assignment : public std::false_type {}; - struct propagate_on_container_swap : public std::false_type {}; - - pointer allocate(size_type n, const void* hint = nullptr) { - Y_UNUSED(hint); - auto size = n * sizeof(TType); - T::Add(size); - return (pointer)malloc(size); - } - - void deallocate(pointer ptr, size_t n) { - auto size = n * sizeof(TType); - T::Sub(size); - free((void*)ptr); - } -}; - -} // NPrivate - - -template <const char* Name> -using TLabel = NPrivate::TNameLabel<Name>; - -template <typename TType, const char* Name = nullptr> -struct TTrack - : public NPrivate::TTrackHelper<NPrivate::TNameLabel<Name>> -{ -}; - -template <typename TType> -struct TTrack<TType, nullptr> - : public NPrivate::TTrackHelper<NPrivate::TTypeLabel<TType>> -{ -}; - -template <typename TType, const char* Name = nullptr> -struct TAlloc - : public NPrivate::TAllocHelper<TType, NPrivate::TNameLabel<Name>> -{ - template<typename U> - struct rebind { - typedef TAlloc<U, Name> other; - }; -}; - -template <typename TType> -struct TAlloc<TType, nullptr> - : public NPrivate::TAllocHelper<TType, NPrivate::TTypeLabel<TType>> -{ - template<typename U> - struct rebind { - typedef TAlloc<U> other; - }; -}; - -} -} - diff --git a/library/cpp/actors/util/memory_tracker.cpp b/library/cpp/actors/util/memory_tracker.cpp deleted file mode 100644 index 8a12452c71..0000000000 --- a/library/cpp/actors/util/memory_tracker.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "memory_tracker.h" - -#include <util/generic/xrange.h> - -namespace NActors { -namespace NMemory { - -namespace NPrivate { - -TMemoryTracker* TMemoryTracker::Instance() { - return SingletonWithPriority<TMemoryTracker, 0>(); -} - -void TMemoryTracker::Initialize() { - GlobalMetrics.resize(Indices.size()); -} - -const std::map<TString, size_t>& TMemoryTracker::GetMetricIndices() const { - return Indices; -} - -const std::unordered_set<size_t>& TMemoryTracker::GetSensors() const { - return Sensors; -} - -TString TMemoryTracker::GetName(size_t index) const { - return Names[index]; -} - -size_t TMemoryTracker::GetCount() const { - return Indices.size(); -} - -void TMemoryTracker::GatherMetrics(std::vector<TMetric>& metrics) const { - metrics.resize(0); - auto count = GetCount(); - - if (!count || GlobalMetrics.size() != count) { - return; - } - - TReadGuard guard(LockThreadInfo); - - metrics.resize(count); - for (size_t i : xrange(count)) { - metrics[i] += GlobalMetrics[i]; - } - - for (auto info : ThreadInfo) { - auto& localMetrics = info->GetMetrics(); - if (localMetrics.size() == count) { - for (size_t i : xrange(count)) { - metrics[i] += localMetrics[i]; - } - } - } -} - -size_t TMemoryTracker::RegisterStaticMemoryLabel(const char* name, bool hasSensor) { - size_t index = 0; - auto found = Indices.find(name); - if (found == Indices.end()) { - TString str(name); - auto next = Names.size(); - Indices.emplace(str, next); - Names.push_back(str); - index = next; - } else { - index = found->second; - } - - if (hasSensor) { - Sensors.emplace(index); - } - return index; -} - -void TMemoryTracker::OnCreateThread(TThreadLocalInfo* info) { - TWriteGuard guard(LockThreadInfo); - ThreadInfo.insert(info); -} - -void TMemoryTracker::OnDestroyThread(TThreadLocalInfo* info) { - TWriteGuard guard(LockThreadInfo); - - auto count = GetCount(); - if (count && GlobalMetrics.size() == count) { - const auto& localMetrics = info->GetMetrics(); - if (localMetrics.size() == count) { - for (size_t i : xrange(count)) { - GlobalMetrics[i] += localMetrics[i]; - } - } - } - - ThreadInfo.erase(info); -} - -} - -} -} - diff --git a/library/cpp/actors/util/memory_tracker.h b/library/cpp/actors/util/memory_tracker.h deleted file mode 100644 index e74508191b..0000000000 --- a/library/cpp/actors/util/memory_tracker.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include "memory_track.h" - -#include <map> -#include <unordered_map> -#include <unordered_set> - -#include <util/system/rwlock.h> - -namespace NActors { -namespace NMemory { - -namespace NPrivate { - -class TMemoryTracker { -public: - static TMemoryTracker* Instance(); - - void Initialize(); - - const std::map<TString, size_t>& GetMetricIndices() const; - const std::unordered_set<size_t>& GetSensors() const; - TString GetName(size_t index) const; - size_t GetCount() const; - - void GatherMetrics(std::vector<TMetric>& metrics) const; - -private: - size_t RegisterStaticMemoryLabel(const char* name, bool hasSensor); - - void OnCreateThread(TThreadLocalInfo* info); - void OnDestroyThread(TThreadLocalInfo* info); - -private: - std::map<TString, size_t> Indices; - std::vector<TString> Names; - - std::vector<TMetric> GlobalMetrics; - - std::unordered_set<size_t> Sensors; - - std::unordered_set<TThreadLocalInfo*> ThreadInfo; - TRWMutex LockThreadInfo; - - friend class TThreadLocalInfo; - friend class TBaseLabel; -}; - -} - -} -} diff --git a/library/cpp/actors/util/memory_tracker_ut.cpp b/library/cpp/actors/util/memory_tracker_ut.cpp deleted file mode 100644 index 1b8eff7cc5..0000000000 --- a/library/cpp/actors/util/memory_tracker_ut.cpp +++ /dev/null @@ -1,263 +0,0 @@ -#include "memory_tracker.h" - -#include <library/cpp/testing/unittest/registar.h> - -#include <util/system/hp_timer.h> -#include <util/system/thread.h> - -namespace NActors { -namespace NMemory { - -Y_UNIT_TEST_SUITE(TMemoryTrackerTest) { - -#if defined(ENABLE_MEMORY_TRACKING) - -using namespace NPrivate; - -size_t FindLabelIndex(const char* label) { - auto indices = TMemoryTracker::Instance()->GetMetricIndices(); - auto it = indices.find(label); - UNIT_ASSERT(it != indices.end()); - return it->second; -} - - -struct TTypeLabeled - : public NActors::NMemory::TTrack<TTypeLabeled> -{ - char payload[16]; -}; - -static constexpr char NamedLabel[] = "NamedLabel"; - -struct TNameLabeled - : public NActors::NMemory::TTrack<TNameLabeled, NamedLabel> -{ - char payload[32]; -}; - -#ifndef _win_ -Y_UNIT_TEST(Gathering) -{ - TMemoryTracker::Instance()->Initialize(); - - auto* typed = new TTypeLabeled; - auto* typedArray = new TTypeLabeled[3]; - - auto* named = new TNameLabeled; - auto* namedArray = new TNameLabeled[5]; - NActors::NMemory::TLabel<NamedLabel>::Add(100); - - std::vector<TMetric> metrics; - TMemoryTracker::Instance()->GatherMetrics(metrics); - - auto typeIndex = FindLabelIndex(TypeName<TTypeLabeled>().c_str()); - UNIT_ASSERT(typeIndex < metrics.size()); - UNIT_ASSERT(metrics[typeIndex].GetMemory() == sizeof(TTypeLabeled) * 4 + sizeof(size_t)); - UNIT_ASSERT(metrics[typeIndex].GetCount() == 2); - - auto nameIndex = FindLabelIndex(NamedLabel); - UNIT_ASSERT(nameIndex < metrics.size()); - UNIT_ASSERT(metrics[nameIndex].GetMemory() == sizeof(TNameLabeled) * 6 + sizeof(size_t) + 100); - UNIT_ASSERT(metrics[nameIndex].GetCount() == 3); - - NActors::NMemory::TLabel<NamedLabel>::Sub(100); - delete [] namedArray; - delete named; - - delete [] typedArray; - delete typed; - - TMemoryTracker::Instance()->GatherMetrics(metrics); - - UNIT_ASSERT(metrics[typeIndex].GetMemory() == 0); - UNIT_ASSERT(metrics[typeIndex].GetCount() == 0); - - UNIT_ASSERT(metrics[nameIndex].GetMemory() == 0); - UNIT_ASSERT(metrics[nameIndex].GetCount() == 0); -} -#endif - -static constexpr char InContainerLabel[] = "InContainerLabel"; - -struct TInContainer { - char payload[16]; -}; - -Y_UNIT_TEST(Containers) { - TMemoryTracker::Instance()->Initialize(); - - std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer>> vecT; - vecT.resize(5); - - std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer, InContainerLabel>> vecN; - vecN.resize(7); - - using TKey = int; - - std::map<TKey, TInContainer, std::less<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> mapT; - mapT.emplace(0, TInContainer()); - mapT.emplace(1, TInContainer()); - - std::map<TKey, TInContainer, std::less<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> mapN; - mapN.emplace(0, TInContainer()); - - std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> umapT; - umapT.emplace(0, TInContainer()); - - std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> umapN; - umapN.emplace(0, TInContainer()); - umapN.emplace(1, TInContainer()); - - std::vector<TMetric> metrics; - TMemoryTracker::Instance()->GatherMetrics(metrics); - - auto indices = TMemoryTracker::Instance()->GetMetricIndices(); - for (auto& [name, index] : indices) { - Cerr << "---- " << name - << ": memory = " << metrics[index].GetMemory() - << ", count = " << metrics[index].GetCount() << Endl; - } - - auto vecTIndex = FindLabelIndex(TypeName<TInContainer>().c_str()); - UNIT_ASSERT(metrics[vecTIndex].GetMemory() >= ssize_t(sizeof(TInContainer) * 5)); - UNIT_ASSERT(metrics[vecTIndex].GetCount() == 1); - - auto labelIndex = FindLabelIndex(InContainerLabel); - UNIT_ASSERT(metrics[labelIndex].GetCount() == 5); - UNIT_ASSERT(metrics[labelIndex].GetMemory() >= ssize_t( - sizeof(TInContainer) * 7 + - sizeof(decltype(mapN)::value_type) + - sizeof(decltype(umapN)::value_type) * 2)); -} - - -static constexpr char InThreadLabel[] = "InThreadLabel"; - -struct TInThread - : public NActors::NMemory::TTrack<TInThread, InThreadLabel> -{ - char payload[16]; -}; - -void* ThreadProc(void*) { - return new TInThread; -} - -Y_UNIT_TEST(Threads) { - TMemoryTracker::Instance()->Initialize(); - - auto index = FindLabelIndex(InThreadLabel); - - auto* object1 = new TInThread; - - std::vector<TMetric> metrics; - TMemoryTracker::Instance()->GatherMetrics(metrics); - UNIT_ASSERT(metrics[index].GetMemory() == sizeof(TInThread)); - UNIT_ASSERT(metrics[index].GetCount() == 1); - - TThread thread(&ThreadProc, nullptr); - thread.Start(); - auto* object2 = static_cast<TInThread*>(thread.Join()); - - TMemoryTracker::Instance()->GatherMetrics(metrics); - UNIT_ASSERT(metrics[index].GetMemory() == sizeof(TInThread) * 2); - UNIT_ASSERT(metrics[index].GetCount() == 2); - - delete object2; - - TMemoryTracker::Instance()->GatherMetrics(metrics); - UNIT_ASSERT(metrics[index].GetMemory() == sizeof(TInThread)); - UNIT_ASSERT(metrics[index].GetCount() == 1); - - delete object1; -} - - -struct TNotTracked { - char payload[16]; -}; - -struct TTracked - : public NActors::NMemory::TTrack<TTracked> -{ - char payload[16]; -}; - -template <typename T> -double MeasureAllocations() { - constexpr size_t objectsCount = 4 << 20; - - std::vector<T*> objects; - objects.resize(objectsCount); - - THPTimer timer; - - for (size_t i = 0; i < objectsCount; ++i) { - objects[i] = new T; - } - - for (size_t i = 0; i < objectsCount; ++i) { - delete objects[i]; - } - - auto seconds = timer.Passed(); - Cerr << "---- objects: " << objectsCount << ", time: " << seconds << Endl; - return seconds; -} - -Y_UNIT_TEST(Performance) { - TMemoryTracker::Instance()->Initialize(); - - constexpr size_t Runs = 16; - - Cerr << "---- warmup" << Endl; - MeasureAllocations<TNotTracked>(); - MeasureAllocations<TTracked>(); - - std::vector<double> noTrack; - std::vector<double> track; - - for (size_t run = 0; run < Runs; ++run) { - Cerr << "---- no track" << Endl; - auto time = MeasureAllocations<TNotTracked>(); - noTrack.push_back(time); - - Cerr << "---- track" << Endl; - time = MeasureAllocations<TTracked>(); - track.push_back(time); - } - - double meanNoTrack = 0, stddevNoTrack = 0; - double meanTrack = 0, stddevTrack = 0; - for (size_t i = 0; i < Runs; ++i) { - meanNoTrack += noTrack[i]; - meanTrack += track[i]; - } - meanNoTrack /= Runs; - meanTrack /= Runs; - - auto sqr = [](double val) { return val * val; }; - - for (size_t i = 0; i < Runs; ++i) { - stddevNoTrack += sqr(noTrack[i] - meanNoTrack); - stddevTrack += sqr(track[i] - meanTrack); - } - stddevNoTrack = sqrt(stddevNoTrack / (Runs - 1)); - stddevTrack = sqrt(stddevTrack / (Runs - 1)); - - Cerr << "---- no track - mean: " << meanNoTrack << ", stddev: " << stddevNoTrack << Endl; - Cerr << "---- track - mean: " << meanTrack << ", stddev: " << stddevTrack << Endl; - Cerr << "---- tracking is slower by " << int((meanTrack / meanNoTrack - 1.0) * 100) << "%" << Endl; -} - -#endif - -} - -} -} diff --git a/library/cpp/actors/util/named_tuple.h b/library/cpp/actors/util/named_tuple.h deleted file mode 100644 index 67f185bba8..0000000000 --- a/library/cpp/actors/util/named_tuple.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "defs.h" - -template <typename TDerived> -struct TNamedTupleBase { - friend bool operator==(const TDerived& x, const TDerived& y) { - return x.ConvertToTuple() == y.ConvertToTuple(); - } - - friend bool operator!=(const TDerived& x, const TDerived& y) { - return x.ConvertToTuple() != y.ConvertToTuple(); - } - - friend bool operator<(const TDerived& x, const TDerived& y) { - return x.ConvertToTuple() < y.ConvertToTuple(); - } - - friend bool operator<=(const TDerived& x, const TDerived& y) { - return x.ConvertToTuple() <= y.ConvertToTuple(); - } - - friend bool operator>(const TDerived& x, const TDerived& y) { - return x.ConvertToTuple() > y.ConvertToTuple(); - } - - friend bool operator>=(const TDerived& x, const TDerived& y) { - return x.ConvertToTuple() >= y.ConvertToTuple(); - } -}; diff --git a/library/cpp/actors/util/queue_chunk.h b/library/cpp/actors/util/queue_chunk.h deleted file mode 100644 index 8a4e02d8cb..0000000000 --- a/library/cpp/actors/util/queue_chunk.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "defs.h" - -template <typename T, ui32 TSize, typename TDerived> -struct TQueueChunkDerived { - static const ui32 EntriesCount = (TSize - sizeof(TQueueChunkDerived*)) / sizeof(T); - static_assert(EntriesCount > 0, "expect EntriesCount > 0"); - - volatile T Entries[EntriesCount]; - TDerived* volatile Next; - - TQueueChunkDerived() { - memset(this, 0, sizeof(TQueueChunkDerived)); - } -}; - -template <typename T, ui32 TSize> -struct TQueueChunk { - static const ui32 EntriesCount = (TSize - sizeof(TQueueChunk*)) / sizeof(T); - static_assert(EntriesCount > 0, "expect EntriesCount > 0"); - - volatile T Entries[EntriesCount]; - TQueueChunk* volatile Next; - - TQueueChunk() { - memset(this, 0, sizeof(TQueueChunk)); - } -}; diff --git a/library/cpp/actors/util/queue_oneone_inplace.h b/library/cpp/actors/util/queue_oneone_inplace.h deleted file mode 100644 index 288011955a..0000000000 --- a/library/cpp/actors/util/queue_oneone_inplace.h +++ /dev/null @@ -1,118 +0,0 @@ -#pragma once - -#include "defs.h" -#include "queue_chunk.h" - -template <typename T, ui32 TSize, typename TChunk = TQueueChunk<T, TSize>> -class TOneOneQueueInplace : TNonCopyable { - static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::valuer"); - - TChunk* ReadFrom; - ui32 ReadPosition; - ui32 WritePosition; - TChunk* WriteTo; - - friend class TReadIterator; - -public: - class TReadIterator { - TChunk* ReadFrom; - ui32 ReadPosition; - - public: - TReadIterator(TChunk* readFrom, ui32 readPosition) - : ReadFrom(readFrom) - , ReadPosition(readPosition) - { - } - - inline T Next() { - TChunk* head = ReadFrom; - if (ReadPosition != TChunk::EntriesCount) { - return AtomicLoad(&head->Entries[ReadPosition++]); - } else if (TChunk* next = AtomicLoad(&head->Next)) { - ReadFrom = next; - ReadPosition = 0; - return Next(); - } - return T{}; - } - }; - - TOneOneQueueInplace() - : ReadFrom(new TChunk()) - , ReadPosition(0) - , WritePosition(0) - , WriteTo(ReadFrom) - { - } - - ~TOneOneQueueInplace() { - Y_DEBUG_ABORT_UNLESS(Head() == 0); - delete ReadFrom; - } - - struct TPtrCleanDestructor { - static inline void Destroy(TOneOneQueueInplace<T, TSize>* x) noexcept { - while (T head = x->Pop()) - delete head; - delete x; - } - }; - - struct TCleanDestructor { - static inline void Destroy(TOneOneQueueInplace<T, TSize>* x) noexcept { - while (x->Pop() != nullptr) - continue; - delete x; - } - }; - - struct TPtrCleanInplaceMallocDestructor { - template <typename TPtrVal> - static inline void Destroy(TOneOneQueueInplace<TPtrVal*, TSize>* x) noexcept { - while (TPtrVal* head = x->Pop()) { - head->~TPtrVal(); - free(head); - } - delete x; - } - }; - - void Push(T x) noexcept { - if (WritePosition != TChunk::EntriesCount) { - AtomicStore(&WriteTo->Entries[WritePosition], x); - ++WritePosition; - } else { - TChunk* next = new TChunk(); - next->Entries[0] = x; - AtomicStore(&WriteTo->Next, next); - WriteTo = next; - WritePosition = 1; - } - } - - T Head() { - TChunk* head = ReadFrom; - if (ReadPosition != TChunk::EntriesCount) { - return AtomicLoad(&head->Entries[ReadPosition]); - } else if (TChunk* next = AtomicLoad(&head->Next)) { - ReadFrom = next; - delete head; - ReadPosition = 0; - return Head(); - } - return T{}; - } - - T Pop() { - T ret = Head(); - if (ret) - ++ReadPosition; - return ret; - } - - TReadIterator Iterator() { - return TReadIterator(ReadFrom, ReadPosition); - } -}; diff --git a/library/cpp/actors/util/rc_buf.cpp b/library/cpp/actors/util/rc_buf.cpp deleted file mode 100644 index 946c9846ee..0000000000 --- a/library/cpp/actors/util/rc_buf.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "rc_buf.h" - -template<> -void Out<TRcBuf>(IOutputStream& s, const TRcBuf& x) { - s.Write(TStringBuf(x)); -} diff --git a/library/cpp/actors/util/rc_buf.h b/library/cpp/actors/util/rc_buf.h deleted file mode 100644 index db0f7deff5..0000000000 --- a/library/cpp/actors/util/rc_buf.h +++ /dev/null @@ -1,1120 +0,0 @@ -#pragma once - -#include <atomic> -#include <new> - -#include <util/generic/ptr.h> -#include <util/generic/string.h> -#include <util/generic/hash_set.h> -#include <util/generic/scope.h> -#include <util/stream/str.h> -#include <util/system/sanitizers.h> -#include <util/system/valgrind.h> -#include <util/generic/array_ref.h> -#include <util/system/sys_alloc.h> - -#include "shared_data.h" -#include "rc_buf_backend.h" - -#ifdef KIKIMR_TRACE_CONTIGUOUS_DATA_GROW -#include "shared_data_backtracing_owner.h" -#endif - -namespace NContiguousDataDetails { - template<typename TContainer> - struct TContainerTraits { - static char* UnsafeGetDataMut(const TContainer& backend) { - return const_cast<char*>(backend.data()); - } - }; -} // NContiguousDataDetails - -class TContiguousSpan -{ -private: - const char *Data_ = nullptr; - size_t Size_ = 0; - -public: - TContiguousSpan() = default; - - TContiguousSpan(const char *data, size_t size) - : Data_(data) - , Size_(size) - {} - - TContiguousSpan(const TString& str) - : Data_(str.data()) - , Size_(str.size()) - {} - - TContiguousSpan(const TStringBuf& str) - : Data_(str.data()) - , Size_(str.size()) - {} - - TContiguousSpan(const TArrayRef<char>& ref) - : Data_(ref.data()) - , Size_(ref.size()) - {} - - TContiguousSpan(const TArrayRef<const char>& ref) - : Data_(ref.data()) - , Size_(ref.size()) - {} - - TContiguousSpan(const NActors::TSharedData& data) - : Data_(data.data()) - , Size_(data.size()) - {} - - const char& operator[](size_t index) const { - Y_DEBUG_ABORT_UNLESS(index < Size_); - return Data_[index]; - } - - const char *data() const noexcept { - return Data_; - } - - size_t size() const noexcept { - return Size_; - } - - const char *GetData() const noexcept { - return Data_; - } - - size_t GetSize() const noexcept { - return Size_; - } - - const char *Data() const noexcept { - return Data_; - } - - size_t Size() const noexcept { - return Size_; - } - - TContiguousSpan SubSpan(size_t pos, size_t n) const noexcept { - pos = Min(pos, size()); - n = Min(n, size() - pos); - return TContiguousSpan(data() + pos, n); - } - - template<std::size_t Index> - auto get() const noexcept - { - static_assert(Index < 2, - "Index out of bounds for TContiguousSpan"); - if constexpr (Index == 0) return Data_; - if constexpr (Index == 1) return Size_; - } - - friend bool operator==(const TContiguousSpan& x, const TContiguousSpan& y) { return Compare(x, y) == 0; } - friend bool operator!=(const TContiguousSpan& x, const TContiguousSpan& y) { return Compare(x, y) != 0; } - friend bool operator< (const TContiguousSpan& x, const TContiguousSpan& y) { return Compare(x, y) < 0; } - friend bool operator<=(const TContiguousSpan& x, const TContiguousSpan& y) { return Compare(x, y) <= 0; } - friend bool operator> (const TContiguousSpan& x, const TContiguousSpan& y) { return Compare(x, y) > 0; } - friend bool operator>=(const TContiguousSpan& x, const TContiguousSpan& y) { return Compare(x, y) >= 0; } - -private: - static int Compare(const TContiguousSpan& x, const TContiguousSpan& y) { - int res = 0; - if (const size_t common = std::min(x.size(), y.size())) { - res = std::memcmp(x.data(), y.data(), common); - } - return res ? res : x.size() - y.size(); - } -}; - - - -namespace std -{ - template<> - struct tuple_size<::TContiguousSpan> - : integral_constant<size_t, 2> {}; - - template<> - struct tuple_element<0, ::TContiguousSpan> - { - using type = const char *; - }; - - template<> - struct tuple_element<1, ::TContiguousSpan> - { - using type = size_t; - }; -} - -template < - class TLeft, - class TRight, - typename std::enable_if<std::is_convertible<TLeft,TContiguousSpan>::value>::type* = nullptr, - typename std::enable_if<std::is_convertible<TRight,TContiguousSpan>::value>::type* = nullptr - > -bool operator==(const TLeft& lhs, const TRight& rhs) { - return TContiguousSpan(lhs) == TContiguousSpan(rhs); -} - -template < - class TLeft, - class TRight, - typename std::enable_if<std::is_convertible<TLeft,TContiguousSpan>::value>::type* = nullptr, - typename std::enable_if<std::is_convertible<TRight,TContiguousSpan>::value>::type* = nullptr - > -bool operator!=(const TLeft& lhs, const TRight& rhs) { - return TContiguousSpan(lhs) != TContiguousSpan(rhs); -} - -template < - class TLeft, - class TRight, - typename std::enable_if<std::is_convertible<TLeft,TContiguousSpan>::value>::type* = nullptr, - typename std::enable_if<std::is_convertible<TRight,TContiguousSpan>::value>::type* = nullptr - > -bool operator<(const TLeft& lhs, const TRight& rhs) { - return TContiguousSpan(lhs) < TContiguousSpan(rhs); -} - -template < - class TLeft, - class TRight, - typename std::enable_if<std::is_convertible<TLeft,TContiguousSpan>::value>::type* = nullptr, - typename std::enable_if<std::is_convertible<TRight,TContiguousSpan>::value>::type* = nullptr - > -bool operator<=(const TLeft& lhs, const TRight& rhs) { - return TContiguousSpan(lhs) <= TContiguousSpan(rhs); -} - -template < - class TLeft, - class TRight, - typename std::enable_if<std::is_convertible<TLeft,TContiguousSpan>::value>::type* = nullptr, - typename std::enable_if<std::is_convertible<TRight,TContiguousSpan>::value>::type* = nullptr - > -bool operator>(const TLeft& lhs, const TRight& rhs) { - return TContiguousSpan(lhs) > TContiguousSpan(rhs); -} - -template < - class TLeft, - class TRight, - typename std::enable_if<std::is_convertible<TLeft,TContiguousSpan>::value>::type* = nullptr, - typename std::enable_if<std::is_convertible<TRight,TContiguousSpan>::value>::type* = nullptr - > -bool operator>=(const TLeft& lhs, const TRight& rhs) { - return TContiguousSpan(lhs) >= TContiguousSpan(rhs); -} - - -class TMutableContiguousSpan -{ -private: - char *Data = nullptr; - size_t Size = 0; - -public: - TMutableContiguousSpan() = default; - - TMutableContiguousSpan(char *data, size_t size) - : Data(data) - , Size(size) - {} - - char *data() noexcept { - return Data; - } - - char *GetData() noexcept { - return Data; - } - - TMutableContiguousSpan SubSpan(size_t pos, size_t n) noexcept { - pos = Min(pos, size()); - n = Min(n, size() - pos); - return TMutableContiguousSpan(data() + pos, n); - } - - const char *data() const noexcept { - return Data; - } - - size_t size() const noexcept { - return Size; - } - - const char *GetData() const noexcept { - return Data; - } - - size_t GetSize() const noexcept { - return Size; - } - - TContiguousSpan SubSpan(size_t pos, size_t n) const noexcept { - pos = Min(pos, size()); - n = Min(n, size() - pos); - return TContiguousSpan(data() + pos, n); - } - - operator TContiguousSpan() const noexcept { - return TContiguousSpan(Data, Size); - } -}; - -struct IContiguousChunk : TThrRefBase { - using TPtr = TIntrusivePtr<IContiguousChunk>; - - virtual ~IContiguousChunk() = default; - - /** - * Should give immutable access to data - */ - virtual TContiguousSpan GetData() const = 0; - - /** - * Should give mutable access to underlying data - * If data is shared - data should be copied - * E.g. for TString str.Detach() should be used - * Possibly invalidates previous *GetData*() calls - */ - virtual TMutableContiguousSpan GetDataMut() = 0; - - /** - * Should give mutable access to undelying data as fast as possible - * Even if data is shared this property should be ignored - * E.g. in TString const_cast<char *>(str.data()) should be used - * Possibly invalidates previous *GetData*() calls - */ - virtual TMutableContiguousSpan UnsafeGetDataMut() { - return GetDataMut(); - } - - /** - * Should return true if GetDataMut() would not copy contents when called. - */ - virtual bool IsPrivate() const { - return true; - } - - virtual size_t GetOccupiedMemorySize() const = 0; -}; - -class TRope; -class TRopeArena; - -class TRcBuf { - friend class TRope; - friend class TRopeArena; - - using TInternalBackend = NDetail::TRcBufInternalBackend; - - class TBackend { - enum class EType : uintptr_t { - STRING, - SHARED_DATA, - INTERNAL_BACKEND, - EXTERNAL_BACKEND, - }; - - struct TBackendHolder { - uintptr_t Data[2]; - explicit operator bool() const noexcept { - return Data[0] || Data[1]; - } - friend bool operator ==(const TBackendHolder& x, const TBackendHolder& y) { - return x.Data[0] == y.Data[0] && x.Data[1] == y.Data[1]; - } - }; - - constexpr static TBackendHolder Empty = {0, 0}; - -#ifndef TSTRING_IS_STD_STRING - static_assert(sizeof(TBackendHolder) >= sizeof(TString)); -#endif - static_assert(sizeof(TBackendHolder) >= sizeof(NActors::TSharedData)); - static_assert(sizeof(TBackendHolder) >= sizeof(TInternalBackend)); - - TBackendHolder Owner = TBackend::Empty; // lower bits contain type of the owner - - public: - using TCookies = TInternalBackend::TCookies; - - static constexpr struct TControlToken {} ControlToken; - static constexpr size_t CookiesSize = sizeof(TCookies); - - TBackend() = default; - - TBackend(const TBackend& other) - : Owner(other.Owner ? Clone(other.Owner) : TBackend::Empty) - {} - - TBackend(TBackend&& other) - : Owner(std::exchange(other.Owner, TBackend::Empty)) - {} - - TBackend(TString s) - : Owner(Construct<TString>(EType::STRING, std::move(s))) - {} - - TBackend(NActors::TSharedData s) - : Owner(Construct<NActors::TSharedData>(EType::SHARED_DATA, std::move(s))) - {} - - TBackend(TInternalBackend backend) - : Owner(Construct<TInternalBackend>(EType::INTERNAL_BACKEND, std::move(backend))) - {} - - TBackend(IContiguousChunk::TPtr backend) - : Owner(Construct<IContiguousChunk::TPtr>(EType::EXTERNAL_BACKEND, std::move(backend))) - {} - - ~TBackend() { - if (Owner) { - Destroy(Owner); - } - } - - TBackend& operator =(const TBackend& other) { - if (Y_UNLIKELY(this == &other)) { - return *this; - } - - if (Owner) { - Destroy(Owner); - } - if (other.Owner) { - Owner = Clone(other.Owner); - } else { - Owner = TBackend::Empty; - } - return *this; - } - - TBackend& operator =(TBackend&& other) { - if (Y_UNLIKELY(this == &other)) { - return *this; - } - - if (Owner) { - Destroy(Owner); - } - Owner = std::exchange(other.Owner, TBackend::Empty); - return *this; - } - - bool operator ==(const TBackend& other) const { - return Owner == other.Owner; - } - - const void *UniqueId() const { - return reinterpret_cast<const void*>(Owner.Data[0]); - } - - TCookies* GetCookies() { - if(!Owner) { - return nullptr; - } - return Visit(Owner, [](EType, auto& value) -> TCookies* { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, TInternalBackend>) { - return value.GetCookies(); - } else { - return nullptr; - } - }); - } - - const TCookies* GetCookies() const { - return const_cast<TBackend&>(*this).GetCookies(); - } - - bool IsPrivate() const { - if(!Owner) { - return true; - } - return Visit(Owner, [](EType, auto& value) -> bool { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, NActors::TSharedData> || std::is_same_v<T, TInternalBackend>) { - return value.IsPrivate(); - } else if constexpr (std::is_same_v<T, TString>) { - return value.IsDetached(); - } else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) { - return value.RefCount() == 1 && value->IsPrivate(); - } else { - static_assert(TDependentFalse<T>); - } - }); - } - - TContiguousSpan GetData() const { - if (!Owner) { - return TContiguousSpan(); - } - return Visit(Owner, [](EType, auto& value) -> TContiguousSpan { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, TString> || std::is_same_v<T, NActors::TSharedData> || std::is_same_v<T, TInternalBackend>) { - return {value.data(), value.size()}; - } else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) { - return value->GetData(); - } else { - static_assert(TDependentFalse<T>, "unexpected type"); - } - }); - } - - TMutableContiguousSpan GetDataMut() { - if (!Owner) { - return TMutableContiguousSpan(); - } - return Visit(Owner, [](EType, auto& value) -> TMutableContiguousSpan { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, TString>) { - return {value.Detach(), value.size()}; - } else if constexpr (std::is_same_v<T, NActors::TSharedData>) { - if (value.IsShared()) { - value = NActors::TSharedData::Copy(value.data(), value.size()); - } - return {value.mutable_data(), value.size()}; - } else if constexpr (std::is_same_v<T, TInternalBackend>) { - if (value.IsShared()) { - value = TInternalBackend::Copy(value.data(), value.size()); - } - return {value.mutable_data(), value.size()}; - } else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) { - return value->GetDataMut(); - } else { - static_assert(TDependentFalse<T>, "unexpected type"); - } - }); - } - - TMutableContiguousSpan UnsafeGetDataMut() const { - if (!Owner) { - return TMutableContiguousSpan(); - } - return Visit(Owner, [](EType, auto& value) -> TMutableContiguousSpan { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, TString>) { - return {const_cast<char*>(value.data()), value.size()}; - } else if constexpr (std::is_same_v<T, NActors::TSharedData> || std::is_same_v<T, TInternalBackend>) { - return {const_cast<char*>(value.data()), value.size()}; - } else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) { - return value->UnsafeGetDataMut(); - } else { - static_assert(TDependentFalse<T>, "unexpected type"); - } - }); - } - - size_t GetOccupiedMemorySize() const { - if (!Owner) { - return 0; - } - return Visit(Owner, [](EType, auto& value) { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, TString>) { - return value.capacity(); - } else if constexpr (std::is_same_v<T, NActors::TSharedData> || std::is_same_v<T, TInternalBackend>) { - return value.size(); // There is no capacity - } else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) { - return value->GetOccupiedMemorySize(); - } else { - static_assert(TDependentFalse<T>, "unexpected type"); - } - }); - } - - template <class TType> - bool ContainsNativeType() const { - if (!Owner) { - return false; - } - return Visit(Owner, [](EType, auto& value) { - using T = std::decay_t<decltype(value)>; - return std::is_same_v<T, TType>; - }); - } - - bool CanGrowFront(const char* begin) const { - if (!Owner) { - return false; - } - const TCookies* cookies = GetCookies(); - return cookies && (IsPrivate() || cookies->Begin.load() == begin); - } - - bool CanGrowBack(const char* end) const { - if (!Owner) { - return false; - } - const TCookies* cookies = GetCookies(); - return cookies && (IsPrivate() || cookies->End.load() == end); - } - - void UpdateCookiesUnsafe(const char* contBegin, const char* contEnd) { - if (!Owner) { - return; - } - TCookies* cookies = GetCookies(); - if (cookies) { - cookies->Begin.store(contBegin); - cookies->End.store(contEnd); - } - } - - bool UpdateCookiesBegin(const char* curBegin, const char* contBegin) { - if (!Owner) { - return false; - } - - TCookies* cookies = GetCookies(); - if (cookies) { - return cookies->Begin.compare_exchange_weak(curBegin, contBegin); - } - return false; - } - - bool UpdateCookiesEnd(const char* curEnd, const char* contEnd) { - if (!Owner) { - return false; - } - - TCookies* cookies = GetCookies(); - if (cookies) { - return cookies->End.compare_exchange_weak(curEnd, contEnd); - } - return false; - } - - template <typename TResult, typename TCallback> - std::invoke_result_t<TCallback, const TResult*> ApplySpecificValue(TCallback&& callback) const { - static_assert(std::is_same_v<TResult, TString> || - std::is_same_v<TResult, NActors::TSharedData> || - std::is_same_v<TResult, TInternalBackend> || - std::is_same_v<TResult, IContiguousChunk::TPtr>); - - if (!Owner) { - return callback(nullptr); - } - return Visit(Owner, [&](EType, auto& value) { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, TResult>) { - return callback(&value); - } else { - return callback(nullptr); - } - }); - } - - explicit operator bool() const { - return static_cast<bool>(Owner); - } - - private: - static constexpr uintptr_t TypeMask = (1 << 3) - 1; - static constexpr uintptr_t ValueMask = ~TypeMask; - - template<typename T> - struct TObjectHolder { - struct TWrappedObject : TThrRefBase { - T Value; - TWrappedObject(T&& value) - : Value(std::move(value)) - {} - }; - TIntrusivePtr<TWrappedObject> Object; - - TObjectHolder(T&& object) - : Object(MakeIntrusive<TWrappedObject>(std::move(object))) - {} - }; - - template<typename TObject> - static TBackendHolder Construct(EType type, TObject&& object) { - if constexpr (sizeof(TObject) <= sizeof(TBackendHolder)) { - TBackendHolder res = TBackend::Empty; - new(&res) std::decay_t<TObject>(std::forward<TObject>(object)); - Y_DEBUG_ABORT_UNLESS((res.Data[0] & ValueMask) == res.Data[0]); - res.Data[0] = res.Data[0] | static_cast<uintptr_t>(type); - return res; - } else { - return Construct<TObjectHolder<TObject>>(type, TObjectHolder<TObject>(std::forward<TObject>(object))); - } - } - - template<typename TOwner, typename TCallback, bool IsConst = std::is_const_v<TOwner>> - static std::invoke_result_t<TCallback, EType, std::conditional_t<IsConst, const TString&, TString&>> VisitRaw(TOwner& origValue, TCallback&& callback) { - Y_DEBUG_ABORT_UNLESS(origValue); - const EType type = static_cast<EType>(origValue.Data[0] & TypeMask); - TBackendHolder value(origValue); - value.Data[0] = value.Data[0] & ValueMask; - // bring object type back - Y_SCOPE_EXIT(&value, &origValue, type){ - if constexpr(!IsConst) { - value.Data[0] = value.Data[0] | static_cast<uintptr_t>(type); - origValue = value; - } else { - Y_UNUSED(value); - Y_UNUSED(origValue); - Y_UNUSED(type); - } - }; - auto caller = [&](auto& value) { return std::invoke(std::forward<TCallback>(callback), type, value); }; - auto wrapper = [&](auto& value) { - using T = std::decay_t<decltype(value)>; - if constexpr (sizeof(T) <= sizeof(TBackendHolder)) { - return caller(value); - } else { - return caller(reinterpret_cast<std::conditional_t<IsConst, const TObjectHolder<T>&, TObjectHolder<T>&>>(value)); - } - }; - switch (type) { - case EType::STRING: return wrapper(reinterpret_cast<std::conditional_t<IsConst, const TString&, TString&>>(value)); - case EType::SHARED_DATA: return wrapper(reinterpret_cast<std::conditional_t<IsConst, const NActors::TSharedData&, NActors::TSharedData&>>(value)); - case EType::INTERNAL_BACKEND: return wrapper(reinterpret_cast<std::conditional_t<IsConst, const TInternalBackend&, TInternalBackend&>>(value)); - case EType::EXTERNAL_BACKEND: return wrapper(reinterpret_cast<std::conditional_t<IsConst, const IContiguousChunk::TPtr&, IContiguousChunk::TPtr&>>(value)); - } - Y_ABORT("Unexpected type# %" PRIu64, static_cast<ui64>(type)); - } - - template<typename TOwner, typename TCallback, bool IsConst = std::is_const_v<TOwner>> - static std::invoke_result_t<TCallback, EType, std::conditional_t<IsConst, const TString&, TString&>> Visit(TOwner& value, TCallback&& callback) { - return VisitRaw(value, [&](EType type, auto& value) { - return std::invoke(std::forward<TCallback>(callback), type, Unwrap(value)); - }); - } - - template<typename T> static T& Unwrap(T& object) { return object; } - template<typename T> static T& Unwrap(TObjectHolder<T>& holder) { return holder.Object->Value; } - template<typename T> static const T& Unwrap(const TObjectHolder<T>& holder) { return holder.Object->Value; } - - template<typename TOwner> - static TBackendHolder Clone(TOwner& value) { - return VisitRaw(value, [](EType type, auto& value) { return Construct(type, value); }); - } - - template<typename TOwner> - static void Destroy(TOwner& value) { - VisitRaw(value, [](EType, auto& value) { CallDtor(value); }); - } - - template<typename T> - static void CallDtor(T& value) { - value.~T(); - } - }; - - static constexpr struct TOwnedPiece {} OwnedPiece{}; - - TBackend Backend; // who actually holds the data - const char *Begin; // data start - const char *End; // data end - - explicit TRcBuf(TInternalBackend s, const char *data, size_t size) - : Backend(std::move(s)) - { - Y_ABORT_UNLESS(Backend.GetData().data() == nullptr || - (Backend.GetCookies() && Backend.GetCookies()->Begin == data && Backend.GetCookies()->End == data + size)); - Begin = data; - End = data + size; - } - - explicit TRcBuf(TInternalBackend s) - : Backend(std::move(s)) - { - auto span = Backend.GetData(); - Begin = span.data(); - End = Begin + span.size(); - } - - TRcBuf(TOwnedPiece, const char *data, size_t size, const TRcBuf& from) - : TRcBuf(from.Backend, {data, size}) - { - Y_ABORT_UNLESS(data >= from.GetData()); - Y_ABORT_UNLESS(data < from.GetData() + from.GetSize()); - Y_ABORT_UNLESS(data + size <= from.GetData() + from.GetSize()); - Backend.UpdateCookiesUnsafe(Begin, End); - } - - TRcBuf(TOwnedPiece, const char *begin, const char *end, const TRcBuf& from) - : TRcBuf(OwnedPiece, begin, end - begin, from) - {} - -public: - static constexpr struct TPiece {} Piece{}; - - enum class EResizeResult { - NoAlloc, - Alloc, - }; - - enum class EResizeStrategy { - KeepRooms, - FailOnCopy, - // SaveAllocs, // Move data if there is enough space in (headroom + size + tailroom) - }; - - TRcBuf() - : Begin(nullptr) - , End(nullptr) - {} - - template<typename T> - TRcBuf(T&& backend, const TContiguousSpan& data) - : Backend(std::forward<T>(backend)) - , Begin(data.data()) - , End(Begin + data.size()) - {} - - explicit TRcBuf(TString s) - : Backend(std::move(s)) - { - auto span = Backend.GetData(); - Begin = span.data(); - End = Begin + span.size(); - } - - explicit TRcBuf(NActors::TSharedData s) - : Backend(std::move(s)) - { - auto span = Backend.GetData(); - Begin = span.data(); - End = Begin + span.size(); - } - - TRcBuf(IContiguousChunk::TPtr backend) - : TRcBuf(backend, backend->GetData()) - {} - - TRcBuf(TPiece, const char *data, size_t size, const TRcBuf& from) - : TRcBuf(from.Backend, {data, size}) - { - Y_ABORT_UNLESS(data >= from.GetData()); - Y_ABORT_UNLESS(data < from.GetData() + from.GetSize()); - Y_ABORT_UNLESS(data + size <= from.GetData() + from.GetSize()); - } - - TRcBuf(TPiece, const char *begin, const char *end, const TRcBuf& from) - : TRcBuf(Piece, begin, end - begin, from) - {} - - TRcBuf(const TRcBuf& other) - : Backend(other.Backend) - , Begin(other.Begin) - , End(other.End) - {} - - TRcBuf(TRcBuf&& other) - : Backend(std::move(other.Backend)) - , Begin(other.Begin) - , End(other.End) - {} - - TRcBuf& operator =(const TRcBuf&) = default; - TRcBuf& operator =(TRcBuf&&) = default; - - static TRcBuf Uninitialized(size_t size, size_t headroom = 0, size_t tailroom = 0) - { - if (size == 0) { - return TRcBuf(); - } - - if (headroom == 0 && tailroom == 0) { - TInternalBackend res = TInternalBackend::Uninitialized(size); - return TRcBuf( - OwnedPiece, - res.data(), - res.data() + res.size(), - TRcBuf(res)); - } - - TInternalBackend res = TInternalBackend::Uninitialized(size, headroom, tailroom); - return TRcBuf(res, res.data() + headroom, size); - } - - static TRcBuf Copy(TContiguousSpan data, size_t headroom = 0, size_t tailroom = 0) { - TRcBuf res = Uninitialized(data.size(), headroom, tailroom); - std::memcpy(res.UnsafeGetDataMut(), data.GetData(), data.GetSize()); - return res; - } - - static TRcBuf Copy(const char* data, size_t size, size_t headroom = 0, size_t tailroom = 0) { - return Copy({data, size}, headroom, tailroom); - } - - template <class TType> - bool ContainsNativeType() const { - return Backend.ContainsNativeType<TType>(); - } - - bool CanGrowFront() const noexcept { - return Backend.CanGrowFront(Begin); - } - - bool CanGrowBack() const noexcept { - return Backend.CanGrowBack(End); - } - - size_t GetSize() const { - return End - Begin; - } - - size_t Size() const { - return End - Begin; - } - - size_t GetOccupiedMemorySize() const { - return Backend.GetOccupiedMemorySize(); - } - - const char* GetData() const { - return Begin; - } - - char* GetDataMut(size_t headroom = 0, size_t tailroom = 0) { - const TContiguousSpan backendData = Backend.GetData(); - if (IsPrivate() || (backendData.data() == GetData() && backendData.size() == GetSize())) { // if we own container or reference it whole - const char* oldBegin = backendData.data(); - ptrdiff_t offset = Begin - oldBegin; - size_t size = GetSize(); - char* newBegin = Backend.GetDataMut().data(); - Begin = newBegin + offset; - End = Begin + size; - return newBegin + offset; - } else { // make a copy of referenced data - *this = Copy(GetContiguousSpan(), headroom, tailroom); - return Backend.GetDataMut().data(); - } - } - - char* UnsafeGetDataMut() { - const char* oldBegin = Backend.GetData().data(); - ptrdiff_t offset = Begin - oldBegin; - size_t size = GetSize(); - char* newBegin = Backend.UnsafeGetDataMut().data(); - Begin = newBegin + offset; - End = Begin + size; - return newBegin + offset; - } - - template <class TResult> - TResult ExtractUnderlyingContainerOrCopy() const { - static_assert(std::is_same_v<TResult, TString> || - std::is_same_v<TResult, NActors::TSharedData> || - std::is_same_v<TResult, TInternalBackend>); - - constexpr bool isSharedData = std::is_same_v<TResult, NActors::TSharedData>; - TResult res; - - const bool found = Backend.ApplySpecificValue<TResult>([&](const TResult *raw) { - if (raw && raw->data() == Begin && (isSharedData ? End <= Begin + raw->size() : End == Begin + raw->size())) { - if constexpr (isSharedData) { - raw->TrimBack(size()); - } - res = TResult(*raw); - return true; - } - return false; - }); - - if (!found) { - res = TResult::Uninitialized(GetSize()); - char* data = NContiguousDataDetails::TContainerTraits<TResult>::UnsafeGetDataMut(res); - std::memcpy(data, GetData(), GetSize()); - } - - return res; - } - - TContiguousSpan GetContiguousSpan() const { - return {GetData(), GetSize()}; - } - - TStringBuf Slice(size_t pos = 0, size_t len = Max<size_t>()) const noexcept { - pos = Min(pos, size()); - len = Min(len, size() - pos); - return {const_cast<TRcBuf*>(this)->UnsafeGetDataMut() + pos, len}; - } - - explicit operator TStringBuf() const noexcept { - return Slice(); - } - - TMutableContiguousSpan GetContiguousSpanMut() { - return {GetDataMut(), GetSize()}; - } - - TMutableContiguousSpan UnsafeGetContiguousSpanMut() { - return {UnsafeGetDataMut(), GetSize()}; - } - - bool HasBuffer() const { - return static_cast<bool>(Backend); - } - - size_t size() const { - return GetSize(); - } - - bool empty() const { - return !static_cast<bool>(Backend); - } - - operator bool() const { - return !empty(); - } - - const char* data() const { - return GetData(); - } - - const char* Data() const { - return GetData(); - } - - const char* begin() const { - return Begin; - } - - const char* end() const { - return End; - } - - char& operator[](size_t pos) { - return UnsafeGetDataMut()[pos]; - } - - const char& operator[](size_t pos) const { - return GetData()[pos]; - } - - void reserve(size_t size) { - ReserveTailroom(size); - } - - void ReserveHeadroom(size_t size) { - if (Headroom() >= size) { - return; - } - auto newData = TRcBuf::Uninitialized(GetSize(), size, UnsafeTailroom()); - if (auto data = GetData(); data) { - std::memcpy(newData.UnsafeGetDataMut(), GetData(), GetSize()); - } - *this = std::move(newData); - } - - void ReserveTailroom(size_t size) { - if (Tailroom() >= size) { - return; - } - auto newData = TRcBuf::Uninitialized(GetSize(), UnsafeHeadroom(), size); - if (auto data = GetData(); data) { - std::memcpy(newData.UnsafeGetDataMut(), GetData(), GetSize()); - } - *this = std::move(newData); - } - - void ReserveBidi(size_t headroom, size_t tailroom) { - if (Headroom() >= headroom && Tailroom() >= tailroom) { - return; - } - auto newData = TRcBuf::Uninitialized( - GetSize(), - std::max(UnsafeHeadroom(), headroom), - std::max(UnsafeTailroom(), tailroom)); - if (auto data = GetData(); data) { - std::memcpy(newData.UnsafeGetDataMut(), GetData(), GetSize()); - } - *this = std::move(newData); - } - - EResizeResult GrowFront(size_t size, EResizeStrategy strategy = EResizeStrategy::KeepRooms) { - if (Headroom() >= size && Backend.UpdateCookiesBegin(Begin, Begin - size)) { - Begin -= size; - return EResizeResult::NoAlloc; - } else { - if (strategy == EResizeStrategy::FailOnCopy && static_cast<bool>(Backend)) { - Y_ABORT("Fail on grow"); - } - auto newData = TRcBuf::Uninitialized(size + GetSize(), UnsafeHeadroom() > size ? UnsafeHeadroom() - size : 0, UnsafeTailroom()); - if (auto data = GetData(); data) { - std::memcpy(newData.UnsafeGetDataMut() + size, GetData(), GetSize()); - } - *this = std::move(newData); - return EResizeResult::Alloc; - } - } - - EResizeResult GrowBack(size_t size, EResizeStrategy strategy = EResizeStrategy::KeepRooms) { - if (Tailroom() > size && Backend.UpdateCookiesEnd(End, End + size)) { - End += size; - return EResizeResult::NoAlloc; - } else { - if (strategy == EResizeStrategy::FailOnCopy && static_cast<bool>(Backend)) { - Y_ABORT("Fail on grow"); - } - auto newData = TRcBuf::Uninitialized(size + GetSize(), UnsafeHeadroom(), UnsafeTailroom() > size ? UnsafeTailroom() - size : 0); - if (auto data = GetData(); data) { - std::memcpy(newData.UnsafeGetDataMut(), GetData(), GetSize()); - } - *this = std::move(newData); - return EResizeResult::Alloc; - } - } - - void TrimBack(size_t size) { - Y_ABORT_UNLESS(size <= GetSize()); - End = End - (GetSize() - size); - } - - void TrimFront(size_t size) { - Y_ABORT_UNLESS(size <= GetSize()); - Begin = Begin + (GetSize() - size); - } - - char* Detach() { - return GetDataMut(); - } - - bool IsPrivate() const { - return Backend.IsPrivate(); - } - - size_t UnsafeHeadroom() const { - return Begin - Backend.GetData().data(); - } - - size_t UnsafeTailroom() const { - auto span = Backend.GetData(); - return (span.GetData() + span.GetSize()) - End; - } - - size_t Headroom() const { - if (Backend.CanGrowFront(Begin)) { - return UnsafeHeadroom(); - } - - return 0; - } - - size_t Tailroom() const { - if (Backend.CanGrowBack(End)) { - return UnsafeTailroom(); - } - - return 0; - } - - operator TContiguousSpan() const noexcept { - return TContiguousSpan(GetData(), GetSize()); - } - - explicit operator TMutableContiguousSpan() noexcept { - return TMutableContiguousSpan(GetDataMut(), GetSize()); - } -}; diff --git a/library/cpp/actors/util/rc_buf_backend.h b/library/cpp/actors/util/rc_buf_backend.h deleted file mode 100644 index 9cb8616554..0000000000 --- a/library/cpp/actors/util/rc_buf_backend.h +++ /dev/null @@ -1,230 +0,0 @@ -#pragma once - -#include <atomic> - -#include <library/cpp/deprecated/atomic/atomic.h> - -#include <util/system/types.h> -#include <util/system/compiler.h> -#include <util/generic/array_ref.h> -#include <util/system/sys_alloc.h> - -namespace NDetail { - -struct TRcBufInternalBackend { -public: - struct TCookies { - using TSelf = TCookies; - std::atomic<const char*> Begin; - std::atomic<const char*> End; - - static size_t BytesToAligned(size_t size) { - bool misaligned = size % alignof(TSelf); - return misaligned ? alignof(TSelf) - size % alignof(TSelf) : 0; - } - - static size_t BytesToAlloc(size_t size) { - return size + BytesToAligned(size) + sizeof(TSelf); - } - }; -private: - // to be binary compatible with TSharedData - struct THeader : public TCookies { - TAtomic RefCount; - ui64 Zero = 0; - }; - - enum : size_t { - HeaderSize = sizeof(THeader), - OverheadSize = HeaderSize, - MaxDataSize = (std::numeric_limits<size_t>::max() - OverheadSize) - }; - -public: - TRcBufInternalBackend() noexcept - : Data_(nullptr) - , Size_(0) - { } - - ~TRcBufInternalBackend() noexcept { - Release(); - } - - TRcBufInternalBackend(const TRcBufInternalBackend& other) noexcept - : Data_(other.Data_) - , Size_(other.Size_) - { - AddRef(); - } - - TRcBufInternalBackend(TRcBufInternalBackend&& other) noexcept - : Data_(other.Data_) - , Size_(other.Size_) - { - other.Data_ = nullptr; - other.Size_ = 0; - } - - TRcBufInternalBackend& operator=(const TRcBufInternalBackend& other) noexcept { - if (this != &other) { - Release(); - Data_ = other.Data_; - Size_ = other.Size_; - AddRef(); - } - return *this; - } - - TRcBufInternalBackend& operator=(TRcBufInternalBackend&& other) noexcept { - if (this != &other) { - Release(); - Data_ = other.Data_; - Size_ = other.Size_; - other.Data_ = nullptr; - other.Size_ = 0; - } - return *this; - } - - Y_FORCE_INLINE explicit operator bool() const { return Size_ > 0; } - - Y_FORCE_INLINE char* mutable_data() { return Data(); } - Y_FORCE_INLINE char* mutable_begin() { return Data(); } - Y_FORCE_INLINE char* mutable_end() { return Data() + Size_; } - - Y_FORCE_INLINE const char* data() const { return Data(); } - Y_FORCE_INLINE const char* begin() const { return Data(); } - Y_FORCE_INLINE const char* end() const { return Data() + Size_; } - - Y_FORCE_INLINE size_t size() const { return Size_; } - - /** - * Copies data to new allocated buffer if data is shared - * New container loses original owner - * Returns pointer to mutable buffer - */ - char* Detach() { - if (IsShared()) { - *this = TRcBufInternalBackend::Copy(data(), size()); - } - return Data_; - } - - bool IsPrivate() const { - return Data_ ? IsPrivate(Header()) : true; - } - - bool IsShared() const { - return !IsPrivate(); - } - - TString ToString() const { - return TString(data(), size()); - } - - TCookies* GetCookies() { - return Header(); - } - - /** - * Attach to pre-allocated data with a preceding THeader - */ - static TRcBufInternalBackend AttachUnsafe(char* data, size_t size) noexcept { - TRcBufInternalBackend result; - result.Data_ = data; - result.Size_ = size; - return result; - } - - /** - * Make uninitialized buffer of the specified size - */ - static TRcBufInternalBackend Uninitialized(size_t size, size_t headroom = 0, size_t tailroom = 0) { - size_t fullSize = checkedSum(size, checkedSum(headroom, tailroom)); - return AttachUnsafe(Allocate(size, headroom, tailroom), fullSize); - } - - /** - * Make a copy of the specified data - */ - static TRcBufInternalBackend Copy(const void* data, size_t size) { - TRcBufInternalBackend result = Uninitialized(size); - if (size) { - ::memcpy(result.Data(), data, size); - } - return result; - } - -private: - Y_FORCE_INLINE THeader* Header() const noexcept { - Y_DEBUG_ABORT_UNLESS(Data_); - return reinterpret_cast<THeader*>(Data_); - } - - Y_FORCE_INLINE char* Data() const noexcept { - Y_DEBUG_ABORT_UNLESS(Data_); - return Data_ + OverheadSize; - } - - static bool IsPrivate(THeader* header) noexcept { - return 1 == AtomicGet(header->RefCount); - } - - void AddRef() noexcept { - if (Data_) { - AtomicIncrement(Header()->RefCount); - } - } - - void Release() noexcept { - if (Data_) { - auto* header = Header(); - if (IsPrivate(header) || 0 == AtomicDecrement(header->RefCount)) { - Deallocate(Data_); - } - } - } - -private: - static size_t checkedSum(size_t a, size_t b) { - if (a > std::numeric_limits<size_t>::max() - b) { - throw std::length_error("Allocate size overflow"); - } - return a + b; - } - - static char* Allocate(size_t size, size_t headroom = 0, size_t tailroom = 0) { - char* data = nullptr; - size_t fullSize = checkedSum(size, checkedSum(headroom, tailroom)); - if (fullSize > 0) { - if (fullSize >= MaxDataSize) { - throw std::length_error("Allocate size overflow"); - } - auto allocSize = OverheadSize + fullSize; - char* raw = reinterpret_cast<char*>(y_allocate(allocSize)); - - auto* header = reinterpret_cast<THeader*>(raw); - header->Begin = raw + OverheadSize + headroom; - header->End = raw + allocSize - tailroom; - header->RefCount = 1; - - data = raw; - } - - return data; - } - - static void Deallocate(char* data) noexcept { - if (data) { - char* raw = data; - - y_deallocate(raw); - } - } - -private: - char* Data_; - size_t Size_; -}; - -} // namespace NDetail diff --git a/library/cpp/actors/util/rc_buf_ut.cpp b/library/cpp/actors/util/rc_buf_ut.cpp deleted file mode 100644 index c23e8b68d0..0000000000 --- a/library/cpp/actors/util/rc_buf_ut.cpp +++ /dev/null @@ -1,207 +0,0 @@ -#include "rc_buf.h" -#include "ut_helpers.h" -#include "rope.h" - -#include <library/cpp/testing/unittest/registar.h> -#include <util/random/random.h> - -Y_UNIT_TEST_SUITE(TRcBuf) { - Y_UNIT_TEST(TypeSize) { - UNIT_ASSERT_EQUAL(sizeof(TRcBuf), 4 * sizeof(uintptr_t)); - } - - Y_UNIT_TEST(Slice) { - auto data = TRcBuf::Copy("Hello", 5); - UNIT_ASSERT_VALUES_EQUAL(TString(TStringBuf(data)), TString("Hello")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice()), TString("Hello")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice(1)), TString("ello")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice(1, 3)), TString("ell")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice(1, 100)), TString("ello")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice(0, 4)), TString("Hell")); - } - - Y_UNIT_TEST(CrossCompare) { - TString str = "some very long string"; - const TString constStr(str); - TStringBuf strbuf = str; - const TStringBuf constStrbuf = str; - TContiguousSpan span(str); - const TContiguousSpan constSpan(str); - TMutableContiguousSpan mutableSpan(const_cast<char*>(str.data()), str.size()); - const TMutableContiguousSpan constMutableSpan(const_cast<char*>(str.data()), str.size()); - TRcBuf data(str); - const TRcBuf constData(str); - TArrayRef<char> arrRef(const_cast<char*>(str.data()), str.size()); - const TArrayRef<char> constArrRef(const_cast<char*>(str.data()), str.size()); - TArrayRef<const char> arrConstRef(const_cast<char*>(str.data()), str.size()); - const TArrayRef<const char> constArrConstRef(const_cast<char*>(str.data()), str.size()); - NActors::TSharedData sharedData = NActors::TSharedData::Copy(str.data(), str.size()); - const NActors::TSharedData constSharedData(sharedData); - - Permutate( - [](auto& arg1, auto& arg2) { - UNIT_ASSERT(arg1 == arg2); - }, - str, - constStr, - strbuf, - constStrbuf, - span, - constSpan, - mutableSpan, - constMutableSpan, - data, - constData, - arrRef, - constArrRef, - arrConstRef, - constArrConstRef, - sharedData, - constSharedData); - } - - Y_UNIT_TEST(Detach) { - TRcBuf data = TRcBuf::Copy(TString("test")); - TRcBuf data2 = data; - char* res = data2.Detach(); - UNIT_ASSERT_UNEQUAL(data.GetData(), data2.GetData()); - UNIT_ASSERT_EQUAL(res, data2.GetData()); - UNIT_ASSERT_EQUAL(::memcmp(res, "test", 4), 0); - UNIT_ASSERT_EQUAL(::memcmp(data.GetData(), "test", 4), 0); - } - - Y_UNIT_TEST(Resize) { - TRcBuf data = TRcBuf::Uninitialized(10, 20, 30); - UNIT_ASSERT_EQUAL(data.size(), 10); - UNIT_ASSERT_EQUAL(data.Headroom(), 20); - UNIT_ASSERT_EQUAL(data.Tailroom(), 30); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 60); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), data.size() + data.Headroom() + data.Tailroom()); - data.GrowFront(5); - UNIT_ASSERT_EQUAL(data.size(), 15); - UNIT_ASSERT_EQUAL(data.Headroom(), 15); - UNIT_ASSERT_EQUAL(data.Tailroom(), 30); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 60); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), data.size() + data.Headroom() + data.Tailroom()); - data.GrowBack(5); - UNIT_ASSERT_EQUAL(data.size(), 20); - UNIT_ASSERT_EQUAL(data.Headroom(), 15); - UNIT_ASSERT_EQUAL(data.Tailroom(), 25); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 60); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), data.size() + data.Headroom() + data.Tailroom()); - data.GrowFront(21); - UNIT_ASSERT_EQUAL(data.size(), 41); - UNIT_ASSERT_EQUAL(data.Headroom(), 0); - UNIT_ASSERT_EQUAL(data.Tailroom(), 25); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 66); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), data.size() + data.Headroom() + data.Tailroom()); - data.GrowBack(32); - UNIT_ASSERT_EQUAL(data.size(), 73); - UNIT_ASSERT_EQUAL(data.Headroom(), 0); - UNIT_ASSERT_EQUAL(data.Tailroom(), 0); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 73); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), data.size() + data.Headroom() + data.Tailroom()); - } - - Y_UNIT_TEST(ResizeUnshare) { - TRcBuf data = TRcBuf::Uninitialized(10, 20, 30); - TRcBuf otherData(data); - UNIT_ASSERT_EQUAL(data.data(), otherData.data()); - UNIT_ASSERT_EQUAL(data.size(), 10); - UNIT_ASSERT_EQUAL(data.Headroom(), 20); - UNIT_ASSERT_EQUAL(data.Tailroom(), 30); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 60); - UNIT_ASSERT_EQUAL(otherData.size(), 10); - UNIT_ASSERT_EQUAL(otherData.Headroom(), 20); - UNIT_ASSERT_EQUAL(otherData.Tailroom(), 30); - UNIT_ASSERT_EQUAL(otherData.GetOccupiedMemorySize(), 60); - data.GrowFront(5); - data.GrowBack(5); - UNIT_ASSERT_EQUAL(data.data() + 5, otherData.data()); - UNIT_ASSERT_EQUAL(data.size(), 20); - UNIT_ASSERT_EQUAL(data.Headroom(), 15); - UNIT_ASSERT_EQUAL(data.Tailroom(), 25); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 60); - otherData.GrowFront(5); - UNIT_ASSERT_UNEQUAL(data.data(), otherData.data()); - UNIT_ASSERT_EQUAL(otherData.size(), 15); - UNIT_ASSERT_EQUAL(otherData.Headroom(), 15); - UNIT_ASSERT_EQUAL(otherData.Tailroom(), 30); - UNIT_ASSERT_EQUAL(otherData.GetOccupiedMemorySize(), 60); - data.TrimBack(15); - data.TrimFront(10); - UNIT_ASSERT_EQUAL(data.size(), 10); - UNIT_ASSERT_EQUAL(data.Headroom(), 20); - UNIT_ASSERT_EQUAL(data.Tailroom(), 30); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 60); - } - - Y_UNIT_TEST(Trim) { - TRcBuf data = TRcBuf::Uninitialized(10, 20, 30); - TRcBuf otherData(data); - otherData.TrimBack(5); - UNIT_ASSERT_EQUAL(data.data(), otherData.data()); - UNIT_ASSERT_EQUAL(otherData.Headroom(), 20); - UNIT_ASSERT_EQUAL(otherData.Tailroom(), 0); - TRcBuf otherData2(data); - otherData2.TrimBack(2); - otherData2.TrimFront(1); - UNIT_ASSERT_EQUAL(data.data() + 1, otherData2.data()); - UNIT_ASSERT_EQUAL(otherData2.Headroom(), 0); - UNIT_ASSERT_EQUAL(otherData2.Tailroom(), 0); - otherData.TrimBack(2); - otherData.TrimFront(1); - UNIT_ASSERT_EQUAL(otherData.data(), otherData2.data()); - data.GrowFront(5); - data.GrowBack(5); - UNIT_ASSERT_EQUAL(data.data() + 6, otherData2.data()); - UNIT_ASSERT_EQUAL(data.data() + 6, otherData.data()); - otherData.GrowFront(1); - UNIT_ASSERT_UNEQUAL(data.data() + 7, otherData.data()); - otherData2.GrowBack(1); - UNIT_ASSERT_UNEQUAL(data.data() + 6, otherData2.data()); - data = TRcBuf::Uninitialized(10); - otherData = data; - data.TrimBack(5); - UNIT_ASSERT_EQUAL(data.data(), otherData.data()); - UNIT_ASSERT_EQUAL(data.size(), 5); - } - - Y_UNIT_TEST(SliceUnshare) { - TRcBuf data = TRcBuf::Uninitialized(10, 20, 30); - TRcBuf otherData(TRcBuf::Piece, data.data() + 1, data.size() - 2, data); - UNIT_ASSERT_EQUAL(otherData.Headroom(), 0); - UNIT_ASSERT_EQUAL(otherData.Tailroom(), 0); - } - - Y_UNIT_TEST(Reserve) { - TRcBuf data = TRcBuf::Copy("test", 4, 5, 6); - TRcBuf data2 = data; - data.reserve(1); - data.ReserveTailroom(6); - UNIT_ASSERT_EQUAL(data.GetData(), data2.GetData()); - UNIT_ASSERT_EQUAL(data.GetSize(), data2.GetSize()); - UNIT_ASSERT_EQUAL(data.Tailroom(), 6); - data.ReserveHeadroom(5); - UNIT_ASSERT_EQUAL(data.GetData(), data2.GetData()); - UNIT_ASSERT_EQUAL(data.GetSize(), data2.GetSize()); - UNIT_ASSERT_EQUAL(data.Headroom(), 5); - data.ReserveBidi(5, 6); - UNIT_ASSERT_EQUAL(data.GetData(), data2.GetData()); - UNIT_ASSERT_EQUAL(data.GetSize(), data2.GetSize()); - UNIT_ASSERT_EQUAL(data.Headroom(), 5); - UNIT_ASSERT_EQUAL(data.Tailroom(), 6); - data.ReserveHeadroom(6); - UNIT_ASSERT_EQUAL(data.Headroom(), 6); - UNIT_ASSERT_EQUAL(data.Tailroom(), 6); - UNIT_ASSERT_EQUAL(::memcmp(data.GetData(), "test", 4), 0); - data.ReserveTailroom(7); - UNIT_ASSERT_EQUAL(data.Headroom(), 6); - UNIT_ASSERT_EQUAL(data.Tailroom(), 7); - UNIT_ASSERT_EQUAL(::memcmp(data.GetData(), "test", 4), 0); - data.ReserveBidi(7, 8); - UNIT_ASSERT_EQUAL(data.Headroom(), 7); - UNIT_ASSERT_EQUAL(data.Tailroom(), 8); - UNIT_ASSERT_EQUAL(::memcmp(data.GetData(), "test", 4), 0); - } -} diff --git a/library/cpp/actors/util/recentwnd.h b/library/cpp/actors/util/recentwnd.h deleted file mode 100644 index 0f5ee17fa0..0000000000 --- a/library/cpp/actors/util/recentwnd.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include <util/generic/deque.h> - -template <typename TElem, - template <typename, typename...> class TContainer = TDeque> -class TRecentWnd { -public: - TRecentWnd(ui32 wndSize) - : MaxWndSize_(wndSize) - { - } - - void Push(const TElem& elem) { - if (Window_.size() == MaxWndSize_) - Window_.erase(Window_.begin()); - Window_.emplace_back(elem); - } - - void Push(TElem&& elem) { - if (Window_.size() == MaxWndSize_) - Window_.erase(Window_.begin()); - Window_.emplace_back(std::move(elem)); - } - - TElem& Last() { - return Window_.back(); - } - const TElem& Last() const { - return Window_.back(); - } - bool Full() const { - return Window_.size() == MaxWndSize_; - } - ui64 Size() const { - return Window_.size(); - } - - using const_iterator = typename TContainer<TElem>::const_iterator; - - const_iterator begin() { - return Window_.begin(); - } - const_iterator end() { - return Window_.end(); - } - - void Reset(ui32 wndSize = 0) { - Window_.clear(); - if (wndSize != 0) { - MaxWndSize_ = wndSize; - } - } - - void ResetWnd(ui32 wndSize) { - Y_ABORT_UNLESS(wndSize != 0); - MaxWndSize_ = wndSize; - if (Window_.size() > MaxWndSize_) { - Window_.erase(Window_.begin(), - Window_.begin() + Window_.size() - MaxWndSize_); - } - } - -private: - TContainer<TElem> Window_; - ui32 MaxWndSize_; -}; diff --git a/library/cpp/actors/util/rope.cpp b/library/cpp/actors/util/rope.cpp deleted file mode 100644 index 0927774099..0000000000 --- a/library/cpp/actors/util/rope.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "rope.h" -#include <library/cpp/containers/absl_flat_hash/flat_hash_set.h> - -size_t TRope::GetOccupiedMemorySize() const { - size_t res = 0; - absl::flat_hash_set<const void*> chunks; - for (const auto& chunk : Chain) { - if (const auto [it, inserted] = chunks.insert(chunk.Backend.UniqueId()); inserted) { - res += chunk.Backend.GetOccupiedMemorySize(); - } - } - return res; -} diff --git a/library/cpp/actors/util/rope.h b/library/cpp/actors/util/rope.h deleted file mode 100644 index b092d502cd..0000000000 --- a/library/cpp/actors/util/rope.h +++ /dev/null @@ -1,1148 +0,0 @@ -#pragma once - -#include <util/generic/ptr.h> -#include <util/generic/string.h> -#include <util/generic/hash_set.h> -#include <util/generic/scope.h> -#include <util/stream/zerocopy.h> -#include <util/stream/str.h> -#include <util/system/sanitizers.h> -#include <util/system/valgrind.h> - -// exactly one of them must be included -#include "rope_cont_embedded_list.h" -//#include "rope_cont_list.h" -//#include "rope_cont_deque.h" - -#include "rc_buf.h" - -class TRopeAlignedBuffer : public IContiguousChunk { - static constexpr size_t Alignment = 16; - static constexpr size_t MallocAlignment = sizeof(size_t); - - ui32 Size; - const ui32 Capacity; - const ui32 Offset; - alignas(Alignment) char Data[]; - - TRopeAlignedBuffer(size_t size) - : Size(size) - , Capacity(size) - , Offset((Alignment - reinterpret_cast<uintptr_t>(Data)) & (Alignment - 1)) - { - Y_ABORT_UNLESS(Offset <= Alignment - MallocAlignment); - } - -public: - static TIntrusivePtr<TRopeAlignedBuffer> Allocate(size_t size) { - return new(malloc(sizeof(TRopeAlignedBuffer) + size + Alignment - MallocAlignment)) TRopeAlignedBuffer(size); - } - - void *operator new(size_t) { - Y_ABORT(); - } - - void *operator new(size_t, void *ptr) { - return ptr; - } - - void operator delete(void *ptr) { - free(ptr); - } - - void operator delete(void* p, void* ptr) { - Y_UNUSED(p); - Y_UNUSED(ptr); - } - - TContiguousSpan GetData() const override { - return {Data + Offset, Size}; - } - - TMutableContiguousSpan GetDataMut() override { - return {Data + Offset, Size}; - } - - size_t GetOccupiedMemorySize() const override { - return Capacity; - } - - size_t GetCapacity() const { - return Capacity; - } - - char *GetBuffer() { - return Data + Offset; - } -}; - -namespace NRopeDetails { - - template<bool IsConst, typename TRope, typename TList> - struct TIteratorTraits; - - template<typename TRope, typename TList> - struct TIteratorTraits<true, TRope, TList> { - using TRopePtr = const TRope*; - using TListIterator = typename TList::const_iterator; - }; - - template<typename TRope, typename TList> - struct TIteratorTraits<false, TRope, TList> { - using TRopePtr = TRope*; - using TListIterator = typename TList::iterator; - }; - -} // NRopeDetails - -class TRopeArena; - -template<typename T> -struct always_false : std::false_type {}; - -class TRope { - friend class TRopeArena; - - using TChunkList = NRopeDetails::TChunkList<TRcBuf>; - -private: - // we use list here to store chain items as we have to keep valid iterators when erase/insert operations are invoked; - // iterator uses underlying container's iterator, so we have to use container that keeps valid iterators on delete, - // thus, the list - TChunkList Chain; - size_t Size = 0; - -private: - template<bool IsConst> - class TIteratorImpl { - using TTraits = NRopeDetails::TIteratorTraits<IsConst, TRope, TChunkList>; - - typename TTraits::TRopePtr Rope; - typename TTraits::TListIterator Iter; - const char *Ptr; // ptr is always nullptr when iterator is positioned at the rope end - -#ifndef NDEBUG - ui32 ValidityToken; -#endif - - private: - TIteratorImpl(typename TTraits::TRopePtr rope, typename TTraits::TListIterator iter, const char *ptr = nullptr) - : Rope(rope) - , Iter(iter) - , Ptr(ptr) -#ifndef NDEBUG - , ValidityToken(Rope->GetValidityToken()) -#endif - {} - - public: - TIteratorImpl() - : Rope(nullptr) - , Ptr(nullptr) - {} - - template<bool IsOtherConst> - TIteratorImpl(const TIteratorImpl<IsOtherConst>& other) - : Rope(other.Rope) - , Iter(other.Iter) - , Ptr(other.Ptr) -#ifndef NDEBUG - , ValidityToken(other.ValidityToken) -#endif - {} - - void CheckValid() const { -#ifndef NDEBUG - Y_ABORT_UNLESS(ValidityToken == Rope->GetValidityToken()); - Y_ABORT_UNLESS(Iter == Rope->Chain.end() || Iter->Backend); -#endif - } - - TIteratorImpl& operator +=(size_t amount) { - CheckValid(); - - while (amount) { - Y_DEBUG_ABORT_UNLESS(Valid()); - const size_t max = ContiguousSize(); - const size_t num = std::min(amount, max); - amount -= num; - Ptr += num; - if (Ptr == Iter->End) { - AdvanceToNextContiguousBlock(); - } - } - - return *this; - } - - TIteratorImpl operator +(size_t amount) const { - CheckValid(); - - return TIteratorImpl(*this) += amount; - } - - TIteratorImpl& operator -=(size_t amount) { - CheckValid(); - - while (amount) { - const size_t num = Ptr ? std::min<size_t>(amount, Ptr - Iter->Begin) : 0; - amount -= num; - Ptr -= num; - if (amount) { - Y_DEBUG_ABORT_UNLESS(Iter != GetChainBegin()); - --Iter; - Ptr = Iter->End; - } - } - - return *this; - } - - TIteratorImpl operator -(size_t amount) const { - CheckValid(); - return TIteratorImpl(*this) -= amount; - } - - std::pair<const char*, size_t> operator *() const { - return {ContiguousData(), ContiguousSize()}; - } - - TIteratorImpl& operator ++() { - AdvanceToNextContiguousBlock(); - return *this; - } - - TIteratorImpl operator ++(int) const { - auto it(*this); - it.AdvanceToNextContiguousBlock(); - return it; - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Operation with contiguous data - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - // Get the pointer to the contiguous block of data; valid locations are [Data; Data + Size). - const char *ContiguousData() const { - CheckValid(); - return Ptr; - } - - template<bool Mut = !IsConst, std::enable_if_t<Mut, bool> = true> - char *ContiguousDataMut() { - CheckValid(); - return GetChunk().GetDataMut(); - } - - template<bool Mut = !IsConst, std::enable_if_t<Mut, bool> = true> - char *UnsafeContiguousDataMut() { - CheckValid(); - return GetChunk().UnsafeGetDataMut(); - } - - // Get the amount of contiguous block. - size_t ContiguousSize() const { - CheckValid(); - return Ptr ? Iter->End - Ptr : 0; - } - - size_t ChunkOffset() const { - return Ptr ? Ptr - Iter->Begin : 0; - } - - // Advance to next contiguous block of data. - void AdvanceToNextContiguousBlock() { - CheckValid(); - Y_DEBUG_ABORT_UNLESS(Valid()); - ++Iter; - Ptr = Iter != GetChainEnd() ? Iter->Begin : nullptr; - } - - // Extract some data and advance. Size is not checked here, to it must be provided valid. - void ExtractPlainDataAndAdvance(void *buffer, size_t len) { - CheckValid(); - - while (len) { - Y_DEBUG_ABORT_UNLESS(Ptr); - - // calculate amount of bytes we need to move - const size_t max = ContiguousSize(); - const size_t num = std::min(len, max); - - // copy data to the buffer and advance buffer pointers - memcpy(buffer, Ptr, num); - buffer = static_cast<char*>(buffer) + num; - len -= num; - - // advance iterator itself - Ptr += num; - if (Ptr == Iter->End) { - AdvanceToNextContiguousBlock(); - } - } - } - - // Checks if the iterator points to the end of the rope or not. - bool Valid() const { - CheckValid(); - return Ptr; - } - - template<bool IsOtherConst> - bool operator ==(const TIteratorImpl<IsOtherConst>& other) const { - Y_DEBUG_ABORT_UNLESS(Rope == other.Rope); - CheckValid(); - other.CheckValid(); - return Iter == other.Iter && Ptr == other.Ptr; - } - - template<bool IsOtherConst> - bool operator !=(const TIteratorImpl<IsOtherConst>& other) const { - CheckValid(); - other.CheckValid(); - return !(*this == other); - } - - private: - friend class TRope; - - typename TTraits::TListIterator operator ->() const { - CheckValid(); - return Iter; - } - - const TRcBuf& GetChunk() const { - CheckValid(); - return *Iter; - } - - template<bool Mut = !IsConst, std::enable_if_t<Mut, bool> = true> - TRcBuf& GetChunk() { - CheckValid(); - return *Iter; - } - - typename TTraits::TListIterator GetChainBegin() const { - CheckValid(); - return Rope->Chain.begin(); - } - - typename TTraits::TListIterator GetChainEnd() const { - CheckValid(); - return Rope->Chain.end(); - } - - bool PointsToChunkMiddle() const { - CheckValid(); - return Ptr && Ptr != Iter->Begin; - } - }; - -public: -#ifndef NDEBUG - ui32 ValidityToken = 0; - ui32 GetValidityToken() const { return ValidityToken; } - void InvalidateIterators() { ++ValidityToken; } -#else - void InvalidateIterators() {} -#endif - -public: - using TConstIterator = TIteratorImpl<true>; - using TIterator = TIteratorImpl<false>; - -public: - TRope() = default; - TRope(const TRope& rope) = default; - - TRope(const TRcBuf& data) { - if(!data.HasBuffer()) { - return; - } - Size = data.GetSize(); - Chain.PutToEnd(data); - } - - TRope(TRcBuf&& data) { - if(!data.HasBuffer()) { - return; - } - Size = data.GetSize(); - Chain.PutToEnd(std::move(data)); - } - - TRope(TRope&& rope) - : Chain(std::move(rope.Chain)) - , Size(std::exchange(rope.Size, 0)) - { - rope.InvalidateIterators(); - } - - explicit TRope(TString s) { - if (s) { - Size = s.size(); - if (s.capacity() < 32) { - s.reserve(32); - } - Chain.PutToEnd(std::move(s)); - } - } - - explicit TRope(NActors::TSharedData s) { - Size = s.size(); - Chain.PutToEnd(std::move(s)); - } - - TRope(IContiguousChunk::TPtr item) { - Size = item->GetData().size(); - Chain.PutToEnd(std::move(item)); - } - - TRope(TConstIterator begin, TConstIterator end) { - Y_DEBUG_ABORT_UNLESS(begin.Rope == end.Rope); - if (begin.Rope == this) { - TRope temp(begin, end); - *this = std::move(temp); - return; - } - - while (begin.Iter != end.Iter) { - const size_t size = begin.ContiguousSize(); - Chain.PutToEnd(TRcBuf::Piece, begin.ContiguousData(), size, begin.GetChunk()); - begin.AdvanceToNextContiguousBlock(); - Size += size; - } - - if (begin != end && end.PointsToChunkMiddle()) { - Chain.PutToEnd(TRcBuf::Piece, begin.Ptr, end.Ptr, begin.GetChunk()); - Size += end.Ptr - begin.Ptr; - } - } - - ~TRope() { - } - - // creates a copy of rope with chunks with inefficient storage ratio being copied with arena allocator - static TRope CopySpaceOptimized(TRope&& origin, size_t worstRatioPer1k, TRopeArena& arena); - - TRope& operator=(const TRope& other) { - Chain = other.Chain; - Size = other.Size; - return *this; - } - - TRope& operator=(TRope&& other) { - Chain = std::move(other.Chain); - Size = std::exchange(other.Size, 0); - InvalidateIterators(); - other.InvalidateIterators(); - return *this; - } - - size_t GetSize() const { - return Size; - } - - size_t size() const { - return Size; - } - - size_t capacity() const { - return Size; - } - - bool IsEmpty() const { - return !Size; - } - - bool empty() const { - return IsEmpty(); - } - - operator bool() const { - return Chain; - } - - TIterator Begin() { - return *this ? TIterator(this, Chain.begin(), Chain.GetFirstChunk().Begin) : End(); - } - - TIterator End() { - return TIterator(this, Chain.end()); - } - - TIterator Iterator(TChunkList::iterator it) { - return TIterator(this, it, it != Chain.end() ? it->Begin : nullptr); - } - - TIterator Position(size_t index) { - return Begin() + index; - } - - TConstIterator Begin() const { - return *this ? TConstIterator(this, Chain.begin(), Chain.GetFirstChunk().Begin) : End(); - } - - TConstIterator End() const { - return TConstIterator(this, Chain.end()); - } - - TConstIterator Position(size_t index) const { - return Begin() + index; - } - - TConstIterator begin() const { return Begin(); } - TConstIterator end() const { return End(); } - - void Erase(TIterator begin, TIterator end) { - Cut(begin, end, nullptr); - } - - TRope Extract(TIterator begin, TIterator end) { - TRope res; - Cut(begin, end, &res); - return res; - } - - void ExtractFront(size_t num, TRope *dest) { - Y_ABORT_UNLESS(Size >= num); - if (num == Size && !*dest) { - *dest = std::move(*this); - return; - } - Size -= num; - dest->Size += num; - - TChunkList::iterator first = Chain.begin(); - - if (num >= first->GetSize() && dest->Chain) { // see if we can glue first chunk to the destination rope - auto& last = dest->Chain.GetLastChunk(); - if (last.Backend == first->Backend && last.End == first->Begin) { - last.End = first->End; - num -= first->GetSize(); - first = Chain.Erase(first); - } - } - - TChunkList::iterator it; - for (it = first; num && num >= it->GetSize(); ++it) { - num -= it->GetSize(); - } - first = dest->Chain.Splice(dest->Chain.end(), Chain, first, it); - - if (num) { // still more data to extract - if (dest->Chain) { - auto& last = dest->Chain.GetLastChunk(); - if (last.Backend == first->Backend && last.End == first->Begin) { - first->Begin += num; - last.End = first->Begin; - return; - } - } - dest->Chain.PutToEnd(TRcBuf::Piece, first->Begin, first->Begin + num, *first); - first->Begin += num; - } - } - - void Insert(TIterator pos, TRope&& rope) { - Y_DEBUG_ABORT_UNLESS(this == pos.Rope); - Y_DEBUG_ABORT_UNLESS(this != &rope); - - if (!rope) { - return; // do nothing for empty rope - } - - // adjust size - Size += std::exchange(rope.Size, 0); - - // check if we have to split the block - if (pos.PointsToChunkMiddle()) { - pos.Iter = Chain.InsertBefore(pos.Iter, TRcBuf::Piece, pos->Begin, pos.Ptr, pos.GetChunk()); - ++pos.Iter; - pos->Begin = pos.Ptr; - } - - // perform glueing if possible - TRcBuf *ropeLeft = &rope.Chain.GetFirstChunk(); - TRcBuf *ropeRight = &rope.Chain.GetLastChunk(); - bool gluedLeft = false, gluedRight = false; - if (pos.Iter != Chain.begin()) { // glue left part whenever possible - // obtain iterator to previous chunk - auto prev(pos.Iter); - --prev; - if (prev->End == ropeLeft->Begin && prev->Backend == ropeLeft->Backend) { // it is glueable - prev->End = ropeLeft->End; - gluedLeft = true; - } - } - if (pos.Iter != Chain.end() && ropeRight->End == pos->Begin && ropeRight->Backend == pos->Backend) { - pos->Begin = ropeRight->Begin; - gluedRight = true; - } - if (gluedLeft) { - rope.Chain.EraseFront(); - } - if (gluedRight) { - if (rope) { - rope.Chain.EraseBack(); - } else { // it looks like double-glueing for the same chunk, we have to drop previous one - auto prev(pos.Iter); - --prev; - pos->Begin = prev->Begin; - pos.Iter = Chain.Erase(prev); - } - } - if (rope) { // insert remains - Chain.Splice(pos.Iter, rope.Chain, rope.Chain.begin(), rope.Chain.end()); - } - Y_DEBUG_ABORT_UNLESS(!rope); - InvalidateIterators(); - } - - void EraseFront(size_t len) { - Y_DEBUG_ABORT_UNLESS(Size >= len); - Size -= len; - - while (len) { - Y_DEBUG_ABORT_UNLESS(Chain); - TRcBuf& item = Chain.GetFirstChunk(); - const size_t itemSize = item.GetSize(); - if (len >= itemSize) { - Chain.EraseFront(); - len -= itemSize; - } else { - item.Begin += len; - break; - } - } - - InvalidateIterators(); - } - - void EraseBack(size_t len) { - Y_DEBUG_ABORT_UNLESS(Size >= len); - Size -= len; - - while (len) { - Y_DEBUG_ABORT_UNLESS(Chain); - TRcBuf& item = Chain.GetLastChunk(); - const size_t itemSize = item.GetSize(); - if (len >= itemSize) { - Chain.EraseBack(); - len -= itemSize; - } else { - item.End -= len; - break; - } - } - - InvalidateIterators(); - } - - bool ExtractFrontPlain(void *buffer, size_t len) { - // check if we have enough data in the rope - if (Size < len) { - return false; - } - Size -= len; - while (len) { - auto& chunk = Chain.GetFirstChunk(); - Y_DEBUG_ABORT_UNLESS(chunk.Backend); - const size_t num = Min(len, chunk.GetSize()); - memcpy(buffer, chunk.Begin, num); - buffer = static_cast<char*>(buffer) + num; - len -= num; - chunk.Begin += num; - if (chunk.Begin == chunk.End) { - Chain.EraseFront(); - } - } - InvalidateIterators(); - return true; - } - - bool FetchFrontPlain(char **ptr, size_t *remain) { - const size_t num = Min(*remain, Size); - ExtractFrontPlain(*ptr, num); - *ptr += num; - *remain -= num; - return !*remain; - } - - static int Compare(const TRope& x, const TRope& y) { - TConstIterator xIter = x.Begin(), yIter = y.Begin(); - while (xIter.Valid() && yIter.Valid()) { - const size_t step = std::min(xIter.ContiguousSize(), yIter.ContiguousSize()); - if (int res = memcmp(xIter.ContiguousData(), yIter.ContiguousData(), step)) { - return res; - } - xIter += step; - yIter += step; - } - return xIter.Valid() - yIter.Valid(); - } - - static int Compare(const TRope& x, const TContiguousSpan& y) { - TConstIterator xIter = x.Begin(); - const char* yData = y.data(); - size_t yOffset = 0; - while (xIter.Valid() && yOffset != y.size()) { - const size_t step = std::min(xIter.ContiguousSize(), y.size() - yOffset); - if (int res = memcmp(xIter.ContiguousData(), yData + yOffset, step)) { - return res; - } - xIter += step; - yOffset += step; - } - return xIter.Valid() - (yOffset != y.size()); - } - - static int Compare(const TContiguousSpan& x, const TRope& y) { - return -Compare(y, x); - } - - // Use this method carefully -- it may significantly reduce performance when misused. - TString ConvertToString() const { - return ExtractUnderlyingContainerOrCopy<TString>(); - } - - /** - * WARN: this method supports extracting only for natively supported types for any other type the data *will* be copied - */ - template <class TResult> - TResult ExtractUnderlyingContainerOrCopy() const { - if (Chain.begin() != Chain.end() && ++Chain.begin() == Chain.end()) { - return Chain.GetFirstChunk().ExtractUnderlyingContainerOrCopy<TResult>(); - } - - const size_t size = GetSize(); - TResult res = TResult::Uninitialized(size); - char* data = NContiguousDataDetails::TContainerTraits<TResult>::UnsafeGetDataMut(res); - Begin().ExtractPlainDataAndAdvance(data, size); - return res; - } - - void clear() { - Erase(Begin(), End()); - } - - bool IsContiguous() const { - if(Begin() == End() || (++Begin() == End())) { - return true; - } - return false; - } - - void Compact(size_t headroom = 0, size_t tailroom = 0) { - if(!IsContiguous()) { - // TODO(innokentii): use better container, when most outer users stop use TString - TRcBuf res = TRcBuf::Uninitialized(GetSize(), headroom, tailroom); - Begin().ExtractPlainDataAndAdvance(res.UnsafeGetDataMut(), res.size()); - Erase(Begin(), End()); - Insert(End(), TRope(res)); - } - } - - static TRope Uninitialized(size_t size) - { - TRcBuf res = TRcBuf::Uninitialized(size); - return TRope(res); - } - - /** - * Compacts data and calls GetData() on undelying container - * WARN: Will copy if data isn't contiguous - */ - TContiguousSpan GetContiguousSpan() { - if(Begin() == End()) { - return {nullptr, 0}; - } - Compact(); - return Begin()->GetContiguousSpan(); - } - - /** - * Compacts data and calls GetDataMut() on undelying container - * WARN: Will copy if data isn't contiguous - */ - TMutableContiguousSpan GetContiguousSpanMut() { - if(Begin() == End()) { - return {nullptr, 0}; - } - Compact(); - return Begin()->GetContiguousSpanMut(); - } - - /** - * Compacts data and calls UnsafeGetDataMut() on undelying container - * WARN: Will copy if data isn't contiguous - * WARN: Even if underlying container is shared - returns reference to its underlying data - */ - TMutableContiguousSpan UnsafeGetContiguousSpanMut() { - if(Begin() == End()) { - return {nullptr, 0}; - } - Compact(); - return Begin()->UnsafeGetContiguousSpanMut(); - } - - TString DebugString() const { - TStringStream s; - s << "{Size# " << Size; - for (const auto& chunk : Chain) { - const char *data; - data = chunk.Backend.GetData().data(); - s << " [" << chunk.Begin - data << ", " << chunk.End - data << ")@" << chunk.Backend.UniqueId(); - } - s << "}"; - return s.Str(); - } - - explicit operator TRcBuf() { - if(GetSize() == 0) { - return TRcBuf(); - } - Compact(); - return TRcBuf(Begin().GetChunk()); - } - - size_t GetOccupiedMemorySize() const; - - friend bool operator==(const TRope& x, const TRope& y) { return Compare(x, y) == 0; } - friend bool operator!=(const TRope& x, const TRope& y) { return Compare(x, y) != 0; } - friend bool operator< (const TRope& x, const TRope& y) { return Compare(x, y) < 0; } - friend bool operator<=(const TRope& x, const TRope& y) { return Compare(x, y) <= 0; } - friend bool operator> (const TRope& x, const TRope& y) { return Compare(x, y) > 0; } - friend bool operator>=(const TRope& x, const TRope& y) { return Compare(x, y) >= 0; } - - friend bool operator==(const TRope& x, const TContiguousSpan& y) { return Compare(x, y) == 0; } - friend bool operator!=(const TRope& x, const TContiguousSpan& y) { return Compare(x, y) != 0; } - friend bool operator< (const TRope& x, const TContiguousSpan& y) { return Compare(x, y) < 0; } - friend bool operator<=(const TRope& x, const TContiguousSpan& y) { return Compare(x, y) <= 0; } - friend bool operator> (const TRope& x, const TContiguousSpan& y) { return Compare(x, y) > 0; } - friend bool operator>=(const TRope& x, const TContiguousSpan& y) { return Compare(x, y) >= 0; } - - friend bool operator==(const TContiguousSpan& x, const TRope& y) { return Compare(x, y) == 0; } - friend bool operator!=(const TContiguousSpan& x, const TRope& y) { return Compare(x, y) != 0; } - friend bool operator< (const TContiguousSpan& x, const TRope& y) { return Compare(x, y) < 0; } - friend bool operator<=(const TContiguousSpan& x, const TRope& y) { return Compare(x, y) <= 0; } - friend bool operator> (const TContiguousSpan& x, const TRope& y) { return Compare(x, y) > 0; } - friend bool operator>=(const TContiguousSpan& x, const TRope& y) { return Compare(x, y) >= 0; } - - // FIXME(innokentii) temporary hack - friend bool operator==(const TRope& x, const TRcBuf& y) { return Compare(x, y.GetContiguousSpan()) == 0; } - friend bool operator!=(const TRope& x, const TRcBuf& y) { return Compare(x, y.GetContiguousSpan()) != 0; } - friend bool operator< (const TRope& x, const TRcBuf& y) { return Compare(x, y.GetContiguousSpan()) < 0; } - friend bool operator<=(const TRope& x, const TRcBuf& y) { return Compare(x, y.GetContiguousSpan()) <= 0; } - friend bool operator> (const TRope& x, const TRcBuf& y) { return Compare(x, y.GetContiguousSpan()) > 0; } - friend bool operator>=(const TRope& x, const TRcBuf& y) { return Compare(x, y.GetContiguousSpan()) >= 0; } - - friend bool operator==(const TRcBuf& x, const TRope& y) { return Compare(x.GetContiguousSpan(), y) == 0; } - friend bool operator!=(const TRcBuf& x, const TRope& y) { return Compare(x.GetContiguousSpan(), y) != 0; } - friend bool operator< (const TRcBuf& x, const TRope& y) { return Compare(x.GetContiguousSpan(), y) < 0; } - friend bool operator<=(const TRcBuf& x, const TRope& y) { return Compare(x.GetContiguousSpan(), y) <= 0; } - friend bool operator> (const TRcBuf& x, const TRope& y) { return Compare(x.GetContiguousSpan(), y) > 0; } - friend bool operator>=(const TRcBuf& x, const TRope& y) { return Compare(x.GetContiguousSpan(), y) >= 0; } - - -private: - void Cut(TIterator begin, TIterator end, TRope *target) { - // ensure all iterators are belong to us - Y_DEBUG_ABORT_UNLESS(this == begin.Rope && this == end.Rope); - - // if begin and end are equal, we do nothing -- checking this case allows us to find out that begin does not - // point to End(), for example - if (begin == end) { - return; - } - - auto addBlock = [&](const TRcBuf& from, const char *begin, const char *end) { - if (target) { - target->Chain.PutToEnd(TRcBuf::Piece, begin, end, from); - target->Size += end - begin; - } - Size -= end - begin; - }; - - // consider special case -- when begin and end point to the same block; in this case we have to split up this - // block into two parts - if (begin.Iter == end.Iter) { - TRcBuf chunkToSplit = begin.GetChunk(); - addBlock(chunkToSplit, begin.Ptr, end.Ptr); - const char *firstChunkBegin = begin.PointsToChunkMiddle() ? begin->Begin : nullptr; - begin->Begin = end.Ptr; // this affects both begin and end iterator pointed values - if (firstChunkBegin) { - Chain.InsertBefore(begin.Iter, TRcBuf::Piece, firstChunkBegin, begin.Ptr, chunkToSplit); - } - } else { - // check the first iterator -- if it starts not from the begin of the block, we have to adjust end of the - // first block to match begin iterator and switch to next block - if (begin.PointsToChunkMiddle()) { - addBlock(begin.GetChunk(), begin.Ptr, begin->End); - begin->End = begin.Ptr; - begin.AdvanceToNextContiguousBlock(); - } - - // now drop full blocks - size_t rangeSize = 0; - for (auto it = begin.Iter; it != end.Iter; ++it) { - Y_DEBUG_ABORT_UNLESS(it->GetSize()); - rangeSize += it->GetSize(); - } - if (rangeSize) { - if (target) { - end.Iter = target->Chain.Splice(target->Chain.end(), Chain, begin.Iter, end.Iter); - target->Size += rangeSize; - } else { - end.Iter = Chain.Erase(begin.Iter, end.Iter); - } - Size -= rangeSize; - } - - // and cut the last block if necessary - if (end.PointsToChunkMiddle()) { - addBlock(end.GetChunk(), end->Begin, end.Ptr); - end->Begin = end.Ptr; - } - } - - InvalidateIterators(); - } -}; - -class TRopeArena { - using TAllocateCallback = std::function<TIntrusivePtr<IContiguousChunk>()>; - - TAllocateCallback Allocator; - TRope Arena; - -public: - TRopeArena(TAllocateCallback&& allocator) - : Allocator(std::move(allocator)) - {} - - TRope CreateRope(const void *buffer, size_t len) { - TRope res; - - while (len) { - if (Arena) { - auto iter = Arena.Begin(); - Y_DEBUG_ABORT_UNLESS(iter.Valid()); - char *dest = const_cast<char*>(iter.ContiguousData()); - const size_t bytesToCopy = std::min(len, iter.ContiguousSize()); - memcpy(dest, buffer, bytesToCopy); - buffer = static_cast<const char*>(buffer) + bytesToCopy; - len -= bytesToCopy; - res.Insert(res.End(), Arena.Extract(Arena.Begin(), Arena.Position(bytesToCopy))); - } else { - Arena.Insert(Arena.End(), TRope(Allocator())); - } - } - - // align arena on 8-byte boundary - const size_t align = 8; - if (const size_t padding = Arena.GetSize() % align) { - Arena.EraseFront(padding); - } - - return res; - } -}; - -struct TRopeUtils { - static void Memset(TRope::TConstIterator dst, char c, size_t size) { - while (size) { - Y_DEBUG_ABORT_UNLESS(dst.Valid()); - size_t len = std::min(size, dst.ContiguousSize()); - memset(const_cast<char*>(dst.ContiguousData()), c, len); - dst += len; - size -= len; - } - } - - static void Memcpy(TRope::TConstIterator dst, TRope::TConstIterator src, size_t size) { - while (size) { - Y_DEBUG_ABORT_UNLESS(dst.Valid() && src.Valid(), - "Invalid iterator in memcpy: dst.Valid() - %" PRIu32 ", src.Valid() - %" PRIu32, - (ui32)dst.Valid(), (ui32)src.Valid()); - size_t len = std::min(size, std::min(dst.ContiguousSize(), src.ContiguousSize())); - memcpy(const_cast<char*>(dst.ContiguousData()), src.ContiguousData(), len); - dst += len; - src += len; - size -= len; - } - } - - static void Memcpy(TRope::TConstIterator dst, const char* src, size_t size) { - while (size) { - Y_DEBUG_ABORT_UNLESS(dst.Valid()); - size_t len = std::min(size, dst.ContiguousSize()); - memcpy(const_cast<char*>(dst.ContiguousData()), src, len); - size -= len; - dst += len; - src += len; - } - } - - static void Memcpy(char* dst, TRope::TConstIterator src, size_t size) { - while (size) { - Y_DEBUG_ABORT_UNLESS(src.Valid()); - size_t len = std::min(size, src.ContiguousSize()); - memcpy(dst, src.ContiguousData(), len); - size -= len; - dst += len; - src += len; - } - } - - // copy less or equal to sizeBound bytes, until src is valid - static size_t SafeMemcpy(char* dst, TRope::TIterator src, size_t sizeBound) { - size_t origSize = sizeBound; - while (sizeBound && src.Valid()) { - size_t len = Min(sizeBound, src.ContiguousSize()); - memcpy(dst, src.ContiguousData(), len); - sizeBound -= len; - dst += len; - src += len; - } - return origSize - sizeBound; - } -}; - -template<size_t BLOCK, size_t ALIGN = 16> -class TRopeSlideView { - alignas(ALIGN) char Slide[BLOCK]; // use if distance from current point and next chunk is less than BLOCK - TRope::TIterator Position; // current position at rope - size_t Size; - char* Head; // points to data, it might be current rope chunk or Slide - -private: - void FillBlock() { - size_t chunkSize = Position.ContiguousSize(); - if (chunkSize >= BLOCK) { - Size = chunkSize; - Head = const_cast<char*>(Position.ContiguousData()); - } else { - Size = TRopeUtils::SafeMemcpy(Slide, Position, BLOCK); - Head = Slide; - } - } - -public: - TRopeSlideView(TRope::TIterator position) - : Position(position) - { - FillBlock(); - } - - TRopeSlideView(TRope &rope) - : TRopeSlideView(rope.Begin()) - {} - - // if view on slide then copy slide to rope - void FlushBlock() { - if (Head == Slide) { - TRopeUtils::Memcpy(Position, Head, Size); - } - } - - TRope::TIterator operator+=(size_t amount) { - Position += amount; - FillBlock(); - return Position; - } - - TRope::TIterator GetPosition() const { - return Position; - } - - char* GetHead() const { - return Head; - } - - ui8* GetUi8Head() const { - return reinterpret_cast<ui8*>(Head); - } - - size_t ContiguousSize() const { - return Size; - } - - bool IsOnChunk() const { - return Head != Slide; - } -}; - -class TRopeZeroCopyInput : public IZeroCopyInput { - TRope::TConstIterator Iter; - const char* Data = nullptr; - size_t Len = 0; - -private: - size_t DoNext(const void** ptr, size_t len) override { - Y_DEBUG_ABORT_UNLESS(ptr); - if (Len == 0) { - if (Iter.Valid()) { - Data = Iter.ContiguousData(); - Len = Iter.ContiguousSize(); - Y_DEBUG_ABORT_UNLESS(Len); - Y_DEBUG_ABORT_UNLESS(Data); - ++Iter; - } else { - Data = nullptr; - } - } - - size_t chunk = std::min(Len, len); - *ptr = Data; - Data += chunk; - Len -= chunk; - return chunk; - } - -public: - explicit TRopeZeroCopyInput(TRope::TConstIterator iter) - : Iter(iter) - { - } -}; - -inline TRope TRope::CopySpaceOptimized(TRope&& origin, size_t worstRatioPer1k, TRopeArena& arena) { - TRope res; - for (TRcBuf& chunk : origin.Chain) { - size_t ratio = chunk.GetSize() * 1024 / chunk.GetOccupiedMemorySize(); - if (ratio < 1024 - worstRatioPer1k) { - res.Insert(res.End(), arena.CreateRope(chunk.Begin, chunk.GetSize())); - } else { - res.Chain.PutToEnd(std::move(chunk)); - } - } - res.Size = origin.Size; - origin = TRope(); - return res; -} - - -#if defined(WITH_VALGRIND) || defined(_msan_enabled_) - -inline void CheckRopeIsDefined(TRope::TConstIterator begin, ui64 size) { - while (size) { - ui64 contiguousSize = Min(size, begin.ContiguousSize()); -# if defined(WITH_VALGRIND) - VALGRIND_CHECK_MEM_IS_DEFINED(begin.ContiguousData(), contiguousSize); -# endif -# if defined(_msan_enabled_) - NSan::CheckMemIsInitialized(begin.ContiguousData(), contiguousSize); -# endif - size -= contiguousSize; - begin += contiguousSize; - } -} - -# define CHECK_ROPE_IS_DEFINED(begin, size) CheckRopeIsDefined(begin, size) - -#else - -# define CHECK_ROPE_IS_DEFINED(begin, size) do {} while (false) - -#endif diff --git a/library/cpp/actors/util/rope_cont_embedded_list.h b/library/cpp/actors/util/rope_cont_embedded_list.h deleted file mode 100644 index 294599538f..0000000000 --- a/library/cpp/actors/util/rope_cont_embedded_list.h +++ /dev/null @@ -1,391 +0,0 @@ -#pragma once - -#include <util/generic/intrlist.h> - -#include <util/random/random.h> - -namespace NRopeDetails { - -template<typename TChunk> -class TChunkList { - struct TItem : TChunk { - TItem *Next = nullptr; - TItem *Prev = nullptr; -#ifndef NDEBUG - ui64 ValidityToken = RandomNumber<ui64>(); -#endif - - template<typename... TArgs> TItem(TArgs&&... args) : TChunk(std::forward<TArgs>(args)...) {} - - ~TItem() { - Invalidate(); - if (IsInUse()) { - Unlink(); - } - } - - void LinkBefore(TItem *item) { - Next = item; - Prev = item->Prev; - Next->Prev = Prev->Next = this; - } - - void Unlink() { - Next->Prev = Prev; - Prev->Next = Next; - } - - bool IsInUse() const { - return Next != nullptr; - } - - void ClearSingleItem() { - Y_DEBUG_ABORT_UNLESS(Next == this && Prev == this); - static_cast<TChunk&>(*this) = {}; - Next = Prev = nullptr; - } - - template<typename... TArgs> - TItem *PrepareForUse(TArgs&&... args) { - Y_DEBUG_ABORT_UNLESS(!IsInUse()); - static_cast<TChunk&>(*this) = TChunk(std::forward<TArgs>(args)...); - Next = Prev = this; - Invalidate(); - return this; - } - - static void TransferRange(TItem *insertBefore, TItem *first, TItem *last) { // [first, last] -> insertBefore - first->Prev->Next = last->Next; - last->Next->Prev = first->Prev; - first->Prev = insertBefore->Prev; - last->Next = insertBefore; - first->Prev->Next = first; - last->Next->Prev = last; - } - - void Invalidate() { -#ifndef NDEBUG - ValidityToken = RandomNumber<ui64>(); -#endif - } - }; - - // There are three possible states for the list: - // 1. It is empty. Next = Prev = nullptr, TChunk is default-constructed. - // 2. It contains single item. Next = Prev = &Root, TChunk contains data. - // 3. It has more than one item. Next and Prev make up a double-linked list starting with Root item; TChunk contains - // first item. - // This container scheme leads to the following properties: - // 1. Deleting first item in the list invalidates iterators to the first two items. - // 2. Inserting something before the first item also invalidates iterators to the first two items. - // This happens because Root is always the first element of the list and when inserting before the Root, we have to - // shift original Root element to the allocated item and replace Root with newly inserted value. - // This also makes right-to-left traversing more efficient in some cases. - TItem Root; - - template<typename... TArgs> - TItem *AllocateItem(TArgs&&... args) { - return Root.IsInUse() - ? new TItem{std::forward<TArgs>(args)...} - : Root.PrepareForUse(std::forward<TArgs>(args)...); - } - -private: - template<bool IsConst> - class TIterator { - friend class TChunkList; - - using TChunkListType = std::conditional_t<IsConst, const TChunkList, TChunkList>; - using TItemType = std::conditional_t<IsConst, const TItem, TItem>; - using TChunkType = std::conditional_t<IsConst, const TChunk, TChunk>; - - TChunkListType *Cont = nullptr; - TItemType *Item = nullptr; -#ifndef NDEBUG - ui64 ValidityToken = 0; -#endif - - private: - TIterator(TChunkListType *cont, TItemType *item) - : Cont(cont) - , Item(item) - { - UpdateValidityToken(); - } - - public: - TIterator() = default; - - template<bool OtherIsConst, typename = std::enable_if_t<OtherIsConst <= IsConst>> - TIterator(const TIterator<OtherIsConst>& other) - : Cont(other.Cont) - , Item(other.Item) - { - UpdateValidityToken(); - } - - TChunkType& operator *() const { - CheckValid(); - return *Item; - } - - TChunkType *operator ->() const { - CheckValid(); - return Item; - } - - TIterator& operator++() { - CheckValid(); - Y_DEBUG_ABORT_UNLESS(Item); - Item = Item->Next; - if (Item == &Cont->Root) { - Item = nullptr; // make it end - } - UpdateValidityToken(); - return *this; - } - - TIterator operator ++(int) { - TIterator res(*this); - ++*this; - return res; - } - - TIterator& operator--() { - CheckValid(); - if (!Item) { - Y_DEBUG_ABORT_UNLESS(*Cont); - Item = Cont->Root.Prev; - } else { - Y_DEBUG_ABORT_UNLESS(Item != &Cont->Root); - Item = Item->Prev; - } - UpdateValidityToken(); - return *this; - } - - TIterator operator --(int) { - TIterator res(*this); - --*this; - return res; - } - - friend bool operator ==(const TIterator& x, const TIterator& y) { - Y_DEBUG_ABORT_UNLESS(x.Cont == y.Cont); - x.CheckValid(); - y.CheckValid(); - return x.Item == y.Item; - } - - friend bool operator !=(const TIterator& x, const TIterator& y) { - return !(x == y); - } - - private: - void CheckValid() const { -#ifndef NDEBUG - Y_DEBUG_ABORT_UNLESS(ValidityToken == (Item ? Item->ValidityToken : 0)); - Y_DEBUG_ABORT_UNLESS(Cont && (Item != &Cont->Root || *Cont)); -#endif - } - - void UpdateValidityToken() { -#ifndef NDEBUG - ValidityToken = Item ? Item->ValidityToken : 0; -#endif - CheckValid(); - } - }; - -public: - using iterator = TIterator<false>; - using const_iterator = TIterator<true>; - -public: - TChunkList() - {} - - ~TChunkList() { - Erase(begin(), end()); - Y_DEBUG_ABORT_UNLESS(!*this); - } - - TChunkList(const TChunkList& other) { - *this = other; - } - - TChunkList(TChunkList&& other) { - *this = std::move(other); - } - - TChunkList& operator=(const TChunkList& other) { - if (this != &other) { - Erase(begin(), end()); - for (const TChunk& chunk : other) { - PutToEnd(TChunk(chunk)); - } - } - return *this; - } - - TChunkList& operator=(TChunkList&& other) { - if (this != &other) { - Erase(begin(), end()); - Y_DEBUG_ABORT_UNLESS(!*this); - if (other.Root.IsInUse()) { // do we have something to move? - Root.PrepareForUse(std::move(static_cast<TChunk&>(other.Root))); - if (other.Root.Next != &other.Root) { // does other contain more than one item? - TItem::TransferRange(&Root, other.Root.Next, other.Root.Prev); - } - other.Root.ClearSingleItem(); - } - } - return *this; - } - - template<typename... TArgs> - void PutToEnd(TArgs&&... args) { - InsertBefore(end(), std::forward<TArgs>(args)...); - } - - template<typename... TArgs> - iterator InsertBefore(iterator pos, TArgs&&... args) { - TItem *item = AllocateItem<TArgs...>(std::forward<TArgs>(args)...); - if (item == &Root) { - // this is the first item, we don't do anything about it - } else if (pos.Item != &Root) { - item->LinkBefore(pos.Item ? pos.Item : &Root); - } else { - item->LinkBefore(Root.Next); - std::swap(static_cast<TChunk&>(*item), static_cast<TChunk&>(Root)); - item = &Root; - Root.Invalidate(); - } - return {this, item}; - } - - iterator Erase(iterator pos) { - Pop(pos); - return pos; - } - - iterator Erase(iterator first, iterator last) { - if (first == last) { - return last; - } - for (;;) { - if (last == begin()) { - EraseFront(); - return begin(); - } else if (--last == first) { - return Erase(last); - } else { - last = Erase(last); - } - } - } - - void EraseFront() { - PopFront(); - } - - void EraseBack() { - Y_DEBUG_ABORT_UNLESS(*this); - if (Root.Prev != &Root) { - delete Root.Prev; - } else { - EraseFront(); - } - } - - // Splice moves elements from the 'from' list in the range [first, last) to *this, inserting them before 'pos'. It - // returns iterator of the next remaining item in the 'from' list. - iterator Splice(iterator pos, TChunkList& from, iterator first, iterator last) { - if (first == last) { // the source range is empty - return last; - } - - const bool fromBegin = first == from.begin(); - if (fromBegin) { // remember we have to transfer the first item before returning - ++first; - } - - // 'first' here either equals to 'last' or points to the middle of the 'from' list - - const bool toBegin = pos == begin(); - if (toBegin && first != last) { - // we are inserting item to the begin of the list, so move the first item of the range; it is important here - // that 'last' iterator doesn't get invalidated - pos = InsertBefore(begin(), from.Pop(first)); - ++pos; - } - - const auto temp = last; - if (first != last) { - --last; // set 'last' pointing to the actual last element of the source range - - Y_DEBUG_ABORT_UNLESS(first.Item != &from.Root); - Y_DEBUG_ABORT_UNLESS(pos.Item != &Root); - - TItem* const firstItem = first.Item; - TItem* const lastItem = last.Item; - TItem* const posItem = pos.Item ? pos.Item : &Root; - - TItem::TransferRange(posItem, firstItem, lastItem); - - // adjust 'pos' to point to the first inserted item - pos = {this, firstItem}; - } - - if (fromBegin) { - InsertBefore(toBegin ? begin() : pos, from.PopFront()); - return from.begin(); - } else { - return temp; - } - } - - operator bool() const { return Root.IsInUse(); } - - TChunk& GetFirstChunk() { Y_DEBUG_ABORT_UNLESS(*this); return Root; } - const TChunk& GetFirstChunk() const { Y_DEBUG_ABORT_UNLESS(*this); return Root; } - TChunk& GetLastChunk() { Y_DEBUG_ABORT_UNLESS(*this); return *Root.Prev; } - - iterator begin() { return *this ? iterator(this, &Root) : end(); } - const_iterator begin() const { return *this ? const_iterator(this, &Root) : end(); } - iterator end() { return {this, nullptr}; } - const_iterator end() const { return {this, nullptr}; } - -private: - TChunk Pop(iterator& pos) { - pos.CheckValid(); - Y_DEBUG_ABORT_UNLESS(pos.Item); - - if (pos.Item == &Root) { - TChunk res = PopFront(); - pos = begin(); - return res; - } else { - Y_DEBUG_ABORT_UNLESS(pos != end()); - TItem* const item = pos++.Item; - TChunk res = std::move(static_cast<TChunk&>(*item)); - delete item; - return res; - } - } - - TChunk PopFront() { - Y_DEBUG_ABORT_UNLESS(*this); - TChunk res = std::move(static_cast<TChunk&>(Root)); - if (Root.Next != &Root) { - static_cast<TChunk&>(Root) = std::move(static_cast<TChunk&>(*Root.Next)); - delete Root.Next; - Root.Invalidate(); - } else { - Root.ClearSingleItem(); - } - return res; - } -}; - -} // NRopeDetails diff --git a/library/cpp/actors/util/rope_ut.cpp b/library/cpp/actors/util/rope_ut.cpp deleted file mode 100644 index 0ff85d6c59..0000000000 --- a/library/cpp/actors/util/rope_ut.cpp +++ /dev/null @@ -1,418 +0,0 @@ -#include "rope.h" -#include <library/cpp/testing/unittest/registar.h> -#include <util/random/random.h> -#include "ut_helpers.h" - -class TRopeStringBackend : public IContiguousChunk { - TString Buffer; - -public: - TRopeStringBackend(TString buffer) - : Buffer(std::move(buffer)) - {} - - TContiguousSpan GetData() const override { - return {Buffer.data(), Buffer.size()}; - } - - TMutableContiguousSpan GetDataMut() override { - return {Buffer.Detach(), Buffer.size()}; - } - - TMutableContiguousSpan UnsafeGetDataMut() override { - return {const_cast<char*>(Buffer.data()), Buffer.size()}; - } - - size_t GetOccupiedMemorySize() const override { - return Buffer.capacity(); - } -}; - -TRope CreateRope(TString s, size_t sliceSize) { - TRope res; - for (size_t i = 0; i < s.size(); ) { - size_t len = std::min(sliceSize, s.size() - i); - if (i % 2) { - res.Insert(res.End(), TRope(MakeIntrusive<TRopeStringBackend>(s.substr(i, len)))); - } else { - res.Insert(res.End(), TRope(s.substr(i, len))); - } - i += len; - } - return res; -} - -TString RopeToString(const TRope& rope) { - TString res; - auto iter = rope.Begin(); - while (iter != rope.End()) { - res.append(iter.ContiguousData(), iter.ContiguousSize()); - iter.AdvanceToNextContiguousBlock(); - } - - UNIT_ASSERT_VALUES_EQUAL(rope.GetSize(), res.size()); - - TString temp = TString::Uninitialized(rope.GetSize()); - rope.Begin().ExtractPlainDataAndAdvance(temp.Detach(), temp.size()); - UNIT_ASSERT_VALUES_EQUAL(temp, res); - - return res; -} - -TString Text = "No elements are copied or moved, only the internal pointers of the list nodes are re-pointed."; - -Y_UNIT_TEST_SUITE(TRope) { - Y_UNIT_TEST(StringCompare) { - TRope rope = CreateRope(Text, 10); - UNIT_ASSERT_EQUAL(rope, Text); - UNIT_ASSERT_EQUAL(Text, rope); - rope.Erase(rope.Begin() + 10, rope.Begin() + 11); - UNIT_ASSERT_UNEQUAL(rope, Text); - UNIT_ASSERT_UNEQUAL(Text, rope); - TString str("aa"); - rope = TRope(TString("ab")); - UNIT_ASSERT_LT(str, rope); - UNIT_ASSERT_GT(rope, str); - str = TString("aa"); - rope = TRope(TString("a")); - UNIT_ASSERT_LT(rope, str); - UNIT_ASSERT_GT(str, rope); - str = TString("a"); - rope = TRope(TString("aa")); - UNIT_ASSERT_LT(str, rope); - UNIT_ASSERT_GT(rope, str); - } - - Y_UNIT_TEST(Leak) { - const size_t begin = 10, end = 20; - TRope rope = CreateRope(Text, 10); - rope.Erase(rope.Begin() + begin, rope.Begin() + end); - } - - Y_UNIT_TEST(Compacted) { - TRope rope = CreateRope(Text, 10); - UNIT_ASSERT_EQUAL(rope.UnsafeGetContiguousSpanMut(), Text); - UNIT_ASSERT(rope.IsContiguous()); - } - -#ifndef TSTRING_IS_STD_STRING - Y_UNIT_TEST(ExtractZeroCopy) { - TString str = Text; - TRope packed(str); - TString extracted = packed.ExtractUnderlyingContainerOrCopy<TString>(); - UNIT_ASSERT_EQUAL(str.data(), extracted.data()); - } - - Y_UNIT_TEST(ExtractZeroCopySlice) { - TString str = Text; - TRope sliced(str); - sliced.EraseFront(1); - TString extracted = sliced.ExtractUnderlyingContainerOrCopy<TString>(); - UNIT_ASSERT_UNEQUAL(str.data(), extracted.data()); - TRope sliced2(str); - sliced2.EraseBack(1); - TString extracted2 = sliced2.ExtractUnderlyingContainerOrCopy<TString>(); - UNIT_ASSERT_UNEQUAL(str.data(), extracted2.data()); - } - - Y_UNIT_TEST(TStringDetach) { - TRope pf; - TRope rope; - TString string = TString(Text.data(), Text.size()); - rope = TRope(string); - pf = rope; - pf.GetContiguousSpanMut(); - UNIT_ASSERT(!string.IsDetached()); - rope.GetContiguousSpanMut(); - UNIT_ASSERT(string.IsDetached()); - } - - Y_UNIT_TEST(TStringUnsafeShared) { - TRope pf; - TRope rope; - TString string = TString(Text.data(), Text.size()); - rope = TRope(string); - pf = rope; - UNIT_ASSERT(pf.IsContiguous()); - UNIT_ASSERT_EQUAL(pf.UnsafeGetContiguousSpanMut().data(), string.data()); - UNIT_ASSERT(!string.IsDetached()); - } - - Y_UNIT_TEST(ContiguousDataInterop) { - TString string = "Some long-long text needed for not sharing data and testing"; - TRcBuf data(string); - UNIT_ASSERT_EQUAL(data.UnsafeGetDataMut(), &(*string.cbegin())); - TRope rope(data); // check operator TRope - UNIT_ASSERT_EQUAL(rope.UnsafeGetContiguousSpanMut().data(), &(*string.cbegin())); - TRcBuf otherData(rope); - UNIT_ASSERT_EQUAL(otherData.UnsafeGetDataMut(), &(*string.cbegin())); - TString extractedBack = otherData.ExtractUnderlyingContainerOrCopy<TString>(); - UNIT_ASSERT_EQUAL(extractedBack.data(), &(*string.cbegin())); - } -#endif - Y_UNIT_TEST(CrossCompare) { - TString str = "some very long string"; - const TString constStr(str); - TStringBuf strbuf = str; - const TStringBuf constStrbuf = str; - TContiguousSpan span(str); - const TContiguousSpan constSpan(str); - TMutableContiguousSpan mutableSpan(const_cast<char*>(str.data()), str.size()); - const TMutableContiguousSpan constMutableSpan(const_cast<char*>(str.data()), str.size()); - TRcBuf data(str); - const TRcBuf constData(str); - TArrayRef<char> arrRef(const_cast<char*>(str.data()), str.size()); - const TArrayRef<char> constArrRef(const_cast<char*>(str.data()), str.size()); - TArrayRef<const char> arrConstRef(const_cast<char*>(str.data()), str.size()); - const TArrayRef<const char> constArrConstRef(const_cast<char*>(str.data()), str.size()); - NActors::TSharedData sharedData = NActors::TSharedData::Copy(str.data(), str.size()); - const NActors::TSharedData constSharedData(sharedData); - TRope rope(str); - const TRope constRope(str); - - Permutate( - [](auto& arg1, auto& arg2) { - UNIT_ASSERT(arg1 == arg2); - }, - str, - constStr, - strbuf, - constStrbuf, - span, - constSpan, - mutableSpan, - constMutableSpan, - data, - constData, - arrRef, - constArrRef, - arrConstRef, - constArrConstRef, - sharedData, - constSharedData, - rope, - constRope); - } - - Y_UNIT_TEST(BasicRange) { - TRope rope = CreateRope(Text, 10); - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope::TIterator rBegin = rope.Begin() + begin; - TRope::TIterator rEnd = rope.Begin() + end; - UNIT_ASSERT_VALUES_EQUAL(RopeToString(TRope(rBegin, rEnd)), Text.substr(begin, end - begin)); - } - } - } - - Y_UNIT_TEST(Erase) { - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope rope = CreateRope(Text, 10); - rope.Erase(rope.Begin() + begin, rope.Begin() + end); - TString text = Text; - text.erase(text.begin() + begin, text.begin() + end); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), text); - } - } - } - - Y_UNIT_TEST(Insert) { - TRope rope = CreateRope(Text, 10); - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope part = TRope(rope.Begin() + begin, rope.Begin() + end); - for (size_t where = 0; where <= Text.size(); ++where) { - TRope x(rope); - x.Insert(x.Begin() + where, TRope(part)); - UNIT_ASSERT_VALUES_EQUAL(x.GetSize(), rope.GetSize() + part.GetSize()); - TString text = Text; - text.insert(text.begin() + where, Text.begin() + begin, Text.begin() + end); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(x), text); - } - } - } - } - - Y_UNIT_TEST(Extract) { - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope rope = CreateRope(Text, 10); - TRope part = rope.Extract(rope.Begin() + begin, rope.Begin() + end); - TString text = Text; - text.erase(text.begin() + begin, text.begin() + end); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), text); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(part), Text.substr(begin, end - begin)); - } - } - } - - Y_UNIT_TEST(EraseFront) { - for (size_t pos = 0; pos <= Text.size(); ++pos) { - TRope rope = CreateRope(Text, 10); - rope.EraseFront(pos); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text.substr(pos)); - } - } - - Y_UNIT_TEST(EraseBack) { - for (size_t pos = 0; pos <= Text.size(); ++pos) { - TRope rope = CreateRope(Text, 10); - rope.EraseBack(pos); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text.substr(0, Text.size() - pos)); - } - } - - Y_UNIT_TEST(ExtractFront) { - for (size_t step = 1; step <= Text.size(); ++step) { - TRope rope = CreateRope(Text, 10); - TRope out; - while (const size_t len = Min(step, rope.GetSize())) { - rope.ExtractFront(len, &out); - UNIT_ASSERT(rope.GetSize() + out.GetSize() == Text.size()); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(out), Text.substr(0, out.GetSize())); - } - } - } - - Y_UNIT_TEST(ExtractFrontPlain) { - for (size_t step = 1; step <= Text.size(); ++step) { - TRope rope = CreateRope(Text, 10); - TString buffer = Text; - size_t remain = rope.GetSize(); - while (const size_t len = Min(step, remain)) { - TString data = TString::Uninitialized(len); - rope.ExtractFrontPlain(data.Detach(), data.size()); - UNIT_ASSERT_VALUES_EQUAL(data, buffer.substr(0, len)); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), buffer.substr(len)); - buffer = buffer.substr(len); - remain -= len; - } - } - } - - Y_UNIT_TEST(FetchFrontPlain) { - char s[10]; - char *data = s; - size_t remain = sizeof(s); - TRope rope = TRope(TString("HELLO")); - UNIT_ASSERT(!rope.FetchFrontPlain(&data, &remain)); - UNIT_ASSERT(!rope); - rope.Insert(rope.End(), TRope(TString("WORLD!!!"))); - UNIT_ASSERT(rope.FetchFrontPlain(&data, &remain)); - UNIT_ASSERT(!remain); - UNIT_ASSERT(rope.GetSize() == 3); - UNIT_ASSERT_VALUES_EQUAL(rope.ConvertToString(), "!!!"); - UNIT_ASSERT(!strncmp(s, "HELLOWORLD", 10)); - } - - Y_UNIT_TEST(Glueing) { - TRope rope = CreateRope(Text, 10); - for (size_t begin = 0; begin <= Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TString repr = rope.DebugString(); - TRope temp = rope.Extract(rope.Position(begin), rope.Position(end)); - rope.Insert(rope.Position(begin), std::move(temp)); - UNIT_ASSERT_VALUES_EQUAL(repr, rope.DebugString()); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text); - } - } - } - - Y_UNIT_TEST(IterWalk) { - TRope rope = CreateRope(Text, 10); - for (size_t step1 = 0; step1 <= rope.GetSize(); ++step1) { - for (size_t step2 = 0; step2 <= step1; ++step2) { - TRope::TConstIterator iter = rope.Begin(); - iter += step1; - iter -= step2; - UNIT_ASSERT(iter == rope.Position(step1 - step2)); - } - } - } - - Y_UNIT_TEST(Compare) { - auto check = [](const TString& x, const TString& y) { - const TRope xRope = CreateRope(x, 7); - const TRope yRope = CreateRope(y, 11); - UNIT_ASSERT_VALUES_EQUAL(xRope == yRope, x == y); - UNIT_ASSERT_VALUES_EQUAL(xRope == y, x == y); - UNIT_ASSERT_VALUES_EQUAL(x == yRope, x == y); - UNIT_ASSERT_VALUES_EQUAL(xRope != yRope, x != y); - UNIT_ASSERT_VALUES_EQUAL(xRope != y, x != y); - UNIT_ASSERT_VALUES_EQUAL(x != yRope, x != y); - UNIT_ASSERT_VALUES_EQUAL(xRope < yRope, x < y); - UNIT_ASSERT_VALUES_EQUAL(xRope < y, x < y); - UNIT_ASSERT_VALUES_EQUAL(x < yRope, x < y); - UNIT_ASSERT_VALUES_EQUAL(xRope <= yRope, x <= y); - UNIT_ASSERT_VALUES_EQUAL(xRope <= y, x <= y); - UNIT_ASSERT_VALUES_EQUAL(x <= yRope, x <= y); - UNIT_ASSERT_VALUES_EQUAL(xRope > yRope, x > y); - UNIT_ASSERT_VALUES_EQUAL(xRope > y, x > y); - UNIT_ASSERT_VALUES_EQUAL(x > yRope, x > y); - UNIT_ASSERT_VALUES_EQUAL(xRope >= yRope, x >= y); - UNIT_ASSERT_VALUES_EQUAL(xRope >= y, x >= y); - UNIT_ASSERT_VALUES_EQUAL(x >= yRope, x >= y); - }; - - TVector<TString> pool; - for (size_t k = 0; k < 10; ++k) { - size_t len = RandomNumber<size_t>(100) + 100; - TString s = TString::Uninitialized(len); - char *p = s.Detach(); - for (size_t j = 0; j < len; ++j) { - *p++ = RandomNumber<unsigned char>(); - } - pool.push_back(std::move(s)); - } - - for (const TString& x : pool) { - for (const TString& y : pool) { - check(x, y); - } - } - } - - Y_UNIT_TEST(RopeZeroCopyInputBasic) { - TRope rope = CreateRope(Text, 3); - TRopeZeroCopyInput input(rope.Begin()); - - TString result; - TStringOutput output(result); - TransferData(&input, &output); - UNIT_ASSERT_EQUAL(result, Text); - } - - Y_UNIT_TEST(RopeZeroCopyInput) { - TRope rope; - rope.Insert(rope.End(), TRope{"abc"}); - rope.Insert(rope.End(), TRope{TString{}}); - rope.Insert(rope.End(), TRope{"de"}); - rope.Insert(rope.End(), TRope{TString{}}); - rope.Insert(rope.End(), TRope{TString{}}); - rope.Insert(rope.End(), TRope{"fghi"}); - - TRopeZeroCopyInput input(rope.Begin()); - - const char* data = nullptr; - size_t len; - - len = input.Next(&data, 2); - UNIT_ASSERT_EQUAL("ab", TStringBuf(data, len)); - - len = input.Next(&data, 3); - UNIT_ASSERT_EQUAL("c", TStringBuf(data, len)); - - len = input.Next(&data, 3); - UNIT_ASSERT_EQUAL("de", TStringBuf(data, len)); - - len = input.Next(&data); - UNIT_ASSERT_EQUAL("fghi", TStringBuf(data, len)); - - len = input.Next(&data); - UNIT_ASSERT_EQUAL(len, 0); - - len = input.Next(&data); - UNIT_ASSERT_EQUAL(len, 0); - } -} diff --git a/library/cpp/actors/util/shared_data.cpp b/library/cpp/actors/util/shared_data.cpp deleted file mode 100644 index 51311ce7a3..0000000000 --- a/library/cpp/actors/util/shared_data.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "shared_data.h" - -#include "memory_tracker.h" - -#include <util/system/sys_alloc.h> -#include <util/system/sanitizers.h> - -namespace NActors { - - static constexpr char MemoryLabelSharedData[] = "Tablet/TSharedData/Buffers"; - - char* TSharedData::Allocate(size_t size) { - char* data = nullptr; - if (size > 0) { - if (size >= MaxDataSize) { - throw std::length_error("Allocate size overflow"); - } - auto allocSize = OverheadSize + size; - char* raw = reinterpret_cast<char*>(y_allocate(allocSize)); - - auto* privateHeader = reinterpret_cast<TPrivateHeader*>(raw); - privateHeader->AllocSize = allocSize; - NActors::NMemory::TLabel<MemoryLabelSharedData>::Add(allocSize); - - auto* header = reinterpret_cast<THeader*>(raw + PrivateHeaderSize); - header->RefCount = 1; - header->Owner = nullptr; - - data = raw + OverheadSize; - NSan::Poison(data, size); - } - return data; - } - - void TSharedData::Deallocate(char* data) noexcept { - if (data) { - char* raw = data - OverheadSize; - - auto* privateHeader = reinterpret_cast<TPrivateHeader*>(raw); - NActors::NMemory::TLabel<MemoryLabelSharedData>::Sub(privateHeader->AllocSize); - - auto* header = reinterpret_cast<THeader*>(raw + PrivateHeaderSize); - Y_DEBUG_ABORT_UNLESS(header->Owner == nullptr); - - y_deallocate(raw); - } - } - -} diff --git a/library/cpp/actors/util/shared_data.h b/library/cpp/actors/util/shared_data.h deleted file mode 100644 index bd9afb00a5..0000000000 --- a/library/cpp/actors/util/shared_data.h +++ /dev/null @@ -1,227 +0,0 @@ -#pragma once - -#include <library/cpp/deprecated/atomic/atomic.h> - -#include <util/system/types.h> -#include <util/system/compiler.h> -#include <util/generic/array_ref.h> - -namespace NActors { - - class TSharedData { - public: - class IOwner { - public: - virtual ~IOwner() = default; - - virtual void Deallocate(char*) noexcept = 0; - }; - - struct TPrivateHeader { - size_t AllocSize; - size_t Pad; - }; - - static_assert(sizeof(TPrivateHeader) == 16, "TPrivateHeader has an unexpected size"); - - struct THeader { - TAtomic RefCount; - IOwner* Owner; - }; - - static_assert(sizeof(THeader) == 16, "THeader has an unexpected size"); - - enum : size_t { - PrivateHeaderSize = sizeof(TPrivateHeader), - HeaderSize = sizeof(THeader), - OverheadSize = PrivateHeaderSize + HeaderSize, - MaxDataSize = (std::numeric_limits<size_t>::max() - OverheadSize) - }; - - public: - TSharedData() noexcept - : Data_(nullptr) - , Size_(0) - { } - - ~TSharedData() noexcept { - Release(); - } - - TSharedData(const TSharedData& other) noexcept - : Data_(other.Data_) - , Size_(other.Size_) - { - AddRef(); - } - - TSharedData(TSharedData&& other) noexcept - : Data_(other.Data_) - , Size_(other.Size_) - { - other.Data_ = nullptr; - other.Size_ = 0; - } - - TSharedData& operator=(const TSharedData& other) noexcept { - if (this != &other) { - Release(); - Data_ = other.Data_; - Size_ = other.Size_; - AddRef(); - } - return *this; - } - - TSharedData& operator=(TSharedData&& other) noexcept { - if (this != &other) { - Release(); - Data_ = other.Data_; - Size_ = other.Size_; - other.Data_ = nullptr; - other.Size_ = 0; - } - return *this; - } - - Y_FORCE_INLINE explicit operator bool() const { return Size_ > 0; } - - Y_FORCE_INLINE char* mutable_data() { Y_DEBUG_ABORT_UNLESS(IsPrivate()); return Data_; } - Y_FORCE_INLINE char* mutable_begin() { Y_DEBUG_ABORT_UNLESS(IsPrivate()); return Data_; } - Y_FORCE_INLINE char* mutable_end() { Y_DEBUG_ABORT_UNLESS(IsPrivate()); return Data_ + Size_; } - - Y_FORCE_INLINE const char* data() const { return Data_; } - Y_FORCE_INLINE const char* begin() const { return Data_; } - Y_FORCE_INLINE const char* end() const { return Data_ + Size_; } - - Y_FORCE_INLINE size_t size() const { return Size_; } - - /** - * Trims data to the specified size - * Underlying data is not reallocated - * Returns trimmed amount in bytes - */ - size_t TrimBack(size_t size) noexcept { - size_t trimmed = 0; - if (Size_ > size) { - trimmed = Size_ - size; - if (!size) { - Release(); - Data_ = nullptr; - } - Size_ = size; - } - return trimmed; - } - - /** - * Copies data to new allocated buffer if data is shared - * New container loses original owner - * Returns pointer to mutable buffer - */ - char* Detach() { - if (IsShared()) { - *this = TSharedData::Copy(data(), size()); - } - return Data_; - } - - /** - * Returns a view of underlying data starting with pos and up to len bytes - */ - TStringBuf Slice(size_t pos = 0, size_t len = -1) const noexcept { - pos = Min(pos, Size_); - len = Min(len, Size_ - pos); - return { Data_ + pos, len }; - } - - explicit operator TStringBuf() const noexcept { - return Slice(); - } - - bool IsPrivate() const { - return Data_ ? IsPrivate(Header()) : true; - } - - bool IsShared() const { - return !IsPrivate(); - } - - TString ToString() const { - return TString(data(), size()); - } - - /** - * Attach to pre-allocated data with a preceding THeader - */ - static TSharedData AttachUnsafe(char* data, size_t size) noexcept { - TSharedData result; - result.Data_ = data; - result.Size_ = size; - return result; - } - - /** - * Make uninitialized buffer of the specified size - */ - static TSharedData Uninitialized(size_t size) { - return AttachUnsafe(Allocate(size), size); - } - - /** - * Make a copy of the specified data - */ - static TSharedData Copy(const void* data, size_t size) { - TSharedData result = Uninitialized(size); - if (size) { - ::memcpy(result.Data_, data, size); - } - return result; - } - - /** - * Make a copy of the specified data - */ - static TSharedData Copy(TArrayRef<const char> data) { - return Copy(data.data(), data.size()); - } - - private: - Y_FORCE_INLINE THeader* Header() const noexcept { - Y_DEBUG_ABORT_UNLESS(Data_); - return reinterpret_cast<THeader*>(Data_ - sizeof(THeader)); - } - - static bool IsPrivate(THeader* header) noexcept { - return 1 == AtomicGet(header->RefCount); - } - - void AddRef() noexcept { - if (Data_) { - AtomicIncrement(Header()->RefCount); - } - } - - void Release() noexcept { - if (Data_) { - auto* header = Header(); - if (IsPrivate(header) || 0 == AtomicDecrement(header->RefCount)) { - if (auto* owner = header->Owner) { - owner->Deallocate(Data_); - } else { - Deallocate(Data_); - } - } - } - } - - private: - static char* Allocate(size_t size); - static void Deallocate(char* data) noexcept; - - private: - char* Data_; - size_t Size_; - }; - -} diff --git a/library/cpp/actors/util/shared_data_backtracing_owner.h b/library/cpp/actors/util/shared_data_backtracing_owner.h deleted file mode 100644 index ea479d5fd1..0000000000 --- a/library/cpp/actors/util/shared_data_backtracing_owner.h +++ /dev/null @@ -1,88 +0,0 @@ -#pragma once - -#include <util/system/sys_alloc.h> -#include <util/system/backtrace.h> - -#include "shared_data.h" - -class TBackTracingOwner : public NActors::TSharedData::IOwner { - using THeader = NActors::TSharedData::THeader; - using TSelf = TBackTracingOwner; - using IOwner = NActors::TSharedData::IOwner; - - static constexpr size_t PrivateHeaderSize = NActors::TSharedData::PrivateHeaderSize; - static constexpr size_t HeaderSize = NActors::TSharedData::HeaderSize; - static constexpr size_t OverheadSize = NActors::TSharedData::OverheadSize; - - IOwner* RealOwner = nullptr; - TBackTrace BackTrace; - const char* Info; -public: - - static constexpr const char* INFO_FROM_SHARED_DATA = "FROM_SHARED_DATA"; - static constexpr const char* INFO_COPIED_STRING = "COPIED_STRING"; - static constexpr const char* INFO_ALLOC_UNINITIALIZED = "ALLOC_UNINITIALIZED"; - static constexpr const char* INFO_ALLOC_UNINIT_ROOMS = "ALLOC_UNINIT_ROOMS"; - - static char* Allocate(size_t size, const char* info = nullptr) { - char* raw = reinterpret_cast<char*>(y_allocate(OverheadSize + size)); - THeader* header = reinterpret_cast<THeader*>(raw + PrivateHeaderSize); - TSelf* btOwner = new TSelf; - btOwner->BackTrace.Capture(); - btOwner->Info = info; - header->RefCount = 1; - header->Owner = btOwner; - char* data = raw + OverheadSize; - return data; - } - - static void FakeOwner(const NActors::TSharedData& data, const char* info = nullptr) { - THeader* header = Header(data); - if (header) { - TSelf* btOwner = new TSelf(); - btOwner->BackTrace.Capture(); - btOwner->Info = info; - if (header->Owner) { - btOwner->RealOwner = header->Owner; - } - header->Owner = btOwner; - } - } - - static void UnsafePrintBackTrace(NActors::TSharedData& data) { - THeader* header = Header(data); - if(header->Owner) { - TSelf* owner = static_cast<TSelf*>(header->Owner); - owner->PrintBackTrace(); - } - } - - void Deallocate(char* data) noexcept override { - if (!RealOwner) { - char* raw = data - OverheadSize; - y_deallocate(raw); - } else { - RealOwner->Deallocate(data); - } - - delete this; - } - - IOwner* GetRealOwner() const { - return RealOwner; - } - - void PrintBackTrace() { - Cerr << "Deallocate TSharedData with info# " << Info << Endl; - BackTrace.PrintTo(Cerr); - } -private: - static Y_FORCE_INLINE THeader* Header(const NActors::TSharedData& d) noexcept { - char* data = const_cast<char*>(d.data()); - if (data) { - return reinterpret_cast<THeader*>(data - HeaderSize); - } else { - return nullptr; - } - } -}; diff --git a/library/cpp/actors/util/shared_data_native_rope_backend_ut.cpp b/library/cpp/actors/util/shared_data_native_rope_backend_ut.cpp deleted file mode 100644 index 4939403454..0000000000 --- a/library/cpp/actors/util/shared_data_native_rope_backend_ut.cpp +++ /dev/null @@ -1,231 +0,0 @@ -#include <library/cpp/actors/util/rope.h> -#include <library/cpp/testing/unittest/registar.h> -#include <util/random/random.h> - -#include "shared_data_rope_backend.h" - -namespace NActors { - - namespace { - - TRope CreateRope(TString s, size_t sliceSize) { - TRope res; - for (size_t i = 0; i < s.size(); ) { - size_t len = std::min(sliceSize, s.size() - i); - if (i % 2) { - auto str = s.substr(i, len); - res.Insert(res.End(), TRope( - TSharedData::Copy(str.data(), str.size()))); - } else { - res.Insert(res.End(), TRope(s.substr(i, len))); - } - i += len; - } - return res; - } - - TString RopeToString(const TRope& rope) { - TString res; - auto iter = rope.Begin(); - while (iter != rope.End()) { - res.append(iter.ContiguousData(), iter.ContiguousSize()); - iter.AdvanceToNextContiguousBlock(); - } - - UNIT_ASSERT_VALUES_EQUAL(rope.GetSize(), res.size()); - - TString temp = TString::Uninitialized(rope.GetSize()); - rope.Begin().ExtractPlainDataAndAdvance(temp.Detach(), temp.size()); - UNIT_ASSERT_VALUES_EQUAL(temp, res); - - return res; - } - - TString Text = "No elements are copied or moved, only the internal pointers of the list nodes are re-pointed."; - - } - - Y_UNIT_TEST_SUITE(TRopeSharedDataNativeBackend) { - - // Same tests as in TRope but with new CreateRope using TSharedData backend - - Y_UNIT_TEST(Leak) { - const size_t begin = 10, end = 20; - TRope rope = CreateRope(Text, 10); - rope.Erase(rope.Begin() + begin, rope.Begin() + end); - } - - Y_UNIT_TEST(BasicRange) { - TRope rope = CreateRope(Text, 10); - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope::TIterator rBegin = rope.Begin() + begin; - TRope::TIterator rEnd = rope.Begin() + end; - UNIT_ASSERT_VALUES_EQUAL(RopeToString(TRope(rBegin, rEnd)), Text.substr(begin, end - begin)); - } - } - } - - Y_UNIT_TEST(Erase) { - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope rope = CreateRope(Text, 10); - rope.Erase(rope.Begin() + begin, rope.Begin() + end); - TString text = Text; - text.erase(text.begin() + begin, text.begin() + end); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), text); - } - } - } - - Y_UNIT_TEST(Insert) { - TRope rope = CreateRope(Text, 10); - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope part = TRope(rope.Begin() + begin, rope.Begin() + end); - for (size_t where = 0; where <= Text.size(); ++where) { - TRope x(rope); - x.Insert(x.Begin() + where, TRope(part)); - UNIT_ASSERT_VALUES_EQUAL(x.GetSize(), rope.GetSize() + part.GetSize()); - TString text = Text; - text.insert(text.begin() + where, Text.begin() + begin, Text.begin() + end); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(x), text); - } - } - } - } - - Y_UNIT_TEST(Extract) { - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope rope = CreateRope(Text, 10); - TRope part = rope.Extract(rope.Begin() + begin, rope.Begin() + end); - TString text = Text; - text.erase(text.begin() + begin, text.begin() + end); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), text); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(part), Text.substr(begin, end - begin)); - } - } - } - - Y_UNIT_TEST(EraseFront) { - for (size_t pos = 0; pos <= Text.size(); ++pos) { - TRope rope = CreateRope(Text, 10); - rope.EraseFront(pos); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text.substr(pos)); - } - } - - Y_UNIT_TEST(EraseBack) { - for (size_t pos = 0; pos <= Text.size(); ++pos) { - TRope rope = CreateRope(Text, 10); - rope.EraseBack(pos); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text.substr(0, Text.size() - pos)); - } - } - - Y_UNIT_TEST(ExtractFront) { - for (size_t step = 1; step <= Text.size(); ++step) { - TRope rope = CreateRope(Text, 10); - TRope out; - while (const size_t len = Min(step, rope.GetSize())) { - rope.ExtractFront(len, &out); - UNIT_ASSERT(rope.GetSize() + out.GetSize() == Text.size()); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(out), Text.substr(0, out.GetSize())); - } - } - } - - Y_UNIT_TEST(ExtractFrontPlain) { - for (size_t step = 1; step <= Text.size(); ++step) { - TRope rope = CreateRope(Text, 10); - TString buffer = Text; - auto it = rope.Begin(); - size_t remain = rope.GetSize(); - while (const size_t len = Min(step, remain)) { - TString data = TString::Uninitialized(len); - it.ExtractPlainDataAndAdvance(data.Detach(), data.size()); - UNIT_ASSERT_VALUES_EQUAL(data, buffer.substr(0, len)); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(TRope(it, rope.End())), buffer.substr(len)); - buffer = buffer.substr(len); - remain -= len; - } - } - } - - Y_UNIT_TEST(Glueing) { - TRope rope = CreateRope(Text, 10); - for (size_t begin = 0; begin <= Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TString repr = rope.DebugString(); - TRope temp = rope.Extract(rope.Position(begin), rope.Position(end)); - rope.Insert(rope.Position(begin), std::move(temp)); - UNIT_ASSERT_VALUES_EQUAL(repr, rope.DebugString()); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text); - } - } - } - - Y_UNIT_TEST(IterWalk) { - TRope rope = CreateRope(Text, 10); - for (size_t step1 = 0; step1 <= rope.GetSize(); ++step1) { - for (size_t step2 = 0; step2 <= step1; ++step2) { - TRope::TConstIterator iter = rope.Begin(); - iter += step1; - iter -= step2; - UNIT_ASSERT(iter == rope.Position(step1 - step2)); - } - } - } - - Y_UNIT_TEST(Compare) { - auto check = [](const TString& x, const TString& y) { - const TRope xRope = CreateRope(x, 7); - const TRope yRope = CreateRope(y, 11); - UNIT_ASSERT_VALUES_EQUAL(xRope == yRope, x == y); - UNIT_ASSERT_VALUES_EQUAL(xRope != yRope, x != y); - UNIT_ASSERT_VALUES_EQUAL(xRope < yRope, x < y); - UNIT_ASSERT_VALUES_EQUAL(xRope <= yRope, x <= y); - UNIT_ASSERT_VALUES_EQUAL(xRope > yRope, x > y); - UNIT_ASSERT_VALUES_EQUAL(xRope >= yRope, x >= y); - }; - - TVector<TString> pool; - for (size_t k = 0; k < 10; ++k) { - size_t len = RandomNumber<size_t>(100) + 100; - TString s = TString::Uninitialized(len); - char *p = s.Detach(); - for (size_t j = 0; j < len; ++j) { - *p++ = RandomNumber<unsigned char>(); - } - pool.push_back(std::move(s)); - } - - for (const TString& x : pool) { - for (const TString& y : pool) { - check(x, y); - } - } - } - - // Specific TSharedDataRopeBackend tests - - Y_UNIT_TEST(RopeOnlyBorrows) { - TSharedData data = TSharedData::Copy(Text.data(), Text.size()); - { - TRope rope; - rope.Insert(rope.End(), TRope(data)); - UNIT_ASSERT(data.IsShared()); - TSharedData dataCopy = data; - UNIT_ASSERT(dataCopy.IsShared()); - UNIT_ASSERT_EQUAL(dataCopy.data(), data.data()); - rope.Insert(rope.End(), TRope(data)); - rope.Insert(rope.End(), TRope(data)); - dataCopy.TrimBack(10); - UNIT_ASSERT_EQUAL(rope.GetSize(), data.size() * 3); - } - UNIT_ASSERT(data.IsPrivate()); - } - } - -} // namespace NActors diff --git a/library/cpp/actors/util/shared_data_rope_backend.h b/library/cpp/actors/util/shared_data_rope_backend.h deleted file mode 100644 index a221ae668b..0000000000 --- a/library/cpp/actors/util/shared_data_rope_backend.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include <library/cpp/actors/util/rc_buf.h> - -#include "shared_data.h" - -namespace NActors { - -class TRopeSharedDataBackend : public IContiguousChunk { - TSharedData Buffer; - -public: - TRopeSharedDataBackend(TSharedData buffer) - : Buffer(std::move(buffer)) - {} - - TContiguousSpan GetData() const override { - return {Buffer.data(), Buffer.size()}; - } - - TMutableContiguousSpan GetDataMut() override { - if(Buffer.IsShared()) { - Buffer = TSharedData::Copy(Buffer.data(), Buffer.size()); - } - return {Buffer.mutable_data(), Buffer.size()}; - } - - TMutableContiguousSpan UnsafeGetDataMut() override { - return {const_cast<char *>(Buffer.data()), Buffer.size()}; - } - - bool IsPrivate() const override { - return Buffer.IsPrivate(); - } - - size_t GetOccupiedMemorySize() const override { - return Buffer.size(); - } -}; - -} // namespace NActors diff --git a/library/cpp/actors/util/shared_data_rope_backend_ut.cpp b/library/cpp/actors/util/shared_data_rope_backend_ut.cpp deleted file mode 100644 index b2b4e04634..0000000000 --- a/library/cpp/actors/util/shared_data_rope_backend_ut.cpp +++ /dev/null @@ -1,231 +0,0 @@ -#include <library/cpp/actors/util/rope.h> -#include <library/cpp/testing/unittest/registar.h> -#include <util/random/random.h> - -#include "shared_data_rope_backend.h" - -namespace NActors { - - namespace { - - TRope CreateRope(TString s, size_t sliceSize) { - TRope res; - for (size_t i = 0; i < s.size(); ) { - size_t len = std::min(sliceSize, s.size() - i); - if (i % 2) { - auto str = s.substr(i, len); - res.Insert(res.End(), TRope(MakeIntrusive<TRopeSharedDataBackend>( - TSharedData::Copy(str.data(), str.size())))); - } else { - res.Insert(res.End(), TRope(s.substr(i, len))); - } - i += len; - } - return res; - } - - TString RopeToString(const TRope& rope) { - TString res; - auto iter = rope.Begin(); - while (iter != rope.End()) { - res.append(iter.ContiguousData(), iter.ContiguousSize()); - iter.AdvanceToNextContiguousBlock(); - } - - UNIT_ASSERT_VALUES_EQUAL(rope.GetSize(), res.size()); - - TString temp = TString::Uninitialized(rope.GetSize()); - rope.Begin().ExtractPlainDataAndAdvance(temp.Detach(), temp.size()); - UNIT_ASSERT_VALUES_EQUAL(temp, res); - - return res; - } - - TString Text = "No elements are copied or moved, only the internal pointers of the list nodes are re-pointed."; - - } - - Y_UNIT_TEST_SUITE(TRopeSharedDataBackend) { - - // Same tests as in TRope but with new CreateRope using TSharedData backend - - Y_UNIT_TEST(Leak) { - const size_t begin = 10, end = 20; - TRope rope = CreateRope(Text, 10); - rope.Erase(rope.Begin() + begin, rope.Begin() + end); - } - - Y_UNIT_TEST(BasicRange) { - TRope rope = CreateRope(Text, 10); - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope::TIterator rBegin = rope.Begin() + begin; - TRope::TIterator rEnd = rope.Begin() + end; - UNIT_ASSERT_VALUES_EQUAL(RopeToString(TRope(rBegin, rEnd)), Text.substr(begin, end - begin)); - } - } - } - - Y_UNIT_TEST(Erase) { - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope rope = CreateRope(Text, 10); - rope.Erase(rope.Begin() + begin, rope.Begin() + end); - TString text = Text; - text.erase(text.begin() + begin, text.begin() + end); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), text); - } - } - } - - Y_UNIT_TEST(Insert) { - TRope rope = CreateRope(Text, 10); - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope part = TRope(rope.Begin() + begin, rope.Begin() + end); - for (size_t where = 0; where <= Text.size(); ++where) { - TRope x(rope); - x.Insert(x.Begin() + where, TRope(part)); - UNIT_ASSERT_VALUES_EQUAL(x.GetSize(), rope.GetSize() + part.GetSize()); - TString text = Text; - text.insert(text.begin() + where, Text.begin() + begin, Text.begin() + end); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(x), text); - } - } - } - } - - Y_UNIT_TEST(Extract) { - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope rope = CreateRope(Text, 10); - TRope part = rope.Extract(rope.Begin() + begin, rope.Begin() + end); - TString text = Text; - text.erase(text.begin() + begin, text.begin() + end); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), text); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(part), Text.substr(begin, end - begin)); - } - } - } - - Y_UNIT_TEST(EraseFront) { - for (size_t pos = 0; pos <= Text.size(); ++pos) { - TRope rope = CreateRope(Text, 10); - rope.EraseFront(pos); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text.substr(pos)); - } - } - - Y_UNIT_TEST(EraseBack) { - for (size_t pos = 0; pos <= Text.size(); ++pos) { - TRope rope = CreateRope(Text, 10); - rope.EraseBack(pos); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text.substr(0, Text.size() - pos)); - } - } - - Y_UNIT_TEST(ExtractFront) { - for (size_t step = 1; step <= Text.size(); ++step) { - TRope rope = CreateRope(Text, 10); - TRope out; - while (const size_t len = Min(step, rope.GetSize())) { - rope.ExtractFront(len, &out); - UNIT_ASSERT(rope.GetSize() + out.GetSize() == Text.size()); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(out), Text.substr(0, out.GetSize())); - } - } - } - - Y_UNIT_TEST(ExtractFrontPlain) { - for (size_t step = 1; step <= Text.size(); ++step) { - TRope rope = CreateRope(Text, 10); - TString buffer = Text; - auto it = rope.Begin(); - size_t remain = rope.GetSize(); - while (const size_t len = Min(step, remain)) { - TString data = TString::Uninitialized(len); - it.ExtractPlainDataAndAdvance(data.Detach(), data.size()); - UNIT_ASSERT_VALUES_EQUAL(data, buffer.substr(0, len)); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(TRope(it, rope.End())), buffer.substr(len)); - buffer = buffer.substr(len); - remain -= len; - } - } - } - - Y_UNIT_TEST(Glueing) { - TRope rope = CreateRope(Text, 10); - for (size_t begin = 0; begin <= Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TString repr = rope.DebugString(); - TRope temp = rope.Extract(rope.Position(begin), rope.Position(end)); - rope.Insert(rope.Position(begin), std::move(temp)); - UNIT_ASSERT_VALUES_EQUAL(repr, rope.DebugString()); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text); - } - } - } - - Y_UNIT_TEST(IterWalk) { - TRope rope = CreateRope(Text, 10); - for (size_t step1 = 0; step1 <= rope.GetSize(); ++step1) { - for (size_t step2 = 0; step2 <= step1; ++step2) { - TRope::TConstIterator iter = rope.Begin(); - iter += step1; - iter -= step2; - UNIT_ASSERT(iter == rope.Position(step1 - step2)); - } - } - } - - Y_UNIT_TEST(Compare) { - auto check = [](const TString& x, const TString& y) { - const TRope xRope = CreateRope(x, 7); - const TRope yRope = CreateRope(y, 11); - UNIT_ASSERT_VALUES_EQUAL(xRope == yRope, x == y); - UNIT_ASSERT_VALUES_EQUAL(xRope != yRope, x != y); - UNIT_ASSERT_VALUES_EQUAL(xRope < yRope, x < y); - UNIT_ASSERT_VALUES_EQUAL(xRope <= yRope, x <= y); - UNIT_ASSERT_VALUES_EQUAL(xRope > yRope, x > y); - UNIT_ASSERT_VALUES_EQUAL(xRope >= yRope, x >= y); - }; - - TVector<TString> pool; - for (size_t k = 0; k < 10; ++k) { - size_t len = RandomNumber<size_t>(100) + 100; - TString s = TString::Uninitialized(len); - char *p = s.Detach(); - for (size_t j = 0; j < len; ++j) { - *p++ = RandomNumber<unsigned char>(); - } - pool.push_back(std::move(s)); - } - - for (const TString& x : pool) { - for (const TString& y : pool) { - check(x, y); - } - } - } - - // Specific TSharedDataRopeBackend tests - - Y_UNIT_TEST(RopeOnlyBorrows) { - TSharedData data = TSharedData::Copy(Text.data(), Text.size()); - { - TRope rope; - rope.Insert(rope.End(), TRope(MakeIntrusive<TRopeSharedDataBackend>(data))); - UNIT_ASSERT(data.IsShared()); - TSharedData dataCopy = data; - UNIT_ASSERT(dataCopy.IsShared()); - UNIT_ASSERT_EQUAL(dataCopy.data(), data.data()); - rope.Insert(rope.End(), TRope(MakeIntrusive<TRopeSharedDataBackend>(data))); - rope.Insert(rope.End(), TRope(MakeIntrusive<TRopeSharedDataBackend>(data))); - dataCopy.TrimBack(10); - UNIT_ASSERT_EQUAL(rope.GetSize(), data.size() * 3); - } - UNIT_ASSERT(data.IsPrivate()); - } - } - -} // namespace NActors diff --git a/library/cpp/actors/util/shared_data_ut.cpp b/library/cpp/actors/util/shared_data_ut.cpp deleted file mode 100644 index 2f7dc2ccc8..0000000000 --- a/library/cpp/actors/util/shared_data_ut.cpp +++ /dev/null @@ -1,205 +0,0 @@ -#include "shared_data.h" - -#include <library/cpp/testing/unittest/registar.h> - -#include <util/generic/hash.h> -#include <util/generic/deque.h> -#include <util/system/sys_alloc.h> - -namespace NActors { - - Y_UNIT_TEST_SUITE(TSharedDataTest) { - - Y_UNIT_TEST(BasicBehavior) { - auto data = TSharedData::Copy("Hello", 5); - UNIT_ASSERT(data.IsPrivate()); - UNIT_ASSERT(!data.IsShared()); - UNIT_ASSERT_VALUES_EQUAL(data.size(), 5u); - UNIT_ASSERT_VALUES_EQUAL(data.end() - data.begin(), 5u); - UNIT_ASSERT_VALUES_EQUAL(data.mutable_end() - data.mutable_begin(), 5u); - UNIT_ASSERT(data.begin() == data.data()); - UNIT_ASSERT(data.mutable_data() == data.data()); - UNIT_ASSERT(data.mutable_begin() == data.mutable_data()); - - UNIT_ASSERT_VALUES_EQUAL(data.ToString(), TString("Hello")); - UNIT_ASSERT_VALUES_EQUAL(::memcmp(data.data(), "Hello", 5), 0); - - auto link = data; - UNIT_ASSERT(!link.IsPrivate()); - UNIT_ASSERT(!data.IsPrivate()); - UNIT_ASSERT(link.IsShared()); - UNIT_ASSERT(data.IsShared()); - UNIT_ASSERT(link.data() == data.data()); - UNIT_ASSERT(link.size() == data.size()); - - link = { }; - UNIT_ASSERT(link.IsPrivate()); - UNIT_ASSERT(data.IsPrivate()); - UNIT_ASSERT(!link.IsShared()); - UNIT_ASSERT(!data.IsShared()); - - UNIT_ASSERT_VALUES_EQUAL(TString(TStringBuf(data)), TString("Hello")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice()), TString("Hello")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice(1)), TString("ello")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice(1, 3)), TString("ell")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice(1, 100)), TString("ello")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice(0, 4)), TString("Hell")); - - link = data; - UNIT_ASSERT(link.data() == data.data()); - UNIT_ASSERT_VALUES_UNEQUAL(link.Detach(), data.data()); - UNIT_ASSERT_EQUAL(data.size(), link.size()); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice()), TString(link.Slice())); - } - - Y_UNIT_TEST(TrimBehavior) { - auto data = TSharedData::Uninitialized(42); - - UNIT_ASSERT_VALUES_EQUAL(data.size(), 42u); - UNIT_ASSERT(data.data() != nullptr); - - // Trim to non-zero does not change addresses - const char* ptr1 = data.data(); - data.TrimBack(31); - const char* ptr2 = data.data(); - - UNIT_ASSERT_VALUES_EQUAL(data.size(), 31u); - UNIT_ASSERT(ptr1 == ptr2); - - // Trim to zero releases underlying data - data.TrimBack(0); - - UNIT_ASSERT_VALUES_EQUAL(data.size(), 0u); - UNIT_ASSERT(data.data() == nullptr); - } - - class TCustomOwner : public TSharedData::IOwner { - using THeader = TSharedData::THeader; - - public: - TSharedData Allocate(size_t size) { - char* raw = reinterpret_cast<char*>(y_allocate(sizeof(THeader) + size)); - THeader* header = reinterpret_cast<THeader*>(raw); - header->RefCount = 1; - header->Owner = this; - char* data = raw + sizeof(THeader); - Y_ABORT_UNLESS(Allocated_.insert(data).second); - return TSharedData::AttachUnsafe(data, size); - } - - void Deallocate(char* data) noexcept { - Y_ABORT_UNLESS(Allocated_.erase(data) > 0); - char* raw = data - sizeof(THeader); - y_deallocate(raw); - Deallocated_.push_back(data); - } - - char* NextDeallocated() { - char* result = nullptr; - if (Deallocated_) { - result = Deallocated_.front(); - Deallocated_.pop_front(); - } - return result; - } - - private: - THashSet<void*> Allocated_; - TDeque<char*> Deallocated_; - }; - - Y_UNIT_TEST(CustomOwner) { - TCustomOwner owner; - const char* ptr; - - // Test destructor releases data - { - auto data = owner.Allocate(42); - UNIT_ASSERT_VALUES_EQUAL(data.size(), 42u); - ptr = data.data(); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - } - - UNIT_ASSERT(owner.NextDeallocated() == ptr); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - - // Test assignment releases data - { - auto data = owner.Allocate(42); - UNIT_ASSERT_VALUES_EQUAL(data.size(), 42u); - ptr = data.data(); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - data = { }; - } - - UNIT_ASSERT(owner.NextDeallocated() == ptr); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - - // Test copies keep references correctly - { - auto data = owner.Allocate(42); - UNIT_ASSERT_VALUES_EQUAL(data.size(), 42u); - ptr = data.data(); - auto copy = data; - UNIT_ASSERT_VALUES_EQUAL(copy.size(), 42u); - UNIT_ASSERT(copy.data() == ptr); - data = { }; - UNIT_ASSERT_VALUES_EQUAL(data.size(), 0u); - UNIT_ASSERT(data.data() == nullptr); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - } - - UNIT_ASSERT(owner.NextDeallocated() == ptr); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - - // Test assignment releases correct data - { - auto data1 = owner.Allocate(42); - UNIT_ASSERT_VALUES_EQUAL(data1.size(), 42u); - auto data2 = owner.Allocate(31); - UNIT_ASSERT_VALUES_EQUAL(data2.size(), 31u); - ptr = data1.data(); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - data1 = data2; - UNIT_ASSERT(owner.NextDeallocated() == ptr); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - ptr = data2.data(); - UNIT_ASSERT_VALUES_EQUAL(data1.size(), 31u); - UNIT_ASSERT(data1.data() == ptr); - } - - UNIT_ASSERT(owner.NextDeallocated() == ptr); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - - // Test moves don't produce dangling references - { - auto data = owner.Allocate(42); - UNIT_ASSERT_VALUES_EQUAL(data.size(), 42u); - ptr = data.data(); - auto moved = std::move(data); - UNIT_ASSERT_VALUES_EQUAL(moved.size(), 42u); - UNIT_ASSERT(moved.data() == ptr); - UNIT_ASSERT_VALUES_EQUAL(data.size(), 0u); - UNIT_ASSERT(data.data() == nullptr); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - } - - UNIT_ASSERT(owner.NextDeallocated() == ptr); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - - // Test Detach copies correctly and doesn't affect owned data - { - auto data = owner.Allocate(42); - auto disowned = data; - disowned.Detach(); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - } - - UNIT_ASSERT(owner.NextDeallocated() == ptr); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - - } - - } - -} diff --git a/library/cpp/actors/util/should_continue.cpp b/library/cpp/actors/util/should_continue.cpp deleted file mode 100644 index 258e6a0aff..0000000000 --- a/library/cpp/actors/util/should_continue.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "should_continue.h" - -void TProgramShouldContinue::ShouldRestart() { - AtomicSet(State, Restart); -} - -void TProgramShouldContinue::ShouldStop(int returnCode) { - AtomicSet(ReturnCode, returnCode); - AtomicSet(State, Stop); -} - -TProgramShouldContinue::EState TProgramShouldContinue::PollState() { - return static_cast<EState>(AtomicGet(State)); -} - -int TProgramShouldContinue::GetReturnCode() { - return static_cast<int>(AtomicGet(ReturnCode)); -} - -void TProgramShouldContinue::Reset() { - AtomicSet(ReturnCode, 0); - AtomicSet(State, Continue); -} diff --git a/library/cpp/actors/util/should_continue.h b/library/cpp/actors/util/should_continue.h deleted file mode 100644 index 76acc40dc4..0000000000 --- a/library/cpp/actors/util/should_continue.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "defs.h" - -class TProgramShouldContinue { -public: - enum EState { - Continue, - Stop, - Restart, - }; - - void ShouldRestart(); - void ShouldStop(int returnCode = 0); - - EState PollState(); - int GetReturnCode(); - - void Reset(); -private: - TAtomic ReturnCode = 0; - TAtomic State = Continue; -}; diff --git a/library/cpp/actors/util/thread.h b/library/cpp/actors/util/thread.h deleted file mode 100644 index d742c8c585..0000000000 --- a/library/cpp/actors/util/thread.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include <util/generic/strbuf.h> -#include <util/stream/str.h> -#include <util/system/execpath.h> -#include <util/system/thread.h> -#include <util/system/thread.h> -#include <time.h> - -inline void SetCurrentThreadName(const TString& name, - const ui32 maxCharsFromProcessName = 8) { -#if defined(_linux_) - // linux limits threadname by 15 + \0 - - TStringBuf procName(GetExecPath()); - procName = procName.RNextTok('/'); - procName = procName.SubStr(0, maxCharsFromProcessName); - - TStringStream linuxName; - linuxName << procName << "." << name; - TThread::SetCurrentThreadName(linuxName.Str().data()); -#else - Y_UNUSED(maxCharsFromProcessName); - TThread::SetCurrentThreadName(name.data()); -#endif -} diff --git a/library/cpp/actors/util/thread_load_log.h b/library/cpp/actors/util/thread_load_log.h deleted file mode 100644 index 132e99a52d..0000000000 --- a/library/cpp/actors/util/thread_load_log.h +++ /dev/null @@ -1,363 +0,0 @@ -#pragma once - -#include "defs.h" - -#include <util/system/types.h> - -#include <type_traits> -#include <algorithm> -#include <atomic> -#include <limits> -#include <queue> - -template <ui64 TIME_SLOT_COUNT, ui64 TIME_SLOT_LENGTH_NS = 131'072, typename Type = std::uint8_t> -class TThreadLoad { -public: - using TimeSlotType = Type; - -private: - static constexpr auto TIME_SLOT_MAX_VALUE = std::numeric_limits<TimeSlotType>::max(); - static constexpr ui64 TIME_SLOT_PART_COUNT = TIME_SLOT_MAX_VALUE + 1; - static constexpr auto TIME_SLOT_PART_LENGTH_NS = TIME_SLOT_LENGTH_NS / TIME_SLOT_PART_COUNT; - - template <typename T> - static void AtomicAddBound(std::atomic<T>& val, i64 inc) { - if (inc == 0) { - return; - } - - auto newVal = val.load(); - auto oldVal = newVal; - - do { - static constexpr auto MAX_VALUE = std::numeric_limits<T>::max(); - - if (oldVal >= MAX_VALUE) { - return; - } - newVal = std::min<i64>(MAX_VALUE, static_cast<i64>(oldVal) + inc); - } while (!val.compare_exchange_weak(oldVal, newVal)); - } - - template <typename T> - static void AtomicSubBound(std::atomic<T>& val, i64 sub) { - if (sub == 0) { - return; - } - - auto newVal = val.load(); - auto oldVal = newVal; - - do { - if (oldVal == 0) { - return; - } - newVal = std::max<i64>(0, static_cast<i64>(oldVal) - sub); - } while (!val.compare_exchange_weak(oldVal, newVal)); - } - - void UpdateCompleteTimeSlots(ui64 firstSlotNumber, ui64 lastSlotNumber, TimeSlotType timeSlotValue) { - ui32 firstSlotIndex = firstSlotNumber % TIME_SLOT_COUNT; - ui32 lastSlotIndex = lastSlotNumber % TIME_SLOT_COUNT; - - const ui64 firstTimeSlotsPass = firstSlotNumber / TIME_SLOT_COUNT; - const ui64 lastTimeSlotsPass = lastSlotNumber / TIME_SLOT_COUNT; - - if (firstTimeSlotsPass == lastTimeSlotsPass) { - // first and last time slots are in the same pass - for (auto slotNumber = firstSlotNumber + 1; slotNumber < lastSlotNumber; ++slotNumber) { - auto slotIndex = slotNumber % TIME_SLOT_COUNT; - TimeSlots[slotIndex] = timeSlotValue; - } - } else if (firstTimeSlotsPass + 1 == lastTimeSlotsPass) { - for (auto slotIndex = (firstSlotNumber + 1) % TIME_SLOT_COUNT; firstSlotIndex < slotIndex && slotIndex < TIME_SLOT_COUNT; ++slotIndex) { - TimeSlots[slotIndex] = timeSlotValue; - } - for (auto slotIndex = 0u; slotIndex < lastSlotIndex; ++slotIndex) { - TimeSlots[slotIndex] = timeSlotValue; - } - } else { - for (auto slotIndex = 0u; slotIndex < TIME_SLOT_COUNT; ++slotIndex) { - TimeSlots[slotIndex] = timeSlotValue; - } - } - } - -public: - std::atomic<ui64> LastTimeNs; - std::atomic<TimeSlotType> TimeSlots[TIME_SLOT_COUNT]; - std::atomic<bool> LastRegisteredPeriodIsBusy = false; - - explicit TThreadLoad(ui64 timeNs = 0) { - static_assert(std::is_unsigned<TimeSlotType>::value); - - LastTimeNs = timeNs; - for (size_t i = 0; i < TIME_SLOT_COUNT; ++i) { - TimeSlots[i] = 0; - } - } - - static constexpr auto GetTimeSlotCount() { - return TIME_SLOT_COUNT; - } - - static constexpr auto GetTimeSlotLengthNs() { - return TIME_SLOT_LENGTH_NS; - } - - static constexpr auto GetTimeSlotPartLengthNs() { - return TIME_SLOT_PART_LENGTH_NS; - } - - static constexpr auto GetTimeSlotPartCount() { - return TIME_SLOT_PART_COUNT; - } - - static constexpr auto GetTimeSlotMaxValue() { - return TIME_SLOT_MAX_VALUE; - } - - static constexpr auto GetTimeWindowLengthNs() { - return TIME_SLOT_COUNT * TIME_SLOT_LENGTH_NS; - } - - void RegisterBusyPeriod(ui64 timeNs) { - RegisterBusyPeriod<true>(timeNs, LastTimeNs.load()); - } - - template <bool ModifyLastTime> - void RegisterBusyPeriod(ui64 timeNs, ui64 lastTimeNs) { - LastRegisteredPeriodIsBusy = true; - - if (timeNs < lastTimeNs) { - // when time goes back, mark all time slots as 'free' - for (size_t i = 0u; i < TIME_SLOT_COUNT; ++i) { - TimeSlots[i] = 0; - } - - if (ModifyLastTime) { - LastTimeNs = timeNs; - } - - return; - } - - // lastTimeNs <= timeNs - ui64 firstSlotNumber = lastTimeNs / TIME_SLOT_LENGTH_NS; - ui32 firstSlotIndex = firstSlotNumber % TIME_SLOT_COUNT; - ui64 lastSlotNumber = timeNs / TIME_SLOT_LENGTH_NS; - ui32 lastSlotIndex = lastSlotNumber % TIME_SLOT_COUNT; - - if (firstSlotNumber == lastSlotNumber) { - ui32 slotLengthNs = timeNs - lastTimeNs; - ui32 slotPartsCount = (slotLengthNs + TIME_SLOT_PART_LENGTH_NS - 1) / TIME_SLOT_PART_LENGTH_NS; - AtomicAddBound(TimeSlots[firstSlotIndex], slotPartsCount); - - if (ModifyLastTime) { - LastTimeNs = timeNs; - } - return; - } - - ui32 firstSlotLengthNs = TIME_SLOT_LENGTH_NS - (lastTimeNs % TIME_SLOT_LENGTH_NS); - ui32 firstSlotPartsCount = (firstSlotLengthNs + TIME_SLOT_PART_LENGTH_NS - 1) / TIME_SLOT_PART_LENGTH_NS; - ui32 lastSlotLengthNs = timeNs % TIME_SLOT_LENGTH_NS; - ui32 lastSlotPartsCount = (lastSlotLengthNs + TIME_SLOT_PART_LENGTH_NS - 1) / TIME_SLOT_PART_LENGTH_NS; - - // process first time slot - AtomicAddBound(TimeSlots[firstSlotIndex], firstSlotPartsCount); - - // process complete time slots - UpdateCompleteTimeSlots(firstSlotNumber, lastSlotNumber, TIME_SLOT_MAX_VALUE); - - // process last time slot - AtomicAddBound(TimeSlots[lastSlotIndex], lastSlotPartsCount); - - if (ModifyLastTime) { - LastTimeNs = timeNs; - } - } - - void RegisterIdlePeriod(ui64 timeNs) { - LastRegisteredPeriodIsBusy = false; - - ui64 lastTimeNs = LastTimeNs.load(); - if (timeNs < lastTimeNs) { - // when time goes back, mark all time slots as 'busy' - for (size_t i = 0u; i < TIME_SLOT_COUNT; ++i) { - TimeSlots[i] = TIME_SLOT_MAX_VALUE; - } - LastTimeNs = timeNs; - return; - } - - // lastTimeNs <= timeNs - ui64 firstSlotNumber = lastTimeNs / TIME_SLOT_LENGTH_NS; - ui32 firstSlotIndex = firstSlotNumber % TIME_SLOT_COUNT; - ui64 lastSlotNumber = timeNs / TIME_SLOT_LENGTH_NS; - ui32 lastSlotIndex = lastSlotNumber % TIME_SLOT_COUNT; - - if (firstSlotNumber == lastSlotNumber) { - ui32 slotLengthNs = timeNs - lastTimeNs; - ui32 slotPartsCount = slotLengthNs / TIME_SLOT_PART_LENGTH_NS; - - AtomicSubBound(TimeSlots[firstSlotIndex], slotPartsCount); - - LastTimeNs = timeNs; - return; - } - - ui32 firstSlotLengthNs = TIME_SLOT_LENGTH_NS - (lastTimeNs % TIME_SLOT_LENGTH_NS); - ui32 firstSlotPartsCount = (firstSlotLengthNs + TIME_SLOT_PART_LENGTH_NS - 1) / TIME_SLOT_PART_LENGTH_NS; - ui32 lastSlotLengthNs = timeNs % TIME_SLOT_LENGTH_NS; - ui32 lastSlotPartsCount = (lastSlotLengthNs + TIME_SLOT_PART_LENGTH_NS - 1) / TIME_SLOT_PART_LENGTH_NS; - - // process first time slot - AtomicSubBound(TimeSlots[firstSlotIndex], firstSlotPartsCount); - - // process complete time slots - UpdateCompleteTimeSlots(firstSlotNumber, lastSlotNumber, 0); - - // process last time slot - AtomicSubBound(TimeSlots[lastSlotIndex], lastSlotPartsCount); - - LastTimeNs = timeNs; - } -}; - -class TMinusOneThreadEstimator { -private: - template <typename T, int MaxSize> - class TArrayQueue { - public: - bool empty() const { - return FrontIndex == -1; - } - - bool full() const { - return (RearIndex + 1) % MaxSize == FrontIndex; - } - - T& front() { - return Data[FrontIndex]; - } - - bool push(T &&t) { - if (full()) { - return false; - } - - if (FrontIndex == -1) { - FrontIndex = 0; - } - - RearIndex = (RearIndex + 1) % MaxSize; - Data[RearIndex] = std::move(t); - return true; - } - - bool pop() { - if (empty()) { - return false; - } - - if (FrontIndex == RearIndex) { - FrontIndex = RearIndex = -1; - } else { - FrontIndex = (FrontIndex + 1) % MaxSize; - } - - return true; - } - - private: - int FrontIndex = -1; - int RearIndex = -1; - T Data[MaxSize]; - }; - -public: - template <typename T> - ui64 MaxLatencyIncreaseWithOneLessCpu(T **threadLoads, ui32 threadCount, ui64 timeNs, ui64 periodNs) { - Y_ABORT_UNLESS(threadCount > 0); - - struct TTimeSlotData { - typename T::TimeSlotType Load; - ui64 Index; - }; - - ui64 lastTimeNs = timeNs; - for (auto threadIndex = 0u; threadIndex < threadCount; ++threadIndex) { - if (threadLoads[threadIndex]->LastRegisteredPeriodIsBusy.load()) { - lastTimeNs = std::min(lastTimeNs, threadLoads[threadIndex]->LastTimeNs.load()); - } else { - // make interval [lastTimeNs, timeNs] 'busy' - threadLoads[threadIndex]->template RegisterBusyPeriod<false>(timeNs, threadLoads[threadIndex]->LastTimeNs.load()); - } - } - - periodNs = std::min(T::GetTimeWindowLengthNs(), periodNs); - - ui64 beginTimeNs = periodNs < timeNs ? timeNs - periodNs : 0; - - ui64 firstSlotNumber = beginTimeNs / T::GetTimeSlotLengthNs(); - ui64 lastSlotNumber = (lastTimeNs + T::GetTimeSlotLengthNs() - 1) / T::GetTimeSlotLengthNs(); - - ui64 maxTimeSlotShiftCount = 0u; - TArrayQueue<TTimeSlotData, T::GetTimeSlotCount()> firstThreadLoadDataQueue; - - for (auto slotNumber = firstSlotNumber; slotNumber < lastSlotNumber; ++slotNumber) { - ui64 slotIndex = slotNumber % T::GetTimeSlotCount(); - - typename T::TimeSlotType firstThreadTimeSlotValue = threadLoads[0]->TimeSlots[slotIndex].load(); - - // distribute previous load of the first thread by other threads - auto foundIdleThread = false; - - for (auto threadIndex = 1u; threadIndex < threadCount; ++threadIndex) { - typename T::TimeSlotType thisThreadAvailableTimeSlotLoad = threadLoads[threadIndex]->GetTimeSlotMaxValue() - threadLoads[threadIndex]->TimeSlots[slotIndex].load(); - - while (!firstThreadLoadDataQueue.empty() && thisThreadAvailableTimeSlotLoad > 0) { - auto& firstThreadLoadData = firstThreadLoadDataQueue.front(); - - auto distributedLoad = std::min(thisThreadAvailableTimeSlotLoad, firstThreadLoadData.Load); - - thisThreadAvailableTimeSlotLoad -= distributedLoad; - firstThreadLoadData.Load -= distributedLoad; - - if (firstThreadLoadData.Load == 0) { - auto timeSlotShiftCount = slotIndex - firstThreadLoadData.Index; - maxTimeSlotShiftCount = std::max(maxTimeSlotShiftCount, timeSlotShiftCount); - auto res = firstThreadLoadDataQueue.pop(); - Y_ABORT_UNLESS(res); - } - } - - if (thisThreadAvailableTimeSlotLoad == threadLoads[threadIndex]->GetTimeSlotMaxValue()) { - foundIdleThread = true; - } - } - - // distribute current load of the first thread by other threads - if (firstThreadTimeSlotValue > 0) { - if (foundIdleThread) { - // The current load of the first thead can be - // moved to the idle thread so there is nothing to do - } else { - // The current load of the first thread can be later - // processed by the following time slots of other threads - auto res = firstThreadLoadDataQueue.push({firstThreadTimeSlotValue, slotIndex}); - Y_ABORT_UNLESS(res); - } - } - } - - if (!firstThreadLoadDataQueue.empty()) { - const auto& timeSlotData = firstThreadLoadDataQueue.front(); - auto timeSlotShiftCount = T::GetTimeSlotCount() - timeSlotData.Index; - maxTimeSlotShiftCount = std::max(maxTimeSlotShiftCount, timeSlotShiftCount); - } - - return maxTimeSlotShiftCount * T::GetTimeSlotLengthNs(); - } -}; diff --git a/library/cpp/actors/util/thread_load_log_ut.cpp b/library/cpp/actors/util/thread_load_log_ut.cpp deleted file mode 100644 index 20e776cff6..0000000000 --- a/library/cpp/actors/util/thread_load_log_ut.cpp +++ /dev/null @@ -1,966 +0,0 @@ -#include "thread_load_log.h" - -#include <library/cpp/testing/unittest/registar.h> - -#include <util/random/random.h> -#include <util/system/hp_timer.h> -#include <util/system/thread.h> -#include <util/system/types.h> -#include <util/system/sanitizers.h> - -#include <limits> - -Y_UNIT_TEST_SUITE(ThreadLoadLog) { - - Y_UNIT_TEST(TThreadLoad8BitSlotType) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - - using TSlotType = std::uint8_t; - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, TSlotType>; - - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeWindowLengthNs(), timeWindowLengthNs); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotLengthNs(), timeSlotLengthNs); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotCount(), timeSlotCount); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotMaxValue(), std::numeric_limits<TSlotType>::max()); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotPartCount(), (ui64)std::numeric_limits<TSlotType>::max() + 1); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotPartLengthNs(), T::GetTimeSlotLengthNs() / T::GetTimeSlotPartCount()); - } - - Y_UNIT_TEST(TThreadLoad16BitSlotType) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - - using TSlotType = std::uint16_t; - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, TSlotType>; - - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeWindowLengthNs(), timeWindowLengthNs); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotLengthNs(), timeSlotLengthNs); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotCount(), timeSlotCount); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotMaxValue(), std::numeric_limits<TSlotType>::max()); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotPartCount(), (ui64)std::numeric_limits<TSlotType>::max() + 1); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotPartLengthNs(), T::GetTimeSlotLengthNs() / T::GetTimeSlotPartCount()); - } - - Y_UNIT_TEST(TThreadLoad8BitSlotTypeWindowBusy) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - - using TSlotType = std::uint8_t; - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, TSlotType>; - - T threadLoad; - threadLoad.RegisterBusyPeriod(T::GetTimeWindowLengthNs()); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), T::GetTimeWindowLengthNs()); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), T::GetTimeSlotMaxValue()); - } - } - - Y_UNIT_TEST(TThreadLoad16BitSlotTypeWindowBusy) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - - using TSlotType = std::uint16_t; - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, TSlotType>; - - T threadLoad; - threadLoad.RegisterBusyPeriod(T::GetTimeWindowLengthNs()); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), T::GetTimeWindowLengthNs()); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), T::GetTimeSlotMaxValue()); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterBusyPeriodFirstTimeSlot1) { - TThreadLoad<38400> threadLoad; - - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = threadLoad.GetTimeSlotLengthNs() - 1; - threadLoad.RegisterBusyPeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - } - - Y_UNIT_TEST(TThreadLoadRegisterBusyPeriodFirstTimeSlot2) { - using T = TThreadLoad<38400>; - - ui32 startNs = 2 * T::GetTimeSlotPartLengthNs(); - T threadLoad(startNs); - - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = 3 * T::GetTimeSlotPartLengthNs() - 1; - threadLoad.RegisterBusyPeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - } - - Y_UNIT_TEST(TThreadLoadRegisterBusyPeriodFirstTimeSlot3) { - TThreadLoad<38400> threadLoad; - - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - } - - Y_UNIT_TEST(TThreadLoadRegisterBusyPeriodFirstTimeSlot4) { - using T = TThreadLoad<38400>; - - ui32 startNs = 2 * T::GetTimeSlotPartLengthNs(); - T threadLoad(startNs); - - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = 3 * T::GetTimeSlotPartLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), (timeNs - startNs) / T::GetTimeSlotPartLengthNs()); - - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - } - - Y_UNIT_TEST(TThreadLoadRegisterBusyPeriodFirstTwoTimeSlots1) { - TThreadLoad<38400> threadLoad; - - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = 2 * threadLoad.GetTimeSlotLengthNs() - 1; - threadLoad.RegisterBusyPeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), threadLoad.GetTimeSlotMaxValue()); - - for (auto slotIndex = 2u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - } - - Y_UNIT_TEST(TThreadLoadRegisterBusyPeriodFirstTwoTimeSlots2) { - TThreadLoad<38400> threadLoad; - - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = 2 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - - for (auto slotIndex = 2u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - } - - Y_UNIT_TEST(TThreadLoadRegisterBusyPeriodFirstThreeTimeSlots1) { - TThreadLoad<38400> threadLoad; - - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = 3 * threadLoad.GetTimeSlotLengthNs() - 1; - threadLoad.RegisterBusyPeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[2].load(), threadLoad.GetTimeSlotMaxValue()); - - for (auto slotIndex = 3u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - } - - Y_UNIT_TEST(TThreadLoadRegisterBusyPeriodFirstThreeTimeSlots2) { - TThreadLoad<38400> threadLoad; - - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = 3 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[2].load(), threadLoad.GetTimeSlotMaxValue()); - - for (auto slotIndex = 3u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - } - - Y_UNIT_TEST(TThreadLoadRegisterBusyPeriodFirstThreeTimeSlots3) { - using T = TThreadLoad<38400>; - - ui32 startNs = 3 * T::GetTimeSlotPartLengthNs(); - T threadLoad(startNs); - - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = 0; - threadLoad.RegisterBusyPeriod(timeNs); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstTimeSlot1) { - using T = TThreadLoad<38400>; - - ui64 timeNs = T::GetTimeSlotPartLengthNs(); - T threadLoad(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 2 * T::GetTimeSlotPartLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 3 * T::GetTimeSlotPartLengthNs(); - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 0); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 4 * T::GetTimeSlotPartLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstTimeSlot2) { - using T = TThreadLoad<38400>; - - ui64 timeNs = T::GetTimeSlotPartLengthNs(); - T threadLoad(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 2 * T::GetTimeSlotPartLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 3 * T::GetTimeSlotPartLengthNs() - 1; - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 4 * T::GetTimeSlotPartLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 3); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstTimeSlot3) { - using T = TThreadLoad<38400>; - - ui64 timeNs = T::GetTimeSlotPartLengthNs(); - T threadLoad(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 2 * T::GetTimeSlotPartLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 3 * T::GetTimeSlotPartLengthNs() - 1; - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 4 * T::GetTimeSlotPartLengthNs() - 2; - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 5 * T::GetTimeSlotPartLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 3); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstTwoTimeSlots1) { - using T = TThreadLoad<38400>; - - T threadLoad; - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), 0); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 2 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 0); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 2u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstTwoTimeSlots2) { - using T = TThreadLoad<38400>; - - T threadLoad; - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), 0); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = threadLoad.GetTimeSlotLengthNs() - 1; - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 2 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 2u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstTwoTimeSlots3) { - using T = TThreadLoad<38400>; - - T threadLoad; - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), 0); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = threadLoad.GetTimeSlotLengthNs() - 1; - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 2 * threadLoad.GetTimeSlotLengthNs() - 1; - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 2u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstThreeTimeSlots1) { - using T = TThreadLoad<38400>; - - T threadLoad; - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), 0); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - timeNs = 2 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterIdlePeriod(timeNs); - - timeNs = 3 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), 0); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[2].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 3u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstThreeTimeSlots2) { - using T = TThreadLoad<38400>; - - T threadLoad; - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), 0); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - timeNs = 3 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstThreeTimeSlots3) { - using T = TThreadLoad<38400>; - - T threadLoad; - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), 0); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterIdlePeriod(timeNs); - - timeNs = 3 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 0); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[2].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 3u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstThreeTimeSlots4) { - using T = TThreadLoad<38400>; - - T threadLoad; - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), 0); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = threadLoad.GetTimeSlotLengthNs() + 2 * threadLoad.GetTimeSlotPartLengthNs(); - threadLoad.RegisterIdlePeriod(timeNs); - - timeNs = 3 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 0); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), threadLoad.GetTimeSlotPartCount() - 2); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[2].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 3u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstThreeTimeSlots5) { - using T = TThreadLoad<38400>; - - T threadLoad; - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), 0); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = 2 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 2u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = timeNs + threadLoad.GetTimeWindowLengthNs() + threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodOverTimeWindow) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, std::uint8_t>; - - T threadLoad; - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), 0); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = 5 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[2].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[3].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[4].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 5u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = timeNs + threadLoad.GetTimeWindowLengthNs() - 3 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 0); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), 0); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[2].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[3].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[4].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 5u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(MinusOneThreadEstimatorTwoThreadLoadsZeroShiftNs) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, std::uint16_t>; - - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotPartCount(), (ui64)std::numeric_limits<std::uint16_t>::max() + 1); - - T *threadLoads[2]; - threadLoads[0] = new T; - threadLoads[1] = new T; - - for (ui64 i = 1; i < timeSlotCount; i += 2) { - threadLoads[0]->RegisterIdlePeriod(i * T::GetTimeSlotLengthNs()); - threadLoads[0]->RegisterBusyPeriod((i + 1) * T::GetTimeSlotLengthNs()); - } - - for (ui64 i = 1; i < timeSlotCount; i += 2) { - threadLoads[1]->RegisterBusyPeriod(i * T::GetTimeSlotLengthNs()); - threadLoads[1]->RegisterIdlePeriod((i + 1) * T::GetTimeSlotLengthNs()); - } - - TMinusOneThreadEstimator estimator; - ui64 value = estimator.MaxLatencyIncreaseWithOneLessCpu(threadLoads, 2, T::GetTimeWindowLengthNs(), T::GetTimeWindowLengthNs()); - UNIT_ASSERT_VALUES_EQUAL(value, 0); - - delete threadLoads[0]; - delete threadLoads[1]; - } - - Y_UNIT_TEST(MinusOneThreadEstimatorTwoThreadLoadsOneTimeSlotShift1) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - constexpr auto threadCount = 2; - - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, std::uint16_t>; - - T *threadLoads[threadCount]; - - for (auto t = 0u; t < threadCount; ++t) { - threadLoads[t] = new T; - - for (ui64 i = 2; i < threadLoads[t]->GetTimeSlotCount(); i += 2) { - threadLoads[t]->RegisterIdlePeriod((i - 1) * T::GetTimeSlotLengthNs()); - threadLoads[t]->RegisterBusyPeriod(i * T::GetTimeSlotLengthNs()); - } - - threadLoads[t]->RegisterIdlePeriod((threadLoads[t]->GetTimeSlotCount() - 1) * T::GetTimeSlotLengthNs()); - threadLoads[t]->RegisterBusyPeriod(threadLoads[t]->GetTimeSlotCount() * T::GetTimeSlotLengthNs()); - - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - if (s % 2 == 1) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } else { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), 0, ToString(s).c_str()); - } - } - } - - TMinusOneThreadEstimator estimator; - auto result = estimator.MaxLatencyIncreaseWithOneLessCpu(threadLoads, threadCount, T::GetTimeWindowLengthNs(), T::GetTimeWindowLengthNs()); - - for (ui64 t = 0; t < threadCount; ++t) { - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - if (s % 2 == 1) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } else { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), 0, ToString(s).c_str()); - } - } - } - - UNIT_ASSERT_VALUES_EQUAL(result, T::GetTimeSlotLengthNs()); - - for (auto t = 0u; t < threadCount; ++t) { - delete threadLoads[t]; - } - } - - Y_UNIT_TEST(MinusOneThreadEstimatorTwoThreadLoadsOneTimeSlotShift2) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - constexpr auto threadCount = 2; - - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, std::uint16_t>; - - T *threadLoads[threadCount]; - - for (auto t = 0u; t < threadCount; ++t) { - threadLoads[t] = new T; - - for (ui64 i = 2; i < threadLoads[t]->GetTimeSlotCount(); i += 2) { - threadLoads[t]->RegisterBusyPeriod((i - 1) * T::GetTimeSlotLengthNs()); - threadLoads[t]->RegisterIdlePeriod(i * T::GetTimeSlotLengthNs()); - } - - threadLoads[t]->RegisterBusyPeriod((threadLoads[t]->GetTimeSlotCount() - 1) * T::GetTimeSlotLengthNs()); - threadLoads[t]->RegisterIdlePeriod(threadLoads[t]->GetTimeSlotCount() * T::GetTimeSlotLengthNs()); - - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - if (s % 2 == 0) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } else { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), 0, ToString(s).c_str()); - } - } - } - - TMinusOneThreadEstimator estimator; - auto result = estimator.MaxLatencyIncreaseWithOneLessCpu(threadLoads, threadCount, T::GetTimeWindowLengthNs(), T::GetTimeWindowLengthNs()); - - for (ui64 t = 0; t < threadCount; ++t) { - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - if (s % 2 == 0) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } else { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), 0, ToString(s).c_str()); - } - } - } - - UNIT_ASSERT_VALUES_EQUAL(result, T::GetTimeSlotLengthNs()); - - for (auto t = 0u; t < threadCount; ++t) { - delete threadLoads[t]; - } - } - - Y_UNIT_TEST(MinusOneThreadEstimatorTwoThreadLoadsTwoTimeSlotsShift1) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - constexpr auto threadCount = 2; - - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, std::uint16_t>; - - T *threadLoads[threadCount]; - - for (auto t = 0u; t < threadCount; ++t) { - threadLoads[t] = new T; - - for (ui64 i = 4; i < threadLoads[t]->GetTimeSlotCount(); i += 4) { - threadLoads[t]->RegisterIdlePeriod((i - 2) * T::GetTimeSlotLengthNs()); - threadLoads[t]->RegisterBusyPeriod(i * T::GetTimeSlotLengthNs()); - } - - threadLoads[t]->RegisterIdlePeriod((threadLoads[t]->GetTimeSlotCount() - 2) * T::GetTimeSlotLengthNs()); - threadLoads[t]->RegisterBusyPeriod(threadLoads[t]->GetTimeSlotCount() * T::GetTimeSlotLengthNs()); - - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - if (s % 4 == 2 || s % 4 == 3) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } else { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), 0, ToString(s).c_str()); - } - } - } - - TMinusOneThreadEstimator estimator; - auto result = estimator.MaxLatencyIncreaseWithOneLessCpu(threadLoads, threadCount, T::GetTimeWindowLengthNs(), T::GetTimeWindowLengthNs()); - - for (ui64 t = 0; t < threadCount; ++t) { - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - if (s % 4 == 2 || s % 4 == 3) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } else { - UNIT_ASSERT_VALUES_EQUAL(threadLoads[t]->TimeSlots[s].load(), 0); - } - } - } - - UNIT_ASSERT_VALUES_EQUAL(result, 2 * T::GetTimeSlotLengthNs()); - - for (auto t = 0u; t < threadCount; ++t) { - delete threadLoads[t]; - } - } - - Y_UNIT_TEST(MinusOneThreadEstimatorTwoThreadLoadsTwoTimeSlotsShift2) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - constexpr auto threadCount = 2; - - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, std::uint16_t>; - - T *threadLoads[threadCount]; - - for (auto t = 0u; t < threadCount; ++t) { - threadLoads[t] = new T; - - for (ui64 i = 4; i < threadLoads[t]->GetTimeSlotCount(); i += 4) { - threadLoads[t]->RegisterBusyPeriod((i - 2) * T::GetTimeSlotLengthNs()); - threadLoads[t]->RegisterIdlePeriod(i * T::GetTimeSlotLengthNs()); - } - - threadLoads[t]->RegisterBusyPeriod((threadLoads[t]->GetTimeSlotCount() - 2) * T::GetTimeSlotLengthNs()); - threadLoads[t]->RegisterIdlePeriod(threadLoads[t]->GetTimeSlotCount() * T::GetTimeSlotLengthNs()); - - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - if (s % 4 == 0 || s % 4 == 1) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } else { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), 0, ToString(s).c_str()); - } - } - } - - TMinusOneThreadEstimator estimator; - auto result = estimator.MaxLatencyIncreaseWithOneLessCpu(threadLoads, threadCount, T::GetTimeWindowLengthNs(), T::GetTimeWindowLengthNs()); - - for (ui64 t = 0; t < threadCount; ++t) { - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - if (s % 4 == 0 || s % 4 == 1) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } else { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), 0, ToString(s).c_str()); - } - } - } - - UNIT_ASSERT_VALUES_EQUAL(result, 2 * T::GetTimeSlotLengthNs()); - - for (auto t = 0u; t < threadCount; ++t) { - delete threadLoads[t]; - } - } - - Y_UNIT_TEST(MinusOneThreadEstimatorTwoThreadLoadsTwoTimeSlotsShift3) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - constexpr auto threadCount = 2; - - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, std::uint16_t>; - - T *threadLoads[threadCount]; - - for (auto t = 0u; t < threadCount; ++t) { - threadLoads[t] = new T; - - auto timeNs = T::GetTimeWindowLengthNs() - 1.5 * T::GetTimeSlotLengthNs(); - threadLoads[t]->RegisterIdlePeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoads[t]->LastTimeNs.load(), timeNs); - - timeNs = T::GetTimeWindowLengthNs(); - threadLoads[t]->RegisterBusyPeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoads[t]->LastTimeNs.load(), timeNs); - - for (ui64 s = 0; s + 2 < threadLoads[t]->GetTimeSlotCount(); ++s) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), 0, ToString(s).c_str()); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoads[t]->TimeSlots[timeSlotCount - 2].load(), T::GetTimeSlotPartCount() / 2); - UNIT_ASSERT_VALUES_EQUAL(threadLoads[t]->TimeSlots[timeSlotCount - 1].load(), T::GetTimeSlotMaxValue()); - } - - TMinusOneThreadEstimator estimator; - auto result = estimator.MaxLatencyIncreaseWithOneLessCpu(threadLoads, threadCount, T::GetTimeWindowLengthNs(), T::GetTimeWindowLengthNs()); - - for (auto t = 0u; t < threadCount; ++t) { - for (ui64 s = 0; s + 2 < threadLoads[t]->GetTimeSlotCount(); ++s) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), 0, ToString(s).c_str()); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoads[t]->TimeSlots[timeSlotCount - 2].load(), T::GetTimeSlotPartCount() / 2); - UNIT_ASSERT_VALUES_EQUAL(threadLoads[t]->TimeSlots[timeSlotCount - 1].load(), T::GetTimeSlotMaxValue()); - } - - UNIT_ASSERT_VALUES_EQUAL(result, 2 * T::GetTimeSlotLengthNs()); - - for (auto t = 0u; t < threadCount; ++t) { - delete threadLoads[t]; - } - } - - Y_UNIT_TEST(MinusOneThreadEstimator16ThreadLoadsAllTimeSlots) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - constexpr auto threadCount = 16; - constexpr auto estimatesCount = 16; - - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, std::uint16_t>; - - for (auto e = 0u; e < estimatesCount; ++e) { - T *threadLoads[threadCount]; - - for (auto t = 0u; t < threadCount; ++t) { - threadLoads[t] = new T; - auto timeNs = threadLoads[t]->GetTimeWindowLengthNs(); - threadLoads[t]->RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoads[t]->LastTimeNs.load(), timeNs); - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } - } - - ui64 result = 0; - { - THPTimer timer; - TMinusOneThreadEstimator estimator; - result = estimator.MaxLatencyIncreaseWithOneLessCpu(threadLoads, threadCount, T::GetTimeWindowLengthNs(), T::GetTimeWindowLengthNs()); - // output in microseconds - auto passed = timer.Passed() * 1000000; - Y_UNUSED(passed); - // Cerr << "timer : " << passed << " " << __LINE__ << Endl; - } - - for (ui64 t = 0; t < threadCount; ++t) { - UNIT_ASSERT_VALUES_EQUAL(threadLoads[t]->LastTimeNs.load(), T::GetTimeWindowLengthNs()); - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } - } - - UNIT_ASSERT_VALUES_EQUAL(result, T::GetTimeWindowLengthNs()); - - for (auto t = 0u; t < threadCount; ++t) { - delete threadLoads[t]; - } - } - } -} diff --git a/library/cpp/actors/util/threadparkpad.cpp b/library/cpp/actors/util/threadparkpad.cpp deleted file mode 100644 index b939d6b61a..0000000000 --- a/library/cpp/actors/util/threadparkpad.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include "threadparkpad.h" -#include <util/system/winint.h> - -#ifdef _linux_ - -#include "futex.h" - -namespace NActors { - class TThreadParkPad::TImpl { - volatile bool Interrupted; - int Futex; - - public: - TImpl() - : Interrupted(false) - , Futex(0) - { - } - ~TImpl() { - } - - bool Park() noexcept { - __atomic_fetch_sub(&Futex, 1, __ATOMIC_SEQ_CST); - while (__atomic_load_n(&Futex, __ATOMIC_ACQUIRE) == -1) - SysFutex(&Futex, FUTEX_WAIT_PRIVATE, -1, nullptr, nullptr, 0); - return IsInterrupted(); - } - - void Unpark() noexcept { - const int old = __atomic_fetch_add(&Futex, 1, __ATOMIC_SEQ_CST); - if (old == -1) - SysFutex(&Futex, FUTEX_WAKE_PRIVATE, -1, nullptr, nullptr, 0); - } - - void Interrupt() noexcept { - __atomic_store_n(&Interrupted, true, __ATOMIC_SEQ_CST); - Unpark(); - } - - bool IsInterrupted() const noexcept { - return __atomic_load_n(&Interrupted, __ATOMIC_ACQUIRE); - } - }; - -#elif defined _win32_ -#include <library/cpp/deprecated/atomic/atomic.h> - -#include <util/generic/bt_exception.h> -#include <util/generic/yexception.h> - -namespace NActors { - class TThreadParkPad::TImpl { - TAtomic Interrupted; - HANDLE EvHandle; - - public: - TImpl() - : Interrupted(false) - { - EvHandle = ::CreateEvent(0, false, false, 0); - if (!EvHandle) - ythrow TWithBackTrace<yexception>() << "::CreateEvent failed"; - } - ~TImpl() { - if (EvHandle) - ::CloseHandle(EvHandle); - } - - bool Park() noexcept { - ::WaitForSingleObject(EvHandle, INFINITE); - return AtomicGet(Interrupted); - } - - void Unpark() noexcept { - ::SetEvent(EvHandle); - } - - void Interrupt() noexcept { - AtomicSet(Interrupted, true); - Unpark(); - } - - bool IsInterrupted() const noexcept { - return AtomicGet(Interrupted); - } - }; - -#else - -#include <library/cpp/deprecated/atomic/atomic.h> - -#include <util/system/event.h> - -namespace NActors { - class TThreadParkPad::TImpl { - TAtomic Interrupted; - TSystemEvent Ev; - - public: - TImpl() - : Interrupted(false) - , Ev(TSystemEvent::rAuto) - { - } - ~TImpl() { - } - - bool Park() noexcept { - Ev.Wait(); - return AtomicGet(Interrupted); - } - - void Unpark() noexcept { - Ev.Signal(); - } - - void Interrupt() noexcept { - AtomicSet(Interrupted, true); - Unpark(); - } - - bool IsInterrupted() const noexcept { - return AtomicGet(Interrupted); - } - }; -#endif - - TThreadParkPad::TThreadParkPad() - : Impl(new TThreadParkPad::TImpl()) - { - } - - TThreadParkPad::~TThreadParkPad() { - } - - bool TThreadParkPad::Park() noexcept { - return Impl->Park(); - } - - void TThreadParkPad::Unpark() noexcept { - Impl->Unpark(); - } - - void TThreadParkPad::Interrupt() noexcept { - Impl->Interrupt(); - } - - bool TThreadParkPad::Interrupted() const noexcept { - return Impl->IsInterrupted(); - } - -} diff --git a/library/cpp/actors/util/threadparkpad.h b/library/cpp/actors/util/threadparkpad.h deleted file mode 100644 index 5b574ccf34..0000000000 --- a/library/cpp/actors/util/threadparkpad.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include <util/generic/ptr.h> - -namespace NActors { - class TThreadParkPad { - private: - class TImpl; - THolder<TImpl> Impl; - - public: - TThreadParkPad(); - ~TThreadParkPad(); - - bool Park() noexcept; - void Unpark() noexcept; - void Interrupt() noexcept; - bool Interrupted() const noexcept; - }; - -} diff --git a/library/cpp/actors/util/ticket_lock.h b/library/cpp/actors/util/ticket_lock.h deleted file mode 100644 index 30355c3390..0000000000 --- a/library/cpp/actors/util/ticket_lock.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include "intrinsics.h" -#include <util/system/guard.h> -#include <util/system/yassert.h> - -class TTicketLock : TNonCopyable { - ui32 TicketIn; - ui32 TicketOut; - -public: - TTicketLock() - : TicketIn(0) - , TicketOut(0) - { - } - - void Release() noexcept { - AtomicUi32Increment(&TicketOut); - } - - ui32 Acquire() noexcept { - ui32 revolves = 0; - const ui32 ticket = AtomicUi32Increment(&TicketIn) - 1; - while (ticket != AtomicLoad(&TicketOut)) { - Y_DEBUG_ABORT_UNLESS(ticket >= AtomicLoad(&TicketOut)); - SpinLockPause(); - ++revolves; - } - return revolves; - } - - bool TryAcquire() noexcept { - const ui32 x = AtomicLoad(&TicketOut); - if (x == AtomicLoad(&TicketIn) && AtomicUi32Cas(&TicketIn, x + 1, x)) - return true; - else - return false; - } - - bool IsLocked() noexcept { - const ui32 ticketIn = AtomicLoad(&TicketIn); - const ui32 ticketOut = AtomicLoad(&TicketOut); - return (ticketIn != ticketOut); - } - - typedef ::TGuard<TTicketLock> TGuard; -}; diff --git a/library/cpp/actors/util/timerfd.h b/library/cpp/actors/util/timerfd.h deleted file mode 100644 index 78ae27e2ee..0000000000 --- a/library/cpp/actors/util/timerfd.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include "datetime.h" - -#include <util/generic/noncopyable.h> - -#ifdef _linux_ - -#include <util/system/yassert.h> -#include <errno.h> -#include <sys/timerfd.h> - -struct TTimerFd: public TNonCopyable { - int Fd; - - TTimerFd() { - Fd = timerfd_create(CLOCK_MONOTONIC, 0); - Y_ABORT_UNLESS(Fd != -1, "timerfd_create(CLOCK_MONOTONIC, 0) -> -1; errno:%d: %s", int(errno), strerror(errno)); - } - - ~TTimerFd() { - close(Fd); - } - - void Set(ui64 ts) { - ui64 now = GetCycleCountFast(); - Arm(now >= ts? 1: NHPTimer::GetSeconds(ts - now) * 1e9); - } - - void Reset() { - Arm(0); // disarm timer - } - - void Wait() { - ui64 expirations; - ssize_t s = read(Fd, &expirations, sizeof(ui64)); - Y_UNUSED(s); // Y_ABORT_UNLESS(s == sizeof(ui64)); - } - - void Wake() { - Arm(1); - } -private: - void Arm(ui64 ns) { - struct itimerspec spec; - spec.it_value.tv_sec = ns / 1'000'000'000; - spec.it_value.tv_nsec = ns % 1'000'000'000; - spec.it_interval.tv_sec = 0; - spec.it_interval.tv_nsec = 0; - int ret = timerfd_settime(Fd, 0, &spec, nullptr); - Y_ABORT_UNLESS(ret != -1, "timerfd_settime(%d, 0, %" PRIu64 "ns, 0) -> %d; errno:%d: %s", Fd, ns, ret, int(errno), strerror(errno)); - } -}; - -#else - -struct TTimerFd: public TNonCopyable { - int Fd = 0; - void Set(ui64) {} - void Reset() {} - void Wait() {} - void Wake() {} -}; - -#endif diff --git a/library/cpp/actors/util/unordered_cache.h b/library/cpp/actors/util/unordered_cache.h deleted file mode 100644 index 40794fc04b..0000000000 --- a/library/cpp/actors/util/unordered_cache.h +++ /dev/null @@ -1,201 +0,0 @@ -#pragma once - -#include "defs.h" -#include "queue_chunk.h" - -template <typename T, ui32 Size = 512, ui32 ConcurrencyFactor = 1, typename TChunk = TQueueChunk<T, Size>> -class TUnorderedCache : TNonCopyable { - static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value"); - -public: - static constexpr ui32 Concurrency = ConcurrencyFactor * 4; - -private: - struct TReadSlot { - TChunk* volatile ReadFrom; - volatile ui32 ReadPosition; - char Padding[64 - sizeof(TChunk*) - sizeof(ui32)]; // 1 slot per cache line - }; - - struct TWriteSlot { - TChunk* volatile WriteTo; - volatile ui32 WritePosition; - char Padding[64 - sizeof(TChunk*) - sizeof(ui32)]; // 1 slot per cache line - }; - - static_assert(sizeof(TReadSlot) == 64, "expect sizeof(TReadSlot) == 64"); - static_assert(sizeof(TWriteSlot) == 64, "expect sizeof(TWriteSlot) == 64"); - -private: - TReadSlot ReadSlots[Concurrency]; - TWriteSlot WriteSlots[Concurrency]; - - static_assert(sizeof(TChunk*) == sizeof(TAtomic), "expect sizeof(TChunk*) == sizeof(TAtomic)"); - -private: - struct TLockedWriter { - TWriteSlot* Slot; - TChunk* WriteTo; - - TLockedWriter() - : Slot(nullptr) - , WriteTo(nullptr) - { } - - TLockedWriter(TWriteSlot* slot, TChunk* writeTo) - : Slot(slot) - , WriteTo(writeTo) - { } - - ~TLockedWriter() noexcept { - Drop(); - } - - void Drop() { - if (Slot) { - AtomicStore(&Slot->WriteTo, WriteTo); - Slot = nullptr; - } - } - - TLockedWriter(const TLockedWriter&) = delete; - TLockedWriter& operator=(const TLockedWriter&) = delete; - - TLockedWriter(TLockedWriter&& rhs) - : Slot(rhs.Slot) - , WriteTo(rhs.WriteTo) - { - rhs.Slot = nullptr; - } - - TLockedWriter& operator=(TLockedWriter&& rhs) { - if (Y_LIKELY(this != &rhs)) { - Drop(); - Slot = rhs.Slot; - WriteTo = rhs.WriteTo; - rhs.Slot = nullptr; - } - return *this; - } - }; - -private: - TLockedWriter LockWriter(ui64 writerRotation) { - ui32 cycle = 0; - for (;;) { - TWriteSlot* slot = &WriteSlots[writerRotation % Concurrency]; - if (AtomicLoad(&slot->WriteTo) != nullptr) { - if (TChunk* writeTo = AtomicSwap(&slot->WriteTo, nullptr)) { - return TLockedWriter(slot, writeTo); - } - } - ++writerRotation; - - // Do a spinlock pause after a full cycle - if (++cycle == Concurrency) { - SpinLockPause(); - cycle = 0; - } - } - } - - void WriteOne(TLockedWriter& lock, T x) { - Y_DEBUG_ABORT_UNLESS(x != 0); - - const ui32 pos = AtomicLoad(&lock.Slot->WritePosition); - if (pos != TChunk::EntriesCount) { - AtomicStore(&lock.Slot->WritePosition, pos + 1); - AtomicStore(&lock.WriteTo->Entries[pos], x); - } else { - TChunk* next = new TChunk(); - AtomicStore(&next->Entries[0], x); - AtomicStore(&lock.Slot->WritePosition, 1u); - AtomicStore(&lock.WriteTo->Next, next); - lock.WriteTo = next; - } - } - -public: - TUnorderedCache() { - for (ui32 i = 0; i < Concurrency; ++i) { - ReadSlots[i].ReadFrom = new TChunk(); - ReadSlots[i].ReadPosition = 0; - - WriteSlots[i].WriteTo = ReadSlots[i].ReadFrom; - WriteSlots[i].WritePosition = 0; - } - } - - ~TUnorderedCache() { - Y_ABORT_UNLESS(!Pop(0)); - - for (ui64 i = 0; i < Concurrency; ++i) { - if (ReadSlots[i].ReadFrom) { - delete ReadSlots[i].ReadFrom; - ReadSlots[i].ReadFrom = nullptr; - } - WriteSlots[i].WriteTo = nullptr; - } - } - - T Pop(ui64 readerRotation) noexcept { - ui64 readerIndex = readerRotation; - const ui64 endIndex = readerIndex + Concurrency; - for (; readerIndex != endIndex; ++readerIndex) { - TReadSlot* slot = &ReadSlots[readerIndex % Concurrency]; - if (AtomicLoad(&slot->ReadFrom) != nullptr) { - if (TChunk* readFrom = AtomicSwap(&slot->ReadFrom, nullptr)) { - const ui32 pos = AtomicLoad(&slot->ReadPosition); - if (pos != TChunk::EntriesCount) { - if (T ret = AtomicLoad(&readFrom->Entries[pos])) { - AtomicStore(&slot->ReadPosition, pos + 1); - AtomicStore(&slot->ReadFrom, readFrom); // release lock with same chunk - return ret; // found, return - } else { - AtomicStore(&slot->ReadFrom, readFrom); // release lock with same chunk - } - } else if (TChunk* next = AtomicLoad(&readFrom->Next)) { - if (T ret = AtomicLoad(&next->Entries[0])) { - AtomicStore(&slot->ReadPosition, 1u); - AtomicStore(&slot->ReadFrom, next); // release lock with next chunk - delete readFrom; - return ret; - } else { - AtomicStore(&slot->ReadPosition, 0u); - AtomicStore(&slot->ReadFrom, next); // release lock with new chunk - delete readFrom; - } - } else { - // nothing in old chunk and no next chunk, just release lock with old chunk - AtomicStore(&slot->ReadFrom, readFrom); - } - } - } - } - - return 0; // got nothing after full cycle, return - } - - void Push(T x, ui64 writerRotation) { - TLockedWriter lock = LockWriter(writerRotation); - WriteOne(lock, x); - } - - void PushBulk(T* x, ui32 xcount, ui64 writerRotation) { - for (;;) { - // Fill no more then one queue chunk per round - const ui32 xround = Min(xcount, (ui32)TChunk::EntriesCount); - - { - TLockedWriter lock = LockWriter(writerRotation++); - for (T* end = x + xround; x != end; ++x) - WriteOne(lock, *x); - } - - if (xcount <= TChunk::EntriesCount) - break; - - xcount -= TChunk::EntriesCount; - } - } -}; diff --git a/library/cpp/actors/util/unordered_cache_ut.cpp b/library/cpp/actors/util/unordered_cache_ut.cpp deleted file mode 100644 index 37865f2f91..0000000000 --- a/library/cpp/actors/util/unordered_cache_ut.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "unordered_cache.h" - -#include <library/cpp/testing/unittest/registar.h> -#include <util/random/random.h> -#include <util/system/hp_timer.h> -#include <util/system/sanitizers.h> -#include <util/system/thread.h> - -Y_UNIT_TEST_SUITE(UnorderedCache) { - - void DoOnePushOnePop(ui64 count) { - TUnorderedCache<ui64> queue; - - ui64 readRotation = 0; - ui64 writeRotation = 0; - - auto popped = queue.Pop(readRotation++); - UNIT_ASSERT_VALUES_EQUAL(popped, 0u); - - for (ui64 i = 0; i < count; ++i) { - queue.Push(i + 1, writeRotation++); - popped = queue.Pop(readRotation++); - UNIT_ASSERT_VALUES_EQUAL(popped, i + 1); - - popped = queue.Pop(readRotation++); - UNIT_ASSERT_VALUES_EQUAL(popped, 0u); - } - } - - Y_UNIT_TEST(OnePushOnePop) { - DoOnePushOnePop(1); - } - - Y_UNIT_TEST(OnePushOnePop_Repeat1M) { - DoOnePushOnePop(1000000); - } - - /** - * Simplified thread spawning for testing - */ - class TWorkerThread : public ISimpleThread { - private: - std::function<void()> Func; - double Time = 0.0; - - public: - TWorkerThread(std::function<void()> func) - : Func(std::move(func)) - { } - - double GetTime() const { - return Time; - } - - static THolder<TWorkerThread> Spawn(std::function<void()> func) { - THolder<TWorkerThread> thread = MakeHolder<TWorkerThread>(std::move(func)); - thread->Start(); - return thread; - } - - private: - void* ThreadProc() noexcept override { - THPTimer timer; - Func(); - Time = timer.Passed(); - return nullptr; - } - }; - - void DoConcurrentPushPop(size_t threads, ui64 perThreadCount) { - // Concurrency factor 4 is up to 16 threads - TUnorderedCache<ui64, 512, 4> queue; - - auto workerFunc = [&](size_t threadIndex) { - ui64 readRotation = 0; - ui64 writeRotation = 0; - ui64 readsDone = 0; - ui64 writesDone = 0; - for (;;) { - bool canRead = readsDone < writesDone; - bool canWrite = writesDone < perThreadCount; - if (!canRead && !canWrite) { - break; - } - if (canRead && canWrite) { - // Randomly choose between read and write - if (RandomNumber<ui64>(2)) { - canRead = false; - } else { - canWrite = false; - } - } - if (canRead) { - ui64 popped = queue.Pop(readRotation++); - if (popped) { - ++readsDone; - } - } - if (canWrite) { - queue.Push(1 + writesDone * threads + threadIndex, writeRotation++); - ++writesDone; - } - } - }; - - TVector<THolder<TWorkerThread>> workers(threads); - for (size_t i = 0; i < threads; ++i) { - workers[i] = TWorkerThread::Spawn([workerFunc, i]() { - workerFunc(i); - }); - } - - double maxTime = 0; - for (size_t i = 0; i < threads; ++i) { - workers[i]->Join(); - maxTime = Max(maxTime, workers[i]->GetTime()); - } - - auto popped = queue.Pop(0); - UNIT_ASSERT_VALUES_EQUAL(popped, 0u); - - Cerr << "Concurrent with " << threads << " threads: " << maxTime << " seconds" << Endl; - } - - void DoConcurrentPushPop_3times(size_t threads, ui64 perThreadCount) { - for (size_t i = 0; i < 3; ++i) { - DoConcurrentPushPop(threads, perThreadCount); - } - } - - static constexpr ui64 PER_THREAD_COUNT = NSan::PlainOrUnderSanitizer(1000000, 100000); - - Y_UNIT_TEST(ConcurrentPushPop_1thread) { DoConcurrentPushPop_3times(1, PER_THREAD_COUNT); } - Y_UNIT_TEST(ConcurrentPushPop_2threads) { DoConcurrentPushPop_3times(2, PER_THREAD_COUNT); } - Y_UNIT_TEST(ConcurrentPushPop_4threads) { DoConcurrentPushPop_3times(4, PER_THREAD_COUNT); } - Y_UNIT_TEST(ConcurrentPushPop_8threads) { DoConcurrentPushPop_3times(8, PER_THREAD_COUNT); } - Y_UNIT_TEST(ConcurrentPushPop_16threads) { DoConcurrentPushPop_3times(16, PER_THREAD_COUNT); } -} diff --git a/library/cpp/actors/util/ut/CMakeLists.darwin-arm64.txt b/library/cpp/actors/util/ut/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 9b02cd1836..0000000000 --- a/library/cpp/actors/util/ut/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,74 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-util-ut) -target_include_directories(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util -) -target_link_libraries(library-cpp-actors-util-ut PUBLIC - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-util -) -target_link_options(library-cpp-actors-util-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/cpu_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/thread_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_native_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/unordered_cache_ut.cpp -) -set_property( - TARGET - library-cpp-actors-util-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-util-ut - TEST_TARGET - library-cpp-actors-util-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-util-ut - system_allocator -) -vcs_info(library-cpp-actors-util-ut) diff --git a/library/cpp/actors/util/ut/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/util/ut/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index f02b2d926c..0000000000 --- a/library/cpp/actors/util/ut/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,75 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-util-ut) -target_include_directories(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util -) -target_link_libraries(library-cpp-actors-util-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-util -) -target_link_options(library-cpp-actors-util-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/cpu_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/thread_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_native_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/unordered_cache_ut.cpp -) -set_property( - TARGET - library-cpp-actors-util-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-util-ut - TEST_TARGET - library-cpp-actors-util-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-util-ut - system_allocator -) -vcs_info(library-cpp-actors-util-ut) diff --git a/library/cpp/actors/util/ut/CMakeLists.linux-aarch64.txt b/library/cpp/actors/util/ut/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 27ff864fef..0000000000 --- a/library/cpp/actors/util/ut/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,78 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-util-ut) -target_include_directories(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util -) -target_link_libraries(library-cpp-actors-util-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-util -) -target_link_options(library-cpp-actors-util-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/cpu_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/thread_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_native_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/unordered_cache_ut.cpp -) -set_property( - TARGET - library-cpp-actors-util-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-util-ut - TEST_TARGET - library-cpp-actors-util-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-util-ut - cpp-malloc-jemalloc -) -vcs_info(library-cpp-actors-util-ut) diff --git a/library/cpp/actors/util/ut/CMakeLists.linux-x86_64.txt b/library/cpp/actors/util/ut/CMakeLists.linux-x86_64.txt deleted file mode 100644 index d1143a475b..0000000000 --- a/library/cpp/actors/util/ut/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,80 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-util-ut) -target_include_directories(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util -) -target_link_libraries(library-cpp-actors-util-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-util -) -target_link_options(library-cpp-actors-util-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/cpu_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/thread_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_native_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/unordered_cache_ut.cpp -) -set_property( - TARGET - library-cpp-actors-util-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-util-ut - TEST_TARGET - library-cpp-actors-util-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-util-ut - cpp-malloc-tcmalloc - libs-tcmalloc-no_percpu_cache -) -vcs_info(library-cpp-actors-util-ut) diff --git a/library/cpp/actors/util/ut/CMakeLists.txt b/library/cpp/actors/util/ut/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/util/ut/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/util/ut/CMakeLists.windows-x86_64.txt b/library/cpp/actors/util/ut/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 3af5d98ef0..0000000000 --- a/library/cpp/actors/util/ut/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,68 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-util-ut) -target_include_directories(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util -) -target_link_libraries(library-cpp-actors-util-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-util -) -target_sources(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/cpu_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/thread_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_native_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/unordered_cache_ut.cpp -) -set_property( - TARGET - library-cpp-actors-util-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-util-ut - TEST_TARGET - library-cpp-actors-util-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-util-ut - system_allocator -) -vcs_info(library-cpp-actors-util-ut) diff --git a/library/cpp/actors/util/ut/ya.make b/library/cpp/actors/util/ut/ya.make deleted file mode 100644 index 9ac8504751..0000000000 --- a/library/cpp/actors/util/ut/ya.make +++ /dev/null @@ -1,20 +0,0 @@ -UNITTEST_FOR(library/cpp/actors/util) - -IF (WITH_VALGRIND) - TIMEOUT(600) - SIZE(MEDIUM) -ENDIF() - -SRCS( - cpu_load_log_ut.cpp - memory_tracker_ut.cpp - thread_load_log_ut.cpp - rope_ut.cpp - rc_buf_ut.cpp - shared_data_ut.cpp - shared_data_rope_backend_ut.cpp - shared_data_native_rope_backend_ut.cpp - unordered_cache_ut.cpp -) - -END() diff --git a/library/cpp/actors/util/ut_helpers.h b/library/cpp/actors/util/ut_helpers.h deleted file mode 100644 index d3fe873233..0000000000 --- a/library/cpp/actors/util/ut_helpers.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -// calls TCallback for all args permutations including (id, id) -template <class TCallback, class... TArgs> -void Permutate(TCallback&& fn, TArgs&&... args) -{ - auto forAll = [&](auto& arg){ - (fn(std::forward<decltype(arg)>(arg), std::forward<decltype(args)>(args)), ...); - }; - - (forAll(std::forward<decltype(args)>(args)), ...); -} diff --git a/library/cpp/actors/util/ya.make b/library/cpp/actors/util/ya.make deleted file mode 100644 index 48d595c156..0000000000 --- a/library/cpp/actors/util/ya.make +++ /dev/null @@ -1,50 +0,0 @@ -LIBRARY() - -SRCS( - affinity.cpp - affinity.h - cpu_load_log.h - cpumask.h - datetime.h - defs.h - funnel_queue.h - futex.h - intrinsics.h - local_process_key.h - named_tuple.h - queue_chunk.h - queue_oneone_inplace.h - memory_track.cpp - memory_track.h - memory_tracker.cpp - memory_tracker.h - recentwnd.h - rope.cpp - rope.h - rc_buf.cpp - rc_buf.h - shared_data.h - shared_data.cpp - shared_data_rope_backend.h - should_continue.cpp - should_continue.h - thread.h - threadparkpad.cpp - threadparkpad.h - thread_load_log.h - ticket_lock.h - timerfd.h - unordered_cache.h -) - -PEERDIR( - library/cpp/containers/absl_flat_hash - library/cpp/deprecated/atomic - library/cpp/pop_count -) - -END() - -RECURSE_FOR_TESTS( - ut -) diff --git a/library/cpp/actors/wilson/CMakeLists.darwin-arm64.txt b/library/cpp/actors/wilson/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 45704ccd5a..0000000000 --- a/library/cpp/actors/wilson/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,25 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(protos) - -add_library(cpp-actors-wilson) -target_link_libraries(cpp-actors-wilson PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core - cpp-actors-protos - actors-wilson-protos -) -target_sources(cpp-actors-wilson PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_event.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_span.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_profile_span.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_trace.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_uploader.cpp -) diff --git a/library/cpp/actors/wilson/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/wilson/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 45704ccd5a..0000000000 --- a/library/cpp/actors/wilson/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,25 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(protos) - -add_library(cpp-actors-wilson) -target_link_libraries(cpp-actors-wilson PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core - cpp-actors-protos - actors-wilson-protos -) -target_sources(cpp-actors-wilson PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_event.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_span.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_profile_span.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_trace.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_uploader.cpp -) diff --git a/library/cpp/actors/wilson/CMakeLists.linux-aarch64.txt b/library/cpp/actors/wilson/CMakeLists.linux-aarch64.txt deleted file mode 100644 index ccc87489ae..0000000000 --- a/library/cpp/actors/wilson/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,26 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(protos) - -add_library(cpp-actors-wilson) -target_link_libraries(cpp-actors-wilson PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-actors-core - cpp-actors-protos - actors-wilson-protos -) -target_sources(cpp-actors-wilson PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_event.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_span.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_profile_span.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_trace.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_uploader.cpp -) diff --git a/library/cpp/actors/wilson/CMakeLists.linux-x86_64.txt b/library/cpp/actors/wilson/CMakeLists.linux-x86_64.txt deleted file mode 100644 index ccc87489ae..0000000000 --- a/library/cpp/actors/wilson/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,26 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(protos) - -add_library(cpp-actors-wilson) -target_link_libraries(cpp-actors-wilson PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-actors-core - cpp-actors-protos - actors-wilson-protos -) -target_sources(cpp-actors-wilson PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_event.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_span.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_profile_span.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_trace.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_uploader.cpp -) diff --git a/library/cpp/actors/wilson/CMakeLists.txt b/library/cpp/actors/wilson/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/wilson/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/wilson/CMakeLists.windows-x86_64.txt b/library/cpp/actors/wilson/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 45704ccd5a..0000000000 --- a/library/cpp/actors/wilson/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,25 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(protos) - -add_library(cpp-actors-wilson) -target_link_libraries(cpp-actors-wilson PUBLIC - contrib-libs-cxxsupp - yutil - cpp-actors-core - cpp-actors-protos - actors-wilson-protos -) -target_sources(cpp-actors-wilson PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_event.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_span.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_profile_span.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_trace.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/wilson/wilson_uploader.cpp -) diff --git a/library/cpp/actors/wilson/protos/CMakeLists.darwin-arm64.txt b/library/cpp/actors/wilson/protos/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 92afc01bb4..0000000000 --- a/library/cpp/actors/wilson/protos/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,15 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(actors-wilson-protos INTERFACE) -target_link_libraries(actors-wilson-protos INTERFACE - contrib-libs-cxxsupp - yutil - contrib-libs-opentelemetry-proto -) diff --git a/library/cpp/actors/wilson/protos/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/wilson/protos/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index 92afc01bb4..0000000000 --- a/library/cpp/actors/wilson/protos/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,15 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(actors-wilson-protos INTERFACE) -target_link_libraries(actors-wilson-protos INTERFACE - contrib-libs-cxxsupp - yutil - contrib-libs-opentelemetry-proto -) diff --git a/library/cpp/actors/wilson/protos/CMakeLists.linux-aarch64.txt b/library/cpp/actors/wilson/protos/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 101316f4fc..0000000000 --- a/library/cpp/actors/wilson/protos/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,16 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(actors-wilson-protos INTERFACE) -target_link_libraries(actors-wilson-protos INTERFACE - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - contrib-libs-opentelemetry-proto -) diff --git a/library/cpp/actors/wilson/protos/CMakeLists.linux-x86_64.txt b/library/cpp/actors/wilson/protos/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 101316f4fc..0000000000 --- a/library/cpp/actors/wilson/protos/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,16 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(actors-wilson-protos INTERFACE) -target_link_libraries(actors-wilson-protos INTERFACE - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - contrib-libs-opentelemetry-proto -) diff --git a/library/cpp/actors/wilson/protos/CMakeLists.txt b/library/cpp/actors/wilson/protos/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/wilson/protos/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/wilson/protos/CMakeLists.windows-x86_64.txt b/library/cpp/actors/wilson/protos/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 92afc01bb4..0000000000 --- a/library/cpp/actors/wilson/protos/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,15 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_library(actors-wilson-protos INTERFACE) -target_link_libraries(actors-wilson-protos INTERFACE - contrib-libs-cxxsupp - yutil - contrib-libs-opentelemetry-proto -) diff --git a/library/cpp/actors/wilson/protos/ya.make b/library/cpp/actors/wilson/protos/ya.make deleted file mode 100644 index e9db290efd..0000000000 --- a/library/cpp/actors/wilson/protos/ya.make +++ /dev/null @@ -1,12 +0,0 @@ -PROTO_LIBRARY() - - PEERDIR( - contrib/libs/opentelemetry-proto - ) - - EXCLUDE_TAGS( - GO_PROTO - JAVA_PROTO - ) - -END() diff --git a/library/cpp/actors/wilson/wilson_event.cpp b/library/cpp/actors/wilson/wilson_event.cpp deleted file mode 100644 index ad51550d91..0000000000 --- a/library/cpp/actors/wilson/wilson_event.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "wilson_event.h" - -namespace NWilson { -} diff --git a/library/cpp/actors/wilson/wilson_event.h b/library/cpp/actors/wilson/wilson_event.h deleted file mode 100644 index 4b6a7612c0..0000000000 --- a/library/cpp/actors/wilson/wilson_event.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "wilson_trace.h" - -#include <library/cpp/string_utils/base64/base64.h> -#include <library/cpp/actors/core/actor.h> -#include <library/cpp/actors/core/log.h> - -namespace NWilson { - - // stub for NBS - template<typename TActorSystem> - inline bool TraceEnabled(const TActorSystem&) { - return false; - } - - template<typename TActorSystem, typename TEvent> - inline void TraceEvent(const TActorSystem&, TTraceId*, TEvent&&, TInstant) - {} - -} // NWilson diff --git a/library/cpp/actors/wilson/wilson_profile_span.cpp b/library/cpp/actors/wilson/wilson_profile_span.cpp deleted file mode 100644 index e908ed2b8a..0000000000 --- a/library/cpp/actors/wilson/wilson_profile_span.cpp +++ /dev/null @@ -1,178 +0,0 @@ -#include "wilson_profile_span.h" -#include <library/cpp/json/writer/json.h> - -namespace NWilson { - -void TProfileSpan::AddMax(const TString& eventId, const TString& /*info*/) { - if (!Enabled) { - return; - } - auto it = PairInstances.find(eventId); - if (it == PairInstances.end()) { - PairInstances.emplace(eventId, TMinMaxPair::BuildMax(Now())); - } else { - it->second.AddMax(Now()); - } -} - -void TProfileSpan::AddMin(const TString& eventId, const TString& /*info*/) { - if (!Enabled) { - return; - } - auto it = PairInstances.find(eventId); - if (it == PairInstances.end()) { - PairInstances.emplace(eventId, TMinMaxPair::BuildMin(Now())); - } else { - it->second.AddMin(Now()); - } -} - -TProfileSpan::TProfileSpan(const ui8 verbosity, TTraceId parentId, std::optional<TString> name) - : TBase(verbosity, std::move(parentId), name, NWilson::EFlags::AUTO_END) -{ - -} - -TProfileSpan::~TProfileSpan() { - if (Enabled && (ResultTimes.GetMapSafe().size() || PairInstances.size())) { - TBase::Attribute("profile", ProfileToString()); - } -} - -NWilson::TProfileSpan TProfileSpan::BuildChildrenSpan(std::optional<TString> name, const ui8 verbosity) const { - TTraceId parentTraceId = TBase::GetTraceId(); - const ui8 newVerbosity = verbosity ? verbosity : parentTraceId.GetVerbosity(); - return TProfileSpan(newVerbosity, std::move(parentTraceId), name); -} - -TString TProfileSpan::ProfileToString() const { - if (!Enabled) { - return "DISABLED"; - } - TStringBuilder sb; - FlushNoGuards(); - { - NJsonWriter::TBuf sout; - ResultTimes.InsertValue("-current_guards_count", CurrentJsonPath.size()); - ResultTimes.InsertValue("-duration", (Now() - StartTime).MicroSeconds() * 0.000001); - sout.WriteJsonValue(&ResultTimes, true, EFloatToStringMode::PREC_POINT_DIGITS, 6); - sb << sout.Str(); - } - sb << ";"; - sb << "Pairs:{"; - for (auto&& i : PairInstances) { - sb << i.first << ":" << i.second.ToString() << ";"; - } - sb << "}"; - return sb; -} - -void TProfileSpan::FlushNoGuards() const { - if (!Enabled) { - return; - } - if (CurrentJsonPath.empty()) { - NJson::TJsonValue* currentNodeOutside; - if (!ResultTimes.GetValuePointer("--outside_duration", ¤tNodeOutside)) { - currentNodeOutside = &ResultTimes.InsertValue("--outside_duration", 0); - currentNodeOutside->SetType(NJson::JSON_DOUBLE); - } - currentNodeOutside->SetValue(currentNodeOutside->GetDoubleRobust() + (Now() - LastNoGuards).MicroSeconds() * 0.000001); - LastNoGuards = Now(); - } -} - -NWilson::TProfileSpan::TMinMaxPair TProfileSpan::TMinMaxPair::BuildMin(const TInstant value) { - TMinMaxPair result; - result.MinMinInstance = value; - result.MaxMinInstance = value; - return result; -} - -NWilson::TProfileSpan::TMinMaxPair TProfileSpan::TMinMaxPair::BuildMax(const TInstant value) { - TMinMaxPair result; - result.MaxInstance = value; - return result; -} - -void TProfileSpan::TMinMaxPair::AddMax(const TInstant instance) { - if (!MaxInstance) { - MaxInstance = instance; - } else { - MaxInstance = Max(*MaxInstance, instance); - } -} - -void TProfileSpan::TMinMaxPair::AddMin(const TInstant instance) { - if (!MinMinInstance) { - MinMinInstance = instance; - } else { - MinMinInstance = Min(*MinMinInstance, instance); - } - if (!MaxMinInstance) { - MaxMinInstance = instance; - } else { - MaxMinInstance = Max(*MaxMinInstance, instance); - } -} - -TString TProfileSpan::TMinMaxPair::ToString() const { - TStringBuilder sb; - sb << "["; - if (MinMinInstance) { - sb << MinMinInstance->MicroSeconds(); - } else { - sb << "UNDEFINED"; - } - sb << "-"; - if (MaxMinInstance) { - sb << MaxMinInstance->MicroSeconds(); - } else { - sb << "UNDEFINED"; - } - sb << ","; - if (MaxInstance) { - sb << MaxInstance->MicroSeconds(); - } else { - sb << "UNDEFINED"; - } - if (MaxInstance && MinMinInstance) { - sb << ","; - sb << *MaxInstance - *MaxMinInstance << "-" << *MaxInstance - *MinMinInstance; - } - sb << "]"; - return sb; -} - -TProfileSpan::TGuard::~TGuard() { - if (!Owner.Enabled) { - return; - } - Y_ABORT_UNLESS(CurrentNodeDuration->IsDouble()); - CurrentNodeDuration->SetValue((Now() - Start).MicroSeconds() * 0.000001 + CurrentNodeDuration->GetDoubleRobust()); - Y_ABORT_UNLESS(Owner.CurrentJsonPath.size()); - Owner.CurrentJsonPath.pop_back(); - if (Owner.CurrentJsonPath.empty()) { - Owner.LastNoGuards = Now(); - } -} - -TProfileSpan::TGuard::TGuard(const TString& event, TProfileSpan& owner, const TString& /*info*/) - : Owner(owner) { - if (!Owner.Enabled) { - return; - } - Owner.FlushNoGuards(); - NJson::TJsonValue* currentNode = Owner.CurrentJsonPath.empty() ? &Owner.ResultTimes : Owner.CurrentJsonPath.back(); - NJson::TJsonValue* currentNodeParent; - if (!currentNode->GetValuePointer(event, ¤tNodeParent)) { - currentNodeParent = ¤tNode->InsertValue(event, NJson::JSON_MAP); - } - Owner.CurrentJsonPath.emplace_back(currentNodeParent); - if (!currentNodeParent->GetValuePointer("--duration", &CurrentNodeDuration)) { - CurrentNodeDuration = ¤tNodeParent->InsertValue("--duration", 0); - CurrentNodeDuration->SetType(NJson::JSON_DOUBLE); - } -} - -} // NWilson diff --git a/library/cpp/actors/wilson/wilson_profile_span.h b/library/cpp/actors/wilson/wilson_profile_span.h deleted file mode 100644 index f12747e4ac..0000000000 --- a/library/cpp/actors/wilson/wilson_profile_span.h +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once -#include "wilson_span.h" -#include <library/cpp/json/writer/json_value.h> - -namespace NWilson { - -class TProfileSpan: public TSpan { -private: - using TBase = TSpan; - class TMinMaxPair { - private: - std::optional<TInstant> MinMinInstance; - std::optional<TInstant> MaxMinInstance; - std::optional<TInstant> MaxInstance; - public: - static TMinMaxPair BuildMin(const TInstant value); - static TMinMaxPair BuildMax(const TInstant value); - void AddMax(const TInstant instance); - void AddMin(const TInstant instance); - TString ToString() const; - }; - mutable NJson::TJsonValue ResultTimes = NJson::JSON_MAP; - std::map<TString, TMinMaxPair> PairInstances; - std::vector<NJson::TJsonValue*> CurrentJsonPath; - mutable TInstant LastNoGuards = Now(); - const TInstant StartTime = Now(); - bool Enabled = true; - - void FlushNoGuards() const; - TProfileSpan() = default; -public: - TProfileSpan(const ui8 verbosity, TTraceId parentId, std::optional<TString> name); - ~TProfileSpan(); - - TProfileSpan BuildChildrenSpan(std::optional<TString> name, const ui8 verbosity = 0) const; - - using TBase::TBase; - TString ProfileToString() const; - - TProfileSpan& SetEnabled(const bool value) { - Enabled = value; - return *this; - } - - class TGuard { - private: - TProfileSpan& Owner; - const TInstant Start = Now(); - NJson::TJsonValue* CurrentNodeDuration; - public: - TGuard(const TString& event, TProfileSpan& owner, const TString& info); - ~TGuard(); - }; - - template <class TEventId, class T = TString> - TGuard StartStackTimeGuard(const TEventId event, const T& info = Default<T>()) { - return TGuard(::ToString(event), *this, ::ToString(info)); - } - - template <class TEventId, class T = TString> - void AddMin(const TEventId event, const T& info = Default<T>()) { - AddMin(::ToString(event), ::ToString(info)); - } - - template <class TEventId, class T = TString> - void AddMax(const TEventId event, const T& info = Default<T>()) { - AddMax(::ToString(event), ::ToString(info)); - } - - void AddMin(const TString& eventId, const TString& info); - void AddMax(const TString& eventId, const TString& info); - -}; - -} // NWilson diff --git a/library/cpp/actors/wilson/wilson_span.cpp b/library/cpp/actors/wilson/wilson_span.cpp deleted file mode 100644 index dcd458be7c..0000000000 --- a/library/cpp/actors/wilson/wilson_span.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "wilson_span.h" -#include "wilson_uploader.h" -#include <library/cpp/actors/core/log.h> -#include <google/protobuf/text_format.h> - -namespace NWilson { - - using namespace NActors; - - void SerializeValue(TAttributeValue value, NCommonProto::AnyValue *pb) { - switch (value.index()) { - case 0: - pb->set_string_value(std::get<0>(std::move(value))); - break; - - case 1: - pb->set_bool_value(std::get<1>(value)); - break; - - case 2: - pb->set_int_value(std::get<2>(value)); - break; - - case 3: - pb->set_double_value(std::get<3>(std::move(value))); - break; - - case 4: { - auto *array = pb->mutable_array_value(); - for (auto&& item : std::get<4>(std::move(value))) { - SerializeValue(std::move(item), array->add_values()); - } - break; - } - - case 5: { - auto *kv = pb->mutable_kvlist_value(); - for (auto&& [key, value] : std::get<5>(std::move(value))) { - SerializeKeyValue(std::move(key), std::move(value), kv->add_values()); - } - break; - } - - case 6: - pb->set_bytes_value(std::get<6>(std::move(value))); - break; - } - } - - void SerializeKeyValue(TString key, TAttributeValue value, NCommonProto::KeyValue *pb) { - pb->set_key(std::move(key)); - SerializeValue(std::move(value), pb->mutable_value()); - } - - void TSpan::Send() { - if (TlsActivationContext) { - TActivationContext::Send(new IEventHandle(MakeWilsonUploaderId(), {}, new TEvWilson(&Data->Span))); - } - Data->Sent = true; - } - -} // NWilson diff --git a/library/cpp/actors/wilson/wilson_span.h b/library/cpp/actors/wilson/wilson_span.h deleted file mode 100644 index 2ebf837cda..0000000000 --- a/library/cpp/actors/wilson/wilson_span.h +++ /dev/null @@ -1,244 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/actor.h> -#include <library/cpp/actors/core/actorsystem.h> -#include <opentelemetry/proto/trace/v1/trace.pb.h> -#include <util/generic/hash.h> -#include <util/datetime/cputimer.h> - -#include "wilson_trace.h" - -namespace NWilson { - - enum class ERelation { - FollowsFrom, - ChildOf, - }; - - namespace NTraceProto = opentelemetry::proto::trace::v1; - namespace NCommonProto = opentelemetry::proto::common::v1; - - struct TArrayValue; - struct TKeyValueList; - struct TBytes; - - using TAttributeValue = std::variant< - TString, - bool, - i64, - double, - TArrayValue, - TKeyValueList, - TBytes - >; - - struct TArrayValue : std::vector<TAttributeValue> {}; - struct TKeyValueList : THashMap<TString, TAttributeValue> {}; - struct TBytes : TString {}; - - void SerializeKeyValue(TString key, TAttributeValue value, NCommonProto::KeyValue *pb); - - enum class EFlags : ui32 { - NONE = 0, - AUTO_END = 1, - }; - - Y_DECLARE_FLAGS(TFlags, EFlags); - Y_DECLARE_OPERATORS_FOR_FLAGS(TFlags); - - class TSpan { - struct TData { - const TInstant StartTime; - const ui64 StartCycles; - const TTraceId TraceId; - NTraceProto::Span Span; - TFlags Flags; - int UncaughtExceptions = std::uncaught_exceptions(); - bool Sent = false; - bool Ignored = false; - - TData(TInstant startTime, ui64 startCycles, TTraceId traceId, TFlags flags) - : StartTime(startTime) - , StartCycles(startCycles) - , TraceId(std::move(traceId)) - , Flags(flags) - {} - - ~TData() { - Y_DEBUG_ABORT_UNLESS(Sent || Ignored); - } - }; - - std::unique_ptr<TData> Data; - - public: - TSpan() = default; - TSpan(const TSpan&) = delete; - TSpan(TSpan&&) = default; - - TSpan(ui8 verbosity, TTraceId parentId, std::optional<TString> name, TFlags flags = EFlags::NONE) - : Data(parentId - ? std::make_unique<TData>(TInstant::Now(), GetCycleCount(), parentId.Span(verbosity), flags) - : nullptr) - { - if (Y_UNLIKELY(*this)) { - if (verbosity <= parentId.GetVerbosity()) { - if (!parentId.IsRoot()) { - Data->Span.set_parent_span_id(parentId.GetSpanIdPtr(), parentId.GetSpanIdSize()); - } - Data->Span.set_start_time_unix_nano(Data->StartTime.NanoSeconds()); - Data->Span.set_kind(opentelemetry::proto::trace::v1::Span::SPAN_KIND_INTERNAL); - - if (name) { - Name(std::move(*name)); - } - - Attribute("node_id", NActors::TActivationContext::ActorSystem()->NodeId); - } else { - Data->Ignored = true; // ignore this span due to verbosity mismatch, still allowing child spans to be created - } - } - } - - ~TSpan() { - if (Y_UNLIKELY(*this)) { - if (std::uncaught_exceptions() != Data->UncaughtExceptions) { - EndError("span terminated due to stack unwinding"); - } else if (Data->Flags & EFlags::AUTO_END) { - End(); - } else { - EndError("unterminated span"); - } - } - } - - TSpan& operator =(const TSpan&) = delete; - - TSpan& operator =(TSpan&& other) { - if (this != &other) { - if (Y_UNLIKELY(*this)) { - EndError("TSpan instance incorrectly overwritten"); - } - Data = std::exchange(other.Data, nullptr); - } - return *this; - } - - explicit operator bool() const { - return Data && !Data->Sent && !Data->Ignored; - } - - TSpan& EnableAutoEnd() { - if (Y_UNLIKELY(*this)) { - Data->Flags |= EFlags::AUTO_END; - } else { - VerifyNotSent(); - } - return *this; - } - - TSpan& Relation(ERelation /*relation*/) { - if (Y_UNLIKELY(*this)) { - // update relation in data somehow - } else { - VerifyNotSent(); - } - return *this; - } - - TSpan& Name(TString name) { - if (Y_UNLIKELY(*this)) { - Data->Span.set_name(std::move(name)); - } else { - VerifyNotSent(); - } - return *this; - } - - TSpan& Attribute(TString name, TAttributeValue value) { - if (Y_UNLIKELY(*this)) { - SerializeKeyValue(std::move(name), std::move(value), Data->Span.add_attributes()); - } else { - VerifyNotSent(); - } - return *this; - } - - TSpan& Event(TString name, TKeyValueList attributes) { - if (Y_UNLIKELY(*this)) { - auto *event = Data->Span.add_events(); - event->set_time_unix_nano(TimeUnixNano()); - event->set_name(std::move(name)); - for (auto&& [key, value] : attributes) { - SerializeKeyValue(std::move(key), std::move(value), event->add_attributes()); - } - } else { - VerifyNotSent(); - } - return *this; - } - - TSpan& Link(const TTraceId& traceId, TKeyValueList attributes) { - if (Y_UNLIKELY(*this)) { - auto *link = Data->Span.add_links(); - link->set_trace_id(traceId.GetTraceIdPtr(), traceId.GetTraceIdSize()); - link->set_span_id(traceId.GetSpanIdPtr(), traceId.GetSpanIdSize()); - for (auto&& [key, value] : attributes) { - SerializeKeyValue(std::move(key), std::move(value), link->add_attributes()); - } - } else { - VerifyNotSent(); - } - return *this; - } - - void EndOk() { - if (Y_UNLIKELY(*this)) { - auto *status = Data->Span.mutable_status(); - status->set_code(NTraceProto::Status::STATUS_CODE_OK); - End(); - } else { - VerifyNotSent(); - } - } - - void EndError(TString error) { - if (Y_UNLIKELY(*this)) { - auto *status = Data->Span.mutable_status(); - status->set_code(NTraceProto::Status::STATUS_CODE_ERROR); - status->set_message(std::move(error)); - End(); - } else { - VerifyNotSent(); - } - } - - void End() { - if (Y_UNLIKELY(*this)) { - Data->Span.set_trace_id(Data->TraceId.GetTraceIdPtr(), Data->TraceId.GetTraceIdSize()); - Data->Span.set_span_id(Data->TraceId.GetSpanIdPtr(), Data->TraceId.GetSpanIdSize()); - Data->Span.set_end_time_unix_nano(TimeUnixNano()); - Send(); - } else { - VerifyNotSent(); - } - } - - TTraceId GetTraceId() const { - return Data ? TTraceId(Data->TraceId) : TTraceId(); - } - - private: - void Send(); - - ui64 TimeUnixNano() const { - const TInstant now = Data->StartTime + CyclesToDuration(GetCycleCount() - Data->StartCycles); - return now.NanoSeconds(); - } - - void VerifyNotSent() { - Y_DEBUG_ABORT_UNLESS(!Data || !Data->Sent, "span has been ended"); - } - }; - -} // NWilson diff --git a/library/cpp/actors/wilson/wilson_trace.cpp b/library/cpp/actors/wilson/wilson_trace.cpp deleted file mode 100644 index 73bed31da3..0000000000 --- a/library/cpp/actors/wilson/wilson_trace.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "wilson_trace.h" - -namespace NWilson { -} diff --git a/library/cpp/actors/wilson/wilson_trace.h b/library/cpp/actors/wilson/wilson_trace.h deleted file mode 100644 index 41a6505134..0000000000 --- a/library/cpp/actors/wilson/wilson_trace.h +++ /dev/null @@ -1,234 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/monotonic.h> -#include <library/cpp/actors/protos/actors.pb.h> - -#include <library/cpp/string_utils/base64/base64.h> - -#include <util/stream/output.h> -#include <util/random/random.h> -#include <util/random/fast.h> - -#include <util/string/printf.h> - -#include <array> - -namespace NWilson { - class TTraceId { - using TTrace = std::array<ui64, 2>; - - TTrace TraceId; // Random id of topmost client request - ui64 SpanId; - union { - struct { - ui32 Verbosity : 4; - ui32 TimeToLive : 12; - }; - ui32 Raw; - }; - - private: - TTraceId(TTrace traceId, ui64 spanId, ui8 verbosity, ui32 timeToLive) - : TraceId(traceId) - { - if (timeToLive == Max<ui32>()) { - timeToLive = 4095; - } - Y_ABORT_UNLESS(verbosity <= 15); - Y_ABORT_UNLESS(timeToLive <= 4095); - SpanId = spanId; - Verbosity = verbosity; - TimeToLive = timeToLive; - } - - static TTrace GenerateTraceId() { - for (;;) { - TTrace res; - ui32 *p = reinterpret_cast<ui32*>(res.data()); - - TReallyFastRng32 rng(RandomNumber<ui64>()); - p[0] = rng(); - p[1] = rng(); - p[2] = rng(); - p[3] = rng(); - - if (res[0] || res[1]) { - return res; - } - } - } - - static ui64 GenerateSpanId() { - for (;;) { - if (const ui64 res = RandomNumber<ui64>(); res) { // SpanId can't be zero - return res; - } - } - } - - public: - using TSerializedTraceId = char[sizeof(TTrace) + sizeof(ui64) + sizeof(ui32)]; - - public: - TTraceId(ui64) // NBS stub - : TTraceId() - {} - - TTraceId() { - TraceId.fill(0); - SpanId = 0; - Raw = 0; - } - - explicit TTraceId(TTrace traceId) - : TraceId(traceId) - { - SpanId = 0; - Raw = 0; - } - - // allow move semantic - TTraceId(TTraceId&& other) - : TraceId(other.TraceId) - , SpanId(other.SpanId) - , Raw(other.Raw) - { - other.TraceId.fill(0); - other.SpanId = 1; // make it explicitly invalid - other.Raw = 0; - } - - // explicit copy - explicit TTraceId(const TTraceId& other) - : TraceId(other.TraceId) - , SpanId(other.SpanId) - , Raw(other.Raw) - { - // validate trace id only when we are making a copy - other.Validate(); - } - - TTraceId(const TSerializedTraceId& in) { - const char *p = in; - memcpy(TraceId.data(), p, sizeof(TraceId)); - p += sizeof(TraceId); - memcpy(&SpanId, p, sizeof(SpanId)); - p += sizeof(SpanId); - memcpy(&Raw, p, sizeof(Raw)); - p += sizeof(Raw); - Y_DEBUG_ABORT_UNLESS(p - in == sizeof(TSerializedTraceId)); - } - - TTraceId(const NActorsProto::TTraceId& pb) - : TTraceId() - { - if (pb.HasData()) { - const auto& data = pb.GetData(); - if (data.size() == sizeof(TSerializedTraceId)) { - *this = *reinterpret_cast<const TSerializedTraceId*>(data.data()); - } - } - } - - void Serialize(TSerializedTraceId *out) const { - char *p = *out; - memcpy(p, TraceId.data(), sizeof(TraceId)); - p += sizeof(TraceId); - memcpy(p, &SpanId, sizeof(SpanId)); - p += sizeof(SpanId); - memcpy(p, &Raw, sizeof(Raw)); - p += sizeof(Raw); - Y_DEBUG_ABORT_UNLESS(p - *out == sizeof(TSerializedTraceId)); - } - - void Serialize(NActorsProto::TTraceId *pb) const { - if (*this) { - TSerializedTraceId data; - Serialize(&data); - pb->SetData(reinterpret_cast<const char*>(&data), sizeof(data)); - } - } - - TTraceId& operator=(TTraceId&& other) { - if (this != &other) { - TraceId = other.TraceId; - SpanId = other.SpanId; - Raw = other.Raw; - other.TraceId.fill(0); - other.SpanId = 1; // make it explicitly invalid - other.Raw = 0; - } - return *this; - } - - // do not allow implicit copy of trace id - TTraceId& operator=(const TTraceId& other) = delete; - - static TTraceId NewTraceId(ui8 verbosity, ui32 timeToLive) { - return TTraceId(GenerateTraceId(), 0, verbosity, timeToLive); - } - - static TTraceId NewTraceIdThrottled(ui8 verbosity, ui32 timeToLive, std::atomic<NActors::TMonotonic>& counter, - NActors::TMonotonic now, TDuration periodBetweenSamples) { - static_assert(std::atomic<NActors::TMonotonic>::is_always_lock_free); - for (;;) { - NActors::TMonotonic ts = counter.load(); - if (now < ts) { - return {}; - } else if (counter.compare_exchange_strong(ts, now + periodBetweenSamples)) { - return NewTraceId(verbosity, timeToLive); - } - } - } - - static TTraceId NewTraceId() { // NBS stub - return TTraceId(); - } - - TTraceId Span(ui8 verbosity) const { - Validate(); - if (!*this || !TimeToLive) { - return TTraceId(); - } else if (verbosity <= Verbosity) { - return TTraceId(TraceId, GenerateSpanId(), Verbosity, TimeToLive - 1); - } else { - return TTraceId(TraceId, SpanId, Verbosity, TimeToLive - 1); - } - } - - TTraceId Span() const { // compatibility stub - return {}; - } - - // Check if request tracing is enabled - explicit operator bool() const { - return TraceId[0] || TraceId[1]; - } - - bool IsRoot() const { - return !SpanId; - } - - friend bool operator==(const TTraceId& x, const TTraceId& y) { - return x.TraceId == y.TraceId && x.SpanId == y.SpanId && x.Raw == y.Raw; - } - - ui8 GetVerbosity() const { - return Verbosity; - } - - const void *GetTraceIdPtr() const { return TraceId.data(); } - static constexpr size_t GetTraceIdSize() { return sizeof(TTrace); } - const void *GetSpanIdPtr() const { return &SpanId; } - static constexpr size_t GetSpanIdSize() { return sizeof(ui64); } - - void Validate() const { - Y_DEBUG_ABORT_UNLESS(*this || !SpanId); - } - - // for compatibility with NBS - TTraceId Clone() const { return NWilson::TTraceId(*this); } - ui64 GetTraceId() const { return 0; } - void OutputSpanId(IOutputStream&) const {} - }; -} diff --git a/library/cpp/actors/wilson/wilson_uploader.cpp b/library/cpp/actors/wilson/wilson_uploader.cpp deleted file mode 100644 index 3599d66809..0000000000 --- a/library/cpp/actors/wilson/wilson_uploader.cpp +++ /dev/null @@ -1,193 +0,0 @@ -#include "wilson_uploader.h" -#include <library/cpp/actors/core/actor_bootstrapped.h> -#include <library/cpp/actors/core/hfunc.h> -#include <library/cpp/actors/core/log.h> -#include <opentelemetry/proto/collector/trace/v1/trace_service.pb.h> -#include <opentelemetry/proto/collector/trace/v1/trace_service.grpc.pb.h> -#include <util/stream/file.h> -#include <util/string/hex.h> -#include <grpc++/grpc++.h> -#include <chrono> - -namespace NWilson { - - using namespace NActors; - - namespace NServiceProto = opentelemetry::proto::collector::trace::v1; - namespace NTraceProto = opentelemetry::proto::trace::v1; - - namespace { - - class TWilsonUploader - : public TActorBootstrapped<TWilsonUploader> - { - TString Host; - ui16 Port; - TString RootCA; - TString ServiceName; - - std::shared_ptr<grpc::Channel> Channel; - std::unique_ptr<NServiceProto::TraceService::Stub> Stub; - grpc::CompletionQueue CQ; - - std::unique_ptr<grpc::ClientContext> Context; - std::unique_ptr<grpc::ClientAsyncResponseReader<NServiceProto::ExportTraceServiceResponse>> Reader; - NServiceProto::ExportTraceServiceResponse Response; - grpc::Status Status; - - struct TSpanQueueItem { - TMonotonic ExpirationTimestamp; - NTraceProto::Span Span; - ui32 Size; - }; - - std::deque<TSpanQueueItem> Spans; - ui64 SpansSize = 0; - TMonotonic NextSendTimestamp; - ui32 MaxSpansAtOnce = 25; - ui32 MaxSpansPerSecond = 10; - TDuration MaxSpanTimeInQueue = TDuration::Seconds(60); - - bool WakeupScheduled = false; - - public: - TWilsonUploader(TString host, ui16 port, TString rootCA, TString serviceName) - : Host(std::move(host)) - , Port(std::move(port)) - , RootCA(std::move(rootCA)) - , ServiceName(std::move(serviceName)) - {} - - ~TWilsonUploader() { - CQ.Shutdown(); - } - - static constexpr char ActorName[] = "WILSON_UPLOADER_ACTOR"; - - void Bootstrap() { - Become(&TThis::StateFunc); - - Channel = grpc::CreateChannel(TStringBuilder() << Host << ":" << Port, RootCA ? grpc::SslCredentials({ - .pem_root_certs = TFileInput(RootCA).ReadAll(), - }) : grpc::InsecureChannelCredentials()); - Stub = NServiceProto::TraceService::NewStub(Channel); - - LOG_INFO_S(*TlsActivationContext, 430 /* NKikimrServices::WILSON */, "TWilsonUploader::Bootstrap"); - } - - void Handle(TEvWilson::TPtr ev) { - if (SpansSize >= 100'000'000) { - LOG_ERROR_S(*TlsActivationContext, 430 /* NKikimrServices::WILSON */, "dropped span due to overflow"); - } else { - const TMonotonic expirationTimestamp = TActivationContext::Monotonic() + MaxSpanTimeInQueue; - auto& span = ev->Get()->Span; - const ui32 size = span.ByteSizeLong(); - Spans.push_back(TSpanQueueItem{expirationTimestamp, std::move(span), size}); - SpansSize += size; - CheckIfDone(); - TryToSend(); - } - } - - void TryToSend() { - const TMonotonic now = TActivationContext::Monotonic(); - - ui32 numSpansDropped = 0; - while (!Spans.empty()) { - const TSpanQueueItem& item = Spans.front(); - if (item.ExpirationTimestamp <= now) { - SpansSize -= item.Size; - Spans.pop_front(); - ++numSpansDropped; - } else { - break; - } - } - - if (numSpansDropped) { - LOG_ERROR_S(*TlsActivationContext, 430 /* NKikimrServices::WILSON */, - "dropped " << numSpansDropped << " span(s) due to expiration"); - } - - if (Context || Spans.empty()) { - return; - } else if (now < NextSendTimestamp) { - ScheduleWakeup(NextSendTimestamp); - return; - } - - NServiceProto::ExportTraceServiceRequest request; - auto *rspan = request.add_resource_spans(); - auto *serviceNameAttr = rspan->mutable_resource()->add_attributes(); - serviceNameAttr->set_key("service.name"); - serviceNameAttr->mutable_value()->set_string_value(ServiceName); - auto *sspan = rspan->add_scope_spans(); - - NextSendTimestamp = now; - for (ui32 i = 0; i < MaxSpansAtOnce && !Spans.empty(); ++i, Spans.pop_front()) { - auto& item = Spans.front(); - auto& s = item.Span; - - LOG_DEBUG_S(*TlsActivationContext, 430 /* NKikimrServices::WILSON */, "exporting span" - << " TraceId# " << HexEncode(s.trace_id()) - << " SpanId# " << HexEncode(s.span_id()) - << " ParentSpanId# " << HexEncode(s.parent_span_id()) - << " Name# " << s.name()); - - SpansSize -= item.Size; - s.Swap(sspan->add_spans()); - NextSendTimestamp += TDuration::MicroSeconds(1'000'000 / MaxSpansPerSecond); - } - - Context = std::make_unique<grpc::ClientContext>(); - Reader = Stub->AsyncExport(Context.get(), std::move(request), &CQ); - Reader->Finish(&Response, &Status, nullptr); - } - - void CheckIfDone() { - if (Context) { - void *tag; - bool ok; - if (CQ.AsyncNext(&tag, &ok, std::chrono::system_clock::now()) == grpc::CompletionQueue::GOT_EVENT) { - if (!Status.ok()) { - LOG_ERROR_S(*TlsActivationContext, 430 /* NKikimrServices::WILSON */, - "failed to commit traces: " << Status.error_message()); - } - - Reader.reset(); - Context.reset(); - } else { - ScheduleWakeup(TDuration::MilliSeconds(100)); - } - } - } - - template<typename T> - void ScheduleWakeup(T&& deadline) { - if (!WakeupScheduled) { - TActivationContext::Schedule(deadline, new IEventHandle(TEvents::TSystem::Wakeup, 0, SelfId(), {}, - nullptr, 0)); - WakeupScheduled = true; - } - } - - void HandleWakeup() { - Y_ABORT_UNLESS(WakeupScheduled); - WakeupScheduled = false; - CheckIfDone(); - TryToSend(); - } - - STRICT_STFUNC(StateFunc, - hFunc(TEvWilson, Handle); - cFunc(TEvents::TSystem::Wakeup, HandleWakeup); - ); - }; - - } // anonymous - - IActor *CreateWilsonUploader(TString host, ui16 port, TString rootCA, TString serviceName) { - return new TWilsonUploader(std::move(host), port, std::move(rootCA), std::move(serviceName)); - } - -} // NWilson diff --git a/library/cpp/actors/wilson/wilson_uploader.h b/library/cpp/actors/wilson/wilson_uploader.h deleted file mode 100644 index 86c23ccefe..0000000000 --- a/library/cpp/actors/wilson/wilson_uploader.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include <library/cpp/actors/core/actor.h> -#include <library/cpp/actors/core/event_local.h> -#include <library/cpp/actors/core/events.h> -#include <opentelemetry/proto/trace/v1/trace.pb.h> - -namespace NWilson { - - struct TEvWilson : NActors::TEventLocal<TEvWilson, NActors::TEvents::TSystem::Wilson> { - opentelemetry::proto::trace::v1::Span Span; - - TEvWilson(opentelemetry::proto::trace::v1::Span *span) { - Span.Swap(span); - } - }; - - inline NActors::TActorId MakeWilsonUploaderId() { - return NActors::TActorId(0, TStringBuf("WilsonUpload", 12)); - } - - NActors::IActor *CreateWilsonUploader(TString host, ui16 port, TString rootCA, TString serviceName); - -} // NWilson diff --git a/library/cpp/actors/wilson/ya.make b/library/cpp/actors/wilson/ya.make deleted file mode 100644 index 0dc8ba79ad..0000000000 --- a/library/cpp/actors/wilson/ya.make +++ /dev/null @@ -1,21 +0,0 @@ -LIBRARY() - -SRCS( - wilson_event.cpp - wilson_span.cpp - wilson_profile_span.cpp - wilson_trace.cpp - wilson_uploader.cpp -) - -PEERDIR( - library/cpp/actors/core - library/cpp/actors/protos - library/cpp/actors/wilson/protos -) - -END() - -RECURSE( - protos -) diff --git a/library/cpp/actors/ya.make b/library/cpp/actors/ya.make deleted file mode 100644 index 00d7801798..0000000000 --- a/library/cpp/actors/ya.make +++ /dev/null @@ -1,16 +0,0 @@ -RECURSE( - log_backend - core - cppcoro - dnsresolver - examples - interconnect - memory_log - helpers - prof - protos - util - wilson - testlib - http -) diff --git a/library/cpp/deprecated/autoarray/README.md b/library/cpp/deprecated/autoarray/README.md deleted file mode 100644 index 1d83147cee..0000000000 --- a/library/cpp/deprecated/autoarray/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Pre-C++11 vector-like container. - -Just use std::vector. If you need to fill your vector with custom-constructed data, use reserve+emplace_back (but make sure that your elements are movable). diff --git a/library/cpp/deprecated/autoarray/autoarray.cpp b/library/cpp/deprecated/autoarray/autoarray.cpp deleted file mode 100644 index 15167f27f6..0000000000 --- a/library/cpp/deprecated/autoarray/autoarray.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "autoarray.h" diff --git a/library/cpp/deprecated/autoarray/autoarray.h b/library/cpp/deprecated/autoarray/autoarray.h deleted file mode 100644 index 2aa12c5916..0000000000 --- a/library/cpp/deprecated/autoarray/autoarray.h +++ /dev/null @@ -1,264 +0,0 @@ -#pragma once - -#include <util/system/compat.h> -#include <util/system/yassert.h> -#include <util/system/defaults.h> -#include <util/system/sys_alloc.h> - -#include <util/generic/typetraits.h> -#include <utility> - -#include <new> -#include <util/generic/noncopyable.h> - -struct autoarray_getindex { - autoarray_getindex() = default; -}; - -struct aarr_b0 { - aarr_b0() = default; -}; - -struct aarr_nofill { - aarr_nofill() = default; -}; - -template <typename T> -struct ynd_type_traits { - enum { - empty_destructor = TTypeTraits<T>::IsPod, - }; -}; - -template <class T> -class autoarray : TNonCopyable { -protected: - T* arr; - size_t _size; - -private: - void AllocBuf(size_t siz) { - arr = nullptr; - _size = 0; - if (siz) { - arr = (T*)y_allocate(sizeof(T) * siz); - _size = siz; - } - } - -public: - using value_type = T; - using iterator = T*; - using const_iterator = const T*; - - autoarray() - : arr(nullptr) - , _size(0) - { - } - autoarray(size_t siz) { - AllocBuf(siz); - T* curr = arr; - try { - for (T* end = arr + _size; curr != end; ++curr) - new (curr) T(); - } catch (...) { - for (--curr; curr >= arr; --curr) - curr->~T(); - y_deallocate(arr); - throw; - } - } - template <class A> - explicit autoarray(size_t siz, A& fill) { - AllocBuf(siz); - T* curr = arr; - try { - for (T* end = arr + _size; curr != end; ++curr) - new (curr) T(fill); - } catch (...) { - for (--curr; curr >= arr; --curr) - curr->~T(); - y_deallocate(arr); - throw; - } - } - explicit autoarray(size_t siz, autoarray_getindex) { - AllocBuf(siz); - size_t nCurrent = 0; - try { - for (nCurrent = 0; nCurrent < _size; ++nCurrent) - new (&arr[nCurrent]) T(nCurrent); - } catch (...) { - for (size_t n = 0; n < nCurrent; ++n) - arr[n].~T(); - y_deallocate(arr); - throw; - } - } - explicit autoarray(size_t siz, aarr_b0) { - AllocBuf(siz); - memset(arr, 0, _size * sizeof(T)); - } - explicit autoarray(size_t siz, aarr_nofill) { - AllocBuf(siz); - } - template <class A> - explicit autoarray(const A* fill, size_t siz) { - AllocBuf(siz); - size_t nCurrent = 0; - try { - for (nCurrent = 0; nCurrent < _size; ++nCurrent) - new (&arr[nCurrent]) T(fill[nCurrent]); - } catch (...) { - for (size_t n = 0; n < nCurrent; ++n) - arr[n].~T(); - y_deallocate(arr); - throw; - } - } - template <class A, class B> - explicit autoarray(const A* fill, const B* cfill, size_t siz) { - AllocBuf(siz); - size_t nCurrent = 0; - try { - for (nCurrent = 0; nCurrent < _size; ++nCurrent) - new (&arr[nCurrent]) T(fill[nCurrent], cfill); - } catch (...) { - for (size_t n = 0; n < nCurrent; ++n) - arr[n].~T(); - y_deallocate(arr); - throw; - } - } - template <class A> - explicit autoarray(const A* fill, size_t initsiz, size_t fullsiz) { - AllocBuf(fullsiz); - size_t nCurrent = 0; - try { - for (nCurrent = 0; nCurrent < ((initsiz < _size) ? initsiz : _size); ++nCurrent) - new (&arr[nCurrent]) T(fill[nCurrent]); - for (; nCurrent < _size; ++nCurrent) - new (&arr[nCurrent]) T(); - } catch (...) { - for (size_t n = 0; n < nCurrent; ++n) - arr[n].~T(); - y_deallocate(arr); - throw; - } - } - template <class A> - explicit autoarray(const A* fill, size_t initsiz, size_t fullsiz, const T& dummy) { - AllocBuf(fullsiz); - size_t nCurrent = 0; - try { - for (nCurrent = 0; nCurrent < ((initsiz < _size) ? initsiz : _size); ++nCurrent) - new (&arr[nCurrent]) T(fill[nCurrent]); - for (; nCurrent < _size; ++nCurrent) - new (&arr[nCurrent]) T(dummy); - } catch (...) { - for (size_t n = 0; n < nCurrent; ++n) - arr[n].~T(); - y_deallocate(arr); - throw; - } - } - - template <class... R> - explicit autoarray(size_t siz, R&&... fill) { - AllocBuf(siz); - T* curr = arr; - try { - for (T* end = arr + _size; curr != end; ++curr) - new (curr) T(std::forward<R>(fill)...); - } catch (...) { - for (--curr; curr >= arr; --curr) - curr->~T(); - y_deallocate(arr); - throw; - } - } - ~autoarray() { - if (_size) { - if (!ynd_type_traits<T>::empty_destructor) - for (T *curr = arr, *end = arr + _size; curr != end; ++curr) - curr->~T(); - y_deallocate(arr); - } - } - T& operator[](size_t pos) { - Y_ASSERT(pos < _size); - return arr[pos]; - } - const T& operator[](size_t pos) const { - Y_ASSERT(pos < _size); - return arr[pos]; - } - size_t size() const { - return _size; - } - void swap(autoarray& with) { - T* tmp_arr = arr; - size_t tmp_size = _size; - arr = with.arr; - _size = with._size; - with.arr = tmp_arr; - with._size = tmp_size; - } - void resize(size_t siz) { - autoarray<T> tmp(arr, _size, siz); - swap(tmp); - } - void resize(size_t siz, const T& dummy) { - autoarray<T> tmp(arr, _size, siz, dummy); - swap(tmp); - } - T* rawpointer() { - return arr; - } - const T* operator~() const { - return arr; - } - T* begin() { - return arr; - } - T* end() { - return arr + _size; - } - T& back() { - Y_ASSERT(_size); - return arr[_size - 1]; - } - bool empty() const { - return !_size; - } - bool operator!() const { - return !_size; - } - size_t operator+() const { - return _size; - } - const T* begin() const { - return arr; - } - const T* end() const { - return arr + _size; - } - const T& back() const { - Y_ASSERT(_size); - return arr[_size - 1]; - } - //operator T*() { return arr; } -}; - -template <class T> -inline bool operator==(const autoarray<T>& a, const autoarray<T>& b) { - size_t count = a.size(); - if (count != b.size()) - return false; - for (size_t i = 0; i < count; ++i) { - if (a[i] != b[i]) - return false; - } - return true; -} diff --git a/library/cpp/deprecated/autoarray/ya.make b/library/cpp/deprecated/autoarray/ya.make deleted file mode 100644 index 4b055f8c29..0000000000 --- a/library/cpp/deprecated/autoarray/ya.make +++ /dev/null @@ -1,7 +0,0 @@ -LIBRARY() - -SRCS( - autoarray.cpp -) - -END() diff --git a/library/cpp/deprecated/fgood/README.md b/library/cpp/deprecated/fgood/README.md deleted file mode 100644 index 4f66289657..0000000000 --- a/library/cpp/deprecated/fgood/README.md +++ /dev/null @@ -1,15 +0,0 @@ -Some ancient wrappers on top of FILE*, and some string manupulation functions. - -Alternatives are as follows. - -For TFILEPtr. Use TIFStream or TOFStream if you need IO. For some rare use cases a TFileMap might also do. - -For fput/fget/getline. Use streams API. - -For struct ffb and struct prnstr. Just don't use them. Even if you can figure out what they do. - -For sf family of functions and TLineSplitter. Just use Split* from util/string/split.h - -For TSFReader. Use TMapTsvFile. - -For read_or_die family of functions. Use streams API. diff --git a/library/cpp/deprecated/fgood/ffb.cpp b/library/cpp/deprecated/fgood/ffb.cpp deleted file mode 100644 index aa9da861a6..0000000000 --- a/library/cpp/deprecated/fgood/ffb.cpp +++ /dev/null @@ -1,407 +0,0 @@ -#include "ffb.h" - -#include <util/string/util.h> // str_spn -#include <util/system/compat.h> -#include <util/generic/yexception.h> - -#include <cstdio> -#include <algorithm> - -#include <ctype.h> - -#ifdef _win_ -#include <io.h> -#else -#include <unistd.h> -#endif - -ffb::ffb(FILE* file) - : TFILEPtr(file) -{ - if (file && !isatty(fileno(file)) && BUFSIZ < 512 * 1024) - setvbuf(file, nullptr, _IOFBF, 512 * 1024); -} - -void ffb::operator=(FILE* f) { - TFILEPtr::operator=(f); - if (f && !isatty(fileno(f)) && BUFSIZ < 512 * 1024) - setvbuf(f, nullptr, _IOFBF, 512 * 1024); -} - -void ffb::open(const char* name, const char* mode) { - TFILEPtr::open(name, mode); - if (!isatty(fileno(*this)) && BUFSIZ < 512 * 1024) - setvbuf(*this, nullptr, _IOFBF, 512 * 1024); -} - -int sf(char** fb, char* buf) { //don't want to call sf(fb, buf, 32) - if (!(*buf && *buf != 10)) { - *fb = nullptr; - return 0; - } - int n = 1; - fb[0] = buf; - while (*buf && *buf != 10 && n < 31) { - if (*buf == '\t') { - *buf++ = 0; - fb[n++] = buf; - continue; - } - buf++; - } - if (*buf == 10 && buf[-1] == 13) - buf[-1] = 0; - *buf = 0; - fb[n] = nullptr; - return n; -} - -int sf(char** fb, char* buf, size_t fb_sz) { - if (!(*buf && *buf != 10)) { - *fb = nullptr; - return 0; - } - fb_sz--; - int n = 1; - fb[0] = buf; - while (*buf && *buf != 10 && n < (int)fb_sz) { - if (*buf == '\t') { - *buf++ = 0; - fb[n++] = buf; - continue; - } - buf++; - } - if (*buf == 10 && buf[-1] == 13) - buf[-1] = 0; - *buf = 0; - fb[n] = nullptr; - return n; -} - -inline int sf_blank(char** fb, char* buf, size_t fb_sz) { - while (isspace((ui8)*buf)) - buf++; - if (!*buf) { - *fb = nullptr; - return 0; - } - fb_sz--; - int n = 1; - fb[0] = buf; - while (*buf && *buf != 10 && n < (int)fb_sz) { - if (isspace((ui8)*buf)) { - *buf++ = 0; - while (isspace((ui8)*buf)) - buf++; - if (*buf) - fb[n++] = buf; - continue; - } - buf++; - } - if (*buf == 10 && buf[-1] == 13) - buf[-1] = 0; - *buf = 0; - fb[n] = nullptr; - return n; -} - -int sf(char fs, char** fb, char* buf, size_t fb_sz) { - if (fs == ' ') - return sf_blank(fb, buf, fb_sz); - while (*buf == fs) - buf++; - if (!(*buf && *buf != 10)) { - *fb = nullptr; - return 0; - } - fb_sz--; - int n = 1; - fb[0] = buf; - while (*buf && *buf != 10 && n < (int)fb_sz) { - if (*buf == fs) { - *buf++ = 0; - while (*buf == fs) - buf++; - fb[n++] = buf; - continue; - } - buf++; - } - if (*buf == 10 && buf[-1] == 13) - buf[-1] = 0; - *buf = 0; - fb[n] = nullptr; - return n; -} - -int sf(const char* fs, char** fb, char* buf, size_t fb_sz) { - if (!(*buf && *buf != 10)) { - *fb = nullptr; - return 0; - } - int fs_len = strlen(fs); - fb_sz--; - int n = 1; - fb[0] = buf; - while (*buf && *buf != 10 && n < (int)fb_sz) { - if (*buf == *fs && !strncmp(buf + 1, fs + 1, fs_len - 1)) { - *buf = 0; - buf += fs_len; - fb[n++] = buf; - continue; - } - buf++; - } - if (*buf == 10 && buf[-1] == 13) - buf[-1] = 0; - *buf = 0; - fb[n] = nullptr; - return n; -} - -inline bool is_end(const char* p) { - return !p || !p[0]; -} - -int sf(const char* seps, char* buf, char** fb, size_t fb_sz) { - if (fb_sz < 1 || is_end(buf)) { - *fb = nullptr; - return 0; - } - str_spn sseps(seps); - fb[0] = nullptr; - int n = 0; - // skip leading delimeters - buf = sseps.cbrk(buf); - if (is_end(buf)) - return 0; - // store fields - while (n < (int)fb_sz) { - fb[n++] = buf; - // find delimeters - buf = sseps.brk(buf + 1); - if (is_end(buf)) - break; - *buf = 0; - // skip delimiters - buf = sseps.cbrk(buf + 1); - if (is_end(buf)) - break; - } - fb[n] = nullptr; - return n; -} - -void TLineSplitter::operator()(char* p, TVector<char*>& fields) const { - if (!p || !*p) - return; - char* q = p; - while (1) { - p = Sep.brk(p); - if (q && (p - q || !SkipEmpty())) - fields.push_back(q); - q = nullptr; - if (!*p) - break; - if (SepStrLen == 1 || (SepStrLen > 1 && !strncmp(p + 1, SepStr + 1, SepStrLen - 1))) { - *p = 0; - p += SepStrLen; - q = p; - } else - p++; - } -} - -void TLineSplitter::operator()(const char* p, TVector<std::pair<const char*, size_t>>& fields) const { - if (!p || !*p) - return; - const char* q = p; - while (1) { - p = Sep.brk(p); - if (q && (p - q || !SkipEmpty())) - fields.push_back(std::make_pair(q, p - q)); - q = nullptr; - if (!*p) - break; - if (SepStrLen == 1 || (SepStrLen > 1 && !strncmp(p + 1, SepStr + 1, SepStrLen - 1))) { - p += SepStrLen; - q = p; - } else - p++; - } -} - -TSFReader::TSFReader(const char* fname, char sep, i32 nfrq) // if sep == ' ' isspace will be imitated (for compat) - : Split(str_spn(sep == ' ' ? "\t\n\v\f\r " : TString(1, sep).data()), sep == ' ') - , OpenPipe(false) -{ - Open(fname, nfrq); -} - -TSFReader::TSFReader(const char* fname, const char* sep, i32 nfrq) - : Split(sep, false) - , OpenPipe(false) -{ - Open(fname, nfrq); -} - -TSFReader::TSFReader(const char* fname, const TLineSplitter& spl, i32 nfrq) - : Split(spl) - , OpenPipe(false) -{ - Open(fname, nfrq); -} - -void TSFReader::Open(const char* fname, i32 nfrq, size_t vbuf_size) { - FieldsRequired = nfrq; - NF = NR = 0; - - if (IsOpen()) - File.close(); - - if (!fname) - return; - - if (!strcmp(fname, "/dev/stdin")) { - File.assign(stdin, "/dev/stdin"); - } else { - if (OpenPipe) - File.popen(fname, "r"); - else - File.open(fname, "r"); - } - OpenPipe = false; - if (!isatty(fileno(File))) - setvbuf(File, nullptr, _IOFBF, vbuf_size); -} - -void TSFReader::Popen(const char* pname, i32 nfrq, size_t vbuf_size) { - OpenPipe = true; - Open(pname, nfrq, vbuf_size); -} - -bool TSFReader::NextLine(segmented_string_pool* pool) { - size_t line_len = 0; - -#ifdef __FreeBSD__ - char* ptr = fgetln(File, &line_len); - if (!ptr) - return false; - if (!line_len || ptr[line_len - 1] != '\n') { // last line w/o newline - Buf.AssignNoAlias(ptr, line_len); - ptr = Buf.begin(); - } else { - // can safely replace newline with \0 - ptr[line_len - 1] = 0; - --line_len; - } -#else - if (!getline(File, Buf)) - return false; - char* ptr = Buf.begin(); - line_len = Buf.size(); -#endif - if (line_len && ptr[line_len - 1] == '\r') - ptr[line_len - 1] = 0; - - if (pool) { - char* nptr = pool->append(ptr); - Y_ASSERT(!strcmp(ptr, nptr)); - ptr = nptr; - } - - ++NR; - Fields.clear(); - Split(ptr, Fields); - NF = Fields.size(); - - if (FieldsRequired != -1 && FieldsRequired != (int)NF) - ythrow yexception() << File.name() << " line " << NR << ": " << NF << " fields, expected " << FieldsRequired; - - return true; -} - -int prnstr::f(const char* c, ...) { - va_list params; - int n = asize - pos, k; - va_start(params, c); - while ((k = vsnprintf(buf + pos, n, c, params)) >= n) { - n += asize, asize *= 2; - while (k + pos >= n) - n += asize, asize *= 2; - char* t = new char[asize]; - memcpy(t, buf, pos); - delete[] buf; - buf = t; - va_end(params); - va_start(params, c); - } - pos += k; - va_end(params); - return k; -} -int prnstr::s(const char* c, size_t k) { - if (!c) - return 0; - size_t n = asize - pos; - if (k >= n) { - n += asize, asize *= 2; - while (k + pos >= n) - n += asize, asize *= 2; - char* t = new char[asize]; - memcpy(t, buf, pos); - delete[] buf; - buf = t; - } - memcpy(buf + pos, c, k); - pos += k; - buf[pos] = 0; - return k; -} -void prnstr::clear() { - pos = 0; - if (asize > 32768) { - asize = 32768; - delete[] buf; - buf = new char[asize]; - } -} - -void prnstr::swap(prnstr& w) { - std::swap(buf, w.buf); - std::swap(pos, w.pos); - std::swap(asize, w.asize); -} - -FILE* read_or_die(const char* fname) { - FILE* f = fopen(fname, "rb"); - if (!f) - err(1, "%s", fname); - return f; -} -FILE* write_or_die(const char* fname) { - FILE* f = fopen(fname, "wb"); - if (!f) - err(1, "%s", fname); - return f; -} -FILE* fopen_or_die(const char* fname, const char* mode) { - FILE* f = fopen(fname, mode); - if (!f) - err(1, "%s (mode '%s')", fname, mode); - return f; -} - -FILE* fopen_chk(const char* fname, const char* mode) { - FILE* f = fopen(fname, mode); - if (!f) - ythrow yexception() << fname << " (mode '" << mode << "'): " << LastSystemErrorText(); - return f; -} - -void fclose_chk(FILE* f, const char* fname) { - if (fclose(f)) - ythrow yexception() << "file " << fname << ": " << LastSystemErrorText(); -} diff --git a/library/cpp/deprecated/fgood/ffb.h b/library/cpp/deprecated/fgood/ffb.h deleted file mode 100644 index ca229eb65a..0000000000 --- a/library/cpp/deprecated/fgood/ffb.h +++ /dev/null @@ -1,264 +0,0 @@ -#pragma once - -#include "fgood.h" - -#include <util/string/util.h> // str_spn -#include <util/string/split.h> // str_spn -#include <util/memory/segmented_string_pool.h> -#include <util/generic/string.h> -#include <util/generic/vector.h> -#include <util/generic/noncopyable.h> - -#include <utility> - -#include <cstdarg> -#include <cstring> - -struct ffb: public TFILEPtr { - ffb() { - } - ffb(FILE* file); - ffb(const char* name, const char* mode) { - open(name, mode); - } - void operator=(FILE* f); // take ownership - void open(const char* name, const char* mode); - int f(const char* c, ...) { - va_list args; - va_start(args, c); - return vfprintf(*this, c, args); - } - void s(const char* c) { - fsput(c, strlen(c)); - } - void b(const void* cc, int n) { - fsput((const char*)cc, n); - } - void B(const void* cc, int N) { - fsput((const char*)cc, N); - } - void c(char c) { - fputc(c); - } - void cbe(wchar16 c) { // big endian utf-16 - fputc(char(c >> 8)); //Hi8 - fputc(char(c & 255)); //Lo8 - } - void sbe(const wchar16* c) { - for (; *c; c++) - cbe(*c); - } - void fclose() { - close(); - } -}; - -// split fields of tab-delimited line of text -// here and below fb actual size must be fb_sz + 1 to allow fb[fb_sz] be zero -int sf(char** fb, char* buf, size_t fb_sz); -int sf(char** fb, char* buf /* fb_sz == 32 */); - -// split fields of char-delimited line of text -// Achtung: delim = ' ' imitates awk: initial separators are skipped, -// repeated seps treated as one, all chars less than ' ' treated as separators. -int sf(char fs, char** fb, char* buf, size_t fb_sz = 32); - -// split fields of string-delimited line of text (fs is NOT a regexp) -// (usually fs is "@@") -int sf(const char* fs, char** fb, char* buf, size_t fb_sz = 32); - -// split fields of char-delimited line of text, set of char-separators is given -// Achtung: repeated seps treated as one, initial seps are skipped -// newlines are NOT ignored. -int sf(const char* seps, char* buf, char** fb, size_t fb_sz = 32); - -inline char* chomp(char* buf) { - char* c = buf + strlen(buf); - if (c > buf && c[-1] == '\n') { - *--c = 0; -#ifdef _win32_ - if (c > buf && c[-1] == '\r') - *--c = 0; -#endif - } - return buf; -} - -inline char* chomp_cr(char* buf) { - char* c = buf + strlen(buf); - if (c > buf && c[-1] == '\n') - *--c = 0; - if (c > buf && c[-1] == '\r') - *--c = 0; - return buf; -} - -class TLineSplitter { -protected: - enum { // Default: Split string by SepStr - SplitByAnySep = 1, // Split string by Sep - NoEmptyFields = 2 // Skip all empty fields between separators - }; - -private: - ui32 Flags; - const str_spn Sep; // collection of separators - const char* SepStr; // pointer exact string to separate by - size_t SepStrLen; // length of separator string - -public: - TLineSplitter(const char* sep, bool noEmpty) - : Flags(noEmpty ? NoEmptyFields : 0) - , Sep(TString(sep, 1).data()) - , SepStr(sep) - , SepStrLen(strlen(sep)) - { - } - TLineSplitter(const str_spn& sep, bool noEmpty = false) - : Flags(SplitByAnySep | (noEmpty ? NoEmptyFields : 0)) - , Sep(sep) - , SepStr(nullptr) - , SepStrLen(1) - { - } - bool AnySep() const { - return Flags & SplitByAnySep; - } - bool SkipEmpty() const { - return Flags & NoEmptyFields; - } - /// Separates string onto tokens - /// Expecting a zero-terminated string - /// By default returns empty fields between sequential separators - void operator()(char* p, TVector<char*>& fields) const; - /// Same, but for const string - fills vector of pairs (pointer, length) - void operator()(const char* p, TVector<std::pair<const char*, size_t>>& fields) const; -}; - -/** - * Use library/cpp/map_text_file/map_tsv_file.h instead. - */ -class TSFReader { - TString Buf; // buffer used for non-'\n'-terminated string and for non-freebsd work - TLineSplitter Split; - TVector<char*> Fields; - size_t NF; // Fields.size() - size_t NR; - - TFILEPtr File; - - bool OpenPipe; // internal flag that turns open() to popen() - - i32 FieldsRequired; // if != -1, != nf, terminate program - -public: - // char separator - // Achtung: delim = ' ' imitates awk: initial separators are skipped, - // all chars less than ' ' treated as separators. - TSFReader(const char* fname = nullptr, char sep = '\t', i32 nf_reqired = -1); - // exact string separator - TSFReader(const char* fname, const char* sep, i32 nf_reqired = -1); - // fully customizable - TSFReader(const char* fname, const TLineSplitter& spl, i32 nf_reqired = -1); - - void Open(const char* fname, i32 nf_reqired = -1, size_t vbufsize = 1u << 21); // use "/dev/stdin" for stdin - void Popen(const char* pname, i32 nf_reqired = -1, size_t vbufsize = 1u << 21); - - bool NextLine(segmented_string_pool* pool = nullptr); - - bool IsOpen() const { - return (FILE*)File != nullptr; - } - bool IsEof() const { - return feof(File); - } - void Close() { - File.close(); - } - void Rewind() { - File.seek(0, SEEK_SET); - } - void Seek(i64 offset, int mode = SEEK_SET) { - File.seek(offset, mode); - } - i64 Tell() const { - return ftell(File); - } - char*& operator[](size_t ind) { - //if (ind >= NF) - // throw yexception("Can't return reference to unexisting field %" PRISZT, ind); - return Fields[ind]; - } - const char* operator[](size_t ind) const { - if (ind >= NF) - return nullptr; - return Fields[ind]; - } - operator int() const { // note: empty input line makes 0 fields - return (int)NF; - } - const char* Name() const { - return File.name().data(); - } - size_t Line() const { - return NR; - } - const TVector<char*>& GetFields() const { - return Fields; - } -}; - -struct prnstr { - char* buf; - int pos; - int asize; - prnstr() - : pos(0) - { - asize = 32; - buf = new char[asize]; - } - explicit prnstr(int asz) - : pos(0) - { - asize = asz; - buf = new char[asize]; - } - int f(const char* c, ...); - int s(const char* c1, const char* c2); - int s(const char* c1, const char* c2, const char* c3); - int s(const char* c, size_t len); - //int s(const char *c); - int s(const char* c) { - return c ? s(c, strlen(c)) : 0; - } - int s(const TString& c); - int s_htmesc(const char* c, bool enc_utf = false); - int s_htmesc_w(const char* c); - int c(char c); - int cu(wchar32 c); //for utf-8 - void restart() { - *buf = 0; - pos = 0; - } - const char* operator~() const { - return buf; - } - int operator+() const { - return pos; - } - ~prnstr() { - delete[] buf; - } - void clear(); - void swap(prnstr& w); -}; - -// functions that terminate program upon failure -FILE* read_or_die(const char* fname); -FILE* write_or_die(const char* fname); -FILE* fopen_or_die(const char* fname, const char* mode); - -// functions that throw upon failure -FILE* fopen_chk(const char* fname, const char* mode); -void fclose_chk(FILE* f, const char* fname_dbg); diff --git a/library/cpp/deprecated/fgood/fgood.cpp b/library/cpp/deprecated/fgood/fgood.cpp deleted file mode 100644 index 5d4725bfae..0000000000 --- a/library/cpp/deprecated/fgood/fgood.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "fgood.h" - -#include <util/generic/cast.h> -#include <util/string/cast.h> -#include <util/system/fstat.h> - -#ifdef _win32_ -#include <io.h> -#endif - -i64 TFILEPtr::length() const { -#ifdef _win32_ - FHANDLE fd = (FHANDLE)_get_osfhandle(fileno(m_file)); -#else - FHANDLE fd = fileno(m_file); -#endif - i64 rv = GetFileLength(fd); - if (rv < 0) - ythrow yexception() << "TFILEPtr::length() " << Name.data() << ": " << LastSystemErrorText(); - return rv; -} - -FILE* OpenFILEOrFail(const TString& name, const char* mode) { - FILE* res = ::fopen(name.data(), mode); - if (!res) { - ythrow yexception() << "can't open \'" << name << "\' with mode \'" << mode << "\': " << LastSystemErrorText(); - } - return res; -} - -void TFILECloser::Destroy(FILE* file) { - ::fclose(file); -} - -#ifdef _freebsd_ // fgetln -#define getline getline_alt_4test -#endif // _freebsd_ - -bool getline(TFILEPtr& f, TString& s) { - char buf[4096]; - char* buf_ptr; - if (s.capacity() > sizeof(buf)) { - s.resize(s.capacity()); - if ((buf_ptr = fgets(s.begin(), IntegerCast<int>(s.capacity()), f)) == nullptr) - return false; - } else { - if ((buf_ptr = fgets(buf, sizeof(buf), f)) == nullptr) - return false; - } - size_t buf_len = strlen(buf_ptr); - bool line_complete = buf_len && buf_ptr[buf_len - 1] == '\n'; - if (line_complete) - buf_len--; - if (buf_ptr == s.begin()) - s.resize(buf_len); - else - s.AssignNoAlias(buf, buf_len); - if (line_complete) - return true; - while (fgets(buf, sizeof(buf), f)) { - size_t buf_len2 = strlen(buf); - if (buf_len2 && buf[buf_len2 - 1] == '\n') { - buf[buf_len2 - 1] = 0; - s.append(buf, buf_len2 - 1); - return true; - } - s.append(buf, buf_len2); - } - return true; -} diff --git a/library/cpp/deprecated/fgood/fgood.h b/library/cpp/deprecated/fgood/fgood.h deleted file mode 100644 index 0aaf910c0f..0000000000 --- a/library/cpp/deprecated/fgood/fgood.h +++ /dev/null @@ -1,328 +0,0 @@ -#pragma once - -#include <util/system/yassert.h> -#include <util/system/defaults.h> -#include <util/generic/string.h> -#include <util/generic/yexception.h> -#include <util/generic/ptr.h> - -#include "fput.h" - -#include <cstdio> - -#include <fcntl.h> - -#ifdef _unix_ -extern "C" int __ungetc(int, FILE*); -#endif - -#if (!defined(__FreeBSD__) && !defined(__linux__) && !defined(_darwin_) && !defined(_cygwin_)) || defined(_bionic_) -#define feof_unlocked(_stream) feof(_stream) -#define ferror_unlocked(_stream) ferror(_stream) -#endif - -#ifndef _unix_ -#if defined(_MSC_VER) && (_MSC_VER < 1900) -#define getc_unlocked(_stream) (--(_stream)->_cnt >= 0 ? 0xff & *(_stream)->_ptr++ : _filbuf(_stream)) -#define putc_unlocked(_c, _stream) (--(_stream)->_cnt >= 0 ? 0xff & (*(_stream)->_ptr++ = (char)(_c)) : _flsbuf((_c), (_stream))) -#else -#define getc_unlocked(_stream) getc(_stream) -#define putc_unlocked(_c, _stream) putc(_c, _stream) -#endif -#endif - -inline bool fgood(FILE* f) { - return !feof_unlocked(f) && !ferror_unlocked(f); -} - -#ifdef _win32_ -// These functions will work only with static MSVC runtime linkage. For dynamic linkage, -// fseeki64.c and ftelli64.c from CRT sources should be included in project -extern "C" int __cdecl _fseeki64(FILE*, __int64, int); -extern "C" __int64 __cdecl _ftelli64(FILE*); - -inline i64 ftello(FILE* stream) { - return _ftelli64(stream); -} - -inline int fseeko(FILE* stream, i64 offset, int origin) { - return _fseeki64(stream, offset, origin); -} -#endif - -class TFILEPtr { -private: - enum { SHOULD_CLOSE = 1, - IS_PIPE = 2 }; - FILE* m_file; - int m_Flags; - TString Name; - -public: - TFILEPtr() noexcept { - m_file = nullptr; - m_Flags = 0; - } - TFILEPtr(const TString& name, const char* mode) { - m_file = nullptr; - m_Flags = 0; - open(name, mode); - } - TFILEPtr(const TFILEPtr& src) noexcept { - m_file = src.m_file; - m_Flags = 0; - } - TFILEPtr& operator=(const TFILEPtr& src) { - if (src.m_file != m_file) { - close(); - m_file = src.m_file; - m_Flags = 0; - } - return *this; - } - explicit TFILEPtr(FILE* f) noexcept { // take ownership - m_file = f; - m_Flags = SHOULD_CLOSE; - } - TFILEPtr& operator=(FILE* f) { // take ownership - if (f != m_file) { - close(); - m_file = f; - m_Flags = SHOULD_CLOSE; - } - return *this; - } - const TString& name() const { - return Name; - } - operator FILE*() const noexcept { - return m_file; - } - FILE* operator->() const noexcept { - return m_file; - } - bool operator!() const noexcept { - return m_file == nullptr; - } - bool operator!=(FILE* f) const noexcept { - return m_file != f; - } - bool operator==(FILE* f) const noexcept { - return m_file == f; - } - ~TFILEPtr() { - close(); - } - void Y_PRINTF_FORMAT(2, 3) check(const char* message, ...) const { - if (Y_UNLIKELY(!fgood(m_file))) { - va_list args; - va_start(args, message); - char buf[512]; - vsnprintf(buf, 512, message, args); - // XXX: errno is undefined here - ythrow yexception() << buf << ": " << LastSystemErrorText() << ", " << Name.data() << " at offset " << (i64)ftell(); - } - } - TFILEPtr& assign(FILE* f, const char* name = nullptr) { // take ownership and have a name - *this = f; - if (name) - Name = name; - return *this; - } - void open(const TString& name, const char* mode) { - Y_ASSERT(!name.empty()); - Y_ASSERT(m_file == nullptr); - m_file = ::fopen(name.data(), mode); - if (!m_file) - ythrow yexception() << "can't open \'" << name << "\' with mode \'" << mode << "\': " << LastSystemErrorText(); - m_Flags = SHOULD_CLOSE; - Name = name; - } - void popen(const TString& command, const char* mode) { - Y_ASSERT(!command.empty()); - Y_ASSERT(m_file == nullptr); - m_file = ::popen(command.data(), mode); - if (!m_file) - ythrow yexception() << "can't execute \'" << command << "\' with mode \'" << mode << "\': " << LastSystemErrorText(); - m_Flags = IS_PIPE | SHOULD_CLOSE; - Name = command; - } - void close() { - if (m_file != nullptr && (m_Flags & SHOULD_CLOSE)) { - if ((m_Flags & IS_PIPE) ? ::pclose(m_file) : ::fclose(m_file)) { - m_file = nullptr; - m_Flags = 0; - if (!UncaughtException()) - ythrow yexception() << "can't close file " << Name.data() << ": " << LastSystemErrorText(); - } - } - m_file = nullptr; - m_Flags = 0; - Name.clear(); - } - size_t write(const void* buffer, size_t size, size_t count) const { - Y_ASSERT(m_file != nullptr); - size_t r = ::fwrite(buffer, size, count, m_file); - check("can't write %lu bytes", (unsigned long)size * count); - return r; - } - size_t read(void* buffer, size_t size, size_t count) const { - Y_ASSERT(m_file != nullptr); - size_t r = ::fread(buffer, size, count, m_file); - if (ferror_unlocked(m_file)) - ythrow yexception() << "can't read " << (unsigned long)size * count << " bytes: " << LastSystemErrorText() << ", " << Name.data() << " at offset " << (i64)ftell(); - return r; - } - char* fgets(char* buffer, int size) const { - Y_ASSERT(m_file != nullptr); - char* r = ::fgets(buffer, size, m_file); - if (ferror_unlocked(m_file)) - ythrow yexception() << "can't read string of maximum size " << size << ": " << LastSystemErrorText() << ", " << Name.data() << " at offset " << (i64)ftell(); - return r; - } - void Y_PRINTF_FORMAT(2, 3) fprintf(const char* format, ...) { - Y_ASSERT(m_file != nullptr); - va_list args; - va_start(args, format); - vfprintf(m_file, format, args); - check("can't write"); - } - void seek(i64 offset, int origin) const { - Y_ASSERT(m_file != nullptr); -#if defined(_unix_) || defined(_win32_) - if (fseeko(m_file, offset, origin) != 0) -#else - Y_ASSERT(offset == (i64)(i32)offset); - if (::fseek(m_file, (long)offset, origin) != 0) -#endif - ythrow yexception() << "can't seek " << Name.data() << " by " << offset << ": " << LastSystemErrorText(); - } - i64 length() const; // uses various system headers -> in fileptr.cpp - - void setDirect() const { -#if !defined(_win_) && !defined(_darwin_) - if (!m_file) - ythrow yexception() << "file not open"; - if (fcntl(fileno(m_file), F_SETFL, O_DIRECT) == -1) - ythrow yexception() << "Cannot set O_DIRECT flag"; -#endif - } - - // for convenience - - i64 ftell() const noexcept { -#if defined(_unix_) || defined(_win32_) - return ftello(m_file); -#else - return ftell(m_file); -#endif - } - bool eof() const noexcept { - Y_ASSERT(m_file != nullptr); - return feof_unlocked(m_file) != 0; - } - int fputc(int c) { - Y_ASSERT(m_file != nullptr); - return putc_unlocked(c, m_file); - } - size_t fputs(const char* buffer) const { - return write(buffer, strlen(buffer), 1); - } - int fgetc() { - Y_ASSERT(m_file != nullptr); - return getc_unlocked(m_file); - } - int ungetc(int c) { - Y_ASSERT(m_file != nullptr); - return ::ungetc(c, m_file); - } - template <class T> - size_t fput(const T& a) { - Y_ASSERT(m_file != nullptr); - return ::fput(m_file, a); - } - template <class T> - size_t fget(T& a) { - Y_ASSERT(m_file != nullptr); - return ::fget(m_file, a); - } - size_t fsput(const char* s, size_t l) { - Y_ASSERT(m_file != nullptr); - return ::fsput(m_file, s, l); - } - size_t fsget(char* s, size_t l) { - Y_ASSERT(m_file != nullptr); - return ::fsget(m_file, s, l); - } - - void fflush() { - ::fflush(m_file); - } - - /* This block contains some TFile/TStream - compatible names */ - size_t Read(void* bufferIn, size_t numBytes) { - size_t r = fsget((char*)bufferIn, numBytes); - if (Y_UNLIKELY(ferror_unlocked(m_file))) - ythrow yexception() << "can't read " << numBytes << " bytes: " << LastSystemErrorText() << ", " << Name << " at offset " << (i64)ftell(); - return r; - } - void Write(const void* buffer, size_t numBytes) { - write(buffer, 1, numBytes); - } - i64 Seek(i64 offset, int origin /*SeekDir*/) { - seek(offset, origin); - return ftell(); - } - i64 GetPosition() const noexcept { - return ftell(); - } - i64 GetLength() const noexcept { - return length(); - } - bool ReadLine(TString& st); - - /* Similar to TAutoPtr::Release - return pointer and forget about it. */ - FILE* Release() noexcept { - FILE* result = m_file; - m_file = nullptr; - m_Flags = 0; - Name.clear(); - return result; - } -}; - -inline void fclose(TFILEPtr& F) { - F.close(); -} - -inline void fseek(const TFILEPtr& F, i64 offset, int whence) { - F.seek(offset, whence); -} - -#ifdef _freebsd_ // fgetln -inline bool getline(TFILEPtr& f, TString& s) { - size_t len; - char* buf = fgetln(f, &len); - if (!buf) - return false; - if (len && buf[len - 1] == '\n') - len--; - s.AssignNoAlias(buf, len); - return true; -} -#else -bool getline(TFILEPtr& f, TString& s); -#endif //_freebsd_ - -inline bool TFILEPtr::ReadLine(TString& st) { - return getline(*this, st); -} - -FILE* OpenFILEOrFail(const TString& name, const char* mode); - -//Should be used with THolder -struct TFILECloser { - static void Destroy(FILE* file); -}; - -using TFILEHolder = THolder<FILE, TFILECloser>; diff --git a/library/cpp/deprecated/fgood/fput.h b/library/cpp/deprecated/fgood/fput.h deleted file mode 100644 index 690b06332d..0000000000 --- a/library/cpp/deprecated/fgood/fput.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once - -#include <util/system/defaults.h> -#include <util/system/valgrind.h> - -#include <cstdio> - -#ifdef __FreeBSD__ -#include <cstring> - -template <class T> -Y_FORCE_INLINE size_t fput(FILE* F, const T& a) { - if (Y_LIKELY(F->_w >= int(sizeof(a)))) { - memcpy(F->_p, &a, sizeof(a)); - F->_p += sizeof(a); - F->_w -= sizeof(a); - return 1; - } else { - return fwrite(&a, sizeof(a), 1, F); - } -} - -template <class T> -Y_FORCE_INLINE size_t fget(FILE* F, T& a) { - if (Y_LIKELY(F->_r >= int(sizeof(a)))) { - memcpy(&a, F->_p, sizeof(a)); - F->_p += sizeof(a); - F->_r -= sizeof(a); - return 1; - } else { - return fread(&a, sizeof(a), 1, F); - } -} - -inline size_t fsput(FILE* F, const char* s, size_t l) { - VALGRIND_CHECK_READABLE(s, l); - - if ((size_t)F->_w >= l) { - memcpy(F->_p, s, l); - F->_p += l; - F->_w -= l; - return l; - } else { - return fwrite(s, 1, l, F); - } -} - -inline size_t fsget(FILE* F, char* s, size_t l) { - if ((size_t)F->_r >= l) { - memcpy(s, F->_p, l); - F->_p += l; - F->_r -= l; - return l; - } else { - return fread(s, 1, l, F); - } -} -#else -template <class T> -Y_FORCE_INLINE size_t fput(FILE* F, const T& a) { - return fwrite(&a, sizeof(a), 1, F); -} - -template <class T> -Y_FORCE_INLINE size_t fget(FILE* F, T& a) { - return fread(&a, sizeof(a), 1, F); -} - -inline size_t fsput(FILE* F, const char* s, size_t l) { -#ifdef WITH_VALGRIND - VALGRIND_CHECK_READABLE(s, l); -#endif - return fwrite(s, 1, l, F); -} - -inline size_t fsget(FILE* F, char* s, size_t l) { - return fread(s, 1, l, F); -} -#endif diff --git a/library/cpp/deprecated/fgood/ya.make b/library/cpp/deprecated/fgood/ya.make deleted file mode 100644 index 2394f9ad7a..0000000000 --- a/library/cpp/deprecated/fgood/ya.make +++ /dev/null @@ -1,8 +0,0 @@ -LIBRARY() - -SRCS( - ffb.cpp - fgood.cpp -) - -END() diff --git a/library/cpp/deprecated/mapped_file/mapped_file.cpp b/library/cpp/deprecated/mapped_file/mapped_file.cpp deleted file mode 100644 index b0e4511299..0000000000 --- a/library/cpp/deprecated/mapped_file/mapped_file.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "mapped_file.h" - -#include <util/generic/yexception.h> -#include <util/system/defaults.h> -#include <util/system/hi_lo.h> -#include <util/system/filemap.h> - -TMappedFile::TMappedFile(TFileMap* map, const char* dbgName) { - Map_ = map; - i64 len = Map_->Length(); - if (Hi32(len) != 0 && sizeof(size_t) <= sizeof(ui32)) - ythrow yexception() << "File '" << dbgName << "' mapping error: " << len << " too large"; - - Map_->Map(0, static_cast<size_t>(len)); -} - -TMappedFile::TMappedFile(const TFile& file, TFileMap::EOpenMode om, const char* dbgName) - : Map_(nullptr) -{ - init(file, om, dbgName); -} - -void TMappedFile::precharge(size_t off, size_t size) const { - if (!Map_) - return; - - Map_->Precharge(off, size); -} - -void TMappedFile::init(const TString& name) { - THolder<TFileMap> map(new TFileMap(name)); - TMappedFile newFile(map.Get(), name.data()); - Y_UNUSED(map.Release()); - newFile.swap(*this); - newFile.term(); -} - -void TMappedFile::init(const TString& name, size_t length, TFileMap::EOpenMode om) { - THolder<TFileMap> map(new TFileMap(name, length, om)); - TMappedFile newFile(map.Get(), name.data()); - Y_UNUSED(map.Release()); - newFile.swap(*this); - newFile.term(); -} - -void TMappedFile::init(const TFile& file, TFileMap::EOpenMode om, const char* dbgName) { - THolder<TFileMap> map(new TFileMap(file, om)); - TMappedFile newFile(map.Get(), dbgName); - Y_UNUSED(map.Release()); - newFile.swap(*this); - newFile.term(); -} - -void TMappedFile::init(const TString& name, TFileMap::EOpenMode om) { - THolder<TFileMap> map(new TFileMap(name, om)); - TMappedFile newFile(map.Get(), name.data()); - Y_UNUSED(map.Release()); - newFile.swap(*this); - newFile.term(); -} - -void TMappedFile::flush() { - Map_->Flush(); -} diff --git a/library/cpp/deprecated/mapped_file/ya.make b/library/cpp/deprecated/mapped_file/ya.make deleted file mode 100644 index 309341f1da..0000000000 --- a/library/cpp/deprecated/mapped_file/ya.make +++ /dev/null @@ -1,7 +0,0 @@ -LIBRARY() - -SRCS( - mapped_file.cpp -) - -END() diff --git a/library/cpp/eventlog/common.h b/library/cpp/eventlog/common.h deleted file mode 100644 index 75c512c13e..0000000000 --- a/library/cpp/eventlog/common.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -template <class T> -class TPacketInputStream { -public: - virtual bool Avail() const = 0; - virtual T operator*() const = 0; - virtual bool Next() = 0; - virtual ~TPacketInputStream() = default; -}; diff --git a/library/cpp/eventlog/evdecoder.cpp b/library/cpp/eventlog/evdecoder.cpp deleted file mode 100644 index e4413a1b0e..0000000000 --- a/library/cpp/eventlog/evdecoder.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include <util/memory/tempbuf.h> -#include <util/string/cast.h> -#include <util/stream/output.h> - -#include "evdecoder.h" -#include "logparser.h" - -static const char* const UNKNOWN_EVENT_CLASS = "Unknown event class"; - -static inline void LogError(ui64 frameAddr, const char* msg, bool strict) { - if (!strict) { - Cerr << "EventDecoder warning @" << frameAddr << ": " << msg << Endl; - } else { - ythrow yexception() << "EventDecoder error @" << frameAddr << ": " << msg; - } -} - -static inline bool SkipData(IInputStream& s, size_t amount) { - return (amount == s.Skip(amount)); -} - -// There are 2 log fomats: the one, that allows event skip without event decode (it has stored event length) -// and another, that requires each event decode just to seek over stream. needRead == true means the latter format. -static inline THolder<TEvent> DoDecodeEvent(IInputStream& s, const TEventFilter* const filter, const bool needRead, IEventFactory* fac) { - TEventTimestamp ts; - TEventClass c; - THolder<TEvent> e; - - ::Load(&s, ts); - ::Load(&s, c); - - bool needReturn = false; - - if (!filter || filter->EventAllowed(c)) { - needReturn = true; - } - - if (needRead || needReturn) { - e.Reset(fac->CreateLogEvent(c)); - - if (!!e) { - e->Timestamp = ts; - e->Load(s); - } else if (needReturn) { - e.Reset(new TUnknownEvent(ts, c)); - } - - if (!needReturn) { - e.Reset(nullptr); - } - } - - return e; -} - -THolder<TEvent> DecodeFramed(IInputStream& inp, ui64 frameAddr, const TEventFilter* const filter, IEventFactory* fac, bool strict) { - ui32 len; - ::Load(&inp, len); - - if (len < sizeof(ui32)) { - ythrow TEventDecoderError() << "invalid event length"; - } - - TLengthLimitedInput s(&inp, len - sizeof(ui32)); - - try { - THolder<TEvent> e = DoDecodeEvent(s, filter, false, fac); - if (!!e) { - if (!s.Left()) { - return e; - } else if (e->Class == 0) { - if (!SkipData(s, s.Left())) { - ythrow TEventDecoderError() << "cannot skip bad event"; - } - - return e; - } - - LogError(frameAddr, "Event is not fully read", strict); - } - } catch (const TLoadEOF&) { - if (s.Left()) { - throw; - } - - LogError(frameAddr, "Unexpected event end", strict); - } - - if (!SkipData(s, s.Left())) { - ythrow TEventDecoderError() << "cannot skip bad event"; - } - - return nullptr; -} - -THolder<TEvent> DecodeEvent(IInputStream& s, bool framed, ui64 frameAddr, const TEventFilter* const filter, IEventFactory* fac, bool strict) { - try { - if (framed) { - return DecodeFramed(s, frameAddr, filter, fac, strict); - } else { - THolder<TEvent> e = DoDecodeEvent(s, filter, true, fac); - // e(0) means event, skipped by filter. Not an error. - if (!!e && !e->Class) { - ythrow TEventDecoderError() << UNKNOWN_EVENT_CLASS; - } - - return e; - } - } catch (const TLoadEOF&) { - ythrow TEventDecoderError() << "unexpected frame end"; - } -} diff --git a/library/cpp/eventlog/evdecoder.h b/library/cpp/eventlog/evdecoder.h deleted file mode 100644 index eedfc82174..0000000000 --- a/library/cpp/eventlog/evdecoder.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include <util/generic/yexception.h> -#include <util/generic/ptr.h> - -#include "eventlog.h" - -class TEvent; -class IInputStream; -class TEventFilter; - -struct TEventDecoderError: public yexception { -}; - -THolder<TEvent> DecodeEvent(IInputStream& s, bool framed, ui64 frameAddr, const TEventFilter* const filter, IEventFactory* fac, bool strict = false); -bool AcceptableContent(TEventLogFormat); diff --git a/library/cpp/eventlog/event_field_output.cpp b/library/cpp/eventlog/event_field_output.cpp deleted file mode 100644 index f9d98dac9d..0000000000 --- a/library/cpp/eventlog/event_field_output.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "event_field_output.h" - -#include <util/string/split.h> - -namespace { - TString MakeSeparators(EFieldOutputFlags flags) { - TString res; - res.reserve(3); - - if (flags & EFieldOutputFlag::EscapeTab) { - res.append('\t'); - } - if (flags & EFieldOutputFlag::EscapeNewLine) { - res.append('\n'); - res.append('\r'); - } - if (flags & EFieldOutputFlag::EscapeBackSlash) { - res.append('\\'); - } - - return res; - } -} - -TEventFieldOutput::TEventFieldOutput(IOutputStream& output, EFieldOutputFlags flags) - : Output(output) - , Flags(flags) - , Separators(MakeSeparators(flags)) -{ -} - -IOutputStream& TEventFieldOutput::GetOutputStream() { - return Output; -} - -EFieldOutputFlags TEventFieldOutput::GetFlags() const { - return Flags; -} - -void TEventFieldOutput::DoWrite(const void* buf, size_t len) { - if (!Flags) { - Output.Write(buf, len); - return; - } - - TStringBuf chunk{static_cast<const char*>(buf), len}; - - for (const auto part : StringSplitter(chunk).SplitBySet(Separators.data())) { - TStringBuf token = part.Token(); - TStringBuf delim = part.Delim(); - - if (!token.empty()) { - Output.Write(token); - } - if ("\n" == delim) { - Output.Write(TStringBuf("\\n")); - } else if ("\r" == delim) { - Output.Write(TStringBuf("\\r")); - } else if ("\t" == delim) { - Output.Write(TStringBuf("\\t")); - } else if ("\\" == delim) { - Output.Write(TStringBuf("\\\\")); - } else { - Y_ASSERT(delim.empty()); - } - } -} - diff --git a/library/cpp/eventlog/event_field_output.h b/library/cpp/eventlog/event_field_output.h deleted file mode 100644 index ed9db0ae16..0000000000 --- a/library/cpp/eventlog/event_field_output.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include <util/stream/output.h> -#include <util/generic/flags.h> - -enum class EFieldOutputFlag { - EscapeTab = 0x1, // escape \t in field value - EscapeNewLine = 0x2, // escape \n in field value - EscapeBackSlash = 0x4 // escape \ in field value -}; - -Y_DECLARE_FLAGS(EFieldOutputFlags, EFieldOutputFlag); -Y_DECLARE_OPERATORS_FOR_FLAGS(EFieldOutputFlags); - -class TEventFieldOutput: public IOutputStream { -public: - TEventFieldOutput(IOutputStream& output, EFieldOutputFlags flags); - - IOutputStream& GetOutputStream(); - EFieldOutputFlags GetFlags() const; - -protected: - void DoWrite(const void* buf, size_t len) override; - -private: - IOutputStream& Output; - EFieldOutputFlags Flags; - TString Separators; -}; diff --git a/library/cpp/eventlog/event_field_printer.cpp b/library/cpp/eventlog/event_field_printer.cpp deleted file mode 100644 index 29c6b4b661..0000000000 --- a/library/cpp/eventlog/event_field_printer.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "event_field_printer.h" - -#include <library/cpp/protobuf/json/proto2json.h> - -namespace { - - const NProtobufJson::TProto2JsonConfig PROTO_2_JSON_CONFIG = NProtobufJson::TProto2JsonConfig() - .SetMissingRepeatedKeyMode(NProtobufJson::TProto2JsonConfig::MissingKeyDefault) - .AddStringTransform(MakeIntrusive<NProtobufJson::TBase64EncodeBytesTransform>()); - -} // namespace - -TEventProtobufMessageFieldPrinter::TEventProtobufMessageFieldPrinter(EProtobufMessageFieldPrintMode mode) - : Mode(mode) -{} - -template <> -void TEventProtobufMessageFieldPrinter::PrintProtobufMessageFieldToOutput<google::protobuf::Message, false>(const google::protobuf::Message& field, TEventFieldOutput& output) { - switch (Mode) { - case EProtobufMessageFieldPrintMode::DEFAULT: - case EProtobufMessageFieldPrintMode::JSON: { - // Do not use field.PrintJSON() here: IGNIETFERRO-2002 - NProtobufJson::Proto2Json(field, output, PROTO_2_JSON_CONFIG); - break; - } - } -} diff --git a/library/cpp/eventlog/event_field_printer.h b/library/cpp/eventlog/event_field_printer.h deleted file mode 100644 index 835e8f4a85..0000000000 --- a/library/cpp/eventlog/event_field_printer.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include "event_field_output.h" - -#include <google/protobuf/message.h> - -// NB: For historical reasons print code for all primitive types/repeated fields/etc generated by https://a.yandex-team.ru/arc/trunk/arcadia/tools/event2cpp - -enum class EProtobufMessageFieldPrintMode { - // Use <TEventProtobufMessageFieldType>::Print method for fields that has it - // Print json for other fields - DEFAULT = 0, - - JSON = 1, -}; - -class TEventProtobufMessageFieldPrinter { -public: - explicit TEventProtobufMessageFieldPrinter(EProtobufMessageFieldPrintMode mode); - - template <typename TEventProtobufMessageFieldType, bool HasPrintFunction> - void PrintProtobufMessageFieldToOutput(const TEventProtobufMessageFieldType& field, TEventFieldOutput& output) { - if constexpr (HasPrintFunction) { - if (Mode == EProtobufMessageFieldPrintMode::DEFAULT) { - field.Print(output.GetOutputStream(), output.GetFlags()); - return; - } - } - - PrintProtobufMessageFieldToOutput<google::protobuf::Message, false>(field, output); - } - - template <> - void PrintProtobufMessageFieldToOutput<google::protobuf::Message, false>(const google::protobuf::Message& field, TEventFieldOutput& output); - -private: - EProtobufMessageFieldPrintMode Mode; -}; diff --git a/library/cpp/eventlog/eventlog.cpp b/library/cpp/eventlog/eventlog.cpp deleted file mode 100644 index 458a632b4a..0000000000 --- a/library/cpp/eventlog/eventlog.cpp +++ /dev/null @@ -1,554 +0,0 @@ -#include <util/datetime/base.h> -#include <util/stream/zlib.h> -#include <util/stream/length.h> -#include <util/generic/buffer.h> -#include <util/generic/yexception.h> -#include <util/digest/murmur.h> -#include <util/generic/singleton.h> -#include <util/generic/function.h> -#include <util/stream/output.h> -#include <util/stream/format.h> -#include <util/stream/null.h> - -#include <google/protobuf/messagext.h> - -#include "eventlog.h" -#include "events_extension.h" -#include "evdecoder.h" -#include "logparser.h" -#include <library/cpp/eventlog/proto/internal.pb.h> - -#include <library/cpp/json/json_writer.h> -#include <library/cpp/protobuf/json/proto2json.h> - - -TAtomic eventlogFrameCounter = 0; - -namespace { - - const NProtobufJson::TProto2JsonConfig PROTO_2_JSON_CONFIG = NProtobufJson::TProto2JsonConfig() - .SetMissingRepeatedKeyMode(NProtobufJson::TProto2JsonConfig::MissingKeyDefault) - .AddStringTransform(MakeIntrusive<NProtobufJson::TBase64EncodeBytesTransform>()); - - ui32 GenerateFrameId() { - return ui32(AtomicAdd(eventlogFrameCounter, 1)); - } - - inline const NProtoBuf::Message* UnknownEventMessage() { - return Singleton<NEventLogInternal::TUnknownEvent>(); - } - -} // namespace - -void TEvent::Print(IOutputStream& out, const TOutputOptions& options, const TEventState& eventState) const { - if (options.OutputFormat == TOutputFormat::TabSeparatedRaw) { - PrintHeader(out, options, eventState); - DoPrint(out, {}); - } else if (options.OutputFormat == TOutputFormat::TabSeparated) { - PrintHeader(out, options, eventState); - DoPrint( - out, - EFieldOutputFlags{} | EFieldOutputFlag::EscapeNewLine | EFieldOutputFlag::EscapeBackSlash); - } else if (options.OutputFormat == TOutputFormat::Json) { - NJson::TJsonWriterConfig jsonWriterConfig; - jsonWriterConfig.FormatOutput = 0; - NJson::TJsonWriter jsonWriter(&out, jsonWriterConfig); - - jsonWriter.OpenMap(); - PrintJsonHeader(jsonWriter); - DoPrintJson(jsonWriter); - jsonWriter.CloseMap(); - } -} - -void TEvent::PrintHeader(IOutputStream& out, const TOutputOptions& options, const TEventState& eventState) const { - if (options.HumanReadable) { - out << TInstant::MicroSeconds(Timestamp).ToString() << "\t"; - if (Timestamp >= eventState.FrameStartTime) - out << "+" << HumanReadable(TDuration::MicroSeconds(Timestamp - eventState.FrameStartTime)); - else // a bug somewhere? anyway, let's handle it in a nice fashion - out << "-" << HumanReadable(TDuration::MicroSeconds(eventState.FrameStartTime - Timestamp)); - - if (Timestamp >= eventState.PrevEventTime) - out << " (+" << HumanReadable(TDuration::MicroSeconds(Timestamp - eventState.PrevEventTime)) << ")"; - // else: these events are async and out-of-order, relative time diff makes no sense, skip it - - out << "\tF# " << FrameId << '\t'; - } else { - out << static_cast<TEventTimestamp>(Timestamp); - out << '\t' << FrameId << '\t'; - } -} - -void TEvent::PrintJsonHeader(NJson::TJsonWriter& jsonWriter) const { - jsonWriter.Write("Timestamp", Timestamp); - jsonWriter.Write("FrameId", FrameId); -} - -class TProtobufEvent: public TEvent { -public: - TProtobufEvent(TEventTimestamp t, size_t eventId, const NProtoBuf::Message& msg) - : TEvent(eventId, t) - , Message_(&msg) - , EventFactory_(NProtoBuf::TEventFactory::Instance()) - { - } - - TProtobufEvent() - : TEvent(0, 0) - , EventFactory_(NProtoBuf::TEventFactory::Instance()) - { - } - - explicit TProtobufEvent(ui32 id, NProtoBuf::TEventFactory* eventFactory = NProtoBuf::TEventFactory::Instance()) - : TEvent(id, 0) - , EventFactory_(eventFactory) - { - InnerMsg_.Reset(EventFactory_->CreateEvent(Class)); - Message_ = InnerMsg_.Get(); - } - - ui32 Id() const { - return Class; - } - - void Load(IInputStream& in) override { - if (!!InnerMsg_) { - InnerMsg_->ParseFromArcadiaStream(&in); - } else { - TransferData(&in, &Cnull); - } - } - - void Save(IOutputStream& out) const override { - Message_->SerializeToArcadiaStream(&out); - } - - void SaveToBuffer(TBufferOutput& buf) const override { - size_t messageSize = Message_->ByteSize(); - size_t before = buf.Buffer().Size(); - buf.Buffer().Advance(messageSize); - Y_PROTOBUF_SUPPRESS_NODISCARD Message_->SerializeToArray(buf.Buffer().Data() + before, messageSize); - } - - TStringBuf GetName() const override { - return EventFactory_->NameById(Id()); - } - -private: - void DoPrint(IOutputStream& out, EFieldOutputFlags flags) const override { - EventFactory_->PrintEvent(Id(), Message_, out, flags); - } - void DoPrintJson(NJson::TJsonWriter& jsonWriter) const override { - jsonWriter.OpenMap("EventBody"); - jsonWriter.Write("Type", GetName()); - - jsonWriter.Write("Fields"); - NProtobufJson::Proto2Json(*GetProto(), jsonWriter, PROTO_2_JSON_CONFIG); - - jsonWriter.CloseMap(); - } - - const NProtoBuf::Message* GetProto() const override { - if (Message_) { - return Message_; - } - - return UnknownEventMessage(); - } - -private: - const NProtoBuf::Message* Message_ = nullptr; - NProtoBuf::TEventFactory* EventFactory_; - THolder<NProtoBuf::Message> InnerMsg_; - - friend class TEventLogFrame; -}; - -void TEventLogFrame::LogProtobufEvent(size_t eventId, const NProtoBuf::Message& ev) { - TProtobufEvent event(Now().MicroSeconds(), eventId, ev); - - LogEventImpl(event); -} - -void TEventLogFrame::LogProtobufEvent(TEventTimestamp timestamp, size_t eventId, const NProtoBuf::Message& ev) { - TProtobufEvent event(timestamp, eventId, ev); - - LogEventImpl(event); -} - -template <> -void TEventLogFrame::DebugDump(const TProtobufEvent& ev) { - static TMutex lock; - - with_lock (lock) { - Cerr << ev.Timestamp << "\t" << ev.GetName() << "\t"; - ev.GetProto()->PrintJSON(Cerr); - Cerr << Endl; - } -} - -#pragma pack(push, 1) -struct TFrameHeaderData { - char SyncField[COMPRESSED_LOG_FRAME_SYNC_DATA.size()]; - TCompressedFrameBaseHeader Header; - TCompressedFrameHeader2 HeaderEx; -}; -#pragma pack(pop) - -TEventLogFrame::TEventLogFrame(IEventLog& parentLog, bool needAlwaysSafeAdd, TWriteFrameCallbackPtr writeFrameCallback) - : EvLog_(parentLog.HasNullBackend() ? nullptr : &parentLog) - , NeedAlwaysSafeAdd_(needAlwaysSafeAdd) - , ForceDump_(false) - , WriteFrameCallback_(std::move(writeFrameCallback)) -{ - DoInit(); -} - -TEventLogFrame::TEventLogFrame(IEventLog* parentLog, bool needAlwaysSafeAdd, TWriteFrameCallbackPtr writeFrameCallback) - : EvLog_(parentLog) - , NeedAlwaysSafeAdd_(needAlwaysSafeAdd) - , ForceDump_(false) - , WriteFrameCallback_(std::move(writeFrameCallback)) -{ - if (EvLog_ && EvLog_->HasNullBackend()) { - EvLog_ = nullptr; - } - - DoInit(); -} - -TEventLogFrame::TEventLogFrame(bool needAlwaysSafeAdd, TWriteFrameCallbackPtr writeFrameCallback) - : EvLog_(nullptr) - , NeedAlwaysSafeAdd_(needAlwaysSafeAdd) - , ForceDump_(false) - , WriteFrameCallback_(std::move(writeFrameCallback)) -{ - DoInit(); -} - -void TEventLogFrame::Flush() { - if (EvLog_ == nullptr) - return; - - TBuffer& buf = Buf_.Buffer(); - - if (buf.Empty()) { - return; - } - - EvLog_->WriteFrame(buf, StartTimestamp_, EndTimestamp_, WriteFrameCallback_, std::move(MetaFlags_)); - - DoInit(); - - return; -} - -void TEventLogFrame::SafeFlush() { - TGuard<TMutex> g(Mtx_); - Flush(); -} - -void TEventLogFrame::AddEvent(TEventTimestamp timestamp) { - if (timestamp < StartTimestamp_) { - StartTimestamp_ = timestamp; - } - - if (timestamp > EndTimestamp_) { - EndTimestamp_ = timestamp; - } -} - -void TEventLogFrame::DoInit() { - Buf_.Buffer().Clear(); - - StartTimestamp_ = (TEventTimestamp)-1; - EndTimestamp_ = 0; -} - -void TEventLogFrame::VisitEvents(ILogFrameEventVisitor& visitor, IEventFactory* eventFactory) { - const auto doVisit = [this, &visitor, eventFactory]() { - TBuffer& buf = Buf_.Buffer(); - - TBufferInput bufferInput(buf); - TLengthLimitedInput limitedInput(&bufferInput, buf.size()); - - TEventFilter EventFilter(false); - - while (limitedInput.Left()) { - THolder<TEvent> event = DecodeEvent(limitedInput, true, 0, &EventFilter, eventFactory); - - visitor.Visit(*event); - } - }; - if (NeedAlwaysSafeAdd_) { - TGuard<TMutex> g(Mtx_); - doVisit(); - } else { - doVisit(); - } -} - -TSelfFlushLogFrame::TSelfFlushLogFrame(IEventLog& parentLog, bool needAlwaysSafeAdd, TWriteFrameCallbackPtr writeFrameCallback) - : TEventLogFrame(parentLog, needAlwaysSafeAdd, std::move(writeFrameCallback)) -{ -} - -TSelfFlushLogFrame::TSelfFlushLogFrame(IEventLog* parentLog, bool needAlwaysSafeAdd, TWriteFrameCallbackPtr writeFrameCallback) - : TEventLogFrame(parentLog, needAlwaysSafeAdd, std::move(writeFrameCallback)) -{ -} - -TSelfFlushLogFrame::TSelfFlushLogFrame(bool needAlwaysSafeAdd, TWriteFrameCallbackPtr writeFrameCallback) - : TEventLogFrame(needAlwaysSafeAdd, std::move(writeFrameCallback)) -{ -} - -TSelfFlushLogFrame::~TSelfFlushLogFrame() { - try { - Flush(); - } catch (...) { - } -} - -IEventLog::~IEventLog() { -} - -static THolder<TLogBackend> ConstructBackend(const TString& fileName, const TEventLogBackendOptions& backendOpts) { - try { - THolder<TLogBackend> backend; - if (backendOpts.UseSyncPageCacheBackend) { - backend = MakeHolder<TSyncPageCacheFileLogBackend>(fileName, backendOpts.SyncPageCacheBackendBufferSize, backendOpts.SyncPageCacheBackendMaxPendingSize); - } else { - backend = MakeHolder<TFileLogBackend>(fileName); - } - return MakeHolder<TReopenLogBackend>(std::move(backend)); - } catch (...) { - Cdbg << "Warning: Cannot open event log '" << fileName << "': " << CurrentExceptionMessage() << "." << Endl; - } - - return MakeHolder<TNullLogBackend>(); -} - -TEventLog::TEventLog(const TString& fileName, TEventLogFormat contentFormat, const TEventLogBackendOptions& backendOpts, TMaybe<TEventLogFormat> logFormat) - : Log_(ConstructBackend(fileName, backendOpts)) - , ContentFormat_(contentFormat) - , LogFormat_(logFormat.Defined() ? *logFormat : COMPRESSED_LOG_FORMAT_V4) - , HasNullBackend_(Log_.IsNullLog()) - , Lz4hcCodec_(NBlockCodecs::Codec("lz4hc")) - , ZstdCodec_(NBlockCodecs::Codec("zstd_1")) -{ - Y_ENSURE(LogFormat_ == COMPRESSED_LOG_FORMAT_V4 || LogFormat_ == COMPRESSED_LOG_FORMAT_V5); - - if (contentFormat & 0xff000000) { - ythrow yexception() << "wrong compressed event log content format code (" << contentFormat << ")"; - } -} - -TEventLog::TEventLog(const TString& fileName, TEventLogFormat contentFormat, const TEventLogBackendOptions& backendOpts) - : TEventLog(fileName, contentFormat, backendOpts, COMPRESSED_LOG_FORMAT_V4) -{ -} - -TEventLog::TEventLog(const TLog& log, TEventLogFormat contentFormat, TEventLogFormat logFormat) - : Log_(log) - , ContentFormat_(contentFormat) - , LogFormat_(logFormat) - , HasNullBackend_(Log_.IsNullLog()) - , Lz4hcCodec_(NBlockCodecs::Codec("lz4hc")) - , ZstdCodec_(NBlockCodecs::Codec("zstd_1")) -{ - if (contentFormat & 0xff000000) { - ythrow yexception() << "wrong compressed event log content format code (" << contentFormat << ")"; - } -} - -TEventLog::TEventLog(TEventLogFormat contentFormat, TEventLogFormat logFormat) - : Log_(MakeHolder<TNullLogBackend>()) - , ContentFormat_(contentFormat) - , LogFormat_(logFormat) - , HasNullBackend_(true) - , Lz4hcCodec_(NBlockCodecs::Codec("lz4hc")) - , ZstdCodec_(NBlockCodecs::Codec("zstd_1")) -{ - if (contentFormat & 0xff000000) { - ythrow yexception() << "wrong compressed event log content format code (" << contentFormat << ")"; - } -} - -TEventLog::~TEventLog() { -} - -void TEventLog::ReopenLog() { - Log_.ReopenLog(); -} - -void TEventLog::CloseLog() { - Log_.CloseLog(); -} - -void TEventLog::Flush() { -} - -namespace { - class TOnExceptionAction { - public: - TOnExceptionAction(std::function<void()>&& f) - : F_(std::move(f)) - { - } - - ~TOnExceptionAction() { - if (F_ && UncaughtException()) { - try { - F_(); - } catch (...) { - } - } - } - - private: - std::function<void()> F_; - }; -} - -void TEventLog::WriteFrame(TBuffer& buffer, - TEventTimestamp startTimestamp, - TEventTimestamp endTimestamp, - TWriteFrameCallbackPtr writeFrameCallback, - TLogRecord::TMetaFlags metaFlags) { - Y_ENSURE(LogFormat_ == COMPRESSED_LOG_FORMAT_V4 || LogFormat_ == COMPRESSED_LOG_FORMAT_V5); - - TBuffer& b1 = buffer; - - size_t maxCompressedLength = (LogFormat_ == COMPRESSED_LOG_FORMAT_V4) ? b1.Size() + 256 : ZstdCodec_->MaxCompressedLength(b1); - - // Reserve enough memory to minimize reallocs - TBufferOutput outbuf(sizeof(TFrameHeaderData) + maxCompressedLength); - TBuffer& b2 = outbuf.Buffer(); - b2.Proceed(sizeof(TFrameHeaderData)); - - { - TFrameHeaderData& hdr = *reinterpret_cast<TFrameHeaderData*>(b2.data()); - - memcpy(hdr.SyncField, COMPRESSED_LOG_FRAME_SYNC_DATA.data(), COMPRESSED_LOG_FRAME_SYNC_DATA.size()); - hdr.Header.Format = (LogFormat_ << 24) | (ContentFormat_ & 0xffffff); - hdr.Header.FrameId = GenerateFrameId(); - hdr.HeaderEx.UncompressedDatalen = (ui32)b1.Size(); - hdr.HeaderEx.StartTimestamp = startTimestamp; - hdr.HeaderEx.EndTimestamp = endTimestamp; - hdr.HeaderEx.PayloadChecksum = 0; - hdr.HeaderEx.CompressorVersion = 0; - } - - if (LogFormat_ == COMPRESSED_LOG_FORMAT_V4) { - TBuffer encoded(b1.Size() + sizeof(TFrameHeaderData) + 256); - Lz4hcCodec_->Encode(b1, encoded); - - TZLibCompress compr(&outbuf, ZLib::ZLib, 6, 2048); - compr.Write(encoded.data(), encoded.size()); - compr.Finish(); - } else { - b2.Advance(ZstdCodec_->Compress(b1, b2.Pos())); - } - - { - const size_t k = sizeof(TCompressedFrameBaseHeader) + COMPRESSED_LOG_FRAME_SYNC_DATA.size(); - TFrameHeaderData& hdr = *reinterpret_cast<TFrameHeaderData*>(b2.data()); - hdr.Header.Length = static_cast<ui32>(b2.size() - k); - hdr.HeaderEx.PayloadChecksum = MurmurHash<ui32>(b2.data() + sizeof(TFrameHeaderData), b2.size() - sizeof(TFrameHeaderData)); - - const size_t n = sizeof(TFrameHeaderData) - (COMPRESSED_LOG_FRAME_SYNC_DATA.size() + sizeof(hdr.HeaderEx.HeaderChecksum)); - hdr.HeaderEx.HeaderChecksum = MurmurHash<ui32>(b2.data() + COMPRESSED_LOG_FRAME_SYNC_DATA.size(), n); - } - - const TBuffer& frameData = outbuf.Buffer(); - - TOnExceptionAction actionCallback([this] { - if (ErrorCallback_) { - ErrorCallback_->OnWriteError(); - } - }); - - if (writeFrameCallback) { - writeFrameCallback->OnAfterCompress(frameData, startTimestamp, endTimestamp); - } - - Log_.Write(frameData.Data(), frameData.Size(), std::move(metaFlags)); - if (SuccessCallback_) { - SuccessCallback_->OnWriteSuccess(frameData); - } -} - -TEvent* TProtobufEventFactory::CreateLogEvent(TEventClass c) { - return new TProtobufEvent(c, EventFactory_); -} - -TEventClass TProtobufEventFactory::ClassByName(TStringBuf name) const { - return EventFactory_->IdByName(name); -} - -TEventClass TProtobufEventFactory::EventClassBegin() const { - const auto& items = EventFactory_->FactoryItems(); - - if (items.empty()) { - return static_cast<TEventClass>(0); - } - - return static_cast<TEventClass>(items.begin()->first); -} - -TEventClass TProtobufEventFactory::EventClassEnd() const { - const auto& items = EventFactory_->FactoryItems(); - - if (items.empty()) { - return static_cast<TEventClass>(0); - } - - return static_cast<TEventClass>(items.rbegin()->first + 1); -} - -namespace NEvClass { - IEventFactory* Factory() { - return Singleton<TProtobufEventFactory>(); - } - - IEventProcessor* Processor() { - return Singleton<TProtobufEventProcessor>(); - } -} - -const NProtoBuf::Message* TUnknownEvent::GetProto() const { - return UnknownEventMessage(); -} - -TStringBuf TUnknownEvent::GetName() const { - return TStringBuf("UnknownEvent"); -} - -void TUnknownEvent::DoPrintJson(NJson::TJsonWriter& jsonWriter) const { - jsonWriter.OpenMap("EventBody"); - jsonWriter.Write("Type", GetName()); - jsonWriter.Write("EventId", (size_t)Class); - jsonWriter.CloseMap(); -} - -TStringBuf TEndOfFrameEvent::GetName() const { - return TStringBuf("EndOfFrame"); -} - -const NProtoBuf::Message* TEndOfFrameEvent::GetProto() const { - return Singleton<NEventLogInternal::TEndOfFrameEvent>(); -} - -void TEndOfFrameEvent::DoPrintJson(NJson::TJsonWriter& jsonWriter) const { - jsonWriter.OpenMap("EventBody"); - jsonWriter.Write("Type", GetName()); - jsonWriter.OpenMap("Fields"); - jsonWriter.CloseMap(); - jsonWriter.CloseMap(); -} - -THolder<TEvent> MakeProtobufLogEvent(TEventTimestamp ts, TEventClass eventId, google::protobuf::Message& ev) { - return MakeHolder<TProtobufEvent>(ts, eventId, ev); -} diff --git a/library/cpp/eventlog/eventlog.h b/library/cpp/eventlog/eventlog.h deleted file mode 100644 index 45c2dfb17f..0000000000 --- a/library/cpp/eventlog/eventlog.h +++ /dev/null @@ -1,623 +0,0 @@ -#pragma once - -#include "eventlog_int.h" -#include "event_field_output.h" -#include "events_extension.h" - -#include <library/cpp/blockcodecs/codecs.h> -#include <library/cpp/logger/all.h> - -#include <google/protobuf/message.h> - -#include <util/datetime/base.h> -#include <util/generic/ptr.h> -#include <util/generic/string.h> -#include <util/stream/output.h> -#include <util/stream/buffer.h> -#include <util/stream/str.h> -#include <util/system/mutex.h> -#include <util/stream/output.h> -#include <util/system/env.h> -#include <util/system/unaligned_mem.h> -#include <util/ysaveload.h> - -#include <cstdlib> - -namespace NJson { - class TJsonWriter; -} - -class IEventLog; - -class TEvent : public TThrRefBase { -public: - enum class TOutputFormat { - TabSeparated, - TabSeparatedRaw, // disables escaping - Json - }; - - struct TOutputOptions { - TOutputFormat OutputFormat = TOutputFormat::TabSeparated; - // Dump some fields (e.g. timestamp) in more human-readable format - bool HumanReadable = false; - - TOutputOptions(TOutputFormat outputFormat = TOutputFormat::TabSeparated) - : OutputFormat(outputFormat) - { - } - - TOutputOptions(TOutputFormat outputFormat, bool humanReadable) - : OutputFormat(outputFormat) - , HumanReadable(humanReadable) - { - } - }; - - struct TEventState { - TEventTimestamp FrameStartTime = 0; - TEventTimestamp PrevEventTime = 0; - TEventState() { - } - }; - - TEvent(TEventClass c, TEventTimestamp t) - : Class(c) - , Timestamp(t) - { - } - - virtual ~TEvent() = default; - - // Note, that descendants MUST have Save() & Load() methods to alter - // only its new variables, not the base class! - virtual void Save(IOutputStream& out) const = 0; - virtual void SaveToBuffer(TBufferOutput& out) const { - Save(out); - } - - // Note, that descendants MUST have Save() & Load() methods to alter - // only its new variables, not the base class! - virtual void Load(IInputStream& i) = 0; - - virtual TStringBuf GetName() const = 0; - virtual const NProtoBuf::Message* GetProto() const = 0; - - void Print(IOutputStream& out, const TOutputOptions& options = TOutputOptions(), const TEventState& eventState = TEventState()) const; - void PrintHeader(IOutputStream& out, const TOutputOptions& options, const TEventState& eventState) const; - - TString ToString() const { - TStringStream buff; - Print(buff); - return buff.Str(); - } - - void FullSaveToBuffer(TBufferOutput& buf) const { - SaveMessageHeader(buf); - this->SaveToBuffer(buf); - } - - void FullSave(IOutputStream& o) const { - SaveMessageHeader(o); - this->Save(o); - } - - void FullLoad(IInputStream& i) { - ::Load(&i, Timestamp); - ::Load(&i, Class); - this->Load(i); - } - - template <class T> - const T* Get() const { - return static_cast<const T*>(this->GetProto()); - } - - TEventClass Class; - TEventTimestamp Timestamp; - ui32 FrameId = 0; - -private: - void SaveMessageHeader(IOutputStream& out) const { - ::Save(&out, Timestamp); - ::Save(&out, Class); - } - - virtual void DoPrint(IOutputStream& out, EFieldOutputFlags flags) const = 0; - virtual void DoPrintJson(NJson::TJsonWriter& jsonWriter) const = 0; - - void PrintJsonHeader(NJson::TJsonWriter& jsonWriter) const; -}; - -using TEventPtr = TIntrusivePtr<TEvent>; -using TConstEventPtr = TIntrusiveConstPtr<TEvent>; - -class IEventProcessor { -public: - virtual void SetOptions(const TEvent::TOutputOptions& options) { - Options_ = options; - } - virtual void ProcessEvent(const TEvent* ev) = 0; - virtual bool CheckedProcessEvent(const TEvent* ev) { - ProcessEvent(ev); - return true; - } - virtual ~IEventProcessor() = default; - -protected: - TEvent::TOutputOptions Options_; -}; - -class IEventFactory { -public: - virtual TEvent* CreateLogEvent(TEventClass c) = 0; - virtual TEventLogFormat CurrentFormat() = 0; - virtual TEventClass ClassByName(TStringBuf name) const = 0; - virtual TEventClass EventClassBegin() const = 0; - virtual TEventClass EventClassEnd() const = 0; - virtual ~IEventFactory() = default; -}; - -class TUnknownEvent: public TEvent { -public: - TUnknownEvent(TEventTimestamp ts, TEventClass cls) - : TEvent(cls, ts) - { - } - - ~TUnknownEvent() override = default; - - void Save(IOutputStream& /* o */) const override { - ythrow yexception() << "TUnknownEvent cannot be saved"; - } - - void Load(IInputStream& /* i */) override { - ythrow yexception() << "TUnknownEvent cannot be loaded"; - } - - TStringBuf GetName() const override; - -private: - void DoPrint(IOutputStream& out, EFieldOutputFlags) const override { - out << GetName() << "\t" << (size_t)Class; - } - - void DoPrintJson(NJson::TJsonWriter& jsonWriter) const override; - - const NProtoBuf::Message* GetProto() const override; -}; - -class TEndOfFrameEvent: public TEvent { -public: - enum { - EventClass = 0 - }; - - TEndOfFrameEvent(TEventTimestamp ts) - : TEvent(TEndOfFrameEvent::EventClass, ts) - { - } - - ~TEndOfFrameEvent() override = default; - - void Save(IOutputStream& o) const override { - (void)o; - ythrow yexception() << "TEndOfFrameEvent cannot be saved"; - } - - void Load(IInputStream& i) override { - (void)i; - ythrow yexception() << "TEndOfFrameEvent cannot be loaded"; - } - - TStringBuf GetName() const override; - -private: - void DoPrint(IOutputStream& out, EFieldOutputFlags) const override { - out << GetName(); - } - void DoPrintJson(NJson::TJsonWriter& jsonWriter) const override; - - const NProtoBuf::Message* GetProto() const override; -}; - -class ILogFrameEventVisitor { -public: - virtual ~ILogFrameEventVisitor() = default; - - virtual void Visit(const TEvent& event) = 0; -}; - -class IWriteFrameCallback : public TAtomicRefCount<IWriteFrameCallback> { -public: - virtual ~IWriteFrameCallback() = default; - - virtual void OnAfterCompress(const TBuffer& compressedFrame, TEventTimestamp startTimestamp, TEventTimestamp endTimestamp) = 0; -}; - -using TWriteFrameCallbackPtr = TIntrusivePtr<IWriteFrameCallback>; - -class TEventLogFrame { -public: - TEventLogFrame(bool needAlwaysSafeAdd = false, TWriteFrameCallbackPtr writeFrameCallback = nullptr); - TEventLogFrame(IEventLog& parentLog, bool needAlwaysSafeAdd = false, TWriteFrameCallbackPtr writeFrameCallback = nullptr); - TEventLogFrame(IEventLog* parentLog, bool needAlwaysSafeAdd = false, TWriteFrameCallbackPtr writeFrameCallback = nullptr); - - virtual ~TEventLogFrame() = default; - - void Flush(); - void SafeFlush(); - - void ForceDump() { - ForceDump_ = true; - } - - template <class T> - inline void LogEvent(const T& ev) { - if (NeedAlwaysSafeAdd_) { - SafeLogEvent(ev); - } else { - UnSafeLogEvent(ev); - } - } - - template <class T> - inline void LogEvent(TEventTimestamp timestamp, const T& ev) { - if (NeedAlwaysSafeAdd_) { - SafeLogEvent(timestamp, ev); - } else { - UnSafeLogEvent(timestamp, ev); - } - } - - template <class T> - inline void UnSafeLogEvent(const T& ev) { - if (!IsEventIgnored(ev.ID)) - LogProtobufEvent(ev.ID, ev); - } - - template <class T> - inline void UnSafeLogEvent(TEventTimestamp timestamp, const T& ev) { - if (!IsEventIgnored(ev.ID)) - LogProtobufEvent(timestamp, ev.ID, ev); - } - - template <class T> - inline void SafeLogEvent(const T& ev) { - if (!IsEventIgnored(ev.ID)) { - TGuard<TMutex> g(Mtx_); - LogProtobufEvent(ev.ID, ev); - } - } - - template <class T> - inline void SafeLogEvent(TEventTimestamp timestamp, const T& ev) { - if (!IsEventIgnored(ev.ID)) { - TGuard<TMutex> g(Mtx_); - LogProtobufEvent(timestamp, ev.ID, ev); - } - } - - void VisitEvents(ILogFrameEventVisitor& visitor, IEventFactory* eventFactory); - - inline bool IsEventIgnored(size_t eventId) const { - Y_UNUSED(eventId); // in future we might want to selectively discard only some kinds of messages - return !IsDebugModeEnabled() && EvLog_ == nullptr && !ForceDump_; - } - - void Enable(IEventLog& evLog) { - EvLog_ = &evLog; - } - - void Disable() { - EvLog_ = nullptr; - } - - void SetNeedAlwaysSafeAdd(bool val) { - NeedAlwaysSafeAdd_ = val; - } - - void SetWriteFrameCallback(TWriteFrameCallbackPtr writeFrameCallback) { - WriteFrameCallback_ = writeFrameCallback; - } - - void AddMetaFlag(const TString& key, const TString& value) { - if (NeedAlwaysSafeAdd_) { - TGuard<TMutex> g(Mtx_); - MetaFlags_.emplace_back(key, value); - } else { - MetaFlags_.emplace_back(key, value); - } - } - -protected: - void LogProtobufEvent(size_t eventId, const NProtoBuf::Message& ev); - void LogProtobufEvent(TEventTimestamp timestamp, size_t eventId, const NProtoBuf::Message& ev); - -private: - static bool IsDebugModeEnabled() { - static struct TSelector { - bool Flag; - - TSelector() - : Flag(GetEnv("EVLOG_DEBUG") == TStringBuf("1")) - { - } - } selector; - - return selector.Flag; - } - - template <class T> - void DebugDump(const T& ev); - - // T must be a descendant of NEvClass::TEvent - template <class T> - inline void LogEventImpl(const T& ev) { - if (EvLog_ != nullptr || ForceDump_) { - TBuffer& b = Buf_.Buffer(); - size_t lastSize = b.size(); - ::Save(&Buf_, ui32(0)); - ev.FullSaveToBuffer(Buf_); - WriteUnaligned<ui32>(b.data() + lastSize, (ui32)(b.size() - lastSize)); - AddEvent(ev.Timestamp); - } - - if (IsDebugModeEnabled()) { - DebugDump(ev); - } - } - - void AddEvent(TEventTimestamp timestamp); - void DoInit(); - -private: - TBufferOutput Buf_; - TEventTimestamp StartTimestamp_, EndTimestamp_; - IEventLog* EvLog_; - TMutex Mtx_; - bool NeedAlwaysSafeAdd_; - bool ForceDump_; - TWriteFrameCallbackPtr WriteFrameCallback_; - TLogRecord::TMetaFlags MetaFlags_; - friend class TEventRecord; -}; - -class TSelfFlushLogFrame: public TEventLogFrame, public TAtomicRefCount<TSelfFlushLogFrame> { -public: - TSelfFlushLogFrame(bool needAlwaysSafeAdd = false, TWriteFrameCallbackPtr writeFrameCallback = nullptr); - TSelfFlushLogFrame(IEventLog& parentLog, bool needAlwaysSafeAdd = false, TWriteFrameCallbackPtr writeFrameCallback = nullptr); - TSelfFlushLogFrame(IEventLog* parentLog, bool needAlwaysSafeAdd = false, TWriteFrameCallbackPtr writeFrameCallback = nullptr); - - virtual ~TSelfFlushLogFrame(); -}; - -using TSelfFlushLogFramePtr = TIntrusivePtr<TSelfFlushLogFrame>; - -class IEventLog: public TAtomicRefCount<IEventLog> { -public: - class IErrorCallback { - public: - virtual ~IErrorCallback() { - } - - virtual void OnWriteError() = 0; - }; - - class ISuccessCallback { - public: - virtual ~ISuccessCallback() { - } - - virtual void OnWriteSuccess(const TBuffer& frameData) = 0; - }; - - virtual ~IEventLog(); - - virtual void ReopenLog() = 0; - virtual void CloseLog() = 0; - virtual void Flush() = 0; - virtual void SetErrorCallback(IErrorCallback*) { - } - virtual void SetSuccessCallback(ISuccessCallback*) { - } - - template <class T> - void LogEvent(const T& ev) { - TEventLogFrame frame(*this); - frame.LogEvent(ev); - frame.Flush(); - } - - virtual bool HasNullBackend() const = 0; - - virtual void WriteFrame(TBuffer& buffer, - TEventTimestamp startTimestamp, - TEventTimestamp endTimestamp, - TWriteFrameCallbackPtr writeFrameCallback = nullptr, - TLogRecord::TMetaFlags metaFlags = {}) = 0; -}; - -struct TEventLogBackendOptions { - bool UseSyncPageCacheBackend = false; - size_t SyncPageCacheBackendBufferSize = 0; - size_t SyncPageCacheBackendMaxPendingSize = 0; -}; - -class TEventLog: public IEventLog { -public: - /* - * Параметр contentformat указывает формат контента лога, например какие могут в логе - * встретится классы событий, какие параметры у этих событий, и пр. Старший байт параметра - * должен быть нулевым. - */ - TEventLog(const TString& fileName, TEventLogFormat contentFormat, const TEventLogBackendOptions& backendOpts, TMaybe<TEventLogFormat> logFormat); - TEventLog(const TString& fileName, TEventLogFormat contentFormat, const TEventLogBackendOptions& backendOpts = {}); - TEventLog(const TLog& log, TEventLogFormat contentFormat, TEventLogFormat logFormat = COMPRESSED_LOG_FORMAT_V4); - TEventLog(TEventLogFormat contentFormat, TEventLogFormat logFormat = COMPRESSED_LOG_FORMAT_V4); - - ~TEventLog() override; - - void ReopenLog() override; - void CloseLog() override; - void Flush() override; - void SetErrorCallback(IErrorCallback* errorCallback) override { - ErrorCallback_ = errorCallback; - } - void SetSuccessCallback(ISuccessCallback* successCallback) override { - SuccessCallback_ = successCallback; - } - - template <class T> - void LogEvent(const T& ev) { - TEventLogFrame frame(*this); - frame.LogEvent(ev); - frame.Flush(); - } - - bool HasNullBackend() const override { - return HasNullBackend_; - } - - void WriteFrame(TBuffer& buffer, - TEventTimestamp startTimestamp, - TEventTimestamp endTimestamp, - TWriteFrameCallbackPtr writeFrameCallback = nullptr, - TLogRecord::TMetaFlags metaFlags = {}) override; - -private: - mutable TLog Log_; - TEventLogFormat ContentFormat_; - const TEventLogFormat LogFormat_; - bool HasNullBackend_; - const NBlockCodecs::ICodec* const Lz4hcCodec_; - const NBlockCodecs::ICodec* const ZstdCodec_; - IErrorCallback* ErrorCallback_ = nullptr; - ISuccessCallback* SuccessCallback_ = nullptr; -}; - -using TEventLogPtr = TIntrusivePtr<IEventLog>; - -class TEventLogWithSlave: public IEventLog { -public: - TEventLogWithSlave(IEventLog& parentLog) - : Slave_(&parentLog) - { - } - - TEventLogWithSlave(const TEventLogPtr& parentLog) - : SlavePtr_(parentLog) - , Slave_(SlavePtr_.Get()) - { - } - - ~TEventLogWithSlave() override { - try { - Slave().Flush(); - } catch (...) { - } - } - - void Flush() override { - Slave().Flush(); - } - - void ReopenLog() override { - return Slave().ReopenLog(); - } - void CloseLog() override { - return Slave().CloseLog(); - } - - bool HasNullBackend() const override { - return Slave().HasNullBackend(); - } - - void WriteFrame(TBuffer& buffer, - TEventTimestamp startTimestamp, - TEventTimestamp endTimestamp, - TWriteFrameCallbackPtr writeFrameCallback = nullptr, - TLogRecord::TMetaFlags metaFlags = {}) override { - Slave().WriteFrame(buffer, startTimestamp, endTimestamp, writeFrameCallback, std::move(metaFlags)); - } - - void SetErrorCallback(IErrorCallback* errorCallback) override { - Slave().SetErrorCallback(errorCallback); - } - - void SetSuccessCallback(ISuccessCallback* successCallback) override { - Slave().SetSuccessCallback(successCallback); - } - -protected: - inline IEventLog& Slave() const { - return *Slave_; - } - -private: - TEventLogPtr SlavePtr_; - IEventLog* Slave_ = nullptr; -}; - -extern TAtomic eventlogFrameCounter; - -class TProtobufEventProcessor: public IEventProcessor { -public: - void ProcessEvent(const TEvent* ev) override final { - ProcessEvent(ev, &Cout); - } - - void ProcessEvent(const TEvent* ev, IOutputStream *out) { - UpdateEventState(ev); - DoProcessEvent(ev, out); - EventState_.PrevEventTime = ev->Timestamp; - } -protected: - virtual void DoProcessEvent(const TEvent * ev, IOutputStream *out) { - ev->Print(*out, Options_, EventState_); - (*out) << Endl; - } - ui32 CurrentFrameId_ = Max<ui32>(); - TEvent::TEventState EventState_; - -private: - void UpdateEventState(const TEvent *ev) { - if (ev->FrameId != CurrentFrameId_) { - EventState_.FrameStartTime = ev->Timestamp; - EventState_.PrevEventTime = ev->Timestamp; - CurrentFrameId_ = ev->FrameId; - } - } -}; - -class TProtobufEventFactory: public IEventFactory { -public: - TProtobufEventFactory(NProtoBuf::TEventFactory* factory = NProtoBuf::TEventFactory::Instance()) - : EventFactory_(factory) - { - } - - TEvent* CreateLogEvent(TEventClass c) override; - - TEventLogFormat CurrentFormat() override { - return 0; - } - - TEventClass ClassByName(TStringBuf name) const override; - - TEventClass EventClassBegin() const override; - - TEventClass EventClassEnd() const override; - - ~TProtobufEventFactory() override = default; - -private: - NProtoBuf::TEventFactory* EventFactory_; -}; - -THolder<TEvent> MakeProtobufLogEvent(TEventTimestamp ts, TEventClass eventId, google::protobuf::Message& ev); - -namespace NEvClass { - IEventFactory* Factory(); - IEventProcessor* Processor(); -} diff --git a/library/cpp/eventlog/eventlog_int.cpp b/library/cpp/eventlog/eventlog_int.cpp deleted file mode 100644 index faa8c42cbe..0000000000 --- a/library/cpp/eventlog/eventlog_int.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "eventlog_int.h" - -#include <util/string/cast.h> - -TMaybe<TEventLogFormat> ParseEventLogFormat(TStringBuf str) { - EEventLogFormat format; - if (TryFromString(str, format)) { - return static_cast<TEventLogFormat>(format); - } else { - return {}; - } -} diff --git a/library/cpp/eventlog/eventlog_int.h b/library/cpp/eventlog/eventlog_int.h deleted file mode 100644 index eb00fecfab..0000000000 --- a/library/cpp/eventlog/eventlog_int.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include <util/stream/output.h> -#include <util/generic/maybe.h> -#include <util/generic/utility.h> -#include <util/generic/yexception.h> -#include <util/ysaveload.h> - -using TEventClass = ui32; -using TEventLogFormat = ui32; -using TEventTimestamp = ui64; - -constexpr TStringBuf COMPRESSED_LOG_FRAME_SYNC_DATA = - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\xfe\x00\x00\xff\xff\x00\x00\xff\xff\x00" - "\x00\xff\xff\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00\xff" - "\xff\x00\x00\xff\xff\x00\x00\xff"sv; - -static_assert(COMPRESSED_LOG_FRAME_SYNC_DATA.size() == 64); - -/* - * Коды форматов логов. Форматом лога считается формат служебных - * структур лога. К примеру формат заголовка, наличие компрессии, и т.д. - * Имеет значение только 1 младший байт. - */ - -enum EEventLogFormat : TEventLogFormat { - // Формат версии 1. Используется компрессор LZQ. - COMPRESSED_LOG_FORMAT_V1 = 1, - - // Формат версии 2. Используется компрессор ZLIB. Добавлены CRC заголовка и данных, - // поле типа компрессора. - COMPRESSED_LOG_FORMAT_V2 = 2, - - // Формат версии 3. Используется компрессор ZLIB. В начинке фреймов перед каждым событием добавлен его размер. - COMPRESSED_LOG_FORMAT_V3 = 3, - - // Lz4hc codec + zlib - COMPRESSED_LOG_FORMAT_V4 = 4 /* "zlib_lz4" */, - - // zstd - COMPRESSED_LOG_FORMAT_V5 = 5 /* "zstd" */, -}; - -TMaybe<TEventLogFormat> ParseEventLogFormat(TStringBuf str); - -#pragma pack(push, 1) - -struct TCompressedFrameBaseHeader { - TEventLogFormat Format; - ui32 Length; // Длина остатка фрейма в байтах, после этого заголовка - ui32 FrameId; -}; - -struct TCompressedFrameHeader { - TEventTimestamp StartTimestamp; - TEventTimestamp EndTimestamp; - ui32 UncompressedDatalen; // Длина данных, которые были закомпрессированы - ui32 PayloadChecksum; // В логе версии 1 поле не используется -}; - -struct TCompressedFrameHeader2: public TCompressedFrameHeader { - ui8 CompressorVersion; // Сейчас не используется - ui32 HeaderChecksum; -}; - -#pragma pack(pop) - -Y_DECLARE_PODTYPE(TCompressedFrameBaseHeader); -Y_DECLARE_PODTYPE(TCompressedFrameHeader); -Y_DECLARE_PODTYPE(TCompressedFrameHeader2); diff --git a/library/cpp/eventlog/events_extension.h b/library/cpp/eventlog/events_extension.h deleted file mode 100644 index 0cf062f959..0000000000 --- a/library/cpp/eventlog/events_extension.h +++ /dev/null @@ -1,161 +0,0 @@ -#pragma once - -#include "event_field_output.h" - -#include <google/protobuf/descriptor.h> -#include <google/protobuf/message.h> - -#include <library/cpp/threading/atomic/bool.h> -#include <library/cpp/string_utils/base64/base64.h> - -#include <util/generic/map.h> -#include <util/generic/deque.h> -#include <util/generic/singleton.h> -#include <util/string/hex.h> -#include <util/system/guard.h> -#include <util/system/mutex.h> - -namespace NProtoBuf { - class TEventFactory { - public: - typedef ::google::protobuf::Message Message; - typedef void (*TEventSerializer)(const Message* event, IOutputStream& output, EFieldOutputFlags flags); - typedef void (*TRegistrationFunc)(); - - private: - class TFactoryItem { - public: - TFactoryItem(const Message* prototype, const TEventSerializer serializer) - : Prototype_(prototype) - , Serializer_(serializer) - { - } - - TStringBuf GetName() const { - return Prototype_->GetDescriptor()->name(); - } - - Message* Create() const { - return Prototype_->New(); - } - - void PrintEvent(const Message* event, IOutputStream& out, EFieldOutputFlags flags) const { - (*Serializer_)(event, out, flags); - } - - private: - const Message* Prototype_; - const TEventSerializer Serializer_; - }; - - typedef TMap<size_t, TFactoryItem> TFactoryMap; - - public: - TEventFactory() - : FactoryItems_() - { - } - - void ScheduleRegistration(TRegistrationFunc func) { - EventRegistrators_.push_back(func); - } - - void RegisterEvent(size_t eventId, const Message* prototype, const TEventSerializer serializer) { - FactoryItems_.insert(std::make_pair(eventId, TFactoryItem(prototype, serializer))); - } - - size_t IdByName(TStringBuf eventname) { - DelayedRegistration(); - for (TFactoryMap::const_iterator it = FactoryItems_.begin(); it != FactoryItems_.end(); ++it) { - if (it->second.GetName() == eventname) - return it->first; - } - - ythrow yexception() << "do not know event '" << eventname << "'"; - } - - TStringBuf NameById(size_t id) { - DelayedRegistration(); - TFactoryMap::const_iterator it = FactoryItems_.find(id); - return it != FactoryItems_.end() ? it->second.GetName() : TStringBuf(); - } - - Message* CreateEvent(size_t eventId) { - DelayedRegistration(); - TFactoryMap::const_iterator it = FactoryItems_.find(eventId); - - if (it != FactoryItems_.end()) { - return it->second.Create(); - } - - return nullptr; - } - - const TMap<size_t, TFactoryItem>& FactoryItems() { - DelayedRegistration(); - return FactoryItems_; - } - - void PrintEvent( - size_t eventId, - const Message* event, - IOutputStream& output, - EFieldOutputFlags flags = {}) { - DelayedRegistration(); - TFactoryMap::const_iterator it = FactoryItems_.find(eventId); - - if (it != FactoryItems_.end()) { - it->second.PrintEvent(event, output, flags); - } - } - - static TEventFactory* Instance() { - return Singleton<TEventFactory>(); - } - - private: - void DelayedRegistration() { - if (!DelayedRegistrationDone_) { - TGuard<TMutex> guard(MutexEventRegistrators_); - Y_UNUSED(guard); - while (!EventRegistrators_.empty()) { - EventRegistrators_.front()(); - EventRegistrators_.pop_front(); - } - DelayedRegistrationDone_ = true; - } - } - - private: - TMap<size_t, TFactoryItem> FactoryItems_; - TDeque<TRegistrationFunc> EventRegistrators_; - NAtomic::TBool DelayedRegistrationDone_ = false; - TMutex MutexEventRegistrators_; - }; - - template <typename T> - void PrintAsBytes(const T& obj, IOutputStream& output) { - const ui8* b = reinterpret_cast<const ui8*>(&obj); - const ui8* e = b + sizeof(T); - const char* delim = ""; - - while (b != e) { - output << delim; - output << (int)*b++; - delim = "."; - } - } - - template <typename T> - void PrintAsHex(const T& obj, IOutputStream& output) { - output << "0x"; - output << HexEncode(&obj, sizeof(T)); - } - - inline void PrintAsBase64(TStringBuf data, IOutputStream& output) { - if (!data.empty()) { - output << Base64Encode(data); - } - } - -} diff --git a/library/cpp/eventlog/iterator.cpp b/library/cpp/eventlog/iterator.cpp deleted file mode 100644 index 71f955bca8..0000000000 --- a/library/cpp/eventlog/iterator.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "iterator.h" - -#include <library/cpp/streams/growing_file_input/growing_file_input.h> - -#include <util/string/cast.h> -#include <util/string/split.h> -#include <util/string/type.h> -#include <util/stream/file.h> - -using namespace NEventLog; - -namespace { - inline TIntrusivePtr<TEventFilter> ConstructEventFilter(bool enableEvents, const TString& evList, IEventFactory* fac) { - if (evList.empty()) { - return nullptr; - } - - TVector<TString> events; - - StringSplitter(evList).Split(',').SkipEmpty().Collect(&events); - if (events.empty()) { - return nullptr; - } - - TIntrusivePtr<TEventFilter> filter(new TEventFilter(enableEvents)); - - for (const auto& event : events) { - if (IsNumber(event)) - filter->AddEventClass(FromString<size_t>(event)); - else - filter->AddEventClass(fac->ClassByName(event)); - } - - return filter; - } - - struct TIterator: public IIterator { - inline TIterator(const TOptions& o, IEventFactory* fac) - : First(true) - { - if (o.FileName.size()) { - if (o.ForceStreamMode || o.TailFMode) { - FileInput.Reset(o.TailFMode ? (IInputStream*)new TGrowingFileInput(o.FileName) : (IInputStream*)new TUnbufferedFileInput(o.FileName)); - FrameStream.Reset(new TFrameStreamer(*FileInput, fac, o.FrameFilter)); - } else { - FrameStream.Reset(new TFrameStreamer(o.FileName, o.StartTime, o.EndTime, o.MaxRequestDuration, fac, o.FrameFilter)); - } - } else { - FrameStream.Reset(new TFrameStreamer(*o.Input, fac, o.FrameFilter)); - } - - EvFilter = ConstructEventFilter(o.EnableEvents, o.EvList, fac); - EventStream.Reset(new TEventStreamer(*FrameStream, o.StartTime, o.EndTime, o.ForceStrongOrdering, EvFilter, o.ForceLosslessStrongOrdering)); - } - - TConstEventPtr Next() override { - if (First) { - First = false; - - if (!EventStream->Avail()) { - return nullptr; - } - } else { - if (!EventStream->Next()) { - return nullptr; - } - } - - return **EventStream; - } - - THolder<IInputStream> FileInput; - THolder<TFrameStreamer> FrameStream; - TIntrusivePtr<TEventFilter> EvFilter; - THolder<TEventStreamer> EventStream; - bool First; - }; -} - -IIterator::~IIterator() = default; - -THolder<IIterator> NEventLog::CreateIterator(const TOptions& o, IEventFactory* fac) { - return MakeHolder<TIterator>(o, fac); -} - -THolder<IIterator> NEventLog::CreateIterator(const TOptions& o) { - return MakeHolder<TIterator>(o, NEvClass::Factory()); -} diff --git a/library/cpp/eventlog/iterator.h b/library/cpp/eventlog/iterator.h deleted file mode 100644 index 71a61ed549..0000000000 --- a/library/cpp/eventlog/iterator.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include <util/stream/input.h> -#include <util/generic/ptr.h> -#include <util/generic/string.h> -#include <util/generic/iterator.h> - -#include "eventlog.h" -#include "logparser.h" - -namespace NEventLog { - struct TOptions { - inline TOptions& SetFileName(const TString& fileName) { - FileName = fileName; - - return *this; - } - - inline TOptions& SetForceStrongOrdering(bool v) { - if(!ForceLosslessStrongOrdering) { - ForceStrongOrdering = v; - } - - return *this; - } - - ui64 StartTime = MIN_START_TIME; - ui64 EndTime = MAX_END_TIME; - ui64 MaxRequestDuration = MAX_REQUEST_DURATION; - TString FileName; - bool ForceStrongOrdering = false; - bool ForceWeakOrdering = false; - bool EnableEvents = true; - TString EvList; - bool ForceStreamMode = false; - bool ForceLosslessStrongOrdering = false; - bool TailFMode = false; - IInputStream* Input = &Cin; - IFrameFilterRef FrameFilter; - }; - - class IIterator: public TInputRangeAdaptor<IIterator> { - public: - virtual ~IIterator(); - - virtual TConstEventPtr Next() = 0; - }; - - THolder<IIterator> CreateIterator(const TOptions& o); - THolder<IIterator> CreateIterator(const TOptions& o, IEventFactory* fac); -} diff --git a/library/cpp/eventlog/logparser.cpp b/library/cpp/eventlog/logparser.cpp deleted file mode 100644 index 6f8959f788..0000000000 --- a/library/cpp/eventlog/logparser.cpp +++ /dev/null @@ -1,814 +0,0 @@ -#include "logparser.h" -#include "evdecoder.h" - -#include <util/stream/output.h> -#include <util/stream/zlib.h> -#include <util/digest/murmur.h> -#include <util/generic/algorithm.h> -#include <util/generic/scope.h> -#include <util/generic/hash_set.h> -#include <util/string/split.h> -#include <util/string/cast.h> -#include <util/string/escape.h> -#include <util/string/builder.h> - -#include <contrib/libs/re2/re2/re2.h> - -#include <algorithm> -#include <array> - -namespace { - bool FastforwardUntilSyncHeader(IInputStream* in) { - // Usually this function finds the correct header at the first hit - std::array<char, COMPRESSED_LOG_FRAME_SYNC_DATA.size()> buffer; - if (in->Load(buffer.data(), buffer.size()) != buffer.size()) { - return false; - } - - auto begin = buffer.begin(); - - for (;;) { - if (std::mismatch( - begin, buffer.end(), - COMPRESSED_LOG_FRAME_SYNC_DATA.begin()).first == buffer.end() && - std::mismatch( - buffer.begin(), begin, - COMPRESSED_LOG_FRAME_SYNC_DATA.begin() + (buffer.end() - begin)).first == begin) { - return true; - } - if (!in->ReadChar(*begin)) { - return false; - } - ++begin; - if (begin == buffer.end()) { - begin = buffer.begin(); - } - } - } - - bool HasCorrectChecksum(const TFrameHeader& header) { - // Calculating hash over all the fields of the read header except for the field with the hash of the header itself. - const size_t baseSize = sizeof(TCompressedFrameBaseHeader) + sizeof(TCompressedFrameHeader2) - sizeof(ui32); - const ui32 checksum = MurmurHash<ui32>(&header.Basehdr, baseSize); - return checksum == header.Framehdr.HeaderChecksum; - } - - TMaybe<TFrameHeader> FindNextFrameHeader(IInputStream* in) { - for (;;) { - if (FastforwardUntilSyncHeader(in)) { - try { - return TFrameHeader(*in); - } catch (const TFrameLoadError& err) { - Cdbg << err.what() << Endl; - in->Skip(err.SkipAfter); - } - } else { - return Nothing(); - } - } - } - - std::pair<TMaybe<TFrameHeader>, TStringBuf> FindNextFrameHeader(TStringBuf span) { - for (;;) { - auto iter = std::search( - span.begin(), span.end(), - COMPRESSED_LOG_FRAME_SYNC_DATA.begin(), COMPRESSED_LOG_FRAME_SYNC_DATA.end()); - const size_t offset = iter - span.begin(); - - if (offset != span.size()) { - span = span.substr(offset); - try { - TMemoryInput in( - span.data() + COMPRESSED_LOG_FRAME_SYNC_DATA.size(), - span.size() - COMPRESSED_LOG_FRAME_SYNC_DATA.size()); - return {TFrameHeader(in), span}; - } catch (const TFrameLoadError& err) { - Cdbg << err.what() << Endl; - span = span.substr(err.SkipAfter); - } - } else { - return {Nothing(), {}}; - } - } - } - - size_t FindFrames(const TStringBuf span, ui64 start, ui64 end, ui64 maxRequestDuration) { - Y_ENSURE(start <= end); - - const auto leftTimeBound = start - Min(start, maxRequestDuration); - const auto rightTimeBound = end + Min(maxRequestDuration, Max<ui64>() - end); - - TStringBuf subspan = span; - TMaybe<TFrameHeader> maybeLeftFrame; - std::tie(maybeLeftFrame, subspan) = FindNextFrameHeader(subspan); - - if (!maybeLeftFrame || maybeLeftFrame->EndTime() > rightTimeBound) { - return span.size(); - } - - if (maybeLeftFrame->StartTime() > leftTimeBound) { - return 0; - } - - while (subspan.size() > maybeLeftFrame->FullLength()) { - const auto mid = subspan.data() + subspan.size() / 2; - auto [midFrame, rightHalfSpan] = FindNextFrameHeader({mid, subspan.data() + subspan.size()}); - if (!midFrame) { - // If mid is in the middle of the last frame, here we will lose it meaning that - // we will find previous frame as the result. - // This is fine because we will iterate frames starting from that. - subspan = subspan.substr(0, subspan.size() / 2); - continue; - } - if (midFrame->StartTime() <= leftTimeBound) { - maybeLeftFrame = midFrame; - subspan = rightHalfSpan; - } else { - subspan = subspan.substr(0, subspan.size() / 2); - } - } - - return subspan.data() - span.data(); - } -} - -TFrameHeader::TFrameHeader(IInputStream& in) { - try { - ::Load(&in, Basehdr); - - Y_ENSURE(Basehdr.Length, "Empty frame additional data"); - - ::Load(&in, Framehdr); - switch (LogFormat()) { - case COMPRESSED_LOG_FORMAT_V1: - break; - - case COMPRESSED_LOG_FORMAT_V2: - case COMPRESSED_LOG_FORMAT_V3: - case COMPRESSED_LOG_FORMAT_V4: - case COMPRESSED_LOG_FORMAT_V5: - Y_ENSURE(!Framehdr.CompressorVersion, "Wrong compressor"); - - Y_ENSURE(HasCorrectChecksum(*this), "Wrong header checksum"); - break; - - default: - ythrow yexception() << "Unsupported log structure format"; - }; - - Y_ENSURE(Framehdr.StartTimestamp <= Framehdr.EndTimestamp, "Wrong start/end timestamps"); - - // Each frame must contain at least one event. - Y_ENSURE(Framehdr.UncompressedDatalen, "Empty frame payload"); - } catch (...) { - TString location = ""; - if (const auto* cnt = dynamic_cast<TCountingInput *>(&in)) { - location = "@ " + ToString(cnt->Counter()); - } - ythrow TFrameLoadError(FrameLength()) << "Frame Load Error" << location << ": " << CurrentExceptionMessage(); - } -} - -TFrame::TFrame(IInputStream& in, TFrameHeader header, IEventFactory* fac) - : TFrameHeader(header) - , Limiter_(MakeHolder<TLengthLimitedInput>(&in, header.FrameLength())) - , Fac_(fac) -{ - if (auto* cnt = dynamic_cast<TCountingInput *>(&in)) { - Address_ = cnt->Counter() - sizeof(TFrameHeader); - } else { - Address_ = 0; - } -} - -TFrame::TIterator TFrame::GetIterator(TIntrusiveConstPtr<TEventFilter> eventFilter) const { - if (EventsCache_.empty()) { - for (TFrameDecoder decoder{*this, eventFilter.Get()}; decoder.Avail(); decoder.Next()) { - EventsCache_.emplace_back(*decoder); - } - } - - return TIterator(*this, eventFilter); -} - -void TFrame::ClearEventsCache() const { - EventsCache_.clear(); -} - -TString TFrame::GetCompressedFrame() const { - const auto left = Limiter_->Left(); - TString payload = Limiter_->ReadAll(); - Y_ENSURE(payload.size() == left, "Could not read frame payload: premature end of stream"); - const ui32 checksum = MurmurHash<ui32>(payload.data(), payload.size()); - Y_ENSURE(checksum == Framehdr.PayloadChecksum, "Invalid frame checksum"); - - return payload; -} - -TString TFrame::GetRawFrame() const { - TString frameBuf = GetCompressedFrame(); - TStringInput sin(frameBuf); - return TZLibDecompress{&sin}.ReadAll(); -} - -TFrame::TIterator::TIterator(const TFrame& frame, TIntrusiveConstPtr<TEventFilter> filter) - : Frame_(frame) - , Size_(frame.EventsCache_.size()) - , Filter_(filter) - , Index_(0) -{ - SkipToValidEvent(); -} - -TConstEventPtr TFrame::TIterator::operator*() const { - return Frame_.GetEvent(Index_); -} - -bool TFrame::TIterator::Next() { - Index_++; - SkipToValidEvent(); - return Index_ < Size_; -} - -void TFrame::TIterator::SkipToValidEvent() { - if (!Filter_) { - return; - } - - for (; Index_ < Size_; ++Index_) { - if (Filter_->EventAllowed(Frame_.GetEvent(Index_)->Class)) { - break; - } - } -} - -TMaybe<TFrame> FindNextFrame(IInputStream* in, IEventFactory* eventFactory) { - if (auto header = FindNextFrameHeader(in)) { - return TFrame{*in, *header, eventFactory}; - } else { - return Nothing(); - } -} - -TContainsEventFrameFilter::TContainsEventFrameFilter(const TString& unparsedMatchGroups, const IEventFactory* eventFactory) { - TVector<TStringBuf> tokens; - - SplitWithEscaping(tokens, unparsedMatchGroups, "/"); - - // Amount of match groups - size_t size = tokens.size(); - MatchGroups.resize(size); - - for (size_t i = 0; i < size; i++) { - TMatchGroup& group = MatchGroups[i]; - TVector<TStringBuf> groupTokens; - SplitWithEscaping(groupTokens, tokens[i], ":"); - - Y_ENSURE(groupTokens.size() == 3); - - try { - group.EventID = eventFactory->ClassByName(groupTokens[0]); - } catch (yexception& e) { - if (!TryFromString<TEventClass>(groupTokens[0], group.EventID)) { - e << "\nAppend:\n" << "Cannot derive EventId from EventType: " << groupTokens[0]; - throw e; - } - } - - group.FieldName = groupTokens[1]; - group.ValueToMatch = UnescapeCharacters(groupTokens[2], "/:"); - } -} - -bool TContainsEventFrameFilter::FrameAllowed(const TFrame& frame) const { - THashSet<size_t> toMatchSet; - for (size_t i = 0; i < MatchGroups.size(); i++) { - toMatchSet.insert(i); - } - - for (auto it = frame.GetIterator(); it.Avail(); it.Next()) { - TConstEventPtr event(*it); - TVector<size_t> indicesToErase; - - if (!toMatchSet.empty()) { - const NProtoBuf::Message* message = event->GetProto(); - const google::protobuf::Descriptor* descriptor = message->GetDescriptor(); - const google::protobuf::Reflection* reflection = message->GetReflection(); - - Y_ENSURE(descriptor); - Y_ENSURE(reflection); - - for (size_t groupIndex : toMatchSet) { - const TMatchGroup& group = MatchGroups[groupIndex]; - - if (event->Class == group.EventID) { - TVector<TString> parts = StringSplitter(group.FieldName).Split('.').ToList<TString>(); - TString lastPart = std::move(parts.back()); - parts.pop_back(); - - for (auto part : parts) { - auto fieldDescriptor = descriptor->FindFieldByName(part); - Y_ENSURE(fieldDescriptor, "Cannot find field \"" + part + "\". Full fieldname is \"" + group.FieldName + "\"."); - - message = &reflection->GetMessage(*message, fieldDescriptor); - descriptor = message->GetDescriptor(); - reflection = message->GetReflection(); - - Y_ENSURE(descriptor); - Y_ENSURE(reflection); - } - - const google::protobuf::FieldDescriptor* fieldDescriptor = descriptor->FindFieldByName(lastPart); - Y_ENSURE(fieldDescriptor, "Cannot find field \"" + lastPart + "\". Full fieldname is \"" + group.FieldName + "\"."); - - TString fieldValue = GetEventFieldAsString(message, fieldDescriptor, reflection); - if (re2::RE2::FullMatch(fieldValue, group.ValueToMatch)) { - indicesToErase.push_back(groupIndex); - } - } - } - - for (size_t idx : indicesToErase) { - toMatchSet.erase(idx); - } - - if (toMatchSet.empty()) { - return true; - } - } - } - - return toMatchSet.empty(); -} - -void SplitWithEscaping(TVector<TStringBuf>& tokens, const TStringBuf& stringToSplit, const TStringBuf& externalCharacterSet) { - size_t tokenStart = 0; - const TString characterSet = TString::Join("\\", externalCharacterSet); - - for (size_t position = stringToSplit.find_first_of(characterSet); position != TString::npos; position = stringToSplit.find_first_of(characterSet, position + 1)) { - if (stringToSplit[position] == '\\') { - position++; - } else { - if (tokenStart != position) { - tokens.push_back(TStringBuf(stringToSplit, tokenStart, position - tokenStart)); - } - tokenStart = position + 1; - } - } - - if (tokenStart < stringToSplit.size()) { - tokens.push_back(TStringBuf(stringToSplit, tokenStart, stringToSplit.size() - tokenStart)); - } -} - -TString UnescapeCharacters(const TStringBuf& stringToUnescape, const TStringBuf& characterSet) { - TStringBuilder stringBuilder; - size_t tokenStart = 0; - - for (size_t position = stringToUnescape.find('\\', 0u); position != TString::npos; position = stringToUnescape.find('\\', position + 2)) { - if (position + 1 < stringToUnescape.size() && characterSet.find(stringToUnescape[position + 1]) != TString::npos) { - stringBuilder << TStringBuf(stringToUnescape, tokenStart, position - tokenStart); - tokenStart = position + 1; - } - } - - if (tokenStart < stringToUnescape.size()) { - stringBuilder << TStringBuf(stringToUnescape, tokenStart, stringToUnescape.size() - tokenStart); - } - - return stringBuilder; -} - -TString GetEventFieldAsString(const NProtoBuf::Message* message, const google::protobuf::FieldDescriptor* fieldDescriptor, const google::protobuf::Reflection* reflection) { - Y_ENSURE(message); - Y_ENSURE(fieldDescriptor); - Y_ENSURE(reflection); - - TString result; - switch (fieldDescriptor->type()) { - case google::protobuf::FieldDescriptor::Type::TYPE_DOUBLE: - result = ToString(reflection->GetDouble(*message, fieldDescriptor)); - break; - case google::protobuf::FieldDescriptor::Type::TYPE_FLOAT: - result = ToString(reflection->GetFloat(*message, fieldDescriptor)); - break; - case google::protobuf::FieldDescriptor::Type::TYPE_BOOL: - result = ToString(reflection->GetBool(*message, fieldDescriptor)); - break; - case google::protobuf::FieldDescriptor::Type::TYPE_INT32: - result = ToString(reflection->GetInt32(*message, fieldDescriptor)); - break; - case google::protobuf::FieldDescriptor::Type::TYPE_UINT32: - result = ToString(reflection->GetUInt32(*message, fieldDescriptor)); - break; - case google::protobuf::FieldDescriptor::Type::TYPE_INT64: - result = ToString(reflection->GetInt64(*message, fieldDescriptor)); - break; - case google::protobuf::FieldDescriptor::Type::TYPE_UINT64: - result = ToString(reflection->GetUInt64(*message, fieldDescriptor)); - break; - case google::protobuf::FieldDescriptor::Type::TYPE_STRING: - result = ToString(reflection->GetString(*message, fieldDescriptor)); - break; - case google::protobuf::FieldDescriptor::Type::TYPE_ENUM: - { - const NProtoBuf::EnumValueDescriptor* enumValueDescriptor = reflection->GetEnum(*message, fieldDescriptor); - result = ToString(enumValueDescriptor->name()); - } - break; - default: - throw yexception() << "GetEventFieldAsString for type " << fieldDescriptor->type_name() << " is not implemented."; - } - return result; -} - -TFrameStreamer::TFrameStreamer(IInputStream& s, IEventFactory* fac, IFrameFilterRef ff) - : In_(&s) - , FrameFilter_(ff) - , EventFactory_(fac) -{ - Frame_ = FindNextFrame(&In_, EventFactory_); - - SkipToAllowedFrame(); -} - -TFrameStreamer::TFrameStreamer( - const TString& fileName, - ui64 startTime, - ui64 endTime, - ui64 maxRequestDuration, - IEventFactory* fac, - IFrameFilterRef ff) - : File_(TBlob::FromFile(fileName)) - , MemoryIn_(File_.Data(), File_.Size()) - , In_(&MemoryIn_) - , StartTime_(startTime) - , EndTime_(endTime) - , CutoffTime_(endTime + Min(maxRequestDuration, Max<ui64>() - endTime)) - , FrameFilter_(ff) - , EventFactory_(fac) -{ - In_.Skip(FindFrames(File_.AsStringBuf(), startTime, endTime, maxRequestDuration)); - Frame_ = FindNextFrame(&In_, fac); - SkipToAllowedFrame(); -} - -TFrameStreamer::~TFrameStreamer() = default; - -bool TFrameStreamer::Avail() const { - return Frame_.Defined(); -} - -const TFrame& TFrameStreamer::operator*() const { - Y_ENSURE(Frame_, "Frame streamer depleted"); - - return *Frame_; -} - -bool TFrameStreamer::Next() { - DoNext(); - SkipToAllowedFrame(); - - return Frame_.Defined(); -} - -bool TFrameStreamer::AllowedTimeRange(const TFrame& frame) const { - const bool allowedStartTime = (StartTime_ == 0) || ((StartTime_ <= frame.StartTime()) && (frame.StartTime() <= EndTime_)); - const bool allowedEndTime = (EndTime_ == 0) || ((StartTime_ <= frame.EndTime()) && (frame.EndTime() <= EndTime_)); - return allowedStartTime || allowedEndTime; -} - -bool TFrameStreamer::DoNext() { - if (!Frame_) { - return false; - } - In_.Skip(Frame_->Limiter_->Left()); - Frame_ = FindNextFrame(&In_, EventFactory_); - - if (Frame_ && CutoffTime_ > 0 && Frame_->EndTime() > CutoffTime_) { - Frame_.Clear(); - } - - return Frame_.Defined(); -} - -namespace { - struct TDecodeBuffer { - TDecodeBuffer(const TString codec, IInputStream& src, size_t bs) { - TBuffer from(bs); - - { - TBufferOutput b(from); - TransferData(&src, &b); - } - - NBlockCodecs::Codec(codec)->Decode(from, DecodeBuffer); - } - - explicit TDecodeBuffer(IInputStream& src) { - TBufferOutput b(DecodeBuffer); - TransferData(&src, &b); - } - - TBuffer DecodeBuffer; - }; - - class TBlockCodecStream: private TDecodeBuffer, public TBufferInput { - public: - TBlockCodecStream(const TString codec, IInputStream& src, size_t bs) - : TDecodeBuffer(codec, src, bs) - , TBufferInput(DecodeBuffer) - {} - - explicit TBlockCodecStream(IInputStream& src) - : TDecodeBuffer(src) - , TBufferInput(DecodeBuffer) - {} - }; -} - -TFrameDecoder::TFrameDecoder(const TFrame& fr, const TEventFilter* const filter, bool strict, bool withRawData) - : Frame_(fr) - , Event_(nullptr) - , Flt_(filter) - , Fac_(fr.Fac_) - , EndOfFrame_(new TEndOfFrameEvent(Frame_.EndTime())) - , Strict_(strict) - , WithRawData_(withRawData) -{ - switch (fr.LogFormat()) { - case COMPRESSED_LOG_FORMAT_V2: - case COMPRESSED_LOG_FORMAT_V3: - case COMPRESSED_LOG_FORMAT_V4: - case COMPRESSED_LOG_FORMAT_V5: { - const auto payload = fr.GetCompressedFrame(); - TMemoryInput payloadInput{payload}; - - if (fr.LogFormat() == COMPRESSED_LOG_FORMAT_V5) { - Decompressor_.Reset(new TBlockCodecStream("zstd_1", payloadInput, payload.size())); - } else { - TZLibDecompress zlib(&payloadInput); - Decompressor_.Reset(new TBlockCodecStream(zlib)); - if (fr.LogFormat() == COMPRESSED_LOG_FORMAT_V4) { - Decompressor_.Reset(new TBlockCodecStream("lz4hc", *Decompressor_, payload.size())); - } - } - - break; - } - - default: - ythrow yexception() << "unsupported log format: " << fr.LogFormat() << Endl; - break; - }; - - if (WithRawData_) { - TBufferOutput out(UncompressedData_); - TLengthLimitedInput limiter(Decompressor_.Get(), fr.Framehdr.UncompressedDatalen); - - TransferData(&limiter, &out); - Decompressor_.Reset(new TMemoryInput(UncompressedData_.data(), UncompressedData_.size())); - } - - Limiter_.Reset(new TLengthLimitedInput(Decompressor_.Get(), fr.Framehdr.UncompressedDatalen)); - - Decode(); -} - -TFrameDecoder::~TFrameDecoder() = default; - -bool TFrameDecoder::Avail() const { - return HaveData(); -} - -TConstEventPtr TFrameDecoder::operator*() const { - Y_ENSURE(HaveData(), "Decoder depleted"); - - return Event_; -} - -bool TFrameDecoder::Next() { - if (HaveData()) { - Decode(); - } - - return HaveData(); -} - -void TFrameDecoder::Decode() { - Event_ = nullptr; - const bool framed = (Frame_.LogFormat() == COMPRESSED_LOG_FORMAT_V3) || (Frame_.LogFormat() == COMPRESSED_LOG_FORMAT_V4 || Frame_.LogFormat() == COMPRESSED_LOG_FORMAT_V5); - - size_t evBegin = 0; - size_t evEnd = 0; - if (WithRawData_) - evBegin = UncompressedData_.Size() - Limiter_->Left(); - - while (Limiter_->Left() && !(Event_ = DecodeEvent(*Limiter_, framed, Frame_.Address(), Flt_, Fac_, Strict_).Release())) { - } - - if (WithRawData_) { - evEnd = UncompressedData_.Size() - Limiter_->Left(); - RawEventData_ = TStringBuf(UncompressedData_.data() + evBegin, UncompressedData_.data() + evEnd); - } - - if (!Event_ && (!Flt_ || (Flt_->EventAllowed(TEndOfFrameEvent::EventClass)))) { - Event_ = EndOfFrame_.Release(); - } - - if (!!Event_) { - Event_->FrameId = Frame_.FrameId(); - } -} - -const TStringBuf TFrameDecoder::GetRawEvent() const { - return RawEventData_; -} - -TEventStreamer::TEventStreamer(TFrameStream& fs, ui64 s, ui64 e, bool strongOrdering, TIntrusivePtr<TEventFilter> filter, bool losslessStrongOrdering) - : Frames_(fs) - , Start_(s) - , End_(e) - , MaxEndTimestamp_(0) - , Frontier_(0) - , StrongOrdering_(strongOrdering) - , LosslessStrongOrdering_(losslessStrongOrdering) - , EventFilter_(filter) -{ - - if (Start_ > End_) { - ythrow yexception() << "Wrong main interval"; - } - - TEventStreamer::Next(); -} - -TEventStreamer::~TEventStreamer() = default; - -bool TEventStreamer::Avail() const { - return Events_.Avail() && (*Events_)->Timestamp <= Frontier_; -} - -TConstEventPtr TEventStreamer::operator*() const { - Y_ENSURE(TEventStreamer::Avail(), "Event streamer depleted"); - - return *Events_; -} - -bool TEventStreamer::Next() { - if (Events_.Avail() && Events_.Next() && (*Events_)->Timestamp <= Frontier_) { - return true; - } - - for (;;) { - if (!LoadMoreEvents()) { - return false; - } - - if (TEventStreamer::Avail()) { - return true; - } - } -} - -/* -Two parameters are used in the function: -Frontier - the moment of time up to which inclusively all the log events made their way - into the buffer (and might have been already extracted out of it). -Horizon - the moment of time, that equals to Frontier + MAX_REQUEST_DURATION. -In order to get all the log events up to the Frontier inclusively, - frames need to be read until "end time" of the current frame exceeds the Horizon. -*/ -bool TEventStreamer::LoadMoreEvents() { - if (!Frames_.Avail()) { - return false; - } - - const TFrame& fr1 = *Frames_; - const ui64 maxRequestDuration = (StrongOrdering_ ? MAX_REQUEST_DURATION : 0); - - if (fr1.EndTime() <= Frontier_ + maxRequestDuration) { - ythrow yexception() << "Wrong frame stream state"; - } - - if (Frontier_ >= End_) { - return false; - } - - const ui64 old_frontier = Frontier_; - Frontier_ = fr1.EndTime(); - - { - Y_DEFER { - Events_.Reorder(StrongOrdering_); - }; - - for (; Frames_.Avail(); Frames_.Next()) { - const TFrame& fr2 = *Frames_; - - // Frames need to start later than the Frontier. - if (StrongOrdering_ && fr2.StartTime() <= old_frontier) { - Cdbg << "Invalid frame encountered" << Endl; - continue; - } - - if (fr2.EndTime() > MaxEndTimestamp_) { - MaxEndTimestamp_ = fr2.EndTime(); - } - - if (fr2.EndTime() > Frontier_ + maxRequestDuration && !LosslessStrongOrdering_) { - return true; - } - - // Checking for the frame to be within the main time borders. - if (fr2.EndTime() >= Start_ && fr2.StartTime() <= End_) { - TransferEvents(fr2); - } - } - } - - Frontier_ = MaxEndTimestamp_; - - return true; -} - -void TEventStreamer::TransferEvents(const TFrame& fr) { - Events_.SetCheckpoint(); - - try { - for (auto it = fr.GetIterator(EventFilter_); it.Avail(); it.Next()) { - TConstEventPtr ev = *it; - - if (ev->Timestamp > fr.EndTime() || ev->Timestamp < fr.StartTime()) { - ythrow TInvalidEventTimestamps() << "Event timestamp out of frame range"; - } - - if (ev->Timestamp >= Start_ && ev->Timestamp <= End_) { - Events_.Append(ev, StrongOrdering_); - } - } - } catch (const TInvalidEventTimestamps& err) { - Events_.Rollback(); - Cdbg << "EventsTransfer error: InvalidEventTimestamps: " << err.what() << Endl; - } catch (const TFrameLoadError& err) { - Events_.Rollback(); - Cdbg << "EventsTransfer error: " << err.what() << Endl; - } catch (const TEventDecoderError& err) { - Events_.Rollback(); - Cdbg << "EventsTransfer error: EventDecoder error: " << err.what() << Endl; - } catch (const TZLibDecompressorError& err) { - Events_.Rollback(); - Cdbg << "EventsTransfer error: ZLibDecompressor error: " << err.what() << Endl; - } catch (...) { - Events_.Rollback(); - throw; - } -} - -void TEventStreamer::TEventBuffer::SetCheckpoint() { - BufLen_ = Buffer_.size(); -} - -void TEventStreamer::TEventBuffer::Rollback() { - Buffer_.resize(BufLen_); -} - -void TEventStreamer::TEventBuffer::Reorder(bool strongOrdering) { - SetCheckpoint(); - - std::reverse(Buffer_.begin(), Buffer_.end()); - - if (strongOrdering) { - StableSort(Buffer_.begin(), Buffer_.end(), [&](const auto& a, const auto& b) { - return (a->Timestamp > b->Timestamp) || - ((a->Timestamp == b->Timestamp) && !a->Class && b->Class); - }); - } -} - -void TEventStreamer::TEventBuffer::Append(TConstEventPtr ev, bool strongOrdering) { - // Events in buffer output must be in an ascending order. - Y_ENSURE(!strongOrdering || ev->Timestamp >= LastTimestamp_, "Trying to append out-of-order event"); - - Buffer_.push_back(std::move(ev)); -} - -bool TEventStreamer::TEventBuffer::Avail() const { - return !Buffer_.empty(); -} - -TConstEventPtr TEventStreamer::TEventBuffer::operator*() const { - Y_ENSURE(!Buffer_.empty(), "Event buffer is empty"); - - return Buffer_.back(); -} - -bool TEventStreamer::TEventBuffer::Next() { - if (!Buffer_.empty()) { - LastTimestamp_ = Buffer_.back()->Timestamp; - Buffer_.pop_back(); - return !Buffer_.empty(); - } else { - return false; - } -} diff --git a/library/cpp/eventlog/logparser.h b/library/cpp/eventlog/logparser.h deleted file mode 100644 index f819e72589..0000000000 --- a/library/cpp/eventlog/logparser.h +++ /dev/null @@ -1,343 +0,0 @@ -#pragma once - -#include <util/generic/ptr.h> -#include <util/generic/yexception.h> -#include <util/generic/vector.h> -#include <util/generic/set.h> -#include <util/generic/maybe.h> -#include <util/memory/blob.h> -#include <util/stream/length.h> -#include <util/stream/mem.h> - -#include "eventlog_int.h" -#include "eventlog.h" -#include "common.h" - -class IInputStream; - -static const ui64 MAX_REQUEST_DURATION = 60'000'000; -static const ui64 MIN_START_TIME = MAX_REQUEST_DURATION; -static const ui64 MAX_END_TIME = ((ui64)-1) - MAX_REQUEST_DURATION; - -class TEventFilter: public TSet<TEventClass>, public TSimpleRefCount<TEventFilter> { -public: - TEventFilter(bool enableEvents) - : Enable_(enableEvents) - { - } - - void AddEventClass(TEventClass cls) { - insert(cls); - } - - bool EventAllowed(TEventClass cls) const { - bool found = (find(cls) != end()); - - return Enable_ == found; - } - -private: - bool Enable_; -}; - -using TEventStream = TPacketInputStream<TConstEventPtr>; - -struct TFrameHeader { - // Reads header from the stream. The caller must make sure that the - // sync data is present just befor the stream position. - explicit TFrameHeader(IInputStream& in); - - ui64 StartTime() const { - return Framehdr.StartTimestamp; - } - - ui64 EndTime() const { - return Framehdr.EndTimestamp; - } - - ui32 FrameId() const { - return Basehdr.FrameId; - } - - ui64 Duration() const { - return EndTime() - StartTime(); - } - - TEventLogFormat ContentFormat() const { - return Basehdr.Format & 0xffffff; - } - - TEventLogFormat LogFormat() const { - return Basehdr.Format >> 24; - } - - ui64 FrameLength() const { - return Basehdr.Length - sizeof(TCompressedFrameHeader2); - } - - // Length including the header - ui64 FullLength() const { - return sizeof(*this) + FrameLength(); - } - - TCompressedFrameBaseHeader Basehdr; - TCompressedFrameHeader2 Framehdr; -}; - -struct TFrameLoadError: public yexception { - explicit TFrameLoadError(size_t skipAfter) - : SkipAfter(skipAfter) - {} - - size_t SkipAfter; -}; - -class TFrame : public TFrameHeader { -public: - // Reads the frame after the header has been read. - TFrame(IInputStream& in, TFrameHeader header, IEventFactory*); - - TString GetRawFrame() const; - TString GetCompressedFrame() const; - - ui64 Address() const { return Address_; } - -private: - const TConstEventPtr& GetEvent(size_t index) const { - return EventsCache_[index]; - } - - void ClearEventsCache() const; - - THolder<TLengthLimitedInput> Limiter_; - mutable TVector<TConstEventPtr> EventsCache_; - - IEventFactory* Fac_; - ui64 Address_; - - friend class TFrameDecoder; - friend class TFrameStreamer; - -private: - class TIterator: TEventStream { - public: - TIterator(const TFrame& frame, TIntrusiveConstPtr<TEventFilter> filter); - ~TIterator() override = default; - - bool Avail() const override { - return Index_ < Size_; - } - - TConstEventPtr operator*() const override; - bool Next() override; - - private: - void SkipToValidEvent(); - - const TFrame& Frame_; - size_t Size_; - TIntrusiveConstPtr<TEventFilter> Filter_; - size_t Index_; - }; - -public: - TFrame::TIterator GetIterator(TIntrusiveConstPtr<TEventFilter> eventFilter = nullptr) const; -}; - -// If `in` is derived from TCountingInput, Frame's address will -// be set accorting to the in->Counter(). Otherwise it will be zeroO -TMaybe<TFrame> FindNextFrame(IInputStream* in, IEventFactory*); - -using TFrameStream = TPacketInputStream<const TFrame&>; - -class IFrameFilter: public TSimpleRefCount<IFrameFilter> { -public: - IFrameFilter() { - } - - virtual ~IFrameFilter() = default; - - virtual bool FrameAllowed(const TFrame& frame) const = 0; -}; - -using IFrameFilterRef = TIntrusivePtr<IFrameFilter>; - -class TDurationFrameFilter: public IFrameFilter { -public: - TDurationFrameFilter(ui64 minFrameDuration, ui64 maxFrameDuration = Max<ui64>()) - : MinDuration_(minFrameDuration) - , MaxDuration_(maxFrameDuration) - { - } - - bool FrameAllowed(const TFrame& frame) const override { - return frame.Duration() >= MinDuration_ && frame.Duration() <= MaxDuration_; - } - -private: - const ui64 MinDuration_; - const ui64 MaxDuration_; -}; - -class TFrameIdFrameFilter: public IFrameFilter { -public: - TFrameIdFrameFilter(ui32 frameId) - : FrameId_(frameId) - { - } - - bool FrameAllowed(const TFrame& frame) const override { - return frame.FrameId() == FrameId_; - } - -private: - const ui32 FrameId_; -}; - -class TContainsEventFrameFilter: public IFrameFilter { -public: - TContainsEventFrameFilter(const TString& args, const IEventFactory* fac); - - bool FrameAllowed(const TFrame& frame) const override; - -private: - struct TMatchGroup { - TEventClass EventID; - TString FieldName; - TString ValueToMatch; - }; - - TVector<TMatchGroup> MatchGroups; -}; - -void SplitWithEscaping(TVector<TStringBuf>& tokens, const TStringBuf& stringToSplit, const TStringBuf& externalCharacterSet); - -TString UnescapeCharacters(const TStringBuf& stringToUnescape, const TStringBuf& characterSet); - -TString GetEventFieldAsString(const NProtoBuf::Message* message, const google::protobuf::FieldDescriptor* fieldDescriptor, const google::protobuf::Reflection* reflection); - -class TFrameStreamer: public TFrameStream { -public: - TFrameStreamer(IInputStream&, IEventFactory* fac, IFrameFilterRef ff = nullptr); - TFrameStreamer( - const TString& fileName, - ui64 startTime, - ui64 endTime, - ui64 maxRequestDuration, - IEventFactory* fac, - IFrameFilterRef ff = nullptr); - ~TFrameStreamer() override; - - bool Avail() const override; - const TFrame& operator*() const override; - bool Next() override; - -private: - bool DoNext(); - bool AllowedTimeRange(const TFrame& frame) const; - - bool AllowedFrame(const TFrame& frame) const { - return AllowedTimeRange(frame) && (!FrameFilter_ || FrameFilter_->FrameAllowed(frame)); - } - - void SkipToAllowedFrame() { - if (Frame_) { - while (!AllowedFrame(*Frame_) && DoNext()) { - //do nothing - } - } - } - - TBlob File_; - TMemoryInput MemoryIn_; - TCountingInput In_; - THolder<IInputStream> Stream_; - ui64 StartTime_ = 0; - ui64 EndTime_ = 0; - ui64 CutoffTime_ = 0; - TMaybe<TFrame> Frame_; - IFrameFilterRef FrameFilter_; - IEventFactory* EventFactory_; -}; - -class TFrameDecoder: TEventStream { -public: - TFrameDecoder(const TFrame&, const TEventFilter* const filter, bool strict = false, bool withRawData = false); - ~TFrameDecoder() override; - - bool Avail() const override; - - TConstEventPtr operator*() const override; - bool Next() override; - - const TStringBuf GetRawEvent() const; - -private: - TFrameDecoder(const TFrameDecoder&); - void operator=(const TFrameDecoder&); - - inline bool HaveData() const { - return Event_ != nullptr; - } - - void Decode(); - -private: - const TFrame& Frame_; - THolder<IInputStream> Decompressor_; - THolder<TLengthLimitedInput> Limiter_; - TEventPtr Event_; - const TEventFilter* const Flt_; - IEventFactory* Fac_; - THolder<TEvent> EndOfFrame_; - bool Strict_; - TBuffer UncompressedData_; - TStringBuf RawEventData_; - bool WithRawData_; -}; - -class TEventStreamer: public TEventStream { -public: - TEventStreamer(TFrameStream&, ui64 start, ui64 end, bool strongOrdering, TIntrusivePtr<TEventFilter> filter, bool losslessStrongOrdering = false); - ~TEventStreamer() override; - - bool Avail() const override; - TConstEventPtr operator*() const override; - bool Next() override; - -private: - class TEventBuffer: public TEventStream { - public: - void SetCheckpoint(); - void Rollback(); - void Reorder(bool strongOrdering); - void Append(TConstEventPtr event, bool strongOrdering); - - bool Avail() const override; - TConstEventPtr operator*() const override; - bool Next() override; - - private: - TVector<TConstEventPtr> Buffer_; - size_t BufLen_ = 0; - ui64 LastTimestamp_ = 0; - }; - -private: - struct TInvalidEventTimestamps: public yexception { - }; - - bool LoadMoreEvents(); - void TransferEvents(const TFrame&); - -private: - TFrameStream& Frames_; - TEventBuffer Events_; - - ui64 Start_, End_; - ui64 MaxEndTimestamp_; - ui64 Frontier_; - bool StrongOrdering_; - bool LosslessStrongOrdering_; - TIntrusivePtr<TEventFilter> EventFilter_; -}; diff --git a/library/cpp/eventlog/proto/events_extension.proto b/library/cpp/eventlog/proto/events_extension.proto deleted file mode 100644 index 7db1af3a59..0000000000 --- a/library/cpp/eventlog/proto/events_extension.proto +++ /dev/null @@ -1,22 +0,0 @@ -import "google/protobuf/descriptor.proto"; - -option go_package = "github.com/ydb-platform/ydb/library/cpp/eventlog/proto;extensions"; -option java_package = "NEventLogEventsExtension"; - -extend google.protobuf.MessageOptions { - optional uint32 message_id = 50001; - optional string realm_name = 50002; -} - -message Repr { - enum ReprType { - none = 0; - as_bytes = 1; // Only for primitive types - as_hex = 2; // Only for primitive types - as_base64 = 3; // Only for 'string' and 'bytes' fields - }; -} - -extend google.protobuf.FieldOptions { - optional Repr.ReprType repr = 55003 [default = none]; -} diff --git a/library/cpp/eventlog/proto/internal.proto b/library/cpp/eventlog/proto/internal.proto deleted file mode 100644 index 8070a09685..0000000000 --- a/library/cpp/eventlog/proto/internal.proto +++ /dev/null @@ -1,9 +0,0 @@ -option go_package = "github.com/ydb-platform/ydb/library/cpp/eventlog/proto;extensions"; - -package NEventLogInternal; - -message TUnknownEvent { -}; - -message TEndOfFrameEvent { -}; diff --git a/library/cpp/eventlog/proto/ya.make b/library/cpp/eventlog/proto/ya.make deleted file mode 100644 index fbf5a6c619..0000000000 --- a/library/cpp/eventlog/proto/ya.make +++ /dev/null @@ -1,12 +0,0 @@ -PROTO_LIBRARY() - -IF (NOT PY_PROTOS_FOR) - INCLUDE_TAGS(GO_PROTO) -ENDIF() - -SRCS( - events_extension.proto - internal.proto -) - -END() diff --git a/library/cpp/eventlog/threaded_eventlog.cpp b/library/cpp/eventlog/threaded_eventlog.cpp deleted file mode 100644 index 67839063fb..0000000000 --- a/library/cpp/eventlog/threaded_eventlog.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "threaded_eventlog.h" diff --git a/library/cpp/eventlog/threaded_eventlog.h b/library/cpp/eventlog/threaded_eventlog.h deleted file mode 100644 index 52382b856d..0000000000 --- a/library/cpp/eventlog/threaded_eventlog.h +++ /dev/null @@ -1,154 +0,0 @@ -#pragma once - -#include "eventlog.h" - -#include <util/generic/string.h> -#include <util/thread/pool.h> - -class TThreadedEventLog: public TEventLogWithSlave { -public: - class TWrapper; - using TOverflowCallback = std::function<void(TWrapper& wrapper)>; - - enum class EDegradationResult { - ShouldWrite, - ShouldDrop, - }; - using TDegradationCallback = std::function<EDegradationResult(float fillFactor)>; - -public: - TThreadedEventLog( - IEventLog& parentLog, - size_t threadCount, - size_t queueSize, - TOverflowCallback cb, - TDegradationCallback degradationCallback = {}) - : TEventLogWithSlave(parentLog) - , LogSaver(TThreadPoolParams().SetThreadName("ThreadedEventLog")) - , ThreadCount(threadCount) - , QueueSize(queueSize) - , OverflowCallback(std::move(cb)) - , DegradationCallback(std::move(degradationCallback)) - { - Init(); - } - - TThreadedEventLog( - const TEventLogPtr& parentLog, - size_t threadCount, - size_t queueSize, - TOverflowCallback cb, - TDegradationCallback degradationCallback = {}) - : TEventLogWithSlave(parentLog) - , LogSaver(TThreadPoolParams().SetThreadName("ThreadedEventLog")) - , ThreadCount(threadCount) - , QueueSize(queueSize) - , OverflowCallback(std::move(cb)) - , DegradationCallback(std::move(degradationCallback)) - { - Init(); - } - - TThreadedEventLog(IEventLog& parentLog) - : TThreadedEventLog(parentLog, 1, 0, TOverflowCallback()) - { - } - - TThreadedEventLog(const TEventLogPtr& parentLog) - : TThreadedEventLog(parentLog, 1, 0, TOverflowCallback()) - { - } - - ~TThreadedEventLog() override { - try { - LogSaver.Stop(); - } catch (...) { - } - } - - void ReopenLog() override { - TEventLogWithSlave::ReopenLog(); - } - - void CloseLog() override { - LogSaver.Stop(); - TEventLogWithSlave::CloseLog(); - } - - void WriteFrame(TBuffer& buffer, - TEventTimestamp startTimestamp, - TEventTimestamp endTimestamp, - TWriteFrameCallbackPtr writeFrameCallback = nullptr, - TLogRecord::TMetaFlags metaFlags = {}) override { - float fillFactor = 0.0f; - if (Y_LIKELY(LogSaver.GetMaxQueueSize() > 0)) { - fillFactor = static_cast<float>(LogSaver.Size()) / LogSaver.GetMaxQueueSize(); - } - - EDegradationResult status = EDegradationResult::ShouldWrite; - if (DegradationCallback) { - status = DegradationCallback(fillFactor); - } - if (Y_UNLIKELY(status == EDegradationResult::ShouldDrop)) { - return; - } - - THolder<TWrapper> wrapped; - wrapped.Reset(new TWrapper(buffer, startTimestamp, endTimestamp, Slave(), writeFrameCallback, std::move(metaFlags))); - - if (LogSaver.Add(wrapped.Get())) { - Y_UNUSED(wrapped.Release()); - } else if (OverflowCallback) { - OverflowCallback(*wrapped); - } - } - -private: - void Init() { - LogSaver.Start(ThreadCount, QueueSize); - } - -public: - class TWrapper: public IObjectInQueue { - public: - TWrapper(TBuffer& buffer, - TEventTimestamp startTimestamp, - TEventTimestamp endTimestamp, - IEventLog& slave, - TWriteFrameCallbackPtr writeFrameCallback = nullptr, - TLogRecord::TMetaFlags metaFlags = {}) - : StartTimestamp(startTimestamp) - , EndTimestamp(endTimestamp) - , Slave(&slave) - , WriteFrameCallback(writeFrameCallback) - , MetaFlags(std::move(metaFlags)) - { - Buffer.Swap(buffer); - } - - void Process(void*) override { - THolder<TWrapper> holder(this); - - WriteFrame(); - } - - void WriteFrame() { - Slave->WriteFrame(Buffer, StartTimestamp, EndTimestamp, WriteFrameCallback, std::move(MetaFlags)); - } - - private: - TBuffer Buffer; - TEventTimestamp StartTimestamp; - TEventTimestamp EndTimestamp; - IEventLog* Slave; - TWriteFrameCallbackPtr WriteFrameCallback; - TLogRecord::TMetaFlags MetaFlags; - }; - -private: - TThreadPool LogSaver; - const size_t ThreadCount; - const size_t QueueSize; - const TOverflowCallback OverflowCallback; - const TDegradationCallback DegradationCallback; -}; diff --git a/library/cpp/eventlog/ya.make b/library/cpp/eventlog/ya.make deleted file mode 100644 index fbbc1eff00..0000000000 --- a/library/cpp/eventlog/ya.make +++ /dev/null @@ -1,29 +0,0 @@ -LIBRARY() - -PEERDIR( - library/cpp/blockcodecs - library/cpp/eventlog/proto - library/cpp/json - library/cpp/logger - library/cpp/protobuf/json - library/cpp/streams/growing_file_input - library/cpp/string_utils/base64 - contrib/libs/re2 -) - -SRCS( - common.h - evdecoder.cpp - event_field_output.cpp - event_field_printer.cpp - eventlog.cpp - eventlog_int.cpp - iterator.cpp - logparser.cpp - threaded_eventlog.cpp -) - -GENERATE_ENUM_SERIALIZATION(eventlog.h) -GENERATE_ENUM_SERIALIZATION(eventlog_int.h) - -END() diff --git a/library/cpp/fieldcalc/field_calc.cpp b/library/cpp/fieldcalc/field_calc.cpp deleted file mode 100644 index 1066b5b5e6..0000000000 --- a/library/cpp/fieldcalc/field_calc.cpp +++ /dev/null @@ -1,1136 +0,0 @@ -#include <cstdio> - -#include <util/str_stl.h> -#include <util/string/subst.h> -#include <util/string/util.h> -#include <util/string/cast.h> -#include <util/stream/printf.h> - -#include "field_calc_int.h" - -using namespace std; - -enum Operators { - OP_ADD, - OP_SUBSTRACT, - OP_MULTIPLY, - OP_DIVIDE, - OP_MODULUS, - OP_REGEXP, - OP_REGEXP_NOT, - OP_LEFT_SHIFT, - OP_RIGHT_SHIFT, - OP_EQUAL, - OP_NOT_EQUAL, - OP_LESS, - OP_LESS_OR_EQUAL, - OP_GREATER, - OP_GREATER_OR_EQUAL, - OP_XOR, - OP_BITWISE_OR, - OP_BITWISE_AND, - OP_LOGICAL_OR, - OP_LOGICAL_AND, - OP_UNARY_NOT, - OP_UNARY_COMPLEMENT, - OP_UNARY_MINUS, - OP_LOG, - OP_LOG10, - OP_ROUND, - OP_ASSIGN, - OP_QUESTION, - OP_COLON, - - OP_UNKNOWN, -}; - -struct calc_op; - -struct calc_elem { - dump_item item; - char oper; - int op_prio; -}; - -struct calc_op { - dump_item Left, Right; - char Oper; - bool force_long; - bool unary; - bool is_variable; - bool string_op; // TODO -> bitop - - // for local vars - mutable bool calculated; - mutable eval_res_type result; - - calc_op(calc_elem& left, calc_elem& right) - : Left(left.item) - , Right(right.item) - , Oper(right.oper) - , is_variable(false) - , calculated(false) - , result(false) - { - force_long = Oper == OP_XOR || Oper == OP_BITWISE_OR || Oper == OP_BITWISE_AND || - Oper == OP_LOGICAL_OR || Oper == OP_LOGICAL_AND || Oper == OP_UNARY_NOT || - Oper == OP_UNARY_COMPLEMENT || Oper == OP_LEFT_SHIFT || Oper == OP_RIGHT_SHIFT || - Oper == OP_MODULUS; - unary = Oper == OP_UNARY_NOT || Oper == OP_UNARY_COMPLEMENT || Oper == OP_UNARY_MINUS || - Oper == OP_LOG || Oper == OP_LOG10 || Oper == OP_ROUND; - string_op = IsStringType(Left.type) && IsStringType(Right.type) && - (Oper == OP_REGEXP || Oper == OP_REGEXP_NOT || Oper == OP_EQUAL || Oper == OP_NOT_EQUAL || - Oper == OP_LESS || Oper == OP_LESS_OR_EQUAL || Oper == OP_GREATER || Oper == OP_GREATER_OR_EQUAL); - if (Oper == OP_REGEXP || Oper == OP_REGEXP_NOT) { - if (!string_op) - ythrow yexception() << "calc-expr: regexp requested for non-strings"; - ythrow yexception() << "calc-expr: regexps currently not supported"; - } - } - - Y_FORCE_INLINE void eval(const char** dd) const { - if (is_variable) { - if (!calculated) { - do_eval(dd); - calculated = true; - } - } else { - do_eval(dd); - } - } - -private: - Y_FORCE_INLINE void do_eval(const char** dd) const; -}; - -void calc_op::do_eval(const char** dd) const { - eval_res_type left1 = unary ? (eval_res_type) false : Left.eval(dd); - if (Oper == OP_QUESTION) { - left1.to_long(); - if (left1.res_long) { - result = Right.eval(dd); - } else { - result = eval_res_type(); // null - } - return; - } else if (Oper == OP_COLON) { - if (left1.is_null()) { - result = Right.eval(dd); - } else { - result = left1; - } - return; - } - - if (Y_UNLIKELY(string_op)) { - TStringBuf left2 = Left.GetStrBuf(dd); - TStringBuf right2 = Right.GetStrBuf(dd); - switch (Oper) { - case OP_REGEXP: - result = false; - break; - case OP_REGEXP_NOT: - result = false; - break; - case OP_EQUAL: - result = left2 == right2; - break; - case OP_NOT_EQUAL: - result = left2 != right2; - break; - case OP_LESS: - result = left2 < right2; - break; - case OP_LESS_OR_EQUAL: - result = left2 <= right2; - break; - case OP_GREATER: - result = left2 > right2; - break; - case OP_GREATER_OR_EQUAL: - result = left2 >= right2; - break; - default: - assert(false); - } - return; - } - - eval_res_type right1 = Right.eval(dd); - if (force_long) { // logical ops will be all long - left1.to_long(); - right1.to_long(); - } - switch (Oper) { - case OP_ADD: - result = left1 + right1; - break; - case OP_SUBSTRACT: - result = left1 - right1; - break; - case OP_MULTIPLY: - result = left1 * right1; - break; - case OP_DIVIDE: - result = left1 / right1; - break; - case OP_MODULUS: - result = left1.res_long ? left1.res_long % right1.res_long : 0; - break; - case OP_LEFT_SHIFT: - result = left1.res_long << right1.res_long; - break; - case OP_RIGHT_SHIFT: - result = left1.res_long >> right1.res_long; - break; - case OP_EQUAL: - result = left1 == right1; - break; - case OP_NOT_EQUAL: - result = !(left1 == right1); - break; - case OP_LESS: - result = left1 < right1; - break; - case OP_LESS_OR_EQUAL: - result = !(right1 < left1); - break; // <= - case OP_GREATER: - result = right1 < left1; - break; - case OP_GREATER_OR_EQUAL: - result = !(left1 < right1); - break; // >= - case OP_XOR: - result = left1.res_long ^ right1.res_long; - break; - case OP_BITWISE_OR: - result = left1.res_long | right1.res_long; - break; - case OP_BITWISE_AND: - result = left1.res_long & right1.res_long; - break; - case OP_LOGICAL_OR: - result = left1.res_long || right1.res_long; - break; - case OP_LOGICAL_AND: - result = left1.res_long && right1.res_long; - break; - case OP_UNARY_NOT: - result = !right1.res_long; - break; - case OP_UNARY_COMPLEMENT: - result = ~right1.res_long; - break; - case OP_UNARY_MINUS: - result = Minus(right1); - break; - case OP_LOG: - result = Log(right1); - break; - case OP_LOG10: - result = Log10(right1); - break; - case OP_ROUND: - result = Round(right1); - break; - default: - assert(false); - } -} - -namespace { - // copy-paste of fcat(TString) - // we don't want it to be too slow, yet we don't want do slow down our - // main functionality, libc fprintf, even a little - size_t Y_PRINTF_FORMAT(2, 3) fprintf(TString* s, const char* c, ...) { - TStringOutput so(*s); - - va_list params; - va_start(params, c); - const size_t ret = Printf(so, c, params); - va_end(params); - - return ret; - } - size_t Y_PRINTF_FORMAT(2, 3) fprintf(IOutputStream* s, const char* c, ...) { - va_list params; - va_start(params, c); - const size_t ret = Printf(*s, c, params); - va_end(params); - - return ret; - } -} - -template <class TOut> -void dump_item::print(TOut* p, const char** dd) const { - const char* d = dd[pack_id]; - const fake* f = reinterpret_cast<const fake*>(d); - - switch (type) { - case DIT_FAKE_ITEM: - assert(false); - break; - case DIT_MATH_RESULT: - assert(false); - break; // must call eval instead - case DIT_NAME: - assert(false); - break; // no op - - case DIT_BOOL_FIELD: - fprintf(p, *(bool*)(d + field_offset) ? "true" : "false"); - break; - case DIT_UI8_FIELD: - fprintf(p, "%u", *(ui8*)(d + field_offset)); - break; - case DIT_UI16_FIELD: - fprintf(p, "%u", *(ui16*)(d + field_offset)); - break; - case DIT_UI32_FIELD: - fprintf(p, "%u", *(ui32*)(d + field_offset)); - break; - case DIT_I64_FIELD: - fprintf(p, "%" PRId64, *(i64*)(d + field_offset)); - break; - case DIT_UI64_FIELD: - fprintf(p, "%" PRIu64, *(ui64*)(d + field_offset)); - break; - case DIT_FLOAT_FIELD: - fprintf(p, "%.4f", *(float*)(d + field_offset)); - break; - case DIT_DOUBLE_FIELD: - fprintf(p, "%.7f", *(double*)(d + field_offset)); - break; - case DIT_TIME_T32_FIELD: - fprintf(p, "%ld", (long)*(time_t32*)(d + field_offset)); - break; - case DIT_PF16UI32_FIELD: - fprintf(p, "%u", (ui32) * (pf16ui32*)(d + field_offset)); - break; - case DIT_PF16FLOAT_FIELD: - fprintf(p, "%.4f", (float)*(pf16float*)(d + field_offset)); - break; - case DIT_SF16FLOAT_FIELD: - fprintf(p, "%.4f", (float)*(sf16float*)(d + field_offset)); - break; - case DIT_STRING_FIELD: - fprintf(p, "%s", (d + field_offset)); - break; - - case DIT_LONG_CONST: - fprintf(p, "%ld", long_const); - break; - case DIT_FLOAT_CONST: - fprintf(p, "%.4f", float_const); - break; - case DIT_STR_CONST: - fprintf(p, "%.*s", (int)the_buf.size(), the_buf.data()); - break; - - case DIT_INT_FUNCTION: - fprintf(p, "%d", (f->*int_fn)()); - break; - case DIT_FLOAT_FUNCTION: - fprintf(p, "%.4f", (f->*float_fn)()); - break; - case DIT_BOOL_FUNCTION: - fprintf(p, "%d", (f->*bool_fn)()); - break; - case DIT_STR_FUNCTION: - fprintf(p, "%s", (f->*str_fn)()); - break; - case DIT_STRBUF_FUNCTION: - the_buf.clear(); - fprintf(p, "%s", (f->*strbuf_2_fn)(the_buf, nullptr)); - break; - - case DIT_UI8_EXT_FUNCTION: - fprintf(p, "%u", (*ui8_ext_fn)(f)); - break; - case DIT_UI16_EXT_FUNCTION: - fprintf(p, "%u", (*ui16_ext_fn)(f)); - break; - case DIT_UI32_EXT_FUNCTION: - fprintf(p, "%u", (*ui32_ext_fn)(f)); - break; - case DIT_UI64_EXT_FUNCTION: - fprintf(p, "%" PRIu64, (*ui64_ext_fn)(f)); - break; - - case DIT_UI8_ENUM_EQ: - fprintf(p, "%d", *(ui8*)(d + field_offset) == enum_val); - break; - case DIT_UI8_ENUM_SET: - fprintf(p, "%d", !!(*(ui8*)(d + field_offset) & enum_val)); - break; - - case DIT_UI16_ENUM_EQ: - fprintf(p, "%d", *(ui16*)(d + field_offset) == enum_val); - break; - case DIT_UI16_ENUM_SET: - fprintf(p, "%d", !!(*(ui16*)(d + field_offset) & enum_val)); - break; - - case DIT_UI32_ENUM_EQ: - fprintf(p, "%d", *(ui32*)(d + field_offset) == enum_val); - break; - case DIT_UI32_ENUM_SET: - fprintf(p, "%d", !!(*(ui32*)(d + field_offset) & enum_val)); - break; - - case DIT_INT_ENUM_FUNCTION_EQ: - fprintf(p, "%d", (ui32)(f->*int_enum_fn)() == enum_val); - break; - case DIT_INT_ENUM_FUNCTION_SET: - fprintf(p, "%d", !!(ui32)((f->*int_enum_fn)() & enum_val)); - break; - - case DIT_BOOL_FUNC_FIXED_STR: - fprintf(p, "%u", (ui32)(f->*bool_strbuf_fn)(the_buf)); - break; - case DIT_UI8_FUNC_FIXED_STR: - fprintf(p, "%u", (ui32)(f->*ui8_strbuf_fn)(the_buf)); - break; - case DIT_UI16_FUNC_FIXED_STR: - fprintf(p, "%u", (ui32)(f->*ui16_strbuf_fn)(the_buf)); - break; - case DIT_UI32_FUNC_FIXED_STR: - fprintf(p, "%u", (f->*ui32_strbuf_fn)(the_buf)); - break; - case DIT_I64_FUNC_FIXED_STR: - fprintf(p, "%" PRId64, (f->*i64_strbuf_fn)(the_buf)); - break; - case DIT_UI64_FUNC_FIXED_STR: - fprintf(p, "%" PRIu64, (f->*ui64_strbuf_fn)(the_buf)); - break; - case DIT_FLOAT_FUNC_FIXED_STR: - fprintf(p, "%.4f", (f->*float_strbuf_fn)(the_buf)); - break; - case DIT_DOUBLE_FUNC_FIXED_STR: - fprintf(p, "%.7f", (f->*double_strbuf_fn)(the_buf)); - break; - - case DIT_RESOLVE_BY_NAME: - fprintf(p, "%s", (f->*resolve_fn)(the_buf).data()); - break; - - default: - assert(false); - break; - } -} - -// instantiate, just for a case -template void dump_item::print<FILE>(FILE* p, const char** dd) const; -template void dump_item::print<TString>(TString* p, const char** dd) const; -template void dump_item::print<IOutputStream>(IOutputStream* p, const char** dd) const; - -TStringBuf dump_item::GetStrBuf(const char** dd) const { - const char* d = dd[pack_id]; - const fake* f = reinterpret_cast<const fake*>(d); - switch (type) { - case DIT_STRING_FIELD: - return d + field_offset; - case DIT_STR_CONST: - return the_buf; - case DIT_STR_FUNCTION: - return (f->*str_fn)(); - case DIT_STRBUF_FUNCTION: - the_buf.clear(); - return (f->*strbuf_2_fn)(the_buf, nullptr); - case DIT_RESOLVE_BY_NAME: - return (f->*resolve_fn)(the_buf); - default: - assert(false); - return TStringBuf(); - } -} - -// recursive -eval_res_type dump_item::eval(const char** dd) const { - const char* d = dd[pack_id]; - const fake* f = reinterpret_cast<const fake*>(d); - - switch (type) { - case DIT_FAKE_ITEM: - assert(false); - return (long int)0; - case DIT_MATH_RESULT: - this->op->eval(dd); - return this->op->result; - case DIT_NAME: - assert(false); - return (long int)0; - - case DIT_BOOL_FIELD: - return (ui32) * (bool*)(d + field_offset); - case DIT_UI8_FIELD: - return (ui32) * (ui8*)(d + field_offset); - case DIT_UI16_FIELD: - return (ui32) * (ui16*)(d + field_offset); - case DIT_UI32_FIELD: - return (ui32) * (ui32*)(d + field_offset); - case DIT_I64_FIELD: - return (long)*(i64*)(d + field_offset); // TODO: 64 bit support in calculator? - case DIT_UI64_FIELD: - return (long)*(ui64*)(d + field_offset); // TODO: 64 bit support in calculator? - case DIT_FLOAT_FIELD: - return (float)*(float*)(d + field_offset); - case DIT_DOUBLE_FIELD: - return *(double*)(d + field_offset); - case DIT_TIME_T32_FIELD: - return (long)*(time_t32*)(d + field_offset); - case DIT_PF16UI32_FIELD: - return (ui32) * (pf16ui32*)(d + field_offset); - case DIT_PF16FLOAT_FIELD: - return (float)*(pf16float*)(d + field_offset); - case DIT_SF16FLOAT_FIELD: - return (float)*(sf16float*)(d + field_offset); - case DIT_STRING_FIELD: - return !!d[field_offset]; // we don't have any string functions, just 0 if empty - - case DIT_LONG_CONST: - return long_const; - case DIT_FLOAT_CONST: - return float_const; - case DIT_STR_CONST: - return !!the_buf; - - case DIT_INT_FUNCTION: - return (long)(f->*int_fn)(); - case DIT_FLOAT_FUNCTION: - return (float)(f->*float_fn)(); - case DIT_BOOL_FUNCTION: - return (long)(f->*bool_fn)(); - case DIT_STR_FUNCTION: - return !!*(f->*str_fn)(); // string -> int - case DIT_STRBUF_FUNCTION: - the_buf.clear(); - return !!*(f->*strbuf_2_fn)(the_buf, nullptr); // string -> 0/1 - - case DIT_UI8_EXT_FUNCTION: - return (ui32)(*ui8_ext_fn)(f); - case DIT_UI16_EXT_FUNCTION: - return (ui32)(*ui16_ext_fn)(f); - case DIT_UI32_EXT_FUNCTION: - return (ui32)(*ui32_ext_fn)(f); - case DIT_UI64_EXT_FUNCTION: - return (long)(*ui64_ext_fn)(f); // TODO: 64 bit support in calculator? - - case DIT_UI8_ENUM_EQ: - return (ui32)(*(ui8*)(d + field_offset) == enum_val); - case DIT_UI8_ENUM_SET: - return !!(ui32)(*(ui8*)(d + field_offset) & enum_val); - - case DIT_UI16_ENUM_EQ: - return (ui32)(*(ui16*)(d + field_offset) == enum_val); - case DIT_UI16_ENUM_SET: - return !!(ui32)(*(ui16*)(d + field_offset) & enum_val); - - case DIT_UI32_ENUM_EQ: - return (ui32)(*(ui32*)(d + field_offset) == enum_val); - case DIT_UI32_ENUM_SET: - return !!(ui32)(*(ui32*)(d + field_offset) & enum_val); - - case DIT_INT_ENUM_FUNCTION_EQ: - return (ui32)((ui32)(f->*int_enum_fn)() == enum_val); - case DIT_INT_ENUM_FUNCTION_SET: - return !!(ui32)((ui32)(f->*int_enum_fn)() & enum_val); - - case DIT_BOOL_FUNC_FIXED_STR: - return (ui32)(f->*bool_strbuf_fn)(the_buf); - case DIT_UI8_FUNC_FIXED_STR: - return (ui32)(f->*ui8_strbuf_fn)(the_buf); - case DIT_UI16_FUNC_FIXED_STR: - return (ui32)(f->*ui16_strbuf_fn)(the_buf); - case DIT_UI32_FUNC_FIXED_STR: - return (ui32)(f->*ui32_strbuf_fn)(the_buf); - case DIT_I64_FUNC_FIXED_STR: - return (long)(f->*i64_strbuf_fn)(the_buf); - case DIT_UI64_FUNC_FIXED_STR: - return (long)(f->*ui64_strbuf_fn)(the_buf); - case DIT_FLOAT_FUNC_FIXED_STR: - return (float)(f->*float_strbuf_fn)(the_buf); - case DIT_DOUBLE_FUNC_FIXED_STR: - return (double)(f->*double_strbuf_fn)(the_buf); - - case DIT_RESOLVE_BY_NAME: - return !!(f->*resolve_fn)(the_buf); - - default: - assert(false); - break; - } - - // unreached - return eval_res_type(false); -} - -void dump_item::set_arrind(int arrind) { - switch (type) { - case DIT_BOOL_FIELD: - field_offset += arrind * sizeof(bool); - break; - case DIT_UI8_FIELD: - field_offset += arrind * sizeof(ui8); - break; - case DIT_UI16_FIELD: - field_offset += arrind * sizeof(ui16); - break; - case DIT_UI32_FIELD: - field_offset += arrind * sizeof(ui32); - break; - case DIT_I64_FIELD: - field_offset += arrind * sizeof(i64); - break; - case DIT_UI64_FIELD: - field_offset += arrind * sizeof(ui64); - break; - case DIT_FLOAT_FIELD: - field_offset += arrind * sizeof(float); - break; - case DIT_DOUBLE_FIELD: - field_offset += arrind * sizeof(double); - break; - case DIT_TIME_T32_FIELD: - field_offset += arrind * sizeof(time_t32); - break; - case DIT_PF16UI32_FIELD: - field_offset += arrind * sizeof(pf16ui32); - break; - case DIT_PF16FLOAT_FIELD: - field_offset += arrind * sizeof(pf16float); - break; - case DIT_SF16FLOAT_FIELD: - field_offset += arrind * sizeof(sf16float); - break; - default: - break; - } -} - -static str_spn FieldNameChars("a-zA-Z0-9_$", true); -static str_spn MathOpChars("-+=*%/&|<>()!~^?:#", true); -static str_spn SpaceChars("\t\n\r ", true); - -TFieldCalculatorBase::TFieldCalculatorBase() { -} - -TFieldCalculatorBase::~TFieldCalculatorBase() = default; - -bool TFieldCalculatorBase::item_by_name(dump_item& it, const char* name) const { - for (size_t i = 0; i < named_dump_items.size(); i++) { - const named_dump_item* list = named_dump_items[i].first; - size_t sz = named_dump_items[i].second; - for (unsigned int n = 0; n < sz; n++) { - if (!stricmp(name, list[n].name)) { - it = list[n].item; - it.pack_id = i; - return true; - } - } - } - return false; -} - -bool TFieldCalculatorBase::get_local_var(dump_item& dst, char* var_name) { - TMap<const char*, dump_item>::const_iterator it = local_vars.find(var_name); - if (it == local_vars.end()) { - // New local variable - dst.type = DIT_LOCAL_VARIABLE; - dst.local_var_name = pool.append(var_name); - return false; - } else { - dst = it->second; - return true; - } -} - -char* TFieldCalculatorBase::get_field(dump_item& dst, char* s) { - if (!stricmp(s, "name")) { - dst.type = DIT_NAME; - return s + 4; // leave there 0 - } - - if (*s == '"' || *s == '\'') { - char* end = strchr(s + 1, *s); - bool hasEsc = false; - while (end && end > s + 1 && end[-1] == '\\') { - end = strchr(end + 1, *s); - hasEsc = true; - } - if (!end) - ythrow yexception() << "calc-expr: unterminated string constant at " << s; - dst.type = DIT_STR_CONST; - dst.the_buf.assign(s + 1, end); - if (hasEsc) - SubstGlobal(dst.the_buf, *s == '"' ? "\\\"" : "\\'", *s == '"' ? "\"" : "'"); - dst.set_arrind(0); // just for a case - return end + 1; - } - - bool is_number = isdigit((ui8)*s) || (*s == '+' || *s == '-') && isdigit((ui8)s[1]), is_float = false; - char* end = FieldNameChars.cbrk(s + is_number); - if (is_number && *end == '.') { - is_float = true; - end = FieldNameChars.cbrk(end + 1); - } - char* next = SpaceChars.cbrk(end); - int arr_index = 0; - bool has_arr_index = false; - if (*next == '[') { - arr_index = atoi(next + 1); - has_arr_index = true; - next = strchr(next, ']'); - if (!next) - ythrow yexception() << "calc-expr: No closing ']' for '" << s << "'"; - next = SpaceChars.cbrk(next + 1); - } - char end_sav = *end; - *end = 0; - - if (!item_by_name(dst, s)) { - if (!is_number) { - get_local_var(dst, s); - } else if (is_float) { - dst = (float)strtod(s, nullptr); - } else - dst = strtol(s, nullptr, 10); - - dst.pack_id = 0; - *end = end_sav; - return next; - } - - // check array/not array - if (has_arr_index && !dst.is_array_field()) - ythrow yexception() << "calc-expr: field " << s << " is not an array"; - - //if (!has_arr_index && dst.is_array_field()) - // yexception("calc-expr: field %s is array, index required", s); - - if (has_arr_index && (arr_index < 0 || arr_index >= dst.arr_length)) - ythrow yexception() << "calc-expr: array index [" << arr_index << "] is out of range for field " << s << " (length is " << dst.arr_length << ")"; - - *end = end_sav; - dst.set_arrind(arr_index); - return next; -} - -// BEGIN Stack calculator functions -inline char* skipspace(char* c, int& bracket_depth) { - while ((ui8)*c <= ' ' && *c || *c == '(' || *c == ')') { - if (*c == '(') - bracket_depth++; - else if (*c == ')') - bracket_depth--; - c++; - } - return c; -} - -void ensure_defined(const dump_item& item) { - if (item.type == DIT_LOCAL_VARIABLE) { - ythrow yexception() << "Usage of non-defined field or local variable '" << item.local_var_name << "'"; - } -} - -void TFieldCalculatorBase::emit_op(TVector<calc_op>& ops, calc_elem& left, calc_elem& right) { - int out_op = ops.size(); - char oper = right.oper; - ensure_defined(right.item); - if (oper == OP_ASSIGN) { - if (left.item.type != DIT_LOCAL_VARIABLE) { - ythrow yexception() << "Assignment only to local variables is allowed"; - } - if (local_vars.find(left.item.local_var_name) != local_vars.end()) { - ythrow yexception() << "Reassignment to the local variable " << left.item.local_var_name << " is not allowed"; - } - local_vars[left.item.local_var_name] = right.item; - if (right.item.type == DIT_MATH_RESULT) { - calc_ops[right.item.arr_ind].is_variable = true; - } - left = right; - } else { - ensure_defined(left.item); - ops.push_back(calc_op(left, right)); - left.item.type = DIT_MATH_RESULT; - left.item.arr_ind = out_op; - } -} - -inline int get_op_prio(char c) { - switch (c) { - case OP_ASSIGN: - return 1; - case OP_QUESTION: - case OP_COLON: - return 2; - case OP_LOGICAL_OR: - return 3; - case OP_LOGICAL_AND: - return 4; - case OP_BITWISE_OR: - return 5; - case OP_XOR: - return 6; - case OP_BITWISE_AND: - return 7; - case OP_EQUAL: - case OP_NOT_EQUAL: - return 8; - case OP_LESS: - case OP_LESS_OR_EQUAL: - case OP_GREATER: - case OP_GREATER_OR_EQUAL: - return 9; - case OP_LEFT_SHIFT: - case OP_RIGHT_SHIFT: - return 10; - case OP_ADD: - case OP_SUBSTRACT: - return 11; - case OP_MULTIPLY: - case OP_DIVIDE: - case OP_MODULUS: - return 12; - case OP_REGEXP: - case OP_REGEXP_NOT: - return 13; - case OP_UNARY_NOT: - case OP_UNARY_COMPLEMENT: - case OP_UNARY_MINUS: - case OP_LOG: - case OP_LOG10: - case OP_ROUND: - return 14; - default: - return 0; - } -} - -Operators get_oper(char*& c, bool unary_op_near) { - Operators cur_oper = OP_UNKNOWN; - switch (*c++) { - case '&': - if (*c == '&') - cur_oper = OP_LOGICAL_AND, c++; - else - cur_oper = OP_BITWISE_AND; - break; - case '|': - if (*c == '|') - cur_oper = OP_LOGICAL_OR, c++; - else - cur_oper = OP_BITWISE_OR; - break; - case '<': - if (*c == '=') - cur_oper = OP_LESS_OR_EQUAL, c++; - else if (*c == '<') - cur_oper = OP_LEFT_SHIFT, c++; - else - cur_oper = OP_LESS; - break; - case '>': - if (*c == '=') - cur_oper = OP_GREATER_OR_EQUAL, c++; - else if (*c == '>') - cur_oper = OP_RIGHT_SHIFT, c++; - else - cur_oper = OP_GREATER; - break; - case '!': - if (*c == '=') - cur_oper = OP_NOT_EQUAL, c++; - else if (*c == '~') - cur_oper = OP_REGEXP_NOT, c++; - else - cur_oper = OP_UNARY_NOT; - break; - case '=': - if (*c == '=') - cur_oper = OP_EQUAL, c++; - else if (*c == '~') - cur_oper = OP_REGEXP, c++; - else - cur_oper = OP_ASSIGN; - break; - case '-': - if (unary_op_near) - cur_oper = OP_UNARY_MINUS; - else - cur_oper = OP_SUBSTRACT; - break; - case '#': - if (!strncmp(c, "LOG#", 4)) { - cur_oper = OP_LOG; - c += 4; - } else if (!strncmp(c, "LOG10#", 6)) { - cur_oper = OP_LOG10; - c += 6; - } else if (!strncmp(c, "ROUND#", 6)) { - cur_oper = OP_ROUND; - c += 6; - } - break; - case '+': - cur_oper = OP_ADD; - break; - case '*': - cur_oper = OP_MULTIPLY; - break; - case '/': - cur_oper = OP_DIVIDE; - break; - case '%': - cur_oper = OP_MODULUS; - break; - case '^': - cur_oper = OP_XOR; - break; - case '~': - cur_oper = OP_UNARY_COMPLEMENT; - break; - case '?': - cur_oper = OP_QUESTION; - break; - case ':': - cur_oper = OP_COLON; - break; - } - return cur_oper; -} -// END Stack calculator functions - -void TFieldCalculatorBase::Compile(char** field_names, int field_count) { - out_el = 0, out_cond = 0; - autoarray<dump_item>(field_count).swap(printouts); - autoarray<dump_item>(field_count).swap(conditions); - local_vars.clear(); - - // parse arguments into calculator's "pseudo-code" - for (int el = 0; el < field_count; el++) { - char* c = field_names[el]; - bool is_expr = !!*MathOpChars.brk(c), is_cond = *c == '?'; - if (is_cond) - c++; - if (!is_expr && !is_cond) { - get_field(printouts[out_el], c); - ensure_defined(printouts[out_el]); - ++out_el; - continue; - } else { // Stack Calculator - const int maxstack = 64; - calc_elem fstack[maxstack]; // calculator's stack - int bdepth = 0; // brackets depth - int stack_cur = -1; - bool unary_op_near = false; // indicates that the next operator in unary - bool had_assignment_out_of_brackets = false; - int uop_seq = 0; // maintains right-to left order for unary operators - while (*(c = skipspace(c, bdepth))) { - /** https://wiki.yandex.ru/JandeksPoisk/Antispam/OwnersData/attselect#calc */ - //printf("1.%i c = '%s'\n", unary_op_near, c); - Operators cur_oper = OP_UNKNOWN; - int op_prio = 0; - if (stack_cur >= 0) { - cur_oper = get_oper(c, unary_op_near); - op_prio = get_op_prio(cur_oper); - if (!op_prio) - ythrow yexception() << "calc-expr: Unsupported operator '" << c[-1] << "'"; - op_prio += bdepth * 256 + uop_seq; - if (unary_op_near) - uop_seq += 20; - while (op_prio <= fstack[stack_cur].op_prio && stack_cur > 0) { - emit_op(calc_ops, fstack[stack_cur - 1], fstack[stack_cur]); - stack_cur--; - } - } - //printf("2.%i c = '%s'\n", unary_op_near, c); - had_assignment_out_of_brackets |= (bdepth == 0 && cur_oper == OP_ASSIGN); - c = skipspace(c, bdepth); - unary_op_near = *c == '-' && !isdigit((ui8)c[1]) || *c == '~' || (*c == '!' && c[1] != '=') || - !strncmp(c, "#LOG#", 5) || !strncmp(c, "#LOG10#", 7) || !strncmp(c, "#ROUND#", 7); - if (!unary_op_near) - uop_seq = 0; - if (stack_cur >= maxstack - 1) - ythrow yexception() << "calc-expr: Math eval stack overflow!\n"; - stack_cur++; - fstack[stack_cur].oper = cur_oper; - fstack[stack_cur].op_prio = op_prio; - //printf("3.%i c = '%s'\n", unary_op_near, c); - if (unary_op_near) - fstack[stack_cur].item = dump_item(); - else - c = get_field(fstack[stack_cur].item, c); - } - while (stack_cur > 0) { - emit_op(calc_ops, fstack[stack_cur - 1], fstack[stack_cur]); - stack_cur--; - } - ensure_defined(fstack[0].item); - if (is_cond) { - if (had_assignment_out_of_brackets) - ythrow yexception() << "Assignment in condition. (Did you mean '==' instead of '='?)"; - if (fstack[0].item.type != DIT_FAKE_ITEM) // Skip empty conditions: "?()". - conditions[out_cond++] = fstack[0].item; - } else if (!had_assignment_out_of_brackets) { - printouts[out_el++] = fstack[0].item; - } - } - } - // calc_ops will not grow any more, so arr_ind -> op - for (int n = 0; n < out_cond; n++) - conditions[n].rewrite_op(calc_ops.data()); - for (int n = 0; n < out_el; n++) - printouts[n].rewrite_op(calc_ops.data()); - for (auto& local_var : local_vars) { - local_var.second.rewrite_op(calc_ops.data()); - } - for (int n = 0; n < (int)calc_ops.size(); n++) { - calc_ops[n].Left.rewrite_op(calc_ops.data()); - calc_ops[n].Right.rewrite_op(calc_ops.data()); - } -} - -void dump_item::rewrite_op(const calc_op* ops) { - if (type == DIT_MATH_RESULT) - op = ops + arr_ind; -} - -void TFieldCalculatorBase::MarkLocalVarsAsUncalculated() { - for (auto& local_var : local_vars) { - if (local_var.second.type == DIT_MATH_RESULT) { - local_var.second.op->calculated = false; - } - } -} - -bool TFieldCalculatorBase::Cond(const char** d) { - MarkLocalVarsAsUncalculated(); - for (int n = 0; n < out_cond; n++) { - /** https://wiki.yandex.ru/JandeksPoisk/Antispam/OwnersData/attselect#conditions */ - eval_res_type res = conditions[n].eval(d); - bool is_true = res.type == 0 ? !!res.res_ui32 : res.type == 1 ? !!res.res_long : !!res.res_dbl; - if (!is_true) - return false; - } - return true; -} - -bool TFieldCalculatorBase::CondById(const char** d, int condNumber) { - MarkLocalVarsAsUncalculated(); - if (condNumber >= out_cond) - return false; - eval_res_type res = conditions[condNumber].eval(d); - bool is_true = res.type == 0 ? !!res.res_ui32 : res.type == 1 ? !!res.res_long : !!res.res_dbl; - if (!is_true) - return false; - return true; -} - -void TFieldCalculatorBase::Print(FILE* p, const char** d, const char* Name) { - for (int n = 0; n < out_el; n++) { - if (printouts[n].type == DIT_NAME) { - fprintf(p, "%s", Name); - } else if (printouts[n].type == DIT_MATH_RESULT) { // calculate - eval_res_type res = printouts[n].eval(d); - switch (res.type) { - case 0: - fprintf(p, "%u", res.res_ui32); - break; - case 1: - fprintf(p, "%ld", res.res_long); - break; - case 2: - fprintf(p, "%f", res.res_dbl); - break; - } - } else { - printouts[n].print(p, d); - } - fprintf(p, n != out_el - 1 ? "\t" : "\n"); - } -} - -void TFieldCalculatorBase::CalcAll(const char** d, TVector<float>& result) const { - result.clear(); - for (int n = 0; n < out_el; ++n) { - if (printouts[n].type == DIT_MATH_RESULT || printouts[n].type == DIT_FLOAT_FIELD) { - eval_res_type res = printouts[n].eval(d); - result.push_back(res.res_dbl); - } - } -} - -void TFieldCalculatorBase::SelfTest() { - if (out_el < 1) - ythrow yexception() << "Please specify conditions for test mode"; - const char* dummy = ""; - eval_res_type res = printouts[0].eval(&dummy); - switch (res.type) { - case 0: - printf("%u\n", res.res_ui32); - break; - case 1: - printf("%ld\n", res.res_long); - break; - case 2: - printf("%f\n", res.res_dbl); - break; - } -} - -void TFieldCalculatorBase::PrintDiff(const char* rec1, const char* rec2) { - for (size_t n = 0; n < named_dump_items[0].second; n++) { - const dump_item& field = named_dump_items[0].first[n].item; - if (!field.is_field()) - continue; // not really a field - for (int ind = 0, arrsz = field.is_array_field() ? field.arr_length : 1; ind < arrsz; ind++) { - intptr_t sav_field_offset = field.field_offset; - const_cast<dump_item&>(field).set_arrind(ind); - if (field.eval(&rec1) == field.eval(&rec2)) { - const_cast<dump_item&>(field).field_offset = sav_field_offset; - continue; - } - if (field.is_array_field()) - printf("\t%s[%i]: ", named_dump_items[0].first[n].name, ind); - else - printf("\t%s: ", named_dump_items[0].first[n].name); - field.print(stdout, &rec1); - printf(" -> "); - field.print(stdout, &rec2); - const_cast<dump_item&>(field).field_offset = sav_field_offset; - } - } -} - -void TFieldCalculatorBase::DumpAll(IOutputStream& s, const char** d, const TStringBuf& delim) { - bool firstPrinted = false; - for (size_t k = 0; k < named_dump_items.size(); k++) { - const named_dump_item* fields = named_dump_items[k].first; - size_t numFields = named_dump_items[k].second; - const char* obj = d[k]; - for (size_t n = 0; n < numFields; n++) { - const dump_item& field = fields[n].item; - if (!field.is_field()) - continue; - for (int ind = 0, arrsz = field.is_array_field() ? field.arr_length : 1; ind < arrsz; ind++) { - if (firstPrinted) - s << delim; - else - firstPrinted = true; - s << fields[n].name; - if (field.is_array_field()) - Printf(s, "[%i]", ind); - s << "="; - intptr_t sav_field_offset = field.field_offset; - const_cast<dump_item&>(field).set_arrind(ind); - field.print(&s, &obj); - const_cast<dump_item&>(field).field_offset = sav_field_offset; - } - } - } -} diff --git a/library/cpp/fieldcalc/field_calc.h b/library/cpp/fieldcalc/field_calc.h deleted file mode 100644 index 46bf371a60..0000000000 --- a/library/cpp/fieldcalc/field_calc.h +++ /dev/null @@ -1,136 +0,0 @@ -#pragma once - -#include <cstdio> - -#include <library/cpp/deprecated/autoarray/autoarray.h> -#include <util/generic/map.h> -#include <util/generic/vector.h> -#include <util/memory/segmented_string_pool.h> - -struct dump_item; -struct calc_op; -struct named_dump_item; -struct calc_elem; -class IOutputStream; - -template <class T> -std::pair<const named_dump_item*, size_t> get_named_dump_items(); - -class TFieldCalculatorBase { -private: - segmented_string_pool pool; - void emit_op(TVector<calc_op>& ops, calc_elem& left, calc_elem& right); - void MarkLocalVarsAsUncalculated(); - -protected: - autoarray<dump_item> printouts, conditions; - int out_el, out_cond; - TVector<calc_op> calc_ops; // operands for calculator, indexed by arr_ind for DIT_math_result - - TVector<std::pair<const named_dump_item*, size_t>> named_dump_items; - TMap<const char*, dump_item> local_vars; - - char* get_field(dump_item& dst, char* s); - bool get_local_var(dump_item& dst, char* s); - virtual bool item_by_name(dump_item& it, const char* name) const; - - TFieldCalculatorBase(); - virtual ~TFieldCalculatorBase(); - - bool Cond(const char** d); - bool CondById(const char** d, int condNumber); - void Print(FILE* p, const char** d, const char* Name); - void Compile(char** field_names, int field_count); - void SelfTest(); - void PrintDiff(const char* d1, const char* d2); - void CalcAll(const char** d, TVector<float>& result) const; - void DumpAll(IOutputStream& s, const char** d, const TStringBuf& delim); -}; - -template <class T> -class TFieldCalculator: protected TFieldCalculatorBase { -public: - TFieldCalculator() { - named_dump_items.push_back(get_named_dump_items<T>()); - } - - ~TFieldCalculator() override = default; - - bool Cond(const T& d) { - const char* dd = reinterpret_cast<const char*>(&d); - return TFieldCalculatorBase::Cond(&dd); - } - - bool CondById(const T& d, int condNumber) { - const char* dd = reinterpret_cast<const char*>(&d); - return TFieldCalculatorBase::CondById(&dd, condNumber); - } - - void Print(const T& d, const char* Name) { - const char* dd = reinterpret_cast<const char*>(&d); - return TFieldCalculatorBase::Print(stdout, &dd, Name); - } - - void Print(FILE* p, const T& d, const char* Name) { - const char* dd = reinterpret_cast<const char*>(&d); - return TFieldCalculatorBase::Print(p, &dd, Name); - } - - size_t Compile(char** field_names, int field_count) { - TFieldCalculatorBase::Compile(field_names, field_count); - return out_el; // number of fields printed - } - - void SelfTest() { - return TFieldCalculatorBase::SelfTest(); - } - - void PrintDiff(const T& d1, const T& d2) { - return TFieldCalculatorBase::PrintDiff((const char*)&d1, (const char*)&d2); - } - - void CalcAll(const T& d, TVector<float>& result) const { - const char* dd = reinterpret_cast<const char*>(&d); - return TFieldCalculatorBase::CalcAll(&dd, result); - } - - // it appends to `result', clear it yourself - void DumpAll(IOutputStream& s, const T& d, const TStringBuf& delim) { - const char* dd = reinterpret_cast<const char*>(&d); - return TFieldCalculatorBase::DumpAll(s, &dd, delim); - } -}; - -template <class T, class T2> -class TFieldCalculator2: protected TFieldCalculator<T> { -public: - TFieldCalculator2() { - TFieldCalculator<T>::named_dump_items.push_back(get_named_dump_items<T2>()); - } - - ~TFieldCalculator2() override = default; - - bool Cond(const T& d, const T2& d2) { - const char* dd[2] = {reinterpret_cast<const char*>(&d), reinterpret_cast<const char*>(&d2)}; - return TFieldCalculatorBase::Cond(dd); - } - - bool CondById(const T& d, const T2& d2, int condNumber) { - const char* dd[2] = {reinterpret_cast<const char*>(&d), reinterpret_cast<const char*>(&d2)}; - return TFieldCalculatorBase::CondById(dd, condNumber); - } - - void Print(const T& d, const T2& d2, const char* Name) { - const char* dd[2] = {reinterpret_cast<const char*>(&d), reinterpret_cast<const char*>(&d2)}; - return TFieldCalculatorBase::Print(stdout, dd, Name); - } - - void Print(FILE* p, const T& d, const T2& d2, const char* Name) { - const char* dd[2] = {reinterpret_cast<const char*>(&d), reinterpret_cast<const char*>(&d2)}; - return TFieldCalculatorBase::Print(p, dd, Name); - } - - size_t Compile(char** field_names, int field_count) { - return TFieldCalculator<T>::Compile(field_names, field_count); - } -}; diff --git a/library/cpp/fieldcalc/field_calc_int.h b/library/cpp/fieldcalc/field_calc_int.h deleted file mode 100644 index 5f71fafbda..0000000000 --- a/library/cpp/fieldcalc/field_calc_int.h +++ /dev/null @@ -1,593 +0,0 @@ -#pragma once - -#include <cmath> - -#include <util/system/defaults.h> -#include <util/system/yassert.h> -#include <util/memory/alloc.h> -#include <util/generic/yexception.h> - -#include "lossy_types.h" -#include "field_calc.h" - -// eval_res_type -struct eval_res_type { - union { - ui32 res_ui32; - long res_long; - double res_dbl; - }; - int type; - eval_res_type(ui32 v) - : res_ui32(v) - , type(0) - { - } - eval_res_type(long v) - : res_long(v) - , type(1) - { - } - eval_res_type(bool v) - : res_long(v) - , type(1) - { - } - eval_res_type(double v) - : res_dbl(v) - , type(2) - { - } - // a special null value for ternary operator - explicit eval_res_type() - : type(3) - { - } - operator ui32() const; - operator long() const; - operator double() const; - void to_long(); - bool is_null() const; -}; - -inline bool eval_res_type::is_null() const { - return type == 3; -} - -inline void eval_res_type::to_long() { - if (type == 0) - res_long = res_ui32; - else if (type == 2) - res_long = (long)res_dbl; - type = 1; -} - -inline eval_res_type::operator ui32() const { - assert(type == 0); - return res_ui32; -} - -inline eval_res_type::operator long() const { - assert(type == 0 || type == 1); - return type == 1 ? res_long : res_ui32; -} - -inline eval_res_type::operator double() const { - return type == 2 ? res_dbl : type == 1 ? (double)res_long : (double)res_ui32; -} - -inline eval_res_type operator+(const eval_res_type& a, const eval_res_type& b) { - switch (std::max(a.type, b.type)) { - case 0: - return (ui32)a + (ui32)b; - case 1: - return (long)a + (long)b; - /*case 2*/ default: - return (double)a + (double)b; - } -} - -inline eval_res_type operator-(const eval_res_type& a, const eval_res_type& b) { - switch (std::max(a.type, b.type)) { - case 0: - case 1: - return (long)a - (long)b; - /*case 2*/ default: - return (double)a - (double)b; - } -} - -inline eval_res_type Minus(const eval_res_type& a) { - switch (a.type) { - case 0: - return -(long)a.res_ui32; - case 1: - return -a.res_long; - /*case 2*/ default: - return -a.res_dbl; - } -} - -inline eval_res_type Log(const eval_res_type& a) { - switch (a.type) { - case 0: - return log(a.res_ui32); - case 1: - return log(a.res_long); - /*case 2*/ default: - return log(a.res_dbl); - } -} - -inline eval_res_type Log10(const eval_res_type& a) { - switch (a.type) { - case 0: - return log10(a.res_ui32); - case 1: - return log10(a.res_long); - /*case 2*/ default: - return log10(a.res_dbl); - } -} - -inline eval_res_type Round(const eval_res_type& a) { - switch (a.type) { - case 0: - return a.res_ui32; - case 1: - return a.res_long; - /*case 2*/ default: - return round(a.res_dbl); - } -} - -inline bool operator==(const eval_res_type& a, const eval_res_type& b) { - switch (std::max(a.type, b.type)) { - case 0: - return (ui32)a == (ui32)b; - case 1: - return (long)a == (long)b; - /*case 2*/ default: - return (double)a == (double)b; - } -} - -inline bool operator<(const eval_res_type& a, const eval_res_type& b) { - switch (std::max(a.type, b.type)) { - case 0: - return (ui32)a < (ui32)b; - case 1: - return (long)a < (long)b; - /*case 2*/ default: - return (double)a < (double)b; - } -} - -inline eval_res_type operator*(const eval_res_type& a, const eval_res_type& b) { - switch (std::max(a.type, b.type)) { - case 0: - return (ui32)a * (ui32)b; - case 1: - return (long)a * (long)b; - /*case 2*/ default: - return (double)a * (double)b; - } -} - -inline double operator/(const eval_res_type& a, const eval_res_type& b) { - double a1 = a, b1 = b; - if (b1 == 0) { - if (a1 == 0) - return 0.; // assume that a should be 0 - ythrow yexception() << "Division by zero"; // TODO: show parameter names - } - return a1 / b1; -} - -// dump_item -enum EDumpItemType { - DIT_FAKE_ITEM, // fake item - value never used - DIT_MATH_RESULT, // eval result - DIT_NAME, - - DIT_FIELDS_START, // Start of item types for real fields - - DIT_BOOL_FIELD, - DIT_UI8_FIELD, - DIT_UI16_FIELD, - DIT_UI32_FIELD, - DIT_I64_FIELD, - DIT_UI64_FIELD, - DIT_FLOAT_FIELD, - DIT_DOUBLE_FIELD, - DIT_TIME_T32_FIELD, - DIT_PF16UI32_FIELD, - DIT_PF16FLOAT_FIELD, - DIT_SF16FLOAT_FIELD, - DIT_STRING_FIELD, // new - - DIT_FIELDS_END, // End of item types for real fields - - DIT_LONG_CONST, - DIT_FLOAT_CONST, - DIT_STR_CONST, - - DIT_INT_FUNCTION, - DIT_FLOAT_FUNCTION, - DIT_BOOL_FUNCTION, - DIT_STR_FUNCTION, // new - DIT_STRBUF_FUNCTION, // new - - DIT_UI8_EXT_FUNCTION, - DIT_UI16_EXT_FUNCTION, - DIT_UI32_EXT_FUNCTION, - DIT_UI64_EXT_FUNCTION, - - DIT_UI8_ENUM_EQ, - DIT_UI8_ENUM_SET, - DIT_UI16_ENUM_EQ, - DIT_UI16_ENUM_SET, - DIT_UI32_ENUM_EQ, - DIT_UI32_ENUM_SET, - DIT_INT_ENUM_FUNCTION_EQ, - DIT_INT_ENUM_FUNCTION_SET, - - DIT_BOOL_FUNC_FIXED_STR, - DIT_UI8_FUNC_FIXED_STR, - DIT_UI16_FUNC_FIXED_STR, - DIT_UI32_FUNC_FIXED_STR, - DIT_I64_FUNC_FIXED_STR, - DIT_UI64_FUNC_FIXED_STR, - DIT_FLOAT_FUNC_FIXED_STR, - DIT_DOUBLE_FUNC_FIXED_STR, - - DIT_RESOLVE_BY_NAME, //new - for external functions - - DIT_LOCAL_VARIABLE -}; - -inline bool IsStringType(EDumpItemType type) { - return type == DIT_STRING_FIELD || type == DIT_STR_CONST || type == DIT_STR_FUNCTION || type == DIT_STRBUF_FUNCTION || type == DIT_RESOLVE_BY_NAME; -} - -struct fake {}; - -struct calc_op; - -typedef int (fake::*int_fn_t)() const; -typedef float (fake::*float_fn_t)() const; -typedef bool (fake::*bool_fn_t)() const; -typedef ui16 (fake::*ui16_fn_t)() const; -typedef ui32 (fake::*ui32_fn_t)() const; -typedef bool (fake::*bool_strbuf_fn_t)(const TStringBuf&) const; // string -> bool -typedef ui8 (fake::*ui8_strbuf_fn_t)(const TStringBuf&) const; // string -> ui8 -typedef ui16 (fake::*ui16_strbuf_fn_t)(const TStringBuf&) const; // string -> ui16 -typedef ui32 (fake::*ui32_strbuf_fn_t)(const TStringBuf&) const; // string -> ui32 -typedef i64 (fake::*i64_strbuf_fn_t)(const TStringBuf&) const; // string -> i64 -typedef ui64 (fake::*ui64_strbuf_fn_t)(const TStringBuf&) const; // string -> ui64 -typedef float (fake::*float_strbuf_fn_t)(const TStringBuf&) const; // string -> float -typedef double (fake::*double_strbuf_fn_t)(const TStringBuf&) const; // string -> double -typedef const char* (fake::*str_fn_t)() const; -typedef const char* (fake::*strbuf_2_fn_t)(TString& buf, const char* nul) const; -typedef TStringBuf (fake::*resolve_fn_t)(const TStringBuf&) const; // string -> string, $var -> "value" - -// note: we can not reuse the above signatures, calling conventions may differ -typedef ui8 (*ui8_ext_fn_t)(const fake*); -typedef ui16 (*ui16_ext_fn_t)(const fake*); -typedef ui32 (*ui32_ext_fn_t)(const fake*); -typedef ui64 (*ui64_ext_fn_t)(const fake*); - -struct dump_item { - EDumpItemType type; - int pack_id = 0; - - union { - // fields - intptr_t field_offset; - - // constants - long long_const; - float float_const; - - // functions - int_fn_t int_fn; - float_fn_t float_fn; - bool_fn_t bool_fn; - str_fn_t str_fn; - strbuf_2_fn_t strbuf_2_fn; - resolve_fn_t resolve_fn; - - bool_strbuf_fn_t bool_strbuf_fn; - ui8_strbuf_fn_t ui8_strbuf_fn; - ui16_strbuf_fn_t ui16_strbuf_fn; - ui32_strbuf_fn_t ui32_strbuf_fn; - i64_strbuf_fn_t i64_strbuf_fn; - ui64_strbuf_fn_t ui64_strbuf_fn; - float_strbuf_fn_t float_strbuf_fn; - double_strbuf_fn_t double_strbuf_fn; - - ui8_ext_fn_t ui8_ext_fn; - ui16_ext_fn_t ui16_ext_fn; - ui32_ext_fn_t ui32_ext_fn; - ui64_ext_fn_t ui64_ext_fn; - - // enum - int_fn_t int_enum_fn; - - // for DIT_MATH_RESULT - const calc_op* op; - }; - - // for enum - ui32 enum_val; - - // for local vars, also used to mark accessor functions to use them in dump - const char* local_var_name = nullptr; - - int arr_ind; // externally initialized! - int arr_length; - - mutable TString the_buf; // buffer for string function, string constants also here - - // Ctors - dump_item() - : type(DIT_FAKE_ITEM) - , field_offset(0) - { - } - - dump_item(bool* ptr, int arrlen = 0) - : type(DIT_BOOL_FIELD) - , field_offset(reinterpret_cast<intptr_t>(ptr)) - , arr_length(arrlen) - { - } - dump_item(ui8* ptr, int arrlen = 0) - : type(DIT_UI8_FIELD) - , field_offset(reinterpret_cast<intptr_t>(ptr)) - , arr_length(arrlen) - { - } - dump_item(ui16* ptr, int arrlen = 0) - : type(DIT_UI16_FIELD) - , field_offset(reinterpret_cast<intptr_t>(ptr)) - , arr_length(arrlen) - { - } - dump_item(ui32* ptr, int arrlen = 0) - : type(DIT_UI32_FIELD) - , field_offset(reinterpret_cast<intptr_t>(ptr)) - , arr_length(arrlen) - { - } - dump_item(i64* ptr, int arrlen = 0) - : type(DIT_I64_FIELD) - , field_offset(reinterpret_cast<intptr_t>(ptr)) - , arr_length(arrlen) - { - } - dump_item(ui64* ptr, int arrlen = 0) - : type(DIT_UI64_FIELD) - , field_offset(reinterpret_cast<intptr_t>(ptr)) - , arr_length(arrlen) - { - } - dump_item(float* ptr, int arrlen = 0) - : type(DIT_FLOAT_FIELD) - , field_offset(reinterpret_cast<intptr_t>(ptr)) - , arr_length(arrlen) - { - } - dump_item(double* ptr, int arrlen = 0) - : type(DIT_DOUBLE_FIELD) - , field_offset(reinterpret_cast<intptr_t>(ptr)) - , arr_length(arrlen) - { - } - dump_item(time_t32* ptr, int arrlen = 0) - : type(DIT_TIME_T32_FIELD) - , field_offset(reinterpret_cast<intptr_t>(ptr)) - , arr_length(arrlen) - { - } - dump_item(pf16ui32* ptr, int arrlen = 0) - : type(DIT_PF16UI32_FIELD) - , field_offset(reinterpret_cast<intptr_t>(ptr)) - , arr_length(arrlen) - { - } - dump_item(pf16float* ptr, int arrlen = 0) - : type(DIT_PF16FLOAT_FIELD) - , field_offset(reinterpret_cast<intptr_t>(ptr)) - , arr_length(arrlen) - { - } - dump_item(sf16float* ptr, int arrlen = 0) - : type(DIT_SF16FLOAT_FIELD) - , field_offset(reinterpret_cast<intptr_t>(ptr)) - , arr_length(arrlen) - { - } - dump_item(char* ptr, int arrlen = 0) - : type(DIT_STRING_FIELD) - , field_offset(reinterpret_cast<intptr_t>(ptr)) - , arr_length(arrlen) - { - } - - dump_item(long val) - : type(DIT_LONG_CONST) - , long_const(val) - { - } - dump_item(float val) - : type(DIT_FLOAT_CONST) - , float_const(val) - { - } - dump_item(TString& val) - : type(DIT_STR_CONST) - , the_buf(val) - { - } - - dump_item(int_fn_t fn) - : type(DIT_INT_FUNCTION) - , int_fn(fn) - { - } - dump_item(float_fn_t fn) - : type(DIT_FLOAT_FUNCTION) - , float_fn(fn) - { - } - dump_item(bool_fn_t fn) - : type(DIT_BOOL_FUNCTION) - , bool_fn(fn) - { - } - dump_item(bool_strbuf_fn_t fn, const char* name) - : type(DIT_BOOL_FUNC_FIXED_STR) - , bool_strbuf_fn(fn) - , the_buf(name) - { - } - dump_item(ui8_strbuf_fn_t fn, const char* name) - : type(DIT_UI8_FUNC_FIXED_STR) - , ui8_strbuf_fn(fn) - , the_buf(name) - { - } - dump_item(ui16_strbuf_fn_t fn, const char* name) - : type(DIT_UI16_FUNC_FIXED_STR) - , ui16_strbuf_fn(fn) - , the_buf(name) - { - } - dump_item(ui32_strbuf_fn_t fn, const char* name) - : type(DIT_UI32_FUNC_FIXED_STR) - , ui32_strbuf_fn(fn) - , the_buf(name) - { - } - dump_item(i64_strbuf_fn_t fn, const char* name) - : type(DIT_I64_FUNC_FIXED_STR) - , i64_strbuf_fn(fn) - , the_buf(name) - { - } - dump_item(ui64_strbuf_fn_t fn, const char* name) - : type(DIT_UI64_FUNC_FIXED_STR) - , ui64_strbuf_fn(fn) - , the_buf(name) - { - } - dump_item(float_strbuf_fn_t fn, const char* name) - : type(DIT_FLOAT_FUNC_FIXED_STR) - , float_strbuf_fn(fn) - , the_buf(name) - { - } - dump_item(double_strbuf_fn_t fn, const char* name) - : type(DIT_DOUBLE_FUNC_FIXED_STR) - , double_strbuf_fn(fn) - , the_buf(name) - { - } - dump_item(str_fn_t fn) - : type(DIT_STR_FUNCTION) - , str_fn(fn) - { - } - dump_item(strbuf_2_fn_t fn) - : type(DIT_STRBUF_FUNCTION) - , strbuf_2_fn(fn) - { - } - - dump_item(ui8_ext_fn_t fn, const char* lvn = nullptr) - : type(DIT_UI8_EXT_FUNCTION) - , ui8_ext_fn(fn) - , local_var_name(lvn) - { - } - dump_item(ui16_ext_fn_t fn, const char* lvn = nullptr) - : type(DIT_UI16_EXT_FUNCTION) - , ui16_ext_fn(fn) - , local_var_name(lvn) - { - } - dump_item(ui32_ext_fn_t fn, const char* lvn = nullptr) - : type(DIT_UI32_EXT_FUNCTION) - , ui32_ext_fn(fn) - , local_var_name(lvn) - { - } - dump_item(ui64_ext_fn_t fn, const char* lvn = nullptr) - : type(DIT_UI64_EXT_FUNCTION) - , ui64_ext_fn(fn) - , local_var_name(lvn) - { - } - - dump_item(ui8* ptr, ui32 val, bool bitset) - : type(bitset ? DIT_UI8_ENUM_SET : DIT_UI8_ENUM_EQ) - , field_offset(reinterpret_cast<intptr_t>(ptr)) - , enum_val(val) - { - } - - dump_item(ui16* ptr, ui32 val, bool bitset) - : type(bitset ? DIT_UI16_ENUM_SET : DIT_UI16_ENUM_EQ) - , field_offset(reinterpret_cast<intptr_t>(ptr)) - , enum_val(val) - { - } - - dump_item(ui32* ptr, ui32 val, bool bitset) - : type(bitset ? DIT_UI32_ENUM_SET : DIT_UI32_ENUM_EQ) - , field_offset(reinterpret_cast<intptr_t>(ptr)) - , enum_val(val) - { - } - - dump_item(int_fn_t fn, ui32 val, bool bitset) - : type(bitset ? DIT_INT_ENUM_FUNCTION_SET : DIT_INT_ENUM_FUNCTION_EQ) - , int_enum_fn(fn) - , enum_val(val) - { - } - - dump_item(resolve_fn_t fn, const char* name) - : type(DIT_RESOLVE_BY_NAME) - , resolve_fn(fn) - , the_buf(name) - { - } //name of variable saved in the_buf - - // Functions - template <class TOut> // implemented for FILE*, TString* (appends) and IOutputStream* - void print(TOut* p, const char** dd) const; - TStringBuf GetStrBuf(const char** dd) const; // for char-types only! - eval_res_type eval(const char** dd) const; - void set_arrind(int arrind); - void rewrite_op(const calc_op* ops); - - bool is_accessor_func() const { - return type >= DIT_INT_FUNCTION && type <= DIT_UI64_EXT_FUNCTION && local_var_name; - } - - bool is_field() const { - return type > DIT_FIELDS_START && type < DIT_FIELDS_END || is_accessor_func(); - } - - bool is_array_field() const { - return is_field() && arr_length > 0; - } -}; - -// named_dump_item -struct named_dump_item { - const char* name; - dump_item item; -}; diff --git a/library/cpp/fieldcalc/lossy_types.h b/library/cpp/fieldcalc/lossy_types.h deleted file mode 100644 index 98acfea902..0000000000 --- a/library/cpp/fieldcalc/lossy_types.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include <util/generic/cast.h> - -// although target value is float, this thing is only used as unsigned int container -struct pf16ui32 { - ui16 val; - pf16ui32() - : val(0) - { - } - void operator=(ui32 t) { - val = static_cast<ui16>(BitCast<ui32>(static_cast<float>(t)) >> 15); - } - operator ui32() const { - return (ui32)BitCast<float>((ui32)(val << 15)); - } -}; - -// unsigned float value -struct pf16float { - ui16 val; - pf16float() - : val(0) - { - } - void operator=(float t) { - assert(t >= 0.); - val = static_cast<ui16>(BitCast<ui32>(t) >> 15); - } - operator float() const { - return BitCast<float>((ui32)(val << 15)); - } -}; - -// signed float value -struct sf16float { - ui16 val; - sf16float() - : val(0) - { - } - void operator=(float t) { - assert(t >= 0.); - val = BitCast<ui32>(t) >> 16; - } - operator float() const { - return BitCast<float>((ui32)(val << 16)); - } -}; - -typedef i32 time_t32; // not really lossy, should be placed somewhere else diff --git a/library/cpp/fieldcalc/ya.make b/library/cpp/fieldcalc/ya.make deleted file mode 100644 index 9796592996..0000000000 --- a/library/cpp/fieldcalc/ya.make +++ /dev/null @@ -1,13 +0,0 @@ -LIBRARY() - -PEERDIR( - library/cpp/deprecated/autoarray -) - -SRCS( - field_calc.cpp - lossy_types.h - field_calc_int.h -) - -END() diff --git a/library/cpp/malloc/galloc/malloc-info.cpp b/library/cpp/malloc/galloc/malloc-info.cpp deleted file mode 100644 index fbcfa7ee06..0000000000 --- a/library/cpp/malloc/galloc/malloc-info.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include <library/cpp/malloc/api/malloc.h> - -using namespace NMalloc; - -TMallocInfo NMalloc::MallocInfo() { - TMallocInfo r; - r.Name = "tcmalloc"; - return r; -} diff --git a/library/cpp/malloc/galloc/ya.make b/library/cpp/malloc/galloc/ya.make deleted file mode 100644 index b6646a6cf6..0000000000 --- a/library/cpp/malloc/galloc/ya.make +++ /dev/null @@ -1,15 +0,0 @@ -LIBRARY() - -NO_UTIL() -ALLOCATOR_IMPL() - -PEERDIR( - library/cpp/malloc/api - contrib/deprecated/galloc -) - -SRCS( - malloc-info.cpp -) - -END() diff --git a/library/cpp/on_disk/multi_blob/multiblob.cpp b/library/cpp/on_disk/multi_blob/multiblob.cpp deleted file mode 100644 index d92b31e613..0000000000 --- a/library/cpp/on_disk/multi_blob/multiblob.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include <util/generic/yexception.h> -#include <util/system/align.h> - -#include <library/cpp/on_disk/chunks/reader.h> - -#include "multiblob.h" - -void TSubBlobs::ReadMultiBlob(const TBlob& multi) { - if (multi.Size() < sizeof(TMultiBlobHeader)) { - ythrow yexception() << "not a blob, too small"; - } - - Multi = multi; - memcpy((void*)&Header, Multi.Data(), sizeof(TMultiBlobHeader)); - - if (Header.BlobMetaSig != BLOBMETASIG) { - if (Header.BlobRecordSig != TMultiBlobHeader::RecordSig) { - if (ReadChunkedData(multi)) - return; - } - ythrow yexception() << "is not a blob, MetaSig was read: " - << Header.BlobMetaSig - << ", must be" << BLOBMETASIG; - } - - if (Header.BlobRecordSig != TMultiBlobHeader::RecordSig) - ythrow yexception() << "unknown multiblob RecordSig " - << Header.BlobRecordSig; - - reserve(size() + Header.Count); - if (Header.Flags & EMF_INTERLAY) { - size_t pos = Header.HeaderSize(); - for (size_t i = 0; i < Header.Count; ++i) { - pos = AlignUp<ui64>(pos, sizeof(ui64)); - ui64 size = *((ui64*)((const char*)multi.Data() + pos)); - pos = AlignUp<ui64>(pos + sizeof(ui64), Header.Align); - push_back(multi.SubBlob(pos, pos + size)); - pos += size; - } - } else { - const ui64* sizes = Header.Sizes(multi.Data()); - size_t pos = Header.HeaderSize() + Header.Count * sizeof(ui64); - for (size_t i = 0; i < Header.Count; ++i) { - pos = AlignUp<ui64>(pos, Header.Align); - push_back(multi.SubBlob(pos, pos + *sizes)); - pos += *sizes; - sizes++; - } - } -} - -bool TSubBlobs::ReadChunkedData(const TBlob& multi) noexcept { - Multi = multi; - memset((void*)&Header, 0, sizeof(Header)); - - TChunkedDataReader reader(Multi); - Header.Count = reader.GetBlocksCount(); - resize(GetHeader()->Count); - for (size_t i = 0; i < size(); ++i) - // We can use TBlob::NoCopy() because of reader.GetBlock(i) returns - // address into memory of multi blob. - // This knowledge was acquired from implementation of - // TChunkedDataReader, so we need care about any changes that. - (*this)[i] = TBlob::NoCopy(reader.GetBlock(i), reader.GetBlockLen(i)); - Header.Flags |= EMF_CHUNKED_DATA_READER; - return true; -} diff --git a/library/cpp/on_disk/multi_blob/multiblob.h b/library/cpp/on_disk/multi_blob/multiblob.h deleted file mode 100644 index b40a5ae6af..0000000000 --- a/library/cpp/on_disk/multi_blob/multiblob.h +++ /dev/null @@ -1,77 +0,0 @@ -#pragma once - -#include <util/generic/vector.h> -#include <util/memory/blob.h> - -#define BLOBMETASIG 0x3456789Au - -enum E_Multiblob_Flags { - // if EMF_INTERLAY is clear - // multiblob format - // HeaderSize() bytes for TMultiBlobHeader - // Count*sizeof(ui64) bytes for blob sizes - // blob1 - // (alignment) - // blob2 - // (alignment) - // ... - // (alignment) - // blobn - // if EMF_INTERLAY is set - // multiblob format - // HeaderSize() bytes for TMultiBlobHeader - // size1 ui64, the size of 1st blob - // blob1 - // (alignment) - // size2 ui64, the size of 2nd blob - // blob2 - // (alignment) - // ... - // (alignment) - // sizen ui64, the size of n'th blob - // blobn - EMF_INTERLAY = 1, - - // Means that multiblob contains blocks in TChunkedDataReader format - // Legacy, use it only for old files, created for TChunkedDataReader - EMF_CHUNKED_DATA_READER = 2, - - // Flags that may be configured for blobbuilder in client code - EMF_WRITEABLE = EMF_INTERLAY, -}; - -struct TMultiBlobHeader { - // data - ui32 BlobMetaSig; - ui32 BlobRecordSig; - ui64 Count; // count of sub blobs - ui32 Align; // alignment for every subblob - ui32 Flags; - static const ui32 RecordSig = 0x23456789; - static inline size_t HeaderSize() { - return 4 * sizeof(ui64); - } - inline const ui64* Sizes(const void* Data) const { - return (const ui64*)((const char*)Data + HeaderSize()); - } -}; - -class TSubBlobs: public TVector<TBlob> { -public: - TSubBlobs() { - } - TSubBlobs(const TBlob& multi) { - ReadMultiBlob(multi); - } - void ReadMultiBlob(const TBlob& multi); - const TMultiBlobHeader* GetHeader() const { - return (const TMultiBlobHeader*)&Header; - } - -protected: - TMultiBlobHeader Header; - TBlob Multi; - -private: - bool ReadChunkedData(const TBlob& multi) noexcept; -}; diff --git a/library/cpp/on_disk/multi_blob/multiblob_builder.cpp b/library/cpp/on_disk/multi_blob/multiblob_builder.cpp deleted file mode 100644 index 44aa4a6c2f..0000000000 --- a/library/cpp/on_disk/multi_blob/multiblob_builder.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include <util/memory/tempbuf.h> -#include <util/system/align.h> - -#include "multiblob_builder.h" - -/* - * TBlobSaverMemory - */ -TBlobSaverMemory::TBlobSaverMemory(const void* ptr, size_t size) - : Blob(TBlob::NoCopy(ptr, size)) -{ -} - -TBlobSaverMemory::TBlobSaverMemory(const TBlob& blob) - : Blob(blob) -{ -} - -void TBlobSaverMemory::Save(IOutputStream& output, ui32 /*flags*/) { - output.Write((void*)Blob.Data(), Blob.Length()); -} - -size_t TBlobSaverMemory::GetLength() { - return Blob.Length(); -} - -/* - * TBlobSaverFile - */ - -TBlobSaverFile::TBlobSaverFile(TFile file) - : File(file) -{ - Y_ASSERT(File.IsOpen()); -} - -TBlobSaverFile::TBlobSaverFile(const char* filename, EOpenMode oMode) - : File(filename, oMode) -{ - Y_ASSERT(File.IsOpen()); -} - -void TBlobSaverFile::Save(IOutputStream& output, ui32 /*flags*/) { - TTempBuf buffer(1 << 20); - while (size_t size = File.Read((void*)buffer.Data(), buffer.Size())) - output.Write((void*)buffer.Data(), size); -} - -size_t TBlobSaverFile::GetLength() { - return File.GetLength(); -} - -/* - * TMultiBlobBuilder - */ - -TMultiBlobBuilder::TMultiBlobBuilder(bool isOwn) - : IsOwner(isOwn) -{ -} - -TMultiBlobBuilder::~TMultiBlobBuilder() { - if (IsOwner) - DeleteSubBlobs(); -} - -namespace { - ui64 PadToAlign(IOutputStream& output, ui64 fromPos, ui32 align) { - ui64 toPos = AlignUp<ui64>(fromPos, align); - for (; fromPos < toPos; ++fromPos) { - output << (char)0; - } - return toPos; - } -} - -void TMultiBlobBuilder::Save(IOutputStream& output, ui32 flags) { - TMultiBlobHeader header; - memset((void*)&header, 0, sizeof(header)); - header.BlobMetaSig = BLOBMETASIG; - header.BlobRecordSig = TMultiBlobHeader::RecordSig; - header.Count = Blobs.size(); - header.Align = ALIGN; - header.Flags = flags & EMF_WRITEABLE; - output.Write((void*)&header, sizeof(header)); - for (size_t i = sizeof(header); i < header.HeaderSize(); ++i) - output << (char)0; - ui64 pos = header.HeaderSize(); - if (header.Flags & EMF_INTERLAY) { - for (size_t i = 0; i < Blobs.size(); ++i) { - ui64 size = Blobs[i]->GetLength(); - pos = PadToAlign(output, pos, sizeof(ui64)); // Align size record - output.Write((void*)&size, sizeof(ui64)); - pos = PadToAlign(output, pos + sizeof(ui64), header.Align); // Align blob - Blobs[i]->Save(output, header.Flags); - pos += size; - } - } else { - for (size_t i = 0; i < Blobs.size(); ++i) { - ui64 size = Blobs[i]->GetLength(); - output.Write((void*)&size, sizeof(ui64)); - } - pos += Blobs.size() * sizeof(ui64); - for (size_t i = 0; i < Blobs.size(); ++i) { - pos = PadToAlign(output, pos, header.Align); - Blobs[i]->Save(output, header.Flags); - pos += Blobs[i]->GetLength(); - } - } - // Compensate for imprecise size - for (ui64 len = GetLength(); pos < len; ++pos) { - output << (char)0; - } -} - -size_t TMultiBlobBuilder::GetLength() { - // Sizes may be diferent with and without EMF_INTERLAY, so choose greater of 2 - size_t resNonInter = TMultiBlobHeader::HeaderSize() + Blobs.size() * sizeof(ui64); - size_t resInterlay = TMultiBlobHeader::HeaderSize(); - for (size_t i = 0; i < Blobs.size(); ++i) { - resInterlay = AlignUp<ui64>(resInterlay, sizeof(ui64)) + sizeof(ui64); - resInterlay = AlignUp<ui64>(resInterlay, ALIGN) + Blobs[i]->GetLength(); - resNonInter = AlignUp<ui64>(resNonInter, ALIGN) + Blobs[i]->GetLength(); - } - resInterlay = AlignUp<ui64>(resInterlay, ALIGN); - resNonInter = AlignUp<ui64>(resNonInter, ALIGN); - return Max(resNonInter, resInterlay); -} - -TMultiBlobBuilder::TSavers& TMultiBlobBuilder::GetBlobs() { - return Blobs; -} - -const TMultiBlobBuilder::TSavers& TMultiBlobBuilder::GetBlobs() const { - return Blobs; -} - -void TMultiBlobBuilder::AddBlob(IBlobSaverBase* blob) { - Blobs.push_back(blob); -} - -void TMultiBlobBuilder::DeleteSubBlobs() { - for (size_t i = 0; i < Blobs.size(); ++i) - delete Blobs[i]; - Blobs.clear(); -} diff --git a/library/cpp/on_disk/multi_blob/multiblob_builder.h b/library/cpp/on_disk/multi_blob/multiblob_builder.h deleted file mode 100644 index a8e3c6d35e..0000000000 --- a/library/cpp/on_disk/multi_blob/multiblob_builder.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include <util/system/align.h> -#include <util/stream/output.h> -#include <util/stream/file.h> -#include <util/draft/holder_vector.h> - -#include "multiblob.h" - -class IBlobSaverBase { -public: - virtual ~IBlobSaverBase() { - } - virtual void Save(IOutputStream& output, ui32 flags = 0) = 0; - virtual size_t GetLength() = 0; -}; - -inline void MultiBlobSave(IOutputStream& output, IBlobSaverBase& saver) { - saver.Save(output); -} - -class TBlobSaverMemory: public IBlobSaverBase { -public: - TBlobSaverMemory(const void* ptr, size_t size); - TBlobSaverMemory(const TBlob& blob); - void Save(IOutputStream& output, ui32 flags = 0) override; - size_t GetLength() override; - -private: - TBlob Blob; -}; - -class TBlobSaverFile: public IBlobSaverBase { -public: - TBlobSaverFile(TFile file); - TBlobSaverFile(const char* filename, EOpenMode oMode = RdOnly); - void Save(IOutputStream& output, ui32 flags = 0) override; - size_t GetLength() override; - -protected: - TFile File; -}; - -class TMultiBlobBuilder: public IBlobSaverBase { -protected: - // Data will be stored with default alignment DEVTOOLS-4548 - static const size_t ALIGN = 16; - -public: - typedef TVector<IBlobSaverBase*> TSavers; - - TMultiBlobBuilder(bool isOwn = true); - ~TMultiBlobBuilder() override; - void Save(IOutputStream& output, ui32 flags = 0) override; - size_t GetLength() override; - TSavers& GetBlobs(); - const TSavers& GetBlobs() const; - void AddBlob(IBlobSaverBase* blob); - void DeleteSubBlobs(); - -protected: - TSavers Blobs; - bool IsOwner; -}; diff --git a/library/cpp/on_disk/multi_blob/ya.make b/library/cpp/on_disk/multi_blob/ya.make deleted file mode 100644 index 50615fc901..0000000000 --- a/library/cpp/on_disk/multi_blob/ya.make +++ /dev/null @@ -1,13 +0,0 @@ -LIBRARY() - -SRCS( - multiblob.cpp - multiblob_builder.cpp -) - -PEERDIR( - library/cpp/on_disk/chunks - util/draft -) - -END() diff --git a/library/cpp/on_disk/st_hash/fake.cpp b/library/cpp/on_disk/st_hash/fake.cpp deleted file mode 100644 index ef5af4d432..0000000000 --- a/library/cpp/on_disk/st_hash/fake.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "save_stl.h" -#include "static_hash.h" -#include "static_hash_map.h" -#include "sthash_iterators.h" diff --git a/library/cpp/on_disk/st_hash/save_stl.h b/library/cpp/on_disk/st_hash/save_stl.h deleted file mode 100644 index 00f8f0e20d..0000000000 --- a/library/cpp/on_disk/st_hash/save_stl.h +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once - -#include <util/generic/hash.h> -#include <util/system/yassert.h> -#include <util/stream/output.h> - -// this structure might be replaced with sthashtable class -template <class HF, class Eq, class size_type> -struct sthashtable_nvm_sv { - sthashtable_nvm_sv() { - if (sizeof(sthashtable_nvm_sv) != sizeof(HF) + sizeof(Eq) + 3 * sizeof(size_type)) { - memset(this, 0, sizeof(sthashtable_nvm_sv)); - } - } - - sthashtable_nvm_sv(const HF& phf, const Eq& peq, const size_type& pnb, const size_type& pne, const size_type& pnd) - : sthashtable_nvm_sv() - { - hf = phf; - eq = peq; - num_buckets = pnb; - num_elements = pne; - data_end_off = pnd; - } - - HF hf; - Eq eq; - size_type num_buckets; - size_type num_elements; - size_type data_end_off; -}; - -/** - * Some hack to save both THashMap and sthash. - * Working with stHash does not depend on the template parameters, because the content of stHash is not used inside this method. - */ -template <class V, class K, class HF, class Ex, class Eq, class A> -template <class KeySaver> -inline int THashTable<V, K, HF, Ex, Eq, A>::save_for_st(IOutputStream* stream, KeySaver& ks, sthash<int, int, THash<int>, TEqualTo<int>, typename KeySaver::TSizeType>* stHash) const { - Y_ASSERT(!stHash || stHash->bucket_count() == bucket_count()); - typedef sthashtable_nvm_sv<HF, Eq, typename KeySaver::TSizeType> sv_type; - sv_type sv = {this->_get_hash_fun(), this->_get_key_eq(), static_cast<typename KeySaver::TSizeType>(buckets.size()), static_cast<typename KeySaver::TSizeType>(num_elements), 0}; - // to do: m.b. use just the size of corresponding object? - typename KeySaver::TSizeType cur_off = sizeof(sv_type) + - (sv.num_buckets + 1) * sizeof(typename KeySaver::TSizeType); - sv.data_end_off = cur_off; - const_iterator n; - for (n = begin(); n != end(); ++n) { - sv.data_end_off += static_cast<typename KeySaver::TSizeType>(ks.GetRecordSize(*n)); - } - typename KeySaver::TSizeType* sb = stHash ? (typename KeySaver::TSizeType*)(stHash->buckets()) : nullptr; - if (stHash) - sv.data_end_off += static_cast<typename KeySaver::TSizeType>(sb[buckets.size()] - sb[0]); - //saver.Align(sizeof(char*)); - stream->Write(&sv, sizeof(sv)); - - size_type i; - //save vector - for (i = 0; i < buckets.size(); ++i) { - node* cur = buckets[i]; - stream->Write(&cur_off, sizeof(cur_off)); - if (cur) { - while (!((uintptr_t)cur & 1)) { - cur_off += static_cast<typename KeySaver::TSizeType>(ks.GetRecordSize(cur->val)); - cur = cur->next; - } - } - if (stHash) - cur_off += static_cast<typename KeySaver::TSizeType>(sb[i + 1] - sb[i]); - } - stream->Write(&cur_off, sizeof(cur_off)); // end mark - for (i = 0; i < buckets.size(); ++i) { - node* cur = buckets[i]; - if (cur) { - while (!((uintptr_t)cur & 1)) { - ks.SaveRecord(stream, cur->val); - cur = cur->next; - } - } - if (stHash) - stream->Write((const char*)stHash + sb[i], sb[i + 1] - sb[i]); - } - return 0; -} diff --git a/library/cpp/on_disk/st_hash/static_hash.h b/library/cpp/on_disk/st_hash/static_hash.h deleted file mode 100644 index ca7a6ccd36..0000000000 --- a/library/cpp/on_disk/st_hash/static_hash.h +++ /dev/null @@ -1,420 +0,0 @@ -#pragma once - -#include "save_stl.h" -#include "sthash_iterators.h" - -#include <util/generic/hash.h> -#include <util/generic/vector.h> -#include <util/generic/buffer.h> -#include <util/generic/cast.h> -#include <util/generic/yexception.h> // for save/load only -#include <util/stream/file.h> -#include <util/stream/buffer.h> -#include <utility> - -#include <memory> -#include <algorithm> -#include <functional> - -#include <cstdlib> -#include <cstddef> - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4624) // 'destructor could not be generated because a base class destructor is inaccessible' -#endif - -template <class HashType, class KeySaver> -inline void SaveHashToStreamEx(HashType& hash, IOutputStream* stream) { - KeySaver ks; - if (hash.save_for_st(stream, ks)) - ythrow yexception() << "Could not save hash to stream"; -} - -template <class HashType> -inline void SaveHashToStream(HashType& hash, IOutputStream* stream) { - typedef TSthashWriter<typename HashType::key_type, typename HashType::mapped_type, ui64> KeySaver; - return SaveHashToStreamEx<HashType, KeySaver>(hash, stream); -} - -template <class HashType, class KeySaver> -inline void SaveHashToFileEx(HashType& hash, const char* fileName) { - TFileOutput output(fileName); - SaveHashToStreamEx<HashType, KeySaver>(hash, &output); -} - -template <class HashType> -inline void SaveHashToFile(HashType& hash, const char* fileName) { - typedef TSthashWriter<typename HashType::key_type, typename HashType::mapped_type, ui64> KeySaver; - return SaveHashToFileEx<HashType, KeySaver>(hash, fileName); -} - -template <class HashType> -inline void SaveHashSetToFile(HashType& hash, const char* fileName) { - typedef TSthashSetWriter<typename HashType::key_type, ui64> KeySaver; - return SaveHashToFileEx<HashType, KeySaver>(hash, fileName); -} - -template <class HashType> -inline void SaveHashToFile32(HashType& hash, const char* fileName) { - typedef TSthashWriter<typename HashType::key_type, typename HashType::mapped_type, ui32> KeySaver; - return SaveHashToFileEx<HashType, KeySaver>(hash, fileName); -} - -template <class HashType, class KeySaver> -inline void SaveHashToBufferEx(HashType& hash, TBuffer& buffer, sthash<int, int, THash<int>, TEqualTo<int>, typename KeySaver::TSizeType>* stHash = nullptr) { - TBufferOutput stream(buffer); - KeySaver ks; - if (hash.save_for_st(&stream, ks, stHash)) - ythrow yexception() << "Could not save hash to memory"; -} - -template <class HashType> -inline void SaveHashToBuffer(HashType& hash, TBuffer& buffer) { - typedef TSthashWriter<typename HashType::key_type, typename HashType::mapped_type, ui64> KeySaver; - SaveHashToBufferEx<HashType, KeySaver>(hash, buffer); -} - -/** - * Some hack to save both THashMap and sthash. - * THashMap and sthash must have same bucket_count(). - */ -template <class HashType, class StHashType> -inline void SaveHashToBuffer(HashType& hash, TBuffer& buffer, StHashType* stHash) { - typedef TSthashWriter<typename HashType::key_type, typename HashType::mapped_type, ui64> KeySaver; - typedef sthash<int, int, THash<int>, TEqualTo<int>, typename KeySaver::TSizeType>* SH; - - SH sh = reinterpret_cast<SH>(stHash); - SaveHashToBufferEx<HashType, KeySaver>(hash, buffer, sh); -} - -template <class HashType> -inline void SaveHashToBuffer32(HashType& hash, TBuffer& buffer) { - typedef TSthashWriter<typename HashType::key_type, typename HashType::mapped_type, ui32> KeySaver; - SaveHashToBufferEx<HashType, KeySaver>(hash, buffer); -} - -template <class Iter, typename size_type_f = ui64> -class sthashtable { -public: - typedef typename Iter::TKeyType key_type; - typedef typename Iter::TValueType value_type; - typedef typename Iter::THasherType hasher; - typedef typename Iter::TKeyEqualType key_equal; - - typedef size_type_f size_type; - typedef ptrdiff_t difference_type; - typedef const value_type* const_pointer; - typedef const value_type& const_reference; - - typedef Iter const_iterator; - - const hasher hash_funct() const { - return hash; - } - const key_equal key_eq() const { - return equals; - } - -private: - const hasher hash; - const key_equal equals; - -private: - const_iterator iter_at_bucket(size_type bucket) const { - return (const_iterator)(((char*)this + buckets()[bucket])); - } - - const_iterator iter_at_bucket_or_end(size_type bucket) const { - if (bucket < num_buckets) - return (const_iterator)(((char*)this + buckets()[bucket])); - else - return end(); - } - - const size_type num_buckets; - const size_type num_elements; - const size_type data_end_off; - -protected: //shut up gcc warning - // we can't construct/destroy this object at all! - sthashtable(); - sthashtable(const sthashtable& ht); - ~sthashtable(); - -public: - // const size_type *buckets; - const size_type* buckets() const { - return (size_type*)((char*)this + sizeof(*this)); - } - const size_type buckets(size_type n) const { - return buckets()[n]; - } - - size_type size() const { - return num_elements; - } - size_type max_size() const { - return size_type(-1); - } - bool empty() const { - return size() == 0; - } - - const_iterator begin() const { - return num_buckets ? iter_at_bucket(0) : end(); - } - - const_iterator end() const { - return (const_iterator)(((char*)this + data_end_off)); - } - -public: - size_type size_in_bytes() const { - return data_end_off; - } - - size_type bucket_count() const { - return num_buckets; - } - - size_type elems_in_bucket(size_type bucket) const { - size_type result = 0; - const_iterator first = iter_at_bucket(bucket); - const_iterator last = iter_at_bucket_or_end(bucket + 1); - - for (; first != last; ++first) - ++result; - return result; - } - - template <class TheKey> - const_iterator find(const TheKey& key) const { - size_type n = bkt_num_key(key); - const_iterator first(iter_at_bucket(n)), last(iter_at_bucket_or_end(n + 1)); - for (; - first != last && !first.KeyEquals(equals, key); - ++first) { - } - if (first != last) - return first; - return end(); - } - - size_type count(const key_type& key) const { - const size_type n = bkt_num_key(key); - size_type result = 0; - const_iterator first = iter_at_bucket(n); - const_iterator last = iter_at_bucket_or_end(n + 1); - - for (; first != last; ++first) - if (first.KeyEquals(equals, key)) - ++result; - return result; - } - - std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const; - -private: - template <class TheKey> - size_type bkt_num_key(const TheKey& key) const { - return hash(key) % num_buckets; - } -}; - -template <class I, class size_type_f> -std::pair<I, I> sthashtable<I, size_type_f>::equal_range(const key_type& key) const { - typedef std::pair<const_iterator, const_iterator> pii; - const size_type n = bkt_num_key(key); - const_iterator first = iter_at_bucket(n); - const_iterator last = iter_at_bucket_or_end(n + 1); - - for (; first != last; ++first) { - if (first.KeyEquals(equals, key)) { - const_iterator cur = first; - ++cur; - for (; cur != last; ++cur) - if (!cur.KeyEquals(equals, key)) - return pii(const_iterator(first), - const_iterator(cur)); - return pii(const_iterator(first), - const_iterator(last)); - } - } - return pii(end(), end()); -} - -/* end __SGI_STL_HASHTABLE_H */ - -template <class Key, class T, class HashFcn /*= hash<Key>*/, - class EqualKey = TEqualTo<Key>, typename size_type_f = ui64> -class sthash { -private: - typedef sthashtable<TSthashIterator<const Key, const T, HashFcn, EqualKey>, size_type_f> ht; - ht rep; - -public: - typedef typename ht::key_type key_type; - typedef typename ht::value_type value_type; - typedef typename ht::hasher hasher; - typedef typename ht::key_equal key_equal; - typedef T mapped_type; - - typedef typename ht::size_type size_type; - typedef typename ht::difference_type difference_type; - typedef typename ht::const_pointer const_pointer; - typedef typename ht::const_reference const_reference; - - typedef typename ht::const_iterator const_iterator; - - const hasher hash_funct() const { - return rep.hash_funct(); - } - const key_equal key_eq() const { - return rep.key_eq(); - } - -public: - size_type size() const { - return rep.size(); - } - size_type max_size() const { - return rep.max_size(); - } - bool empty() const { - return rep.empty(); - } - - const_iterator begin() const { - return rep.begin(); - } - const_iterator end() const { - return rep.end(); - } - -public: - template <class TheKey> - const_iterator find(const TheKey& key) const { - return rep.find(key); - } - template <class TheKey> - bool has(const TheKey& key) const { - return rep.find(key) != rep.end(); - } - - size_type count(const key_type& key) const { - return rep.count(key); - } - - std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const { - return rep.equal_range(key); - } - - size_type size_in_bytes() const { - return rep.size_in_bytes(); - } - - size_type bucket_count() const { - return rep.bucket_count(); - } - size_type max_bucket_count() const { - return rep.max_bucket_count(); - } - size_type elems_in_bucket(size_type n) const { - return rep.elems_in_bucket(n); - } - - const size_type* buckets() const { - return rep.buckets(); - } - const size_type buckets(size_type n) const { - return rep.buckets()[n]; - } -}; - -template <class Key, class HashFcn, - class EqualKey = TEqualTo<Key>, typename size_type_f = ui64> -class sthash_set: public sthash<Key, TEmptyValue, HashFcn, EqualKey, size_type_f> { - typedef sthash<Key, TEmptyValue, HashFcn, EqualKey, size_type_f> Base; - -public: - using Base::const_iterator; - using Base::hasher; - using Base::key_equal; - using Base::key_type; - using Base::size_type; - using Base::value_type; -}; - -template <class Key, class T, class HashFcn /*= hash<Key>*/, - class EqualKey = TEqualTo<Key>, typename size_type_f = ui64> -class sthash_mm { -private: - typedef sthashtable<TSthashIterator<const Key, T, HashFcn, EqualKey>, size_type_f> ht; - ht rep; - -public: - typedef typename ht::key_type key_type; - typedef typename ht::value_type value_type; - typedef typename ht::hasher hasher; - typedef typename ht::key_equal key_equal; - typedef T mapped_type; - - typedef typename ht::size_type size_type; - typedef typename ht::difference_type difference_type; - typedef typename ht::const_pointer const_pointer; - typedef typename ht::const_reference const_reference; - - typedef typename ht::const_iterator const_iterator; - - const hasher hash_funct() const { - return rep.hash_funct(); - } - const key_equal key_eq() const { - return rep.key_eq(); - } - -public: - size_type size() const { - return rep.size(); - } - size_type max_size() const { - return rep.max_size(); - } - bool empty() const { - return rep.empty(); - } - - const_iterator begin() const { - return rep.begin(); - } - const_iterator end() const { - return rep.end(); - } - - const_iterator find(const key_type& key) const { - return rep.find(key); - } - - size_type count(const key_type& key) const { - return rep.count(key); - } - - std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const { - return rep.equal_range(key); - } - - size_type bucket_count() const { - return rep.bucket_count(); - } - size_type max_bucket_count() const { - return rep.max_bucket_count(); - } - size_type elems_in_bucket(size_type n) const { - return rep.elems_in_bucket(n); - } -}; - -#ifdef _MSC_VER -#pragma warning(pop) -#endif diff --git a/library/cpp/on_disk/st_hash/static_hash_map.h b/library/cpp/on_disk/st_hash/static_hash_map.h deleted file mode 100644 index 5dc50abd39..0000000000 --- a/library/cpp/on_disk/st_hash/static_hash_map.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include "static_hash.h" - -#include <library/cpp/deprecated/mapped_file/mapped_file.h> - -#include <util/system/filemap.h> - -template <class SH> -struct sthash_mapped_c { - typedef SH H; - typedef typename H::const_iterator const_iterator; - TMappedFile M; - H* hsh; - sthash_mapped_c() - : M() - , hsh(nullptr) - { - } - sthash_mapped_c(const char* fname, bool precharge) - : M() - , hsh(nullptr) - { - Open(fname, precharge); - } - void Open(const char* fname, bool precharge) { - M.init(fname); - if (precharge) - M.precharge(); - hsh = (H*)M.getData(); - if (M.getSize() < sizeof(H) || (ssize_t)M.getSize() != hsh->end().Data - (char*)hsh) - ythrow yexception() << "Could not map hash: " << fname << " is damaged"; - } - H* operator->() { - return hsh; - } - const H* operator->() const { - return hsh; - } - H* GetSthash() { - return hsh; - } - const H* GetSthash() const { - return hsh; - } -}; - -template <class Key, class T, class Hash> -struct sthash_mapped: public sthash_mapped_c<sthash<Key, T, Hash>> { - typedef sthash<Key, T, Hash> H; - sthash_mapped(const char* fname, bool precharge) - : sthash_mapped_c<H>(fname, precharge) - { - } - sthash_mapped() - : sthash_mapped_c<H>() - { - } -}; diff --git a/library/cpp/on_disk/st_hash/sthash_iterators.h b/library/cpp/on_disk/st_hash/sthash_iterators.h deleted file mode 100644 index 6a9ebdd6c3..0000000000 --- a/library/cpp/on_disk/st_hash/sthash_iterators.h +++ /dev/null @@ -1,334 +0,0 @@ -#pragma once - -#include "save_stl.h" - -#include <util/system/align.h> - -/** - This file provides functionality for saving some relatively simple THashMap object - to disk in a form that can be mapped read-only (via mmap) at any address. - That saved object is accessed via pointer to sthash object (that must have - the same parameters as original THashMap object) - - If either key or value are variable-sized (i.e. contain pointers), user must - write his own instantiation of TSthashIterator (read iterator for sthash) and - TSthashWriter (write iterator for THashMap). - An example for <const char *, B> pair is in here. -**/ - -// TEmptyValue and SizeOfEx are helpers for sthash_set -struct TEmptyValue { - TEmptyValue() = default; -}; - -template <class T> -inline size_t SizeOfEx() { - return sizeof(T); -} - -template <> -inline size_t SizeOfEx<TEmptyValue>() { - return 0; -} -template <> -inline size_t SizeOfEx<const TEmptyValue>() { - return 0; -} - -template <class TKey, class TValue, class HashFcn, class EqualKey> -struct TSthashIterator { - // Implementation for simple types - typedef const TKey TKeyType; - typedef const TValue TValueType; - typedef EqualKey TKeyEqualType; - typedef HashFcn THasherType; - - const char* Data; - TSthashIterator() - : Data(nullptr) - { - } - explicit TSthashIterator(const char* data) - : Data(data) - { - } - void operator++() { - Data += GetLength(); - } - - bool operator!=(const TSthashIterator& that) const { - return Data != that.Data; - } - bool operator==(const TSthashIterator& that) const { - return Data == that.Data; - } - TKey& Key() const { - return *(TKey*)Data; - } - TValue& Value() { - return *(TValue*)(Data + sizeof(TKey)); - } - const TValue& Value() const { - return *(const TValue*)(Data + sizeof(TKey)); - } - - template <class AnotherKeyType> - bool KeyEquals(const EqualKey& eq, const AnotherKeyType& key) const { - return eq(*(TKey*)Data, key); - } - - size_t GetLength() const { - return sizeof(TKey) + SizeOfEx<TValue>(); - } -}; - -template <class Key, class Value, typename size_type_o = ui64> -struct TSthashWriter { - typedef size_type_o TSizeType; - size_t GetRecordSize(const std::pair<const Key, const Value>&) const { - return sizeof(Key) + SizeOfEx<Value>(); - } - int SaveRecord(IOutputStream* stream, const std::pair<const Key, const Value>& record) const { - stream->Write(&record.first, sizeof(Key)); - stream->Write(&record.second, SizeOfEx<Value>()); - return 0; - } -}; - -// Remember that this simplified implementation makes a copy of `key' in std::make_pair. -// It can also waste some memory on undesired alignment. -template <class Key, typename size_type_o = ui64> -struct TSthashSetWriter: public TSthashWriter<Key, TEmptyValue, size_type_o> { - typedef TSthashWriter<Key, TEmptyValue, size_type_o> MapWriter; - size_t GetRecordSize(const Key& key) const { - return MapWriter::GetRecordSize(std::make_pair(key, TEmptyValue())); - } - int SaveRecord(IOutputStream* stream, const Key& key) const { - return MapWriter::SaveRecord(stream, std::make_pair(key, TEmptyValue())); - } -}; - -// we can't save something with pointers without additional tricks - -template <class A, class B, class HashFcn, class EqualKey> -struct TSthashIterator<A*, B, HashFcn, EqualKey> {}; - -template <class A, class B, class HashFcn, class EqualKey> -struct TSthashIterator<A, B*, HashFcn, EqualKey> {}; - -template <class A, class B, typename size_type_o> -struct TSthashWriter<A*, B*, size_type_o> {}; - -template <class A, class B, typename size_type_o> -struct TSthashWriter<A*, B, size_type_o> {}; - -template <class A, class B, typename size_type_o> -struct TSthashWriter<A, B*, size_type_o> {}; - -template <class T> -inline size_t AlignForChrKey() { - return 4; // TODO: change this (requeres rebuilt of a few existing files) -} - -template <> -inline size_t AlignForChrKey<TEmptyValue>() { - return 1; -} - -template <> -inline size_t AlignForChrKey<const TEmptyValue>() { - return AlignForChrKey<TEmptyValue>(); -} - -// !! note that for char*, physical placement of key and value is swapped -template <class TValue, class HashFcn, class EqualKey> -struct TSthashIterator<const char* const, TValue, HashFcn, EqualKey> { - typedef const TValue TValueType; - typedef const char* TKeyType; - typedef EqualKey TKeyEqualType; - typedef HashFcn THasherType; - - const char* Data; - TSthashIterator() - : Data(nullptr) - { - } - TSthashIterator(const char* data) - : Data(data) - { - } - void operator++() { - Data += GetLength(); - } - - bool operator!=(const TSthashIterator& that) const { - return Data != that.Data; - } - bool operator==(const TSthashIterator& that) const { - return Data == that.Data; - } - const char* Key() const { - return Data + SizeOfEx<TValue>(); - } - TValue& Value() { - return *(TValue*)Data; - } - const TValue& Value() const { - return *(const TValue*)Data; - } - - template <class K> - bool KeyEquals(const EqualKey& eq, const K& k) const { - return eq(Data + SizeOfEx<TValue>(), k); - } - - size_t GetLength() const { - size_t length = strlen(Data + SizeOfEx<TValue>()) + 1 + SizeOfEx<TValue>(); - length = AlignUp(length, AlignForChrKey<TValue>()); - return length; - } -}; - -template <class Value, typename size_type_o> -struct TSthashWriter<const char*, Value, size_type_o> { - typedef size_type_o TSizeType; - size_t GetRecordSize(const std::pair<const char*, const Value>& record) const { - size_t length = strlen(record.first) + 1 + SizeOfEx<Value>(); - length = AlignUp(length, AlignForChrKey<Value>()); - return length; - } - int SaveRecord(IOutputStream* stream, const std::pair<const char*, const Value>& record) const { - const char* alignBuffer = "qqqq"; - stream->Write(&record.second, SizeOfEx<Value>()); - size_t length = strlen(record.first) + 1; - stream->Write(record.first, length); - length = AlignUpSpace(length, AlignForChrKey<Value>()); - if (length) - stream->Write(alignBuffer, length); - return 0; - } -}; - -template <class TKey, class HashFcn, class EqualKey> -struct TSthashIterator<TKey, const char* const, HashFcn, EqualKey> { - typedef const TKey TKeyType; - typedef const char* TValueType; - typedef EqualKey TKeyEqualType; - typedef HashFcn THasherType; - - const char* Data; - TSthashIterator() - : Data(nullptr) - { - } - TSthashIterator(const char* data) - : Data(data) - { - } - void operator++() { - Data += GetLength(); - } - - bool operator!=(const TSthashIterator& that) const { - return Data != that.Data; - } - bool operator==(const TSthashIterator& that) const { - return Data == that.Data; - } - TKey& Key() { - return *(TKey*)Data; - } - const char* Value() const { - return Data + sizeof(TKey); - } - - template <class K> - bool KeyEquals(const EqualKey& eq, const K& k) const { - return eq(*(TKey*)Data, k); - } - - size_t GetLength() const { - size_t length = strlen(Data + sizeof(TKey)) + 1 + sizeof(TKey); - length = AlignUp(length, (size_t)4); - return length; - } -}; - -template <class Key, typename size_type_o> -struct TSthashWriter<Key, const char*, size_type_o> { - typedef size_type_o TSizeType; - size_t GetRecordSize(const std::pair<const Key, const char*>& record) const { - size_t length = strlen(record.second) + 1 + sizeof(Key); - length = AlignUp(length, (size_t)4); - return length; - } - int SaveRecord(IOutputStream* stream, const std::pair<const Key, const char*>& record) const { - const char* alignBuffer = "qqqq"; - stream->Write(&record.first, sizeof(Key)); - size_t length = strlen(record.second) + 1; - stream->Write(record.second, length); - length = AlignUpSpace(length, (size_t)4); - if (length) - stream->Write(alignBuffer, length); - return 0; - } -}; - -template <class HashFcn, class EqualKey> -struct TSthashIterator<const char* const, const char* const, HashFcn, EqualKey> { - typedef const char* TKeyType; - typedef const char* TValueType; - typedef EqualKey TKeyEqualType; - typedef HashFcn THasherType; - - const char* Data; - TSthashIterator() - : Data(nullptr) - { - } - TSthashIterator(const char* data) - : Data(data) - { - } - void operator++() { - Data += GetLength(); - } - - bool operator!=(const TSthashIterator& that) const { - return Data != that.Data; - } - bool operator==(const TSthashIterator& that) const { - return Data == that.Data; - } - const char* Key() const { - return Data; - } - const char* Value() const { - return Data + strlen(Data) + 1; - } - - template <class K> - bool KeyEquals(const EqualKey& eq, const K& k) const { - return eq(Data, k); - } - - size_t GetLength() const { - size_t length = strlen(Data) + 1; - length += strlen(Data + length) + 1; - return length; - } -}; - -template <typename size_type_o> -struct TSthashWriter<const char*, const char*, size_type_o> { - typedef size_type_o TSizeType; - size_t GetRecordSize(const std::pair<const char*, const char*>& record) const { - size_t size = strlen(record.first) + strlen(record.second) + 2; - return size; - } - int SaveRecord(IOutputStream* stream, const std::pair<const char*, const char*>& record) const { - stream->Write(record.first, strlen(record.first) + 1); - stream->Write(record.second, strlen(record.second) + 1); - return 0; - } -}; diff --git a/library/cpp/on_disk/st_hash/ya.make b/library/cpp/on_disk/st_hash/ya.make deleted file mode 100644 index 8c6d05711c..0000000000 --- a/library/cpp/on_disk/st_hash/ya.make +++ /dev/null @@ -1,15 +0,0 @@ -LIBRARY() - -SRCS( - fake.cpp - save_stl.h - static_hash.h - static_hash_map.h - sthash_iterators.h -) - -PEERDIR( - library/cpp/deprecated/mapped_file -) - -END() diff --git a/library/cpp/remmap/remmap.cpp b/library/cpp/remmap/remmap.cpp deleted file mode 100644 index ce72af7352..0000000000 --- a/library/cpp/remmap/remmap.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include <util/system/info.h> -#include <util/system/defaults.h> - -#if defined(_win_) -#include <util/system/winint.h> -#elif defined(_unix_) -#include <sys/types.h> -#include <sys/mman.h> - -#ifndef MAP_NOCORE -#define MAP_NOCORE 0 -#endif -#else -#error todo -#endif - -#include "remmap.h" - -static const size_t REMMAP_PAGESIZE = NSystemInfo::GetPageSize(); - -#if defined(_unix_) -TRemmapAllocation::TRemmapAllocation() - : Ptr_(nullptr) - , Size_(0) -{ -} - -TRemmapAllocation::TRemmapAllocation(size_t size, char* base) - : Ptr_(nullptr) - , Size_(0) -{ - Alloc(size, base); -} - -char* TRemmapAllocation::Alloc(size_t size, char* base) { - assert(Ptr_ == nullptr); - - if (!size) - return nullptr; - - const size_t HUGESIZE = size_t(16) << 30; - Ptr_ = CommonMMap(HUGESIZE, base); - - if (Ptr_ != (char*)MAP_FAILED) - munmap((void*)Ptr_, HUGESIZE); - else - Ptr_ = nullptr; - - Ptr_ = CommonMMap(AlignUp(size, REMMAP_PAGESIZE), Ptr_); - if (Ptr_ == (char*)MAP_FAILED) - Ptr_ = nullptr; - - Size_ = Ptr_ ? size : 0; - return Ptr_; -} - -char* TRemmapAllocation::Realloc(size_t newsize) { - if (Ptr_ == nullptr) - return Alloc(newsize); - - size_t realSize = AlignUp(Size_, REMMAP_PAGESIZE); - size_t needSize = AlignUp(newsize, REMMAP_PAGESIZE); - - if (needSize > realSize) { - char* part = Ptr_ + realSize; - char* bunch = CommonMMap(needSize - realSize, part); - if (bunch != (char*)MAP_FAILED && bunch != part) - munmap(bunch, needSize - realSize); - if (bunch == (char*)MAP_FAILED || bunch != part) - return FullRealloc(newsize); - } else if (needSize < realSize) - munmap(Ptr_ + needSize, realSize - needSize); - - if ((Size_ = newsize) == 0) - Ptr_ = nullptr; - - return Ptr_; -} - -void TRemmapAllocation::Dealloc() { - if (Ptr_ != nullptr) - munmap(Ptr_, AlignUp(Size_, REMMAP_PAGESIZE)); - Ptr_ = nullptr; - Size_ = 0; -} - -char* TRemmapAllocation::FullRealloc(size_t newsize) { - char* newPtr = CommonMMap(newsize); - Y_ABORT_UNLESS(newPtr != MAP_FAILED, "mmap failed"); - - size_t useful = Min(Size_, newsize), cur = 0; - - for (; cur + REMMAP_PAGESIZE < useful; cur += REMMAP_PAGESIZE) { - memcpy((void*)&newPtr[cur], (void*)&Ptr_[cur], REMMAP_PAGESIZE); - munmap((void*)&Ptr_[cur], REMMAP_PAGESIZE); - } - - memcpy((void*)&newPtr[cur], (void*)&Ptr_[cur], useful - cur); - munmap((void*)&Ptr_[cur], AlignUp(Size_ - cur, REMMAP_PAGESIZE)); - - Size_ = newsize; - return (Ptr_ = newPtr); -} - -inline char* TRemmapAllocation::CommonMMap(size_t size, char* base) { - return (char*)mmap((void*)base, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); -} - -#else -TRemmapAllocation::TRemmapAllocation() - : Allocation_(0, false, NULL) -{ -} - -TRemmapAllocation::TRemmapAllocation(size_t size, char* base) - : Allocation_(size, false, (void*)base) -{ -} - -char* TRemmapAllocation::Alloc(size_t size, char* base) { - return (char*)Allocation_.Alloc(size, (void*)base); -} - -char* TRemmapAllocation::Realloc(size_t newsize) { - return FullRealloc(newsize); -} - -void TRemmapAllocation::Dealloc() { - Allocation_.Dealloc(); -} - -char* TRemmapAllocation::FullRealloc(size_t newsize) { - TMappedAllocation other(newsize); - memcpy(other.Ptr(), Allocation_.Ptr(), Min(other.MappedSize(), Allocation_.MappedSize())); - Allocation_.swap(other); - return Data(); -} -#endif diff --git a/library/cpp/remmap/remmap.h b/library/cpp/remmap/remmap.h deleted file mode 100644 index 7cb738f7ae..0000000000 --- a/library/cpp/remmap/remmap.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include <util/system/yassert.h> -#include <util/system/align.h> -#include <util/system/info.h> -#include <util/system/filemap.h> -#include <util/memory/alloc.h> -#include <util/generic/noncopyable.h> - -class TRemmapAllocation : TNonCopyable { -public: - TRemmapAllocation(); - TRemmapAllocation(size_t size, char* base = nullptr); - - ~TRemmapAllocation() { - Dealloc(); - } - - char* Alloc(size_t size, char* base = nullptr); - char* Realloc(size_t newsize); - void Dealloc(); - char* FullRealloc(size_t newsize); - -#if defined(_unix_) -private: - inline char* CommonMMap(size_t size, char* base = nullptr); - - char* Ptr_; - size_t Size_; - -public: - inline void* Ptr() const { - return (void*)Ptr_; - } - inline char* Data(ui32 pos = 0) const { - return Ptr_ + pos; - } - inline size_t Size() const { - return Size_; - } - inline void swap(TRemmapAllocation& other) { - DoSwap(Ptr_, other.Ptr_); - DoSwap(Size_, other.Size_); - } - -#else -private: - TMappedAllocation Allocation_; - -public: - inline void* Ptr() const { - return Allocation_.Ptr(); - } - inline char* Data(ui32 pos = 0) const { - return Allocation_.Data(pos); - } - inline size_t Size() const { - return Allocation_.MappedSize(); - } - inline void swap(TRemmapAllocation& other) { - Allocation_.swap(other.Allocation_); - } -#endif -}; diff --git a/library/cpp/remmap/ya.make b/library/cpp/remmap/ya.make deleted file mode 100644 index 281df6443a..0000000000 --- a/library/cpp/remmap/ya.make +++ /dev/null @@ -1,7 +0,0 @@ -LIBRARY() - -SRCS( - remmap.cpp -) - -END() diff --git a/library/cpp/sqlite3/sqlite.cpp b/library/cpp/sqlite3/sqlite.cpp deleted file mode 100644 index 98e498f76b..0000000000 --- a/library/cpp/sqlite3/sqlite.cpp +++ /dev/null @@ -1,288 +0,0 @@ -#include "sqlite.h" - -#include <util/generic/singleton.h> -#include <util/generic/scope.h> - -#include <cstdlib> - -using namespace NSQLite; - -namespace { - struct TSQLiteInit { - inline TSQLiteInit() { - int ret = sqlite3_config(SQLITE_CONFIG_MULTITHREAD); - - if (ret != SQLITE_OK) { - ythrow TSQLiteError(ret) << "init failure"; - } - } - - static inline void Ensure() { - Singleton<TSQLiteInit>(); - } - }; -} - -namespace NSQLite { - TSQLiteError::TSQLiteError(sqlite3* hndl) - : ErrorCode(sqlite3_errcode(hndl)) - { - *this << sqlite3_errmsg(hndl) << ". "; - } - - TSQLiteError::TSQLiteError(int rc) - : ErrorCode(rc) - { - *this << sqlite3_errstr(rc) << " (" << rc << "). "; - } - - TSQLiteDB::TSQLiteDB(const TString& path) { - TSQLiteInit::Ensure(); - - sqlite3* db = nullptr; - const int rc = sqlite3_open(path.data(), &db); - - H_.Reset(db); - - if (rc) { - ythrow TSQLiteError(Handle()) << "can not init db " << path.Quote(); - } - } - - TSQLiteDB::TSQLiteDB(const TString& path, int flags) { - TSQLiteInit::Ensure(); - - sqlite3* db = nullptr; - const int rc = sqlite3_open_v2(path.data(), &db, flags, nullptr); - - H_.Reset(db); - - if (rc) { - ythrow TSQLiteError(Handle()) << "can not init db " << path.Quote(); - } - } - - sqlite3* TSQLiteDB::Handle() const noexcept { - return H_.Get(); - } - - size_t TSQLiteDB::RowsAffected() const noexcept { - return static_cast<size_t>(sqlite3_changes(H_.Get())); - } - - TSQLiteStatement::TSQLiteStatement(TSQLiteDB& db, const TString& s) - : S_(s) - { - if (!S_.empty() && S_[S_.size() - 1] != ';') { - S_ += ';'; - } - - sqlite3_stmt* st = nullptr; - const char* tail = nullptr; - const int rc = sqlite3_prepare_v2(db.Handle(), S_.data(), S_.size() + 1, &st, &tail); - - H_.Reset(st); - - if (rc != SQLITE_OK) { - ythrow TSQLiteError(db.Handle()) << "can not prepare " << S_.Quote(); - } - } - - void TSQLiteStatement::Execute() { - while (Step()) { - } - - Reset(); - } - - TSQLiteStatement& TSQLiteStatement::Bind(size_t idx, i64 val) { - sqlite3_bind_int64(Handle(), idx, val); - return *this; - } - - TSQLiteStatement& TSQLiteStatement::Bind(size_t idx, int val) { - sqlite3_bind_int(Handle(), idx, val); - return *this; - } - - TSQLiteStatement& TSQLiteStatement::Bind(size_t idx) { - sqlite3_bind_null(Handle(), idx); - return *this; - } - - TSQLiteStatement& TSQLiteStatement::Bind(size_t idx, double val) { - sqlite3_bind_double(Handle(), idx, val); - return *this; - } - - void TSQLiteStatement::BindText(size_t idx, const char* text, size_t len, TFreeFunc func) { - sqlite3_bind_text(Handle(), idx, text, len, func); - } - - TSQLiteStatement& TSQLiteStatement::Bind(size_t idx, TStringBuf str) { - BindText(idx, str.data(), str.size(), SQLITE_STATIC); - return *this; - } - - TSQLiteStatement& TSQLiteStatement::BindBlob(size_t idx, TStringBuf blob) { - sqlite3_bind_blob(Handle(), idx, blob.data(), blob.size(), SQLITE_STATIC); - return *this; - } - - size_t TSQLiteStatement::BoundNamePosition(TStringBuf name) const noexcept { - return sqlite3_bind_parameter_index(Handle(), name.data()); - } - - size_t TSQLiteStatement::BoundParameterCount() const noexcept { - return sqlite3_bind_parameter_count(Handle()); - } - - const char* TSQLiteStatement::BoundParameterName(size_t idx) const noexcept { - return sqlite3_bind_parameter_name(Handle(), idx); - } - - sqlite3_stmt* TSQLiteStatement::Handle() const noexcept { - return H_.Get(); - } - - bool TSQLiteStatement::Step() { - const int rc = sqlite3_step(Handle()); - - switch (rc) { - case SQLITE_ROW: - return true; - - case SQLITE_DONE: - return false; - - default: - break; - } - - char* stmt = rc == SQLITE_CONSTRAINT ? sqlite3_expanded_sql(Handle()) : nullptr; - Y_DEFER { - if (stmt != nullptr) { - sqlite3_free(reinterpret_cast<void*>(stmt)); - stmt = nullptr; - } - }; - if (stmt != nullptr) { - ythrow TSQLiteError(rc) << "step failed: " << stmt; - } else { - ythrow TSQLiteError(rc) << "step failed"; - } - } - - i64 TSQLiteStatement::ColumnInt64(size_t idx) { - return sqlite3_column_int64(Handle(), idx); - } - - double TSQLiteStatement::ColumnDouble(size_t idx) { - return sqlite3_column_double(Handle(), idx); - } - - TStringBuf TSQLiteStatement::ColumnText(size_t idx) { - return reinterpret_cast<const char*>(sqlite3_column_text(Handle(), idx)); - } - - TStringBuf TSQLiteStatement::ColumnBlob(size_t idx) { - const void* blob = sqlite3_column_blob(Handle(), idx); - size_t size = sqlite3_column_bytes(Handle(), idx); - return TStringBuf(static_cast<const char*>(blob), size); - } - - void TSQLiteStatement::ColumnAccept(size_t idx, ISQLiteColumnVisitor& visitor) { - const auto columnType = sqlite3_column_type(Handle(), idx); - switch (columnType) { - case SQLITE_INTEGER: - visitor.OnColumnInt64(ColumnInt64(idx)); - break; - case SQLITE_FLOAT: - visitor.OnColumnDouble(ColumnDouble(idx)); - break; - case SQLITE_TEXT: - visitor.OnColumnText(ColumnText(idx)); - break; - case SQLITE_BLOB: - visitor.OnColumnBlob(ColumnBlob(idx)); - break; - case SQLITE_NULL: - visitor.OnColumnNull(); - break; - } - } - - size_t TSQLiteStatement::ColumnCount() const noexcept { - return static_cast<size_t>(sqlite3_column_count(Handle())); - } - - TStringBuf TSQLiteStatement::ColumnName(size_t idx) const noexcept { - return sqlite3_column_name(Handle(), idx); - } - - void TSQLiteStatement::Reset() { - const int rc = sqlite3_reset(Handle()); - - if (rc != SQLITE_OK) { - ythrow TSQLiteError(rc) << "reset failed"; - } - } - - void TSQLiteStatement::ResetHard() { - (void)sqlite3_reset(Handle()); - } - - void TSQLiteStatement::ClearBindings() noexcept { - // No error is documented. - // sqlite3.c's code always returns SQLITE_OK. - (void)sqlite3_clear_bindings(Handle()); - } - - TSQLiteTransaction::TSQLiteTransaction(TSQLiteDB& db) - : Db(&db) - { - Execute("BEGIN TRANSACTION"); - } - - TSQLiteTransaction::~TSQLiteTransaction() { - if (Db) { - Rollback(); - } - } - - void TSQLiteTransaction::Commit() { - Execute("COMMIT TRANSACTION"); - Db = nullptr; - } - - void TSQLiteTransaction::Rollback() { - Execute("ROLLBACK TRANSACTION"); - Db = nullptr; - } - - void TSQLiteTransaction::Execute(const TString& query) { - Y_ENSURE(Db, "Transaction is already ended"); - TSQLiteStatement st(*Db, query); - st.Execute(); - } - - TSimpleDB::TSimpleDB(const TString& path) - : TSQLiteDB(path) - , Start_(*this, "begin transaction") - , End_(*this, "end transaction") - { - } - - void TSimpleDB::Execute(const TString& statement) { - TSQLiteStatement(*this, statement).Execute(); - } - - void TSimpleDB::Acquire() { - Start_.Execute(); - } - - void TSimpleDB::Release() { - End_.Execute(); - } - -} diff --git a/library/cpp/sqlite3/sqlite.h b/library/cpp/sqlite3/sqlite.h deleted file mode 100644 index 8b35e2606a..0000000000 --- a/library/cpp/sqlite3/sqlite.h +++ /dev/null @@ -1,136 +0,0 @@ -#pragma once - -#include <util/generic/yexception.h> -#include <util/generic/ptr.h> - -#include <contrib/libs/sqlite3/sqlite3.h> - -namespace NSQLite { - class TSQLiteError: public yexception { - public: - TSQLiteError(sqlite3* hndl); - TSQLiteError(int rc); - - int GetErrorCode() const { - return ErrorCode; - } - - private: - int ErrorCode; - }; - - template <class T, int (*Func)(T*)> - struct TCFree { - static void Destroy(T* t) { - Func(t); - } - }; - - class TSQLiteDB { - public: - TSQLiteDB(const TString& path, int flags); - TSQLiteDB(const TString& path); - - sqlite3* Handle() const noexcept; - size_t RowsAffected() const noexcept; - - private: - THolder<sqlite3, TCFree<sqlite3, sqlite3_close>> H_; - }; - - class ISQLiteColumnVisitor { - public: - virtual ~ISQLiteColumnVisitor() = default; - - virtual void OnColumnInt64(i64 value) = 0; - virtual void OnColumnDouble(double value) = 0; - virtual void OnColumnText(TStringBuf value) = 0; - virtual void OnColumnBlob(TStringBuf value) = 0; - virtual void OnColumnNull() = 0; - }; - - class TSQLiteStatement { - public: - TSQLiteStatement(TSQLiteDB& db, const TString& s); - - void Execute(); - TSQLiteStatement& Bind(size_t idx, i64 val); - TSQLiteStatement& Bind(size_t idx, int val); - TSQLiteStatement& Bind(size_t idx); - TSQLiteStatement& Bind(size_t idx, double val); - TSQLiteStatement& Bind(size_t idx, TStringBuf str); - TSQLiteStatement& BindBlob(size_t idx, TStringBuf blob); - template <typename Value> - TSQLiteStatement& Bind(TStringBuf name, Value val) { - size_t idx = BoundNamePosition(name); - Y_ASSERT(idx > 0); - return Bind(idx, val); - } - TSQLiteStatement& BindBlob(TStringBuf name, TStringBuf blob) { - size_t idx = BoundNamePosition(name); - Y_ASSERT(idx > 0); - return BindBlob(idx, blob); - } - TSQLiteStatement& Bind(TStringBuf name) { - size_t idx = BoundNamePosition(name); - Y_ASSERT(idx > 0); - return Bind(idx); - } - size_t BoundNamePosition(TStringBuf name) const noexcept; - size_t BoundParameterCount() const noexcept; - const char* BoundParameterName(size_t idx) const noexcept; - - sqlite3_stmt* Handle() const noexcept; - bool Step(); - i64 ColumnInt64(size_t idx); - double ColumnDouble(size_t idx); - TStringBuf ColumnText(size_t idx); - TStringBuf ColumnBlob(size_t idx); - void ColumnAccept(size_t idx, ISQLiteColumnVisitor& visitor); - size_t ColumnCount() const noexcept; - TStringBuf ColumnName(size_t idx) const noexcept; - void Reset(); - // Ignore last error on this statement - void ResetHard(); - void ClearBindings() noexcept; - - private: - typedef void (*TFreeFunc)(void*); - void BindText(size_t col, const char* text, size_t len, TFreeFunc func); - - private: - TString S_; - THolder<sqlite3_stmt, TCFree<sqlite3_stmt, sqlite3_finalize>> H_; - }; - - /** - * Forces user to commit transaction explicitly, to not get exception in destructor (with all consequences of it). - */ - class TSQLiteTransaction: private TNonCopyable { - private: - TSQLiteDB* Db; - - public: - TSQLiteTransaction(TSQLiteDB& db); - ~TSQLiteTransaction(); - - void Commit(); - void Rollback(); - - private: - void Execute(const TString& query); - }; - - class TSimpleDB: public TSQLiteDB { - public: - TSimpleDB(const TString& path); - - void Execute(const TString& statement); - void Acquire(); - void Release(); - - private: - TSQLiteStatement Start_; - TSQLiteStatement End_; - }; -} diff --git a/library/cpp/sqlite3/ya.make b/library/cpp/sqlite3/ya.make deleted file mode 100644 index 15417e278d..0000000000 --- a/library/cpp/sqlite3/ya.make +++ /dev/null @@ -1,13 +0,0 @@ -LIBRARY() - -SRCS( - sqlite.cpp -) - -PEERDIR( - contrib/libs/sqlite3 -) - -END() - -RECURSE_FOR_TESTS(ut) diff --git a/library/cpp/streams/growing_file_input/growing_file_input.cpp b/library/cpp/streams/growing_file_input/growing_file_input.cpp deleted file mode 100644 index 0bbfa5ade9..0000000000 --- a/library/cpp/streams/growing_file_input/growing_file_input.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "growing_file_input.h" - -#include <util/datetime/base.h> -#include <util/generic/yexception.h> - -TGrowingFileInput::TGrowingFileInput(const TString& path) - : File_(path, OpenExisting | RdOnly | Seq) -{ - if (!File_.IsOpen()) { - ythrow TIoException() << "file " << path << " not open"; - } - - File_.Seek(0, sEnd); -} - -TGrowingFileInput::TGrowingFileInput(const TFile& file) - : File_(file) -{ - if (!File_.IsOpen()) { - ythrow TIoException() << "file (" << file.GetName() << ") not open"; - } - - File_.Seek(0, sEnd); -} - -size_t TGrowingFileInput::DoRead(void* buf, size_t len) { - for (int sleepTime = 1;;) { - size_t rr = File_.Read(buf, len); - - if (rr != 0) { - return rr; - } - - NanoSleep((ui64)sleepTime * 1000000); - - if (sleepTime < 2000) { - sleepTime <<= 1; - } - } -} diff --git a/library/cpp/streams/growing_file_input/growing_file_input.h b/library/cpp/streams/growing_file_input/growing_file_input.h deleted file mode 100644 index 9054a5f3da..0000000000 --- a/library/cpp/streams/growing_file_input/growing_file_input.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include <util/stream/input.h> -#include <util/system/file.h> - -/** - * Growing file input stream. - * - * File descriptor offsets to the end of the file, when the object is created. - * - * Read function waites for reading at least one byte. - */ -class TGrowingFileInput: public IInputStream { -public: - TGrowingFileInput(const TFile& file); - TGrowingFileInput(const TString& path); - -private: - size_t DoRead(void* buf, size_t len) override; - -private: - TFile File_; -}; diff --git a/library/cpp/streams/growing_file_input/ya.make b/library/cpp/streams/growing_file_input/ya.make deleted file mode 100644 index 69c56fea46..0000000000 --- a/library/cpp/streams/growing_file_input/ya.make +++ /dev/null @@ -1,11 +0,0 @@ -LIBRARY() - -SRCS( - growing_file_input.cpp -) - -END() - -RECURSE_FOR_TESTS( - ut -) diff --git a/library/cpp/string_utils/subst_buf/substbuf.cpp b/library/cpp/string_utils/subst_buf/substbuf.cpp deleted file mode 100644 index f23cb24b19..0000000000 --- a/library/cpp/string_utils/subst_buf/substbuf.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "substbuf.h" diff --git a/library/cpp/string_utils/subst_buf/substbuf.h b/library/cpp/string_utils/subst_buf/substbuf.h deleted file mode 100644 index 357ee68ae3..0000000000 --- a/library/cpp/string_utils/subst_buf/substbuf.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include <util/generic/vector.h> -#include <util/generic/strbuf.h> -#include <util/string/subst.h> - -/// Заменяет в строке одни подстроки на другие. -template <class TBuf, class TPool> -size_t SubstGlobal(TBuf& s, const TBuf& from, const TBuf& to, TPool& pool) { - if (from.empty()) - return 0; - - TVector<size_t> offs; - for (size_t off = 0; (off = s.find(from, off)) != TBuf::npos; off += from.length()) - offs.push_back(off); - if (offs.empty()) - return 0; - - size_t dstSize = s.size() + ssize_t(offs.size()) * ssize_t(to.size() - from.size()); - const size_t charTypeSz = sizeof(typename TBuf::char_type); - typename TBuf::char_type* dst = (typename TBuf::char_type*)pool.Allocate((dstSize + 1) * charTypeSz); - dst[dstSize] = 0; - - typename TBuf::char_type* p = dst; - size_t lastSrc = 0; - for (auto off : offs) { - memcpy(p, s.data() + lastSrc, (off - lastSrc) * charTypeSz); - p += off - lastSrc; - lastSrc = off + from.size(); - memcpy(p, to.data(), to.size() * charTypeSz); - p += to.size(); - } - memcpy(p, s.data() + lastSrc, (s.size() - lastSrc) * charTypeSz); - p += s.size() - lastSrc; - Y_ASSERT(p - dst == (ssize_t)dstSize); - - s = TBuf(dst, dstSize); - return offs.size(); -} - -template <class TPool> -size_t SubstGlobal(TStringBuf& s, const TStringBuf& from, const TStringBuf& to, TPool& pool) { - return SubstGlobal<TStringBuf, TPool>(s, from, to, pool); -} - -/// Заменяет в строке одни подстроки на другие. -template <class TBuf, class TPool> -inline size_t SubstGlobal(TBuf& s, typename TBuf::char_type from, typename TBuf::char_type to, TPool& pool) { - size_t result = 0; - size_t off = s.find(from); - if (off == TBuf::npos) - return 0; - - s = TBuf(pool.Append(s), s.size()); - - for (typename TBuf::char_type* it = const_cast<typename TBuf::char_type*>(s.begin()) + off; it != s.end(); ++it) { - if (*it == from) { - *it = to; - ++result; - } - } - return result; -} diff --git a/library/cpp/string_utils/subst_buf/ya.make b/library/cpp/string_utils/subst_buf/ya.make deleted file mode 100644 index 8b8793f5b3..0000000000 --- a/library/cpp/string_utils/subst_buf/ya.make +++ /dev/null @@ -1,7 +0,0 @@ -LIBRARY() - -SRCS( - substbuf.cpp -) - -END() diff --git a/library/cpp/ucompress/README.md b/library/cpp/ucompress/README.md deleted file mode 100644 index 5a6e9d8f42..0000000000 --- a/library/cpp/ucompress/README.md +++ /dev/null @@ -1 +0,0 @@ -Compatible implementation of library/python/compress (also known as "uc" - uber compressor: tools/uc, ya tool uc). diff --git a/library/cpp/ucompress/common.h b/library/cpp/ucompress/common.h deleted file mode 100644 index d59cde9cf1..0000000000 --- a/library/cpp/ucompress/common.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - - -namespace NUCompress { - // These limitations come from original implementation - library/python/compress - using TBlockLen = ui32; - constexpr TBlockLen MaxCompressedLen = 100000000; -} diff --git a/library/cpp/ucompress/reader.cpp b/library/cpp/ucompress/reader.cpp deleted file mode 100644 index 45a8ca8da2..0000000000 --- a/library/cpp/ucompress/reader.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "reader.h" -#include "common.h" - -#include <library/cpp/blockcodecs/codecs.h> -#include <library/cpp/json/json_reader.h> - -#include <util/system/byteorder.h> - - -using namespace NUCompress; - -TDecodedInput::TDecodedInput(IInputStream* in) - : S_(in) -{ - Y_ENSURE_EX(S_, TBadArgumentException() << "Null output stream"); -} - -TDecodedInput::~TDecodedInput() = default; - -size_t TDecodedInput::DoUnboundedNext(const void** ptr) { - if (!C_) { - TBlockLen blockLen = 0; - S_->LoadOrFail(&blockLen, sizeof(blockLen)); - blockLen = LittleToHost(blockLen); - Y_ENSURE(blockLen <= MaxCompressedLen, "broken stream"); - - TString buf = TString::Uninitialized(blockLen); - S_->LoadOrFail(buf.Detach(), blockLen); - - NJson::TJsonValue hdr; - Y_ENSURE(NJson::ReadJsonTree(buf, &hdr), "cannot parse header, suspect old format"); - - auto& codecName = hdr["codec"].GetString(); - Y_ENSURE(codecName, "header does not have codec info"); - - // Throws TNotFound - C_ = NBlockCodecs::Codec(codecName); - Y_ASSERT(C_); - } - - TBlockLen blockLen = 0; - size_t actualRead = S_->Load(&blockLen, sizeof(blockLen)); - if (!actualRead) { - // End of stream - return 0; - } - Y_ENSURE(actualRead == sizeof(blockLen), "broken stream: cannot read block length"); - blockLen = LittleToHost(blockLen); - Y_ENSURE(blockLen <= MaxCompressedLen, "broken stream"); - - TBuffer block; - block.Resize(blockLen); - S_->LoadOrFail(block.Data(), blockLen); - - C_->Decode(block, D_); - *ptr = D_.Data(); - return D_.Size(); -} diff --git a/library/cpp/ucompress/reader.h b/library/cpp/ucompress/reader.h deleted file mode 100644 index 5a5d1c9a89..0000000000 --- a/library/cpp/ucompress/reader.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include <util/generic/buffer.h> -#include <util/stream/walk.h> - - -namespace NBlockCodecs { - struct ICodec; -} - -namespace NUCompress { - class TDecodedInput: public IWalkInput { - public: - TDecodedInput(IInputStream* in); - ~TDecodedInput() override; - - private: - size_t DoUnboundedNext(const void** ptr) override; - - private: - IInputStream* const S_; - const NBlockCodecs::ICodec* C_ = nullptr; - TBuffer D_; - }; -} diff --git a/library/cpp/ucompress/writer.cpp b/library/cpp/ucompress/writer.cpp deleted file mode 100644 index 40f8b12108..0000000000 --- a/library/cpp/ucompress/writer.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "writer.h" -#include "common.h" - -#include <library/cpp/blockcodecs/codecs.h> -#include <library/cpp/json/writer/json.h> - -#include <util/generic/scope.h> -#include <util/generic/yexception.h> -#include <util/system/byteorder.h> - - -using namespace NUCompress; - -TCodedOutput::TCodedOutput(IOutputStream* out, const NBlockCodecs::ICodec* c, size_t bufLen) - : C_(c) - , D_(bufLen) - , S_(out) -{ - Y_ENSURE_EX(C_, TBadArgumentException() << "Null codec"); - Y_ENSURE_EX(S_, TBadArgumentException() << "Null output stream"); - D_.Resize(bufLen); - Y_ENSURE_EX(C_->MaxCompressedLength(D_) <= MaxCompressedLen, TBadArgumentException() << "Too big buffer size: " << bufLen); - D_.Clear(); -} - -TCodedOutput::~TCodedOutput() { - try { - Finish(); - } catch (...) { - } -} - -void TCodedOutput::DoWrite(const void* buf, size_t len) { - Y_ENSURE(S_, "Stream finished already"); - const char* in = static_cast<const char*>(buf); - - while (len) { - const size_t avail = D_.Avail(); - if (len < avail) { - D_.Append(in, len); - return; - } - - D_.Append(in, avail); - Y_ASSERT(!D_.Avail()); - in += avail; - len -= avail; - - FlushImpl(); - } -} - -void TCodedOutput::FlushImpl() { - if (!HdrWritten) { - NJsonWriter::TBuf jBuf; - jBuf.BeginObject(); - jBuf.WriteKey("codec"); - jBuf.WriteString(C_->Name()); - jBuf.EndObject(); - - TString jStr = jBuf.Str() + '\n'; - const TBlockLen lenToSave = HostToLittle(jStr.length()); - S_->Write(&lenToSave, sizeof(lenToSave)); - S_->Write(jStr.Detach(), jStr.length()); - HdrWritten = true; - } - - O_.Reserve(C_->MaxCompressedLength(D_)); - const size_t oLen = C_->Compress(D_, O_.Data()); - Y_ASSERT(oLen <= MaxCompressedLen); - - const TBlockLen lenToSave = HostToLittle(oLen); - S_->Write(&lenToSave, sizeof(lenToSave)); - S_->Write(O_.Data(), oLen); - - D_.Clear(); - O_.Clear(); -} - -void TCodedOutput::DoFlush() { - if (S_ && D_) { - FlushImpl(); - } -} - -void TCodedOutput::DoFinish() { - if (S_) { - Y_DEFER { - S_ = nullptr; - }; - FlushImpl(); - // Write zero-length block as EOF marker. - FlushImpl(); - } -} diff --git a/library/cpp/ucompress/writer.h b/library/cpp/ucompress/writer.h deleted file mode 100644 index 4d3ae71093..0000000000 --- a/library/cpp/ucompress/writer.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include <util/generic/buffer.h> -#include <util/stream/output.h> - - -namespace NBlockCodecs { - struct ICodec; -} - -namespace NUCompress { - class TCodedOutput: public IOutputStream { - public: - TCodedOutput(IOutputStream* out, const NBlockCodecs::ICodec* c, size_t bufLen = 16 << 20); - ~TCodedOutput() override; - - private: - void DoWrite(const void* buf, size_t len) override; - void DoFlush() override; - void DoFinish() override; - - void FlushImpl(); - - private: - const NBlockCodecs::ICodec* const C_; - TBuffer D_; - TBuffer O_; - IOutputStream* S_; - bool HdrWritten = false; - }; -} diff --git a/library/cpp/ucompress/ya.make b/library/cpp/ucompress/ya.make deleted file mode 100644 index 6582dd9a41..0000000000 --- a/library/cpp/ucompress/ya.make +++ /dev/null @@ -1,18 +0,0 @@ -LIBRARY() - -PEERDIR( - library/cpp/blockcodecs - library/cpp/json -) - -SRCS( - reader.cpp - writer.cpp -) - -END() - -RECURSE( - tests - ut -) diff --git a/library/cpp/zipatch/reader.cpp b/library/cpp/zipatch/reader.cpp deleted file mode 100644 index 03ac365da1..0000000000 --- a/library/cpp/zipatch/reader.cpp +++ /dev/null @@ -1,173 +0,0 @@ -#include "reader.h" - -#include <library/cpp/json/json_reader.h> -#include <library/cpp/json/json_value.h> - -#include <util/generic/hash.h> -#include <util/memory/tempbuf.h> - -#include <contrib/libs/libarchive/libarchive/archive.h> -#include <contrib/libs/libarchive/libarchive/archive_entry.h> - -using namespace NJson; - -namespace NZipatch { - -class TReader::TImpl { - - using TEntry = archive_entry; - -public: - TImpl() { - if ((Archive_ = archive_read_new()) == nullptr) { - ythrow yexception() << "can't create archive object"; - } - } - - TImpl(const TFsPath& path) - : TImpl() - { - archive_read_support_filter_all(Archive_); - archive_read_support_format_zip(Archive_); - - if (ARCHIVE_OK != archive_read_open_filename(Archive_, TString(path).c_str(), 10240)) { - ythrow yexception() << "can't open archive path = " << path; - } - - Read(); - } - - TImpl(const TStringBuf buf) - : TImpl() - { - archive_read_support_filter_all(Archive_); - archive_read_support_format_zip(Archive_); - - if (ARCHIVE_OK != archive_read_open_memory(Archive_, buf.data(), buf.size())) { - ythrow yexception() << "can't open in-memory archive"; - } - - Read(); - } - - ~TImpl() { - for (const auto& item : Files_) { - archive_entry_free(item.second.first); - } - if (Archive_) { - archive_read_free(Archive_); - } - } - - void Enumerate(TOnEvent cb) const { - for (const auto& item : Actions_) { - TEvent event; - - event.Action = GetTypeFromString(item["type"].GetStringSafe(TString())); - event.Path = item["path"].GetStringSafe(TString()); - event.Executable = item["executable"].GetBooleanSafe(false); - event.Symlink = false; - - if (event.Action == Copy || event.Action == Move) { - event.Source.Path = item["orig_path"].GetStringSafe(TString()); - event.Source.Revision = item["orig_revision"].GetUIntegerRobust(); - } - if (event.Action == StoreFile) { - auto fi = Files_.find(event.Path); - if (fi == Files_.end()) { - ythrow yexception() << "can't find file; path = " << event.Path; - } - - event.Data = fi->second.second; - event.Symlink = archive_entry_filetype(fi->second.first) == AE_IFLNK; - } - - if (event.Path) { - cb(event); - } - } - } - -private: - EAction GetTypeFromString(const TString& type) const { - if (type == "store_file") { - return StoreFile; - } - if (type == "mkdir") { - return MkDir; - } - if (type == "remove_file" || type == "remove_tree") { - return Remove; - } - if (type == "svn_copy") { - return Copy; - } - return Unknown; - } - - void Read() { - TEntry* current = nullptr; - - while (archive_read_next_header(Archive_, ¤t) == ARCHIVE_OK) { - const TStringBuf path(archive_entry_pathname(current)); - - if (path == "actions.json") { - TJsonValue value; - ReadJsonFastTree(GetData(current), &value, true); - - for (const auto& item : value.GetArraySafe()) { - Actions_.push_back(item); - } - } else if (AsciiHasPrefix(path, "files/")) { - TEntry* entry = archive_entry_clone(current); - - Files_.emplace(path.substr(6), std::make_pair(entry, GetData(current))); - } - } - - archive_read_close(Archive_); - } - - TString GetData(TEntry* current) const { - if (archive_entry_filetype(current) == AE_IFLNK) { - return archive_entry_symlink(current); - } - - if (const auto size = archive_entry_size(current)) { - TTempBuf data(size); - - if (archive_read_data(Archive_, data.Data(), size) != size) { - ythrow yexception() << "can't read entry"; - } - - return TString(data.Data(), size); - } - - return TString(); - } - -private: - struct archive* Archive_; - TVector<TJsonValue> Actions_; - THashMap<TString, std::pair<TEntry*, TString>> Files_; -}; - -TReader::TReader(const TFsPath& path) - : Impl_(new TImpl(path)) -{ -} - -TReader::TReader(const TStringBuf buf) - : Impl_(new TImpl(buf)) -{ -} - -TReader::~TReader() -{ } - -void TReader::Enumerate(TOnEvent cb) const { - Impl_->Enumerate(cb); -} - -} // namespace NZipatch - diff --git a/library/cpp/zipatch/reader.h b/library/cpp/zipatch/reader.h deleted file mode 100644 index a94bc79b71..0000000000 --- a/library/cpp/zipatch/reader.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include <util/folder/path.h> -#include <util/generic/ptr.h> - -namespace NZipatch { - -class TReader { -public: - enum EAction { - Unknown = 0, - Copy, - MkDir, - Move, - Remove, - StoreFile, - }; - - struct TSource { - TString Path; - ui64 Revision; - }; - - struct TEvent { - EAction Action; - TString Path; - TStringBuf Data; - TSource Source; - bool Executable; - bool Symlink; - }; - - using TOnEvent = std::function<void(const TEvent&)>; - -public: - TReader(const TFsPath& path); - TReader(const TStringBuf buf); - ~TReader(); - - void Enumerate(TOnEvent cb) const; - -private: - class TImpl; - THolder<TImpl> Impl_; -}; - -} // namespace NZipatch - diff --git a/library/cpp/zipatch/writer.cpp b/library/cpp/zipatch/writer.cpp deleted file mode 100644 index a9ca451b01..0000000000 --- a/library/cpp/zipatch/writer.cpp +++ /dev/null @@ -1,232 +0,0 @@ -#include "writer.h" - -#include <library/cpp/json/json_value.h> -#include <library/cpp/json/json_writer.h> - -#include <util/string/join.h> - -#include <contrib/libs/libarchive/libarchive/archive.h> -#include <contrib/libs/libarchive/libarchive/archive_entry.h> - -using namespace NJson; - -namespace NZipatch { - -class TWriter::TImpl { -public: - TImpl(const TFsPath& path) - : Actions_(new TJsonValue(JSON_ARRAY)) - , Meta_(new TJsonValue(JSON_MAP)) - , Revprops_(new TJsonValue(JSON_MAP)) - , Archive_(nullptr) - { - Archive_ = archive_write_new(); - if (!Archive_) { - ythrow yexception() << "can't create archive object"; - } - archive_write_set_format_zip(Archive_); - archive_write_zip_set_compression_deflate(Archive_); - - if (ARCHIVE_OK != archive_write_open_filename(Archive_, TString(path).c_str())) { - ythrow yexception() << "can't open archive path = " << path; - } - } - - ~TImpl() { - if (Actions_ || Meta_ || Revprops_) { - Finish(); - } - if (Archive_) { - archive_write_free(Archive_); - } - } - - void Finish() { - if (Actions_) { - if (Archive_) { - WriteEntry("actions.json", WriteJson(Actions_.Get(), true, false)); - } - - Actions_.Destroy(); - } - - if (Meta_) { - if (Archive_) { - WriteEntry("meta.json", WriteJson(Meta_.Get(), true)); - } - - Meta_.Destroy(); - } - - if (Revprops_) { - if (Archive_) { - WriteEntry("revprops.json", WriteJson(Revprops_.Get(), true)); - } - - Revprops_.Destroy(); - } - - if (Archive_) { - archive_write_close(Archive_); - } - } - - void Copy(const TString& path, const TOrigin& origin) { - Y_ASSERT(origin.Path); - Y_ASSERT(origin.Revision); - - if (Actions_) { - TJsonValue item; - item["type"] = "svn_copy"; - item["path"] = path; - item["orig_path"] = origin.Path; - item["orig_revision"] = origin.Revision; - Actions_->AppendValue(item); - } - } - - void MkDir(const TString& path) { - if (Actions_) { - TJsonValue item; - item["type"] = "mkdir"; - item["path"] = path; - Actions_->AppendValue(item); - } - } - - void RemoveFile(const TString& path) { - if (Actions_) { - TJsonValue item; - item["type"] = "remove_file"; - item["path"] = path; - Actions_->AppendValue(item); - } - } - - void RemoveTree(const TString& path) { - if (Actions_) { - TJsonValue item; - item["type"] = "remove_tree"; - item["path"] = path; - Actions_->AppendValue(item); - } - } - - void StoreFile( - const TString& path, - const TString& data, - const bool execute, - const bool symlink, - const TMaybe<bool> binaryHint, - const TMaybe<bool> encrypted) - { - if (Actions_) { - const TString file = Join("/", "files", path); - TJsonValue item; - item["type"] = "store_file"; - item["executable"] = execute; - item["path"] = path; - item["file"] = file; - if (binaryHint.Defined()) { - item["binary_hint"] = *binaryHint; - } - if (encrypted.Defined()) { - item["encrypted"] = *encrypted; - } - Actions_->AppendValue(item); - WriteEntry(file, data, symlink); - } - } - - void SetBaseSvnRevision(ui64 revision) { - if (Meta_) { - (*Meta_)["base_svn_revision"] = revision; - } - } - - void AddRevprop(const TString& prop, const TString& value) { - if (Revprops_) { - (*Revprops_)[prop] = value; - } - } - -private: - void WriteEntry( - const TString& path, - const TString& data, - const bool symlink = false) - { - struct archive_entry* const entry = archive_entry_new(); - // Write header. - archive_entry_set_pathname(entry, path.c_str()); - archive_entry_set_size(entry, data.size()); - archive_entry_set_filetype(entry, symlink ? AE_IFLNK : AE_IFREG); - archive_entry_set_perm(entry, 0644); - if (symlink) { - archive_entry_set_symlink(entry, data.c_str()); - } - archive_write_header(Archive_, entry); - // Write data. - // If entry is symlink then entry size become zero. - if (archive_entry_size(entry) > 0) { - archive_write_data(Archive_, data.data(), data.size()); - } - archive_entry_free(entry); - } - -private: - THolder<NJson::TJsonValue> Actions_; - THolder<NJson::TJsonValue> Meta_; - THolder<NJson::TJsonValue> Revprops_; - struct archive* Archive_; -}; - -TWriter::TWriter(const TFsPath& path) - : Impl_(new TImpl(path)) -{ -} - -TWriter::~TWriter() -{ } - -void TWriter::Finish() { - Impl_->Finish(); -} - -void TWriter::SetBaseSvnRevision(ui64 revision) { - Impl_->SetBaseSvnRevision(revision); -} - -void TWriter::AddRevprop(const TString& prop, const TString& value) { - Impl_->AddRevprop(prop, value); -} - -void TWriter::Copy(const TString& path, const TOrigin& origin) { - Impl_->Copy(path, origin); -} - -void TWriter::MkDir(const TString& path) { - Impl_->MkDir(path); -} - -void TWriter::RemoveFile(const TString& path) { - Impl_->RemoveFile(path); -} - -void TWriter::RemoveTree(const TString& path) { - Impl_->RemoveTree(path); -} - -void TWriter::StoreFile( - const TString& path, - const TString& data, - const bool execute, - const bool symlink, - const TMaybe<bool> binaryHint, - const TMaybe<bool> encrypted) -{ - Impl_->StoreFile(path, data, execute, symlink, binaryHint, encrypted); -} - -} // namespace NZipatch - diff --git a/library/cpp/zipatch/writer.h b/library/cpp/zipatch/writer.h deleted file mode 100644 index 75cbe49777..0000000000 --- a/library/cpp/zipatch/writer.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include <util/folder/path.h> -#include <util/generic/ptr.h> -#include <util/generic/maybe.h> - -namespace NZipatch { - -class TWriter { -public: - struct TOrigin { - TString Path; - ui64 Revision; - - inline TOrigin(const TString& path, const ui64 revision) - : Path(path) - , Revision(revision) - { } - }; - - TWriter(const TFsPath& path); - ~TWriter(); - - void Finish(); - - void SetBaseSvnRevision(ui64 revision); - - void AddRevprop(const TString& prop, const TString& value); - - void Copy(const TString& path, const TOrigin& origin); - - void MkDir(const TString& path); - - void RemoveFile(const TString& path); - - void RemoveTree(const TString& path); - - void StoreFile(const TString& path, - const TString& data, - const bool execute, - const bool symlink, - const TMaybe<bool> binaryHint = Nothing(), - const TMaybe<bool> encrypted = Nothing()); - -private: - class TImpl; - THolder<TImpl> Impl_; -}; - -} // namespace NZipatch - diff --git a/library/cpp/zipatch/ya.make b/library/cpp/zipatch/ya.make deleted file mode 100644 index f8fd6006b2..0000000000 --- a/library/cpp/zipatch/ya.make +++ /dev/null @@ -1,16 +0,0 @@ -LIBRARY() - -SRCS( - reader.cpp - writer.cpp -) - -PEERDIR( - contrib/libs/libarchive - library/cpp/json -) - -GENERATE_ENUM_SERIALIZATION(reader.h) - -END() - |