a unified interface to key/value stores
Moneta provides a standard interface for interacting with various kinds of key/value stores. Moneta supports the well-known NoSQL and document based stores.
A short overview of the features:
Moneta::Transformer proxy (Marshal/JSON/YAML and many more)Moneta::Transformer proxy (Zlib, Snappy, LZMA, ...)Moneta::Transformer proxyMoneta::Expires if not supported natively)#increment and #decrement)#create)Moneta::Mutex and Moneta::SemaphoreMoneta::Server) and client (Moneta::Adapters::Client)If you are not yet convinced, you might ask why? What are the goals of the project?
Moneta is tested thoroughly using GitHub Actions.
Install Moneta via Rubygems
$ gem install moneta
or add it to your Gemfile
gem 'moneta'
Now you are ready to go:
require 'moneta'
# Create a simple file store
store = Moneta.new(:File, dir: 'moneta')
# Store some entries
store['key'] = 'value'
# Read entry
store.key?('key') # returns true
store['key'] # returns 'value'
store.close
In case you are wondering, Moneta uses Semantic Versioning since v1.0.0.
Out of the box, it supports the following backends. Use the backend name symbol in the Moneta constructor (e.g. Moneta.new(:Memory)).
:Memory):LRUHash):LocalMemCache):Memcached, :MemcachedNative and :MemcachedDalli):DataMapper):ActiveRecord):Sequel):Sqlite):DBM):Cassandra):Daybreak):GDBM):HBase):LevelDB):LMDB):Redis):Riak):SDBM):KyotoCabinet):TokyoCabinet):TokyoTyrant):TDB):Client works with Moneta::Server):RestClient works with Rack::MonetaRest):Fog):Null)Some of the backends are not exactly based on key/value stores, e.g. the relational ones. These are useful if you already use the corresponding backend in your application. You get a key/value store for free then without installing any additional services and you still have the possibility to upgrade to a real key/value store.
NOTE: The backend matrix is much more readable on rubydoc.info than on github. Go there!
AdapterRequired gemsMRI support1JRuby support1Multi-thread safe2Multi-process safe3Atomic increment4Atomic create5Native expires6PersistentKey TraversalBulk read7Bulk write8Description
Persistent stores
Mongomongo✓✓✓✓✓✓✓✓✓✓✓MongoDB database
Redisredis✓✓✓✓✓✓✓✓✓✓✓Redis database
ActiveRecordactiverecord✓✓✓✓✓✓✗✓✓✓✓ActiveRecord ORM
File-✓✓✓✓✓✓✗✓✓✗✗File store
LMDBlmdb✓✗✓✓✓✓✗✓✓✓✓Symas Lightning Memory-Mapped Database (LMDB)
Sequelsequel✓✓✓✓✓✓✗✓✓✓✓Sequel ORM
TokyoTyranttokyotyrant or ruby-tokyotyrant✓✓✗✓✓✓✗✓✗✓✗TokyoTyrant database
PStore-✓✗✗✓9✓✓✗✓✓✓✓PStore store
YAML-✓✓✗✓9✓✓✗✓✓✗✗YAML store
Sqlitesqlite3✓✗?✓9✓✓✗✓✓✓✓Sqlite3 database
Daybreakdaybreak✓✓✗✓✓✓✗✓✓✗✓Incredibly fast pure-ruby key/value store Daybreak
DBM-✓✗✗✗✓✓✗✓✓✓✓Berkeley DB using DBM interface or NDBM (Depends on Ruby environment)
GDBMffi-gdbm on JRuby✓✓✗✗✓✓✗✓✓✓✓GDBM database
LevelDBleveldb✓✗✗✗✓✓✗✓✓✓✓LevelDB database
SDBM-✓✗✗✗✓✓✗✓✓✓✓SDBM database
TDBtdb✓✗✗✗✓✓✗✓✓✗✗TDB database
KyotoCabinetkyotocabinet-ruby or kyotocabinet-ruby-reanimated✓✗✗✗✓✓✗✓✓✓✓KyotoCabinet database
TokyoCabinettokyocabinet✓✗✗✗✓✓✗✓✓✗✗TokyoCabinet database
DataMapperdm-core, dm-migrations✓✗✓✓✗✓✗✓✗✗✗DataMapper ORM
Couchfaraday, multi_json✓✓✗✓✗✓✗✓✓✓✓CouchDB database
HBasehbaserb✗✗?✓✓✗✗✓✗✗✗HBase database
Cassandracassandra✓✓?✓✗✗✓✓✓✓✓Cassandra distributed database
LocalMemCachelocalmemcache✓✗✓✓✗✗✗✓✗✗✗LocalMemCache database
Fogfog✓✓?✓✗✗✗✓✗✗✗Fog cloud store
Riakriak-client✗✗✗✓✗✗✗✓✗✗✗Riak database
Non-persistent stores
MemcachedDallidalli✓✓✓✓✓✓✓✗10✗✓✓Memcached database with Dalli library
Memcacheddalli or memcached✓?11?11✓✓✓✓✗10✗?11?11Memcached database
MemcachedNativememcached✓✗✗✓✓✓✓✗10✗✗✗Memcached database with native library
Cookie-✓✓✗✓12✓✓✓✗✓✗✗Cookie in memory store
LRUHash-✓✓✗✓12✓✓✗✗✓✗✗LRU memory store
Memory-✓✓✗✓12✓✓✗✗✓✓✓Memory store
Null-✓✓✓✓✗✗✗✗✗✗✗No database
Network clients
Client-✓✓✗✓?13?13?13?13?13✗✗Moneta client adapter
RestClient-✓✓✗✓✗✗✗?13✗✗✗Moneta REST client adapter
Moneta::Lock or by passing the option threadsafe: true to Moneta#new. There is also Moneta::Pool which can be used to share a store between multiple threads if the store is multi-process safe. I recommend to add the option :threadsafe to ensure thread-safety since for example under JRuby and Rubinius even the basic datastructures are not thread safe due to the lack of a global interpreter lock (GIL). This differs from MRI where some adapters might appear thread safe already but only due to the GIL.Moneta::Shared (See below).Moneta::Semaphore. You can add weak #increment support using the Moneta::WeakIncrement proxy.Moneta::Mutex. You can add weak #create support using the Moneta::WeakCreate proxy.Moneta::Expires or by passing the option expires: true to Moneta#new.#values_at/#fetch_values or #slice. For instance, the MGET instruction in Redis, or the ability to retrieve several rows in one query in SQL.#merge!/#update.In addition it supports proxies (Similar to Rack middlewares) which add additional features to storage backends:
Moneta::Proxy and Moneta::Wrapper are the proxy base classes.Moneta::Cache combine two stores, one as backend and one as cache (e.g.
Moneta::Adapters::File + Moneta::Adapters::LRUHash). Add it in the
builder using use(:Cache) {}.Moneta::Expires to add expiration support to stores which don't support it
natively. Add it in the builder using use :Expires.Moneta::Fallback use a store as a fallback when exceptions occur (by default the
:Null adapter is used so that an error results in a no-op). Add it to the
builder using use(:Fallback, rescue: IOError)Moneta::Lock to make store thread safe. Add it in the builder using use :Lock.Moneta::Logger to log database accesses. Add it in the builder using use :Logger.Moneta::Pool to create a pool of stores as a means of making the store
thread safe. Add it in the builder using use(:Pool, min: 2, max: 4, ttl: 60, timeout: 5) {}.Moneta::Shared to share a store between multiple processes. Add it in the
builder using use(:Shared) {}.Moneta::Stack to stack multiple stores (Read returns result from first
where the key is found, writes go to all stores). Add it in the builder using
use(:Stack) {}.Moneta::Transformer transforms keys and values (Marshal, YAML, JSON,
Base64, MD5, ...). Add it in the builder using use :Transformer.Moneta::WeakIncrementNo open issues yet, or sync has not completed.