Memstate is a complete redesign of OrigoDB with major improvements in key areas such as performance, availability, licensing, cross-platform, docker and cloud support.
Performance - OrigoDB can process up to 3K write transactions per second, Memstate can process up to 100K, a 33x improvement!
High Availability - An OrigoDB cluster has a single primary and one or more read-only replicas. If the primary fails one of the replicas can be promoted to new primary but this requires manual intervention. Nodes in a Memstate cluster are all read/write.
Licensing - OrigoDB Server is a commercial offering while Memstate server is OSS and free for commercial use.
Cross platform - Memstate targets .NET Standard 2.0 which means it runs on both .NET Framework >= 4.6.1 and .NET Core >=2.0, Mono, Xamarin, UWP.
This is the preferred way of defining queries. In the derived class, write your query by overriding Execute, which accepts the in-memory model and returns the result. It can be as simple as looking up an object by key or some arbitrarily complex calculation.
Two example queries:
Lambda queries
Lambda queries are simply generic functions that take the model as input and return some value. They’re suitable for simple queries, ad-hoc querying with scriptcs, LinqPad or the OrigoDB server web ui. Example given the same model as above:
Parameterized lambda queries
The example above uses the constant 42 but of course you can use variables, parameters, objects and methods etc from the calling context. Here’s an Asp.NET MVC action:
As you can see this can get messy fast, not to mention how difficult it is to test. A pattern which solves this problem is using query functions, functions that take parameters and return lambda queries:
Example usage:
Serializability
Mark your query classes with a Serializable attribute to ensure they can be passed to a remote origodb server.
Lambdas/expression trees can’t easily be sent across the wire. So the Engine.Execute overload which takes a Func is not available on the IEngine interface returned by Engine.For<TModel>(). If you know you have a local engine, cast from IEngine to Engine to access the overload.
Queries and transactions
Queries are fully isolated from commands, the state of the model will not change while the query is executing (unless you change the default ISynchronizer).
Query result cloning
To protect you from returning references to mutable objects, query results are deep cloned. See Views
Performance
For optimal throughput and low latency, queries (and commands) should execute as quickly as possible. Some guidelines:
Don’t do anything unnecessary within the execute method, do it before or after.
Tune your models data structures and algorithms for optimal runtime performance.
Return as little data as possible, minimizing the cost of serialization