Coder Social home page Coder Social logo

triptych / khepri Goto Github PK

View Code? Open in Web Editor NEW

This project forked from rabbitmq/khepri

1.0 0.0 0.0 2.13 MB

Khepri is a tree-like replicated on-disk database library for Erlang and Elixir.

Home Page: https://rabbitmq.github.io/khepri/

License: Apache License 2.0

Erlang 99.88% Elixir 0.12%

khepri's Introduction

The Khepri database library

Hex.pm Test Codecov

Khepri is a tree-like replicated on-disk database library for Erlang and Elixir.

The basics

Data are stored in a tree structure. Each node in the tree is referenced by its path from the root node. A path is a list of Erlang atoms and/or binaries. For ease of use, Unix-like path strings are accepted as well.

For consistency and replication and to manage data on disk, Khepri relies on Ra, an Erlang implementation of the Raft consensus algorithm. In Ra parlance, Khepri is a state machine in a Ra cluster.

Project maturity

Khepri is still under active development and should be considered Alpha at this stage.

Documentation

Getting started

Add as a dependency

Add Khepri as a dependency of your project:

Using Rebar:

%% In rebar.config
{deps, [{khepri, "0.6.0"}]}.

Using Erlang.mk:

# In your Makefile
DEPS += khepri
dep_khepri = hex 0.6.0

Using Mix:

# In mix.exs
defp deps do
  [
    {:khepri, "0.6.0"}
  ]
end

Start default Khepri store

To start the default store, use khepri:start/0:

khepri:start().

The default Khepri store uses the default Ra system. Data is stored in the configured default Ra system data directory, which is khepri#$NODENAME in the current working directory.

It is fine to get started and play with Khepri. However, it is recommended to configure your own Ra system and Ra cluster to select the directory where data is stored and to be able to have multiple Khepri database instances running on the same Erlang node.

Insert data

Here's how to insert a piece of data, say, an email address of Alice:

%% Using a native path:
ok = khepri:put([emails, <<"alice">>], "[email protected]").

%% Using a Unix-like path string:
ok = khepri:put("/:emails/alice", "[email protected]").

Read data back

To get Alice's email address back, query the same path:

{ok, "[email protected]"} = khepri:get("/:emails/alice").

Delete data

To delete Alice's email address:

ok = khepri:delete("/:emails/alice").

The emails parent node was automatically created when the alice node was inserted earlier. It has no data attached to it. However, after the alice node is deleted, the emails node will stay around. It is possible to tell Khepri to automatically remove emails as soon as its last child node is deleted. Khepri supports many more conditions by the way.

Transactional Operations

It is also possible to perform transactional queries and updates using anonymous functions, similar to Mnesia:

%% This transaction checks the quantity of wood left and returns `true` or
%% `false` if we need to process a new order.
khepri:transaction(
    fun() ->
        case khepri_tx:get([stock, wood]) of
            {ok, Quantity} when Quantity >= 100 ->
                %% There is enough wood left.
                false;
            _ ->
                %% There is less than 100 pieces of wood, or there is none
                %% at all (the node does not exist in Khepri). We need to
                %% request a new order.
                ok = khepri_tx:put([order, wood], 1000),
                true
        end
    end).

In this example, the transaction returns a boolean indicating if orders are ready to be processed. It does not send a message to a process or write something on disk for instance.

Because of the nature of the Raft consensus algorithm, transactions are not allowed to have side effects or take non-deterministic inputs such as the node name or the current date & time.

Triggers

Khepri supports stored procedures and triggers. They allow to store code in the database itself and automatically execute it after some event occurs.

  1. Store an anonymous function in the tree:

    StoredProcPath = [path, to, stored_procedure],
    
    Fun = fun(Props) ->
              #{path := Path,
                on_action := Action} = Props
          end,
    
    khepri:put(StoreId, StoredProcPath, Fun).
  2. Register a trigger using an event filter:

    %% A path is automatically considered a tree event filter.
    EventFilter = [stock, wood, <<"oak">>],
    
    ok = khepri:register_trigger(
           StoreId,
           TriggerId,
           EventFilter,
           StoredProcPath).

In the example above, as soon as the [stock, wood, <<"oak">>] node is created, updated or deleted, the anonymous function will be executed.

The function is executed at least once on the Ra leader's Erlang node. It may be executed multiple times if the leader changes and thus should be idempotent.

Unlike transaction functions, stored procedures may have whatever side effects they want.

How to build

Build

rebar3 compile

Build documentation

rebar3 edoc

Test

rebar3 xref
rebar3 eunit
rebar3 proper
rebar3 ct --sname ct
rebar3 as test dialyzer

Copyright and License

© 2021-2022 VMware, Inc. or its affiliates.

This work is dual-licensed under the Apache License 2.0 and the Mozilla Public License 2.0. You can choose between one of them if you use this work.

The logo (doc/khepri-logo.svg) and the favicon (doc/khepri-favicon.svg) are based on the following two resources:

SPDX-License-Identifier: Apache-2.0 OR MPL-2.0

khepri's People

Contributors

dcorbacho avatar dumbbell avatar kianmeng avatar lukebakken avatar michaelklishin avatar mkuratczyk avatar the-mikedavis avatar vkatsuba avatar

Stargazers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.