TCP или не TCP в целом не ясно - это может быть и самодельный UDP шайтан-протокол. Connection - абстракция. В целом ясно, что стурктура данных heap AKA priority queue. Хочется простого: 10 сек не было данных от клиента - close() ему на сокет. Архитектура традиционная - однопоточный евент луп - сидит в epoll_wait() с пробуждениями, скажем, 10 раз в сек, чтобы поделать служебное (позакрывать по таймауту кого-то, другие таймеры попроцессить). Входящих коннектов могут быть тыщи. Обычно для такого юзают heap (min-heap например): пихаешь в эту структуру коннекшены, впереди лежат те, у которых значение time_close_nanosec меньше. time_close_nanosec - это такое uint64_t значение у объекта-connection, которое апдейтится каждый раз, когда из коннекшена выпали байтики и означает «monitonic время, при наступлении которого коннект надо закрыть». Соответственно апдейтится оно на now_nanosec + 10 * 1000 * 1000 * 1000 всякий раз, когда от клиента что-то прилетело.
Проблема в том, что time_close_nanosec таки апдейтится. Прилетели из сокет байты - время close() этого сокета надо отложить до now + 10 * 1000 * 1000 * 1000 как выше сказано. А это значит, в heap его надо перевставить, ведь старая позиция в priority queue уже не валидна. А значит в объекте Connection будет лежить индекс этого Connection в нашем heap (чтобы сходить по этому индексу в этот heap для удаления этого Connection). А ещё, heap должен быть так реализован, что при каждом перетасовывании объектов в нём, heap ходит по указателям в тасуемых и апдейтит им индексы-в-себе на новые (ведь могут вставить кого-то на позицию 0 и я стану допустим 1). То есть, если из клиентов просто регулярно спокойно летят байтики, то эта heap постоянно шевелится и идёт возня с памятью. Это не православно.
Вот пришла в голову оптимизация: time_close_nanosec в объекте Connection апдейтить, а в heap этот Connection не перевставлять. Тогда heap будет постоянно «ложно» срабатывать. И вот в этом ложном срабатывании мы и будем делать всю работу в heap - если срабатывание реально ложное (time_close_nanosec ещё не достигло текущего момента), то передобавлять его в heap, иначе это не ложное и делать close(). Ясно, что в такой heap надо будет хранить не просто указатели на Connection * (по которым будет лазить компаратор, чтобы посмотреть на time_close_nanosec (это вредно, они постоянно меняются и структура развалится)), а ещё и копию time_close_nanosec_COPY которая верна на момент вставки и по которой компаратор работает.
В результате этой оптимизации число операций с heap наверное минимально возможное и постоянно нормально льющиеся байтики от клиентов никак её не трогают, но всё работает как задумано. «Срабатывание heap» - это не что-то плохое, это один if в евент лупе: текущее время с корнем кучи сравнить.
(UPDATE: сделал эту идейку, работает на первый взгляд норм)
Штош, может кто что посоветует по этой теме? Как то же самое сделано в ядре например или где-то ещё в похожем месте. Додумался ли я до чего-то крутого или есть ещё круче оптимизации?






