Boost C++ Libraries

PrevUpHomeNext

Class template context_store

boost::taar::context_store — Thread-safe keyed store of context objects with idle expiry and per-entry serialisation.

Synopsis

// In header: <boost/taar/core/context_store.hpp>

template<typename Key, typename Context> 
class context_store {
public:
  // types
  typedef Key                          key_type;      
  typedef Context                      context_type;  
  typedef std::chrono::steady_clock    clock;         
  typedef clock::duration              duration;      
  typedef clock::time_point            time_point;    
  typedef std::function< Key()>        key_generator; 
  typedef std::function< time_point()> clock_function;
  typedef std::shared_ptr< entry >     entry_ptr;     

  // member classes/structs/unions

  // One stored context with its bookkeeping. Obtain through find, emplace or create. 

  class entry {
  public:

    // public member functions
    entry(Key, std::shared_ptr< Context >, time_point);
    Key  const & key() const noexcept;
    std::shared_ptr< Context > const & context() const noexcept;
    time_point last_activity() const noexcept;
    bool in_flight() const noexcept;
  };

  // Releases an entry's lock (and refreshes its activity) on destruction.

  class lock_guard {
  public:

    // public member functions
    lock_guard() = default;
    lock_guard(lock_guard  const &) = delete;
    lock_guard & operator=(lock_guard  const &) = delete;
    lock_guard(lock_guard &&) noexcept;
    lock_guard & operator=(lock_guard &&) noexcept;
    ~lock_guard();
    entry_ptr const & get() const noexcept;
    explicit operator bool() const noexcept;
  };

  // public member functions
  explicit context_store(duration, 
                         key_generator = default_key_generator< Key >{}, 
                         clock_function = [] { return clock::now();});
  context_store(context_store  const &) = delete;
  context_store & operator=(context_store  const &) = delete;
  duration idle_timeout() const noexcept;
  std::size_t size() const;
  entry_ptr find(Key  const &);
  template<typename... Args> entry_ptr emplace(Key, Args &&...);
  template<typename... Args> std::pair< Key, entry_ptr > create(Args &&...);
  entry_ptr peek(Key  const &) const;
  std::vector< Key > keys() const;
  bool erase(Key  const &);
  std::size_t sweep();
  awaitable< lock_guard > lock(entry_ptr);
};

Description

A context_store holds one Context per Key. Every entry records the time it was last used; entries idle for longer than the store's timeout are removed by sweep, which find, emplace and create run opportunistically, so expired keys behave as unknown without any background timer. Owners that want proactive cleanup (for example to close streams belonging to expired sessions) call sweep themselves on a schedule.

Each entry carries an asynchronous lock. A handler that works on an entry acquires it with lock and holds the returned guard for the duration of the call, so two requests for the same key never run their callables concurrently while requests for different keys run in parallel. Entries that are locked are never swept.

find, emplace and create return shared_ptrs, so a caller that obtained an entry keeps it alive even if it is erased in the meantime.

All members are safe to call from any thread.

Template Parameters

  1. typename Key

    The lookup key, typically std::string.

  2. typename Context

    The user state type held per key.

context_store public member functions

  1. explicit context_store(duration idle_timeout, 
                           key_generator generate = default_key_generator< Key >{}, 
                           clock_function now = [] { return clock::now();});
    Construct a store.

    Parameters:

    idle_timeout

    Entries unused for longer than this are removed by the next sweep.

    generate

    Produces keys for create(). Defaults to default_key_generator.

    now

    Clock source. Defaults to steady_clock::now; tests inject a controllable clock.

  2. context_store(context_store  const &) = delete;
  3. context_store & operator=(context_store  const &) = delete;
  4. duration idle_timeout() const noexcept;
  5. std::size_t size() const;
    Number of entries currently held (including expired, not yet swept).
  6. entry_ptr find(Key  const & key);
    Look up key.

    Expired entries are treated as unknown (and removed). A hit refreshes the entry's activity time.

    Returns:

    The entry, or an empty pointer.

  7. template<typename... Args> entry_ptr emplace(Key key, Args &&... args);
    Create an entry for key, or return the existing one.

    args are forwarded to the Context constructor when a new entry is created.

  8. template<typename... Args> std::pair< Key, entry_ptr > create(Args &&... args);
    Create an entry under a freshly generated key.
  9. entry_ptr peek(Key  const & key) const;
    Look up key without refreshing its activity or sweeping.

    For server-initiated work (pushing a notification to a session) that must not keep an otherwise idle entry alive. Expired entries are reported as unknown.

  10. std::vector< Key > keys() const;
    Keys of all live entries, in no particular order.
  11. bool erase(Key  const & key);
    Remove key. Returns true if an entry was removed.
  12. std::size_t sweep();
    Remove every idle entry that is not currently locked.

    Returns:

    The number of entries removed.

  13. awaitable< lock_guard > lock(entry_ptr e);
    Acquire e's lock.

    Suspends until no other holder exists, then returns a guard. Hold the guard while using the context; destroy it to release.


PrevUpHomeNext