SnmpKit.Agent.Store (snmpkit v2.0.1)
Scalars kept in an ETS table: the handler behind SnmpKit.Agent.put/4.
Every agent has one store covering the whole tree; objects put into it are served unless a handler registered at a more specific prefix shadows them. A value may be a zero-arity function, which is called on every read, so a live gauge is just:
SnmpKit.Agent.put(agent, "hrSystemNumUsers.0", :gauge32, fn -> MyApp.Sessions.count() end)Objects are read-only unless put with writable: true, in which case a
SET of a value with the same type replaces it (type aliases such as
:string/:octet_string are treated as equal). A store can also be
registered on its own at a prefix, with table: naming an ETS
ordered_set you own.
Concurrency
The table is public and every request runs in its own process, so
put/5, delete/2 and SETs interleave. Each is a single ETS operation:
put/5 and delete/2 are one insert or delete, and SnmpKit.Agent.Handler.set/3 is one
:ets.select_replace/2 that succeeds only if the object still exists,
is still writable and still has a compatible type at the moment of the
write. SnmpKit.Agent.Handler.check_set/3 is a separate, read-only phase run by
SnmpKit.Agent.Request before any set/3; an object deleted or made
read-only between the two phases makes the SET fail with noCreation
or notWritable rather than crash. There is no undo across the varbinds
of one SET (see SnmpKit.Agent.Handler).
Summary
Functions
Removes the object at oid.
Reads the object at oid, calling a function value.
Creates the ETS table a store uses (a public ordered_set).
Puts {type, value} at oid; writable: true lets SET replace the value.
Every object in the store as {oid, type, value}, in OID order.
Types
Functions
@spec delete(table(), [non_neg_integer()]) :: :ok
Removes the object at oid.
@spec fetch(table(), [non_neg_integer()]) :: {:ok, {atom(), term()}} | :error
Reads the object at oid, calling a function value.
@spec new_table() :: :ets.tid()
Creates the ETS table a store uses (a public ordered_set).
@spec put(table(), [non_neg_integer()], atom(), term(), keyword()) :: :ok
Puts {type, value} at oid; writable: true lets SET replace the value.
@spec to_list(table()) :: [{[non_neg_integer()], atom(), term()}]
Every object in the store as {oid, type, value}, in OID order.
The table is fixed for the traversal, so an object present throughout the
call appears exactly once. It is not a point-in-time snapshot: a put/5
or delete/2 that runs during the call may or may not be reflected, and
function values are called as each object is visited.