{"id":15047893,"url":"https://github.com/jsnell/ratas","last_synced_at":"2025-04-09T20:06:58.879Z","repository":{"id":48157336,"uuid":"64039402","full_name":"jsnell/ratas","owner":"jsnell","description":"A hierarchical timer wheel, for implementing timed event queues","archived":false,"fork":false,"pushed_at":"2024-04-08T17:38:56.000Z","size":42,"stargazers_count":210,"open_issues_count":0,"forks_count":40,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-09T20:06:53.282Z","etag":null,"topics":["cplusplus-11","single-header-lib","timers"],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jsnell.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-07-23T23:02:16.000Z","updated_at":"2025-03-20T00:46:33.000Z","dependencies_parsed_at":"2022-09-02T07:00:21.261Z","dependency_job_id":null,"html_url":"https://github.com/jsnell/ratas","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsnell%2Fratas","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsnell%2Fratas/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsnell%2Fratas/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsnell%2Fratas/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jsnell","download_url":"https://codeload.github.com/jsnell/ratas/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248103872,"owners_count":21048245,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cplusplus-11","single-header-lib","timers"],"created_at":"2024-09-24T21:05:51.842Z","updated_at":"2025-04-09T20:06:58.846Z","avatar_url":"https://github.com/jsnell.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"*** Ratas - A hierarchical timer wheel\n\nA timer queue which allows events to be scheduled for execution\nat some later point. Reasons you might want to use this implementation\ninstead of some other are:\n\n- A single-file C++11 implementation with no external dependencies.\n- Optimized for high occupancy rates, on the assumption that the\n  utilization of the timer queue is proportional to the utilization\n  of the system as a whole. When a tradeoff needs to be made\n  between efficiency of one operation at a low occupancy rate and\n  another operation at a high rate, we choose the latter.\n- Tries to minimize the cost of event rescheduling or cancelation,\n  on the assumption that a large percentage of events will never\n  be triggered. The implementation avoids unnecessary work when an\n  event is rescheduled, and provides a way for the user specify a\n  range of acceptable execution times instead of just an exact one.\n- Facility for limiting the number of events to execute on a\n  single invocation, to allow fine grained interleaving of timer\n  processing and application logic.\n- An interface that at least the author finds convenient.\n\nThe exact implementation strategy is a hierarchical timer\nwheel. A timer wheel is effectively a ring buffer of linked lists\nof events, and a pointer to the ring buffer. As the time advances,\nthe pointer moves forward, and any events in the ring buffer slots\nthat the pointer passed will get executed.\n\nA hierarchical timer wheel layers multiple timer wheels running at\ndifferent resolutions on top of each other. When an event is\nscheduled so far in the future than it does not fit the innermost\n(core) wheel, it instead gets scheduled on one of the outer\nwheels. On each rotation of the inner wheel, one slot's worth of\nevents are promoted from the second wheel to the core. On each\nrotation of the second wheel, one slot's worth of events is\npromoted from the third wheel to the second, and so on.\n\n*** Usage\nThe basic usage is to create a single =TimerWheel= object and\nmultiple =TimerEvent= or =MemberTimerEvent= objects. The events are\nscheduled for execution using =TimerWheel::schedule()= or\n=TimerWheel::schedule_in_range()=, or unscheduled using the event's\n=cancel()= method. The callbacks of the =TimerEvent= objects will\nget triggered during call =TimerWheel::advance()=, once the time\nadvances far enough.\n\n**** TimerEventInterface\n\nAn abstract class representing an event that can be scheduled to\nhappen at some later time.\n\n***** =TimerEventInterface::~TimerEventInterface()=\n\nTimerEvents are automatically canceled on destruction.\n\n***** =TimerEventInterface::cancel()=\n\nUnschedule this event. It's safe to cancel an event that is inactive.\n\n***** =TimerEventInterface::active()=\n\nReturn true iff the event is currently scheduled for execution.\n\n***** =TimerEventInterface::scheduled_at()=\n\nReturn the absolute tick this event is scheduled to be executed on.\n\n**** =TimerEvent\u003cCBType\u003e=\n\nAn event that takes the callback (of type =CBType=) to execute as\na constructor parameter.\n\n**** =MemberTimerEvent\u003cT, MFun\u003e=\n\nAn event that's specialized with a (static) member function of class =T=,\nand a dynamic instance of =T=. Event execution causes an invocation of the\nmember function on the instance.\n\n**** =TimerWheel=\n\nA =TimerWheel= is the entity that =TimerEvents= can be scheduled on\nfor execution (with =schedule()= or =schedule_in_range()=), and will\neventually be executed once the time advances far enough with the\n=advance()= method.\n\n***** =TimerWheel::advance(Tick delta, size_t max_execute = ..., int level = 0)=\nAdvance the TimerWheel by the specified number of ticks (=delta=), and execute\nany events scheduled for execution at or before that time. The\nnumber of events executed can be restricted using the =max_execute=\nparameter. If that limit is reached, the function will return false,\nand the excess events will be processed on a subsequent call.\n\n- It is safe to cancel or schedule events from within event callbacks.\n- During the execution of the callback the observable event tick will\n  be the tick it was scheduled to run on; not the tick the clock will\n  be advanced to.\n- Events will happen in order; all events scheduled for tick X will\n  be executed before any event scheduled for tick X+1.\n\nDelta should be non-0. The only exception is if the previous\ncall to =advance()= returned false.\n\n=advance()= should not be called from an event callback.\n\nThe =level= parameter is used to trigger timer advances on different\nlevels of the hierarchy. It will generally not be useful to pass in\nany value other than the default 0.\n\n***** =TimerWheel::schedule(TimerEventInterface* event, Tick delta)=\nSchedule the event to be executed =delta= ticks from the current time.\nThe delta must be non-0.\n\n***** =TimerWheel::schedule_in_range(TimerEventInterface* event, Tick start, Tick end)=\nSchedule the event to happen at some time between start and end\nticks from the current time. The actual time will be determined\nby the =TimerWheel= to minimize rescheduling and promotion overhead.\nBoth =start= and =end= must be non-0, and =end= must be greater than\n=start=.\n\n***** =TimerWheel::now()=\nReturn the current tick value. Note that if the time increases\nby multiple ticks during a single call to advance(), during the\nexecution of the event callback now() will return the tick that\nthe event was scheduled to run on.\n\n***** =TimerWheel::ticks_to_next_event(Tick max = ..., int level = 0)=\nReturn the number of ticks remaining until the next event will get\nexecuted. If the max parameter is passed, that will be the maximum\ntick value that gets returned. The max parameter's value will also\nbe returned if no events have been scheduled.\n\nWill return 0 if the wheel still has unprocessed events from the\nprevious call to advance().\n\nThe =level= parameter is used to trigger timer advances on different\nlevels of the hierarchy. It will generally not be useful to pass in\nany value other than the default 0.\n\n*** Examples\n\n#+BEGIN_SRC\n     typedef std::function\u003cvoid()\u003e Callback;\n     TimerWheel timers;\n     int count = 0;\n     TimerEvent\u003cCallback\u003e timer([\u0026count] () { ++count; });\n\n     timers.schedule(\u0026timer, 5);\n     timers.advance(4);\n     assert(count == 0);\n     timers.advance(1);\n     assert(count == 1);\n\n     timers.schedule(\u0026timer, 5);\n     timer.cancel();\n     timers.advance(4);\n     assert(count == 1);\n#+END_SRC\n\nTo tie events to specific member functions of an object instead of\na callback function, use MemberTimerEvent instead of TimerEvent.\nFor example:\n\n#+BEGIN_SRC\n     class Test {\n       public:\n           Test() : inc_timer_(this) {\n           }\n           void start(TimerWheel* timers) {\n               timers-\u003eschedule(\u0026inc_timer_, 10);\n           }\n           void on_inc() {\n               count_++;\n           }\n           int count() { return count_; }\n       private:\n           MemberTimerEvent\u003cTest, \u0026Test::on_inc\u003e inc_timer_;\n           int count_ = 0;\n     };\n#+END_SRC\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjsnell%2Fratas","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjsnell%2Fratas","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjsnell%2Fratas/lists"}