Browse Source

Merge branch 'master' of git://github.com/synrc/kvs

Andrii Zadorozhnii 11 years ago
parent
commit
9a6fea0dae

+ 150 - 1
README.md

@@ -1,6 +1,20 @@
 KVS: Data Framework for KV Stores
 KVS: Data Framework for KV Stores
 =================================
 =================================
 
 
+Features
+--------
+
+* Polymorphic Tuples
+* Managing Linked-Lists
+* Various Backends Support: KAI, Mnesia, Riak, CouchDB
+* Sequential Consistency via Feed Server
+* Basic Schema for Social Sites and Accounting
+* Extendable Schema
+* Supports Secondary Indexes for KAI, Mnesia and Riak
+* Change Backends on-the-fly
+* Supports Multiple backends at the same time
+* Xen Ready
+
 Overview
 Overview
 --------
 --------
 
 
@@ -34,13 +48,148 @@ Currently kvs includes following store backends:
 
 
 * Mnesia
 * Mnesia
 * Riak
 * Riak
-* CouchDB
+* KAI
+
+Configuring
+-----------
+
+First of all you need to tune your backend in the kvs application:
+
+    {kvs, {dba,store_kai}},
+
+Try to check it:
+
+    1> kvs:config(dba).
+    store_kai
+    2> kvs:version().
+    {version,"KVS KAI PURE XEN"}
+
+Create database for single node:
+
+    3> kvs:join().
+
+Create database joining to existing cluster:
+
+    3> kvs:join('kvs@synrc.com').
+
+Check table packages included into the schema:
+
+    4> kvs:dir().
+    [kvs_user,kvs_product,kvs_membership,kvs_payment,kvs_feed,
+     kvs_acl,kvs_account,kvs_group]
+
+Operations
+----------
+
+Try to add some data:
+
+    1> rr(kvs).
+    2> kvs:put(#user{id="maxim@synrc.com"}).
+    ok
+    3> kvs:get(user,"maxim@synrc.com").
+    #user{id = "maxim@synrc.com",container = feed,...}
+    4> kvs:put(#user{id="doxtop@synrc.com"}).
+    5> length(kvs:all(user)).
+    2
+
+Polymorphic Records
+-------------------
+
+The data in KVS represented as plain Erlang records. The first element of the tuple
+as usual indicates the name of bucket. And the second element usually corresponds
+to the index key field. Additional secondary indexes could be applied for stores
+that supports 2i, e.g. kai, mnesia, riak.
+
+    1 record_name -- user, groups, acl, etc... table name -- element(1, Rec).
+    2 id          -- index key -- element(2, Rec).
+
+Iterators
+---------
+
+All record could be chained into the double-linked lists in the database.
+So you can inherit from the ITERATOR record just like that:
+
+    -record(acl_entry, {?ITERATOR(acl),
+        entry_id,
+        acl_id,
+        accessor,
+        action}).
+
+The layout of iterators are following:
+
+    1 record_name -- table name, like
+    2 id          -- index key
+    3 container   -- container name
+    4 feed_id     -- feed id
+    5 prev        -- poniter to previous object in list
+    6 next        -- next
+    7 feeds       -- subfeeds
+    8 guard,      -- aux field
+    9 ...
+
+This means your table will support add/remove operations to lists.
+
+    1> kvs:add(#user{id="mes@ua.fm"}).
+    2> kvs:add(#user{id="dox@ua.fm"}).
+    
+Read the chain (undefined means all)
+    
+    3> kvs:entries(kvs:get(feed, users), user, undefined).
+    [#user{id="mes@ua.fm"},#user{id="dox@ua.fm"}]
+    
+Read flat values by all keys from table:
+
+    4> kvs:all(user).
+    [#user{id="mes@ua.fm"},#user{id="dox@ua.fm"}]
+
+Containers
+----------
+
+If you are using iterators records this automatically means you are using containers.
+Containers are just boxes for storing top/heads of the linked lists. Here is layout
+of containers:
+
+    1 record_name   -- container name
+    2 id            -- unique id
+    3 top           -- pointer to the list's head
+    4 entries_count -- number of elements in list
+
+Extending Schema
+----------------
+
+Usually you need only specify custom mnesia indexes and tables tuning.
+Riak and KAI backends don't need it. Group you table into table packages
+represented as modules with handle_notice API.
+
+    -module(kvs_box).
+    -inclue_lib("kvs/include/kvs.hrl").
+    -record(box,{id,user,email}).
+    -record(box_subscription,{who,whom}).
+    init(Backend=store_mnesia) ->
+        ?CREATE_TAB(box),
+        ?CREATE_TAB(box_subscription),
+        Backend:add_table_index(box, user),
+        Backend:add_table_index(box, email),
+        Backend:add_table_index(box_subscription, who),
+        Backend:add_table_index(box_subscription, whom);
+    init(_) -> ok.
+
+And plug it into schema config:
+
+    {kvs, {schema,[kvs_user,kvs_acl,kvs_account,...,kvs_box]}},
+
+And on database init
+
+    1> kvs:join().
+
+It will create your custom schema.
 
 
 Credits
 Credits
 -------
 -------
 
 
 * Maxim Sokhatsky
 * Maxim Sokhatsky
 * Andrii Zadorozhnii
 * Andrii Zadorozhnii
+* Vladimir Kirillov
 * Alex Kalenuk
 * Alex Kalenuk
 * Sergey Polkovnikov
 * Sergey Polkovnikov
 
 

+ 1 - 1
include/config.hrl

@@ -1,4 +1,4 @@
 -record(config, {key, value}).
 -record(config, {key, value}).
 
 
 -define(DBA, store_mnesia).
 -define(DBA, store_mnesia).
-
+%-define(DBA, kvs:config(dba)).

+ 0 - 2
include/feeds.hrl

@@ -19,8 +19,6 @@
         etc,       %% field to link additional info
         etc,       %% field to link additional info
         type = {user, normal}}).
         type = {user, normal}}).
 
 
--record(id_seq, {thing, id}).
-
 -record(media, {
 -record(media, {
         id,
         id,
         title :: iolist(),
         title :: iolist(),

+ 4 - 1
include/kvs.hrl

@@ -8,6 +8,8 @@
 -define(CMT_FEED, comments).
 -define(CMT_FEED, comments).
 -define(FEED(Type), case Type of user -> ?USR_FEED; product -> ?PRD_FEED; group -> ?GRP_FEED; entry-> ?ENT_FEED; comment-> ?CMT_FEED;_-> undefined end).
 -define(FEED(Type), case Type of user -> ?USR_FEED; product -> ?PRD_FEED; group -> ?GRP_FEED; entry-> ?ENT_FEED; comment-> ?CMT_FEED;_-> undefined end).
 
 
+-record(id_seq, {thing, id}).
+
 -define(CONTAINER, id, top, entries_count=0).
 -define(CONTAINER, id, top, entries_count=0).
 -define(ITERATOR(Container, Guard), id, container=Container, feed_id, prev, next, feeds=[], guard=Guard).
 -define(ITERATOR(Container, Guard), id, container=Container, feed_id, prev, next, feeds=[], guard=Guard).
 -define(ITERATOR(Container), ?ITERATOR(Container, false)).
 -define(ITERATOR(Container), ?ITERATOR(Container, false)).
@@ -21,6 +23,7 @@
 -record(container, {?CONTAINER}).
 -record(container, {?CONTAINER}).
 -record(iterator,  {?ITERATOR(undefined)}).
 -record(iterator,  {?ITERATOR(undefined)}).
 
 
--endif.
+-define(CREATE_TAB(T), store_mnesia:create_table(T, record_info(fields, T), [{storage, permanent}]) ).
 
 
 
 
+-endif.

+ 2 - 2
src/kvs.app.src

@@ -1,6 +1,6 @@
-{application, kvs,
+{application, kvs, 
  [
  [
-  {description, "Distributed Persistance"},
+  {description, "SRC KVS Distributed Persistance"},
   {vsn, "1"},
   {vsn, "1"},
   {registered, []},
   {registered, []},
   {applications, [kernel,stdlib,mnesia,mqs]},
   {applications, [kernel,stdlib,mnesia,mqs]},

+ 16 - 30
src/kvs.erl

@@ -21,8 +21,9 @@ dir() -> DBA = ?DBA, DBA:dir().
 stop() -> DBA = ?DBA, DBA:stop().
 stop() -> DBA = ?DBA, DBA:stop().
 initialize() -> DBA = ?DBA, DBA:initialize().
 initialize() -> DBA = ?DBA, DBA:initialize().
 delete() -> DBA = ?DBA, DBA:delete().
 delete() -> DBA = ?DBA, DBA:delete().
-init_indexes() -> DBA = ?DBA, DBA:init_indexes().
 wait_for_tables() -> DBA=?DBA, DBA:wait_for_tables().
 wait_for_tables() -> DBA=?DBA, DBA:wait_for_tables().
+join() -> DBA = ?DBA, DBA:join().
+join(Node) -> DBA = ?DBA, DBA:join(Node).
 
 
 add(Record) when is_tuple(Record) ->
 add(Record) when is_tuple(Record) ->
     Id = element(#iterator.id, Record),
     Id = element(#iterator.id, Record),
@@ -54,7 +55,8 @@ add(Record) when is_tuple(Record) ->
             R3 = setelement(#iterator.feed_id, R2, element(#container.id, Container)),
             R3 = setelement(#iterator.feed_id, R2, element(#container.id, Container)),
             kvs:put(R3),
             kvs:put(R3),
             error_logger:info_msg("[kvs] PUT: ~p", [element(#container.id,R3)]),
             error_logger:info_msg("[kvs] PUT: ~p", [element(#container.id,R3)]),
-            {ok, R3} end end.
+            {ok, R3} end;
+    E ->  error_logger:info_msg("Entry exist: ~p", [E]),{error, exist} end.
 
 
 remove(RecordName, RecordId) ->
 remove(RecordName, RecordId) ->
     case kvs:get(RecordName, RecordId) of {error, not_found} -> error_logger:info_msg("not found");
     case kvs:get(RecordName, RecordId) of {error, not_found} -> error_logger:info_msg("not found");
@@ -96,13 +98,6 @@ remove(E) when is_tuple(E) ->
 
 
     error_logger:info_msg("[kvs] DELETE: ~p", [Id]),
     error_logger:info_msg("[kvs] DELETE: ~p", [Id]),
     kvs:delete(E).
     kvs:delete(E).
-%purge_feed(FeedId) ->
-%    {ok,Feed} = kvs:get(feed,FeedId),
-%    Removal = entry_traversal(Feed#feed.top, -1),
-%    [kvs:delete(entry,Id)||#entry{id=Id}<-Removal],
-%    kvs:put(Feed#feed{top=undefined}).
-%purge_unverified_feeds() ->
-%    [ [purge_feed(Fid)|| {_, Fid} <- Feeds ] || #user{feeds=Feeds, email=E} <- kvs:all(user), E==undefined].
 
 
 traversal( _,undefined,_,_) -> [];
 traversal( _,undefined,_,_) -> [];
 traversal(_,_,0,_) -> [];
 traversal(_,_,0,_) -> [];
@@ -125,27 +120,9 @@ init_db() ->
         {error,_} ->
         {error,_} ->
             add_seq_ids(),
             add_seq_ids(),
             kvs_account:create_account(system),
             kvs_account:create_account(system),
-            %add_sample_users(),
-%            add_sample_packages(),
-%            add_sample_payments(),
             add_translations();
             add_translations();
         {ok,_} -> ignore end.
         {ok,_} -> ignore end.
 
 
-%add_sample_packages() -> kvs_membership:add_sample_data().
-
-%add_sample_payments() ->
-%    {ok, Pkg1} = kvs:get(membership,1),
-%    {ok, Pkg2} = kvs:get(membership,2),
-%    {ok, Pkg3} = kvs:get(membership,3),
-%    {ok, Pkg4} = kvs:get(membership,4),
-%    PList = [{"doxtop", Pkg1},{"maxim", Pkg2},{"maxim",Pkg4}, {"kate", Pkg3} ],
-%    [ok = add_payment(U, P) || {U, P} <- PList],
-%    ok.
-
-%add_payment(UserId, Package) ->
-%    {ok, MPId} = kvs_payment:add_payment(#payment{user_id=UserId, membership=Package}),
-%    kvs_payment:set_payment_state(MPId, ?MP_STATE_DONE, undefined).
-
 add_seq_ids() ->
 add_seq_ids() ->
     Init = fun(Key) ->
     Init = fun(Key) ->
            case kvs:get(id_seq, Key) of
            case kvs:get(id_seq, Key) of
@@ -190,9 +167,6 @@ add_sample_users() ->
           kvs:put(Me#user{password = kvs:sha(Me#user.password)})
           kvs:put(Me#user{password = kvs:sha(Me#user.password)})
     end || Me <- UserList ],
     end || Me <- UserList ],
 
 
-  %kvs_acl:define_access({user, "maxim"},    {feature, admin}, allow),
-  %kvs_acl:define_access({user_type, admin}, {feature, admin}, allow),
-
   [ kvs_user:subscribe(Me#user.username, Her#user.username) || Her <- UserList, Me <- UserList, Her /= Me ],
   [ kvs_user:subscribe(Me#user.username, Her#user.username) || Her <- UserList, Me <- UserList, Her /= Me ],
   [ kvs_user:init_mq(U) || U <- UserList ],
   [ kvs_user:init_mq(U) || U <- UserList ],
 
 
@@ -327,3 +301,15 @@ sha(Raw) ->
 sha_upper(Raw) ->
 sha_upper(Raw) ->
     SHA = sha(Raw),
     SHA = sha(Raw),
     string:to_upper(SHA).
     string:to_upper(SHA).
+
+config(Key) -> config(kvs, Key, "").
+config(App,Key) -> config(App,Key, "").
+config(App, Key, Default) -> case application:get_env(App,Key) of
+                              undefined -> Default;
+                              {ok,V} -> V end.
+
+modules() -> Modules = case kvs:config(schema) of
+        [] -> [ kvs_user, kvs_product, kvs_membership,
+                kvs_payment, kvs_feed, kvs_acl,
+                kvs_account, kvs_group ];
+        E  -> E end.

+ 7 - 0
src/kvs_account.erl

@@ -1,10 +1,17 @@
 -module(kvs_account).
 -module(kvs_account).
+-include_lib("kvs/include/kvs.hrl").
 -include_lib("kvs/include/accounts.hrl").
 -include_lib("kvs/include/accounts.hrl").
 -include_lib("kvs/include/membership.hrl").
 -include_lib("kvs/include/membership.hrl").
 -include_lib("kvs/include/payments.hrl").
 -include_lib("kvs/include/payments.hrl").
 -include_lib("kvs/include/feed_state.hrl").
 -include_lib("kvs/include/feed_state.hrl").
 -compile(export_all).
 -compile(export_all).
 
 
+init(Backend) ->
+    ?CREATE_TAB(id_seq),
+    ?CREATE_TAB(account),
+    ?CREATE_TAB(transaction),
+    ok.
+
 transaction(Account, Currency, 0, TransactionInfo) -> ok;
 transaction(Account, Currency, 0, TransactionInfo) -> ok;
 transaction(Account, Currency, Amount, TransactionInfo) when Amount /= 0 ->
 transaction(Account, Currency, Amount, TransactionInfo) when Amount /= 0 ->
     {Remitter, Acceptor} = if Amount > 0 -> {system, Account}; true -> {Account, system} end,
     {Remitter, Acceptor} = if Amount > 0 -> {system, Account}; true -> {Account, system} end,

+ 6 - 1
src/kvs_acl.erl

@@ -1,12 +1,17 @@
 -module(kvs_acl).
 -module(kvs_acl).
 -copyright('Synrc Research Center s.r.o.').
 -copyright('Synrc Research Center s.r.o.').
 -compile(export_all).
 -compile(export_all).
-
+-include_lib("kvs/include/kvs.hrl").
 -include_lib("kvs/include/acls.hrl").
 -include_lib("kvs/include/acls.hrl").
 -include_lib("kvs/include/users.hrl").
 -include_lib("kvs/include/users.hrl").
 -include_lib("kvs/include/groups.hrl").
 -include_lib("kvs/include/groups.hrl").
 -include_lib("kvs/include/feeds.hrl").
 -include_lib("kvs/include/feeds.hrl").
 
 
+init(Backend) ->
+    ?CREATE_TAB(acl),
+    ?CREATE_TAB(acl_entry),
+    ok.
+
 define_access(Accessor, Resource, Action) -> 
 define_access(Accessor, Resource, Action) -> 
     Entry = #acl_entry{ id = {Accessor, Resource},
     Entry = #acl_entry{ id = {Accessor, Resource},
                         accessor= Accessor,
                         accessor= Accessor,

+ 12 - 1
src/kvs_feed.erl

@@ -1,15 +1,26 @@
 -module(kvs_feed).
 -module(kvs_feed).
 -author('Maxim Sokhatsky').
 -author('Maxim Sokhatsky').
 -author('Andrii Zadorozhnii').
 -author('Andrii Zadorozhnii').
--author('Alexander Kalenuk').
 -copyright('Synrc Research Center, s.r.o.').
 -copyright('Synrc Research Center, s.r.o.').
 -compile(export_all).
 -compile(export_all).
+-include_lib("kvs/include/kvs.hrl").
 -include_lib("kvs/include/feeds.hrl").
 -include_lib("kvs/include/feeds.hrl").
 -include_lib("kvs/include/users.hrl").
 -include_lib("kvs/include/users.hrl").
 -include_lib("kvs/include/groups.hrl").
 -include_lib("kvs/include/groups.hrl").
 -include_lib("kvs/include/feed_state.hrl").
 -include_lib("kvs/include/feed_state.hrl").
 -define(CACHED_ENTRIES, 20).
 -define(CACHED_ENTRIES, 20).
 
 
+init(Backend) ->
+    ?CREATE_TAB(feed),
+    ?CREATE_TAB(entry),
+    ?CREATE_TAB(comment),
+    Backend:add_table_index(entry, feed_id),
+    Backend:add_table_index(entry, entry_id),
+    Backend:add_table_index(entry, from),
+    Backend:add_table_index(comment, entry_id),
+    Backend:add_table_index(comment, author_id),
+    ok.
+
 create() ->
 create() ->
     FId = kvs:next_id("feed", 1),
     FId = kvs:next_id("feed", 1),
     ok = kvs:put(#feed{id = FId} ),
     ok = kvs:put(#feed{id = FId} ),

+ 8 - 0
src/kvs_group.erl

@@ -1,5 +1,6 @@
 -module(kvs_group).
 -module(kvs_group).
 -compile(export_all).
 -compile(export_all).
+-include_lib("kvs/include/kvs.hrl").
 -include_lib("kvs/include/users.hrl").
 -include_lib("kvs/include/users.hrl").
 -include_lib("kvs/include/groups.hrl").
 -include_lib("kvs/include/groups.hrl").
 -include_lib("kvs/include/accounts.hrl").
 -include_lib("kvs/include/accounts.hrl").
@@ -7,6 +8,13 @@
 -include_lib("kvs/include/config.hrl").
 -include_lib("kvs/include/config.hrl").
 -include_lib("mqs/include/mqs.hrl").
 -include_lib("mqs/include/mqs.hrl").
 
 
+init(Backend) ->
+    ?CREATE_TAB(group_subscription),
+    ?CREATE_TAB(group),
+    Backend:add_table_index(group_subscription, who),
+    Backend:add_table_index(group_subscription, where),
+    ok.
+
 retrieve_groups(User) ->
 retrieve_groups(User) ->
     case participate(User) of
     case participate(User) of
          [] -> [];
          [] -> [];

+ 5 - 0
src/kvs_meeting.erl

@@ -1,10 +1,15 @@
 -module(kvs_meeting).
 -module(kvs_meeting).
+-include_lib("kvs/include/kvs.hrl").
 -include_lib("kvs/include/users.hrl").
 -include_lib("kvs/include/users.hrl").
 -include_lib("kvs/include/meetings.hrl").
 -include_lib("kvs/include/meetings.hrl").
 -include_lib("kvs/include/feed_state.hrl").
 -include_lib("kvs/include/feed_state.hrl").
 -include_lib("kvs/include/config.hrl").
 -include_lib("kvs/include/config.hrl").
 -compile(export_all).
 -compile(export_all).
 
 
+init(Backend) ->
+    ?CREATE_TAB(team),
+    ok.
+
 create_team(Name) ->
 create_team(Name) ->
     TID = kvs:next_id("team",1),
     TID = kvs:next_id("team",1),
     ok = kvs:put(Team = #team{id=TID,name=Name}),
     ok = kvs:put(Team = #team{id=TID,name=Name}),

+ 5 - 0
src/kvs_membership.erl

@@ -1,5 +1,6 @@
 -module(kvs_membership).
 -module(kvs_membership).
 -author('Vladimir Baranov <baranoff.vladimir@gmail.com>').
 -author('Vladimir Baranov <baranoff.vladimir@gmail.com>').
+-include_lib("kvs/include/kvs.hrl").
 -include_lib("kvs/include/membership.hrl").
 -include_lib("kvs/include/membership.hrl").
 -include_lib("kvs/include/payments.hrl").
 -include_lib("kvs/include/payments.hrl").
 -include_lib("kvs/include/products.hrl").
 -include_lib("kvs/include/products.hrl").
@@ -7,6 +8,10 @@
 -include_lib("kvs/include/feed_state.hrl").
 -include_lib("kvs/include/feed_state.hrl").
 -compile(export_all).
 -compile(export_all).
 
 
+init(Backend) ->
+    ?CREATE_TAB(membership),
+    ok.
+
 add_package(#membership{}=Package)->
 add_package(#membership{}=Package)->
     Id = generate_id(),
     Id = generate_id(),
     save_package(Package#membership{id = Id}).
     save_package(Package#membership{id = Id}).

+ 6 - 0
src/kvs_payment.erl

@@ -1,10 +1,16 @@
 -module(kvs_payment).
 -module(kvs_payment).
+-include_lib("kvs/include/kvs.hrl").
 -include_lib("kvs/include/membership.hrl").
 -include_lib("kvs/include/membership.hrl").
 -include_lib("kvs/include/payments.hrl").
 -include_lib("kvs/include/payments.hrl").
 -include_lib("kvs/include/accounts.hrl").
 -include_lib("kvs/include/accounts.hrl").
 -include_lib("kvs/include/feed_state.hrl").
 -include_lib("kvs/include/feed_state.hrl").
 -compile(export_all).
 -compile(export_all).
 
 
+init(Backend) ->
+    ?CREATE_TAB(payment),
+    ?CREATE_TAB(user_payment),
+    ok.
+
 payments(UserId) -> payments(UserId, undefined).
 payments(UserId) -> payments(UserId, undefined).
 payments(UserId, PageAmount) ->
 payments(UserId, PageAmount) ->
     case kvs:get(user_payment, UserId) of
     case kvs:get(user_payment, UserId) of

+ 8 - 0
src/kvs_product.erl

@@ -1,6 +1,8 @@
 -module(kvs_product).
 -module(kvs_product).
 -copyright('Synrc Research Center s.r.o.').
 -copyright('Synrc Research Center s.r.o.').
+-include_lib("kvs/include/kvs.hrl").
 -include_lib("kvs/include/products.hrl").
 -include_lib("kvs/include/products.hrl").
+-include_lib("kvs/include/purchases.hrl").
 -include_lib("kvs/include/users.hrl").
 -include_lib("kvs/include/users.hrl").
 -include_lib("kvs/include/groups.hrl").
 -include_lib("kvs/include/groups.hrl").
 -include_lib("kvs/include/feeds.hrl").
 -include_lib("kvs/include/feeds.hrl").
@@ -10,6 +12,12 @@
 -include_lib("mqs/include/mqs.hrl").
 -include_lib("mqs/include/mqs.hrl").
 -compile(export_all).
 -compile(export_all).
 
 
+init(Backend) ->
+    ?CREATE_TAB(product),
+    ?CREATE_TAB(user_product),
+    ?CREATE_TAB(product_category),
+    ok.
+
 delete(Name) ->
 delete(Name) ->
   case kvs:get(product, Name) of
   case kvs:get(product, Name) of
     {ok, Product} ->
     {ok, Product} ->

+ 0 - 2
src/kvs_sup.erl

@@ -19,8 +19,6 @@ init([]) ->
     Type = worker,
     Type = worker,
 
 
     kvs:start(),
     kvs:start(),
- %  kvs:initialize(),
-    kvs:wait_for_tables(),
 
 
     {ok, { {one_for_one, 5, 10}, []} }.
     {ok, { {one_for_one, 5, 10}, []} }.
 
 

+ 16 - 0
src/kvs_user.erl

@@ -1,14 +1,30 @@
 -module(kvs_user).
 -module(kvs_user).
 -copyright('Synrc Research Center s.r.o.').
 -copyright('Synrc Research Center s.r.o.').
 -include_lib("kvs/include/users.hrl").
 -include_lib("kvs/include/users.hrl").
+-include_lib("kvs/include/purchases.hrl").
+-include_lib("kvs/include/payments.hrl").
 -include_lib("kvs/include/groups.hrl").
 -include_lib("kvs/include/groups.hrl").
 -include_lib("kvs/include/accounts.hrl").
 -include_lib("kvs/include/accounts.hrl").
+-include_lib("kvs/include/products.hrl").
 -include_lib("kvs/include/config.hrl").
 -include_lib("kvs/include/config.hrl").
 -include_lib("kvs/include/feeds.hrl").
 -include_lib("kvs/include/feeds.hrl").
 -include_lib("kvs/include/feed_state.hrl").
 -include_lib("kvs/include/feed_state.hrl").
 -include_lib("mqs/include/mqs.hrl").
 -include_lib("mqs/include/mqs.hrl").
+-include_lib("kvs/include/kvs.hrl").
 -compile(export_all).
 -compile(export_all).
 
 
+init(Backend) ->
+    ?CREATE_TAB(user),
+    ?CREATE_TAB(user_status),
+    ?CREATE_TAB(subscription),
+    Backend:add_table_index(user, facebook_id),
+    Backend:add_table_index(user, googleplus_id),
+    Backend:add_table_index(user, twitter_id),
+    Backend:add_table_index(user, github_id),
+    Backend:add_table_index(subscription, who),
+    Backend:add_table_index(subscription, whom),
+    ok.
+
 delete(UserName) ->
 delete(UserName) ->
     case kvs_user:get(UserName) of
     case kvs_user:get(UserName) of
         {ok, User} ->
         {ok, User} ->

+ 96 - 0
src/store_kai.erl

@@ -0,0 +1,96 @@
+-module(store_kai).
+-author('Maxim Sokhatsky <maxim@synrc.com>').
+-copyright('Synrc Research Center s.r.o.').
+-include_lib("kai/include/kai.hrl").
+-include_lib("kvs/include/config.hrl").
+-include_lib("kvs/include/users.hrl").
+-include_lib("kvs/include/groups.hrl").
+-include_lib("kvs/include/feeds.hrl").
+-include_lib("kvs/include/acls.hrl").
+-include_lib("kvs/include/invites.hrl").
+-include_lib("kvs/include/meetings.hrl").
+-include_lib("kvs/include/membership.hrl").
+-include_lib("kvs/include/payments.hrl").
+-include_lib("kvs/include/purchases.hrl").
+-include_lib("kvs/include/accounts.hrl").
+-include_lib("stdlib/include/qlc.hrl").
+-compile(export_all).
+
+start() -> kai:start(), ok.
+stop() -> kai_store:stop(), ok.
+version() -> {version,"KVS KAI PURE XEN"}.
+join() -> initialize(), ok.
+join(Node) -> initialize(), ok.
+initialize() -> ok.
+dir() -> kvs:modules().
+
+put(Records) when is_list(Records) -> lists:foreach(fun kai_put/1, Records);
+put(Record) -> kai_put(Record).
+
+kai_put(Record) ->
+    Data = #data{key = element(2,Record), bucket = table_to_num(element(1,Record)),
+        last_modified = now(), checksum = erlang:md5(term_to_binary(Record)),
+        vector_clocks = vclock:fresh(), value = Record },
+    kai_store:put(Data).
+
+update(Record, Object) -> ok.
+
+get(Tab, Key) ->
+    Data = #data{key=Key,bucket=table_to_num(Tab)},
+    kai_get(Data).
+
+kai_get(Data) ->
+    case kai_store:get(Data) of
+         #data{value=Value} -> Value;
+         undefined -> {error,not_found};
+         E -> {error,E} end.
+
+delete(Tab, Key) ->
+    ok.
+
+key_to_bin(Key) ->
+    if is_integer(Key) -> erlang:list_to_binary(integer_to_list(Key));
+       is_list(Key) -> erlang:list_to_binary(Key);
+       is_atom(Key) -> erlang:list_to_binary(erlang:atom_to_list(Key));
+       is_binary(Key) -> Key;
+       true ->  [ListKey] = io_lib:format("~p", [Key]), erlang:list_to_binary(ListKey) end.
+
+all(RecordName) ->
+    {list_of_data,List} = kai_store:list(table_to_num(RecordName)),
+    [ kai_get(Data) || Data <- List ].
+
+all_by_index(Tab, IndexId, IndexVal) -> [].
+
+% index funs
+
+products(UId) -> all_by_index(user_product, <<"user_bin">>, list_to_binary(UId)).
+subscriptions(UId) -> all_by_index(subsciption, <<"subs_who_bin">>, list_to_binary(UId)).
+subscribed(Who) -> all_by_index(subscription, <<"subs_whom_bin">>, list_to_binary(Who)).
+participate(UserName) -> all_by_index(group_subscription, <<"who_bin">>, UserName).
+members(GroupName) -> all_by_index(group_subscription, <<"where_bin">>, GroupName).
+user_tournaments(UId) -> all_by_index(play_record, <<"play_record_who_bin">>, list_to_binary(UId)).
+tournament_users(TId) -> all_by_index(play_record, <<"play_record_tournament_bin">>, list_to_binary(integer_to_list(TId))).
+author_comments(Who) ->
+    EIDs = [E || #comment{entry_id=E} <- all_by_index(comment,<<"author_bin">>, Who) ],
+    lists:flatten([ all_by_index(entry,<<"entry_bin">>,EID) || EID <- EIDs]).
+
+table_to_num(user) -> 10;
+table_to_num(user_status) -> 20;
+table_to_num(subscription) -> 30;
+table_to_num(group) -> 40;
+table_to_num(group_subscription) -> 50;
+table_to_num(payment) -> 60;
+table_to_num(user_payment) -> 70;
+table_to_num(account) -> 80;
+table_to_num(transaction) -> 90;
+table_to_num(id_seq) -> 100;
+table_to_num(team) -> 110;
+table_to_num(membership) -> 120;
+table_to_num(product) -> 130;
+table_to_num(product_category) -> 140;
+table_to_num(user_product) -> 150;
+table_to_num(acl) -> 160;
+table_to_num(acl_entry) -> 170;
+table_to_num(feed) -> 180;
+table_to_num(entry) -> 190;
+table_to_num(comment) -> 200.

+ 2 - 40
src/store_mnesia.erl

@@ -16,11 +16,10 @@
 -include_lib("kvs/include/translations.hrl").
 -include_lib("kvs/include/translations.hrl").
 -include_lib("stdlib/include/qlc.hrl").
 -include_lib("stdlib/include/qlc.hrl").
 -compile(export_all).
 -compile(export_all).
--define(CREATE_TAB(T), create_table(T, record_info(fields, T), [{storage, permanent}]) ).
 
 
 start() -> mnesia:start().
 start() -> mnesia:start().
 stop() -> mnesia:stop().
 stop() -> mnesia:stop().
-single() -> mnesia:change_table_copy_type(schema, node(), disc_copies), initialize().
+join() -> mnesia:change_table_copy_type(schema, node(), disc_copies), initialize().
 join(Node) ->
 join(Node) ->
     mnesia:change_config(extra_db_nodes, [Node]),
     mnesia:change_config(extra_db_nodes, [Node]),
     mnesia:change_table_copy_type(schema, node(), disc_copies),
     mnesia:change_table_copy_type(schema, node(), disc_copies),
@@ -29,49 +28,12 @@ join(Node) ->
                                || T <- mnesia:system_info(tables)]].
                                || T <- mnesia:system_info(tables)]].
 delete() -> mnesia:delete_schema([node()]).
 delete() -> mnesia:delete_schema([node()]).
 version() -> {version,"KVS MNESIA Embedded"}.
 version() -> {version,"KVS MNESIA Embedded"}.
-add_indexes() ->
-    add_table_index(comment, entry_id),
-    add_table_index(comment, author_id),
-    add_table_index(subscription, who),
-    add_table_index(subscription, whom),
-    add_table_index(group_subscription, who),
-    add_table_index(group_subscription, where),
-    add_table_index(entry, feed_id),
-    add_table_index(entry, entry_id),
-    add_table_index(entry, from),
-    add_table_index(user, facebook_id),
-    add_table_index(user, googleplus_id),
-    add_table_index(user, twitter_id),
-    add_table_index(user, github_id),
-%    add_table_index(user, email),
-    ok.
-create_users() ->  ?CREATE_TAB(user).
 
 
 initialize() ->
 initialize() ->
     error_logger:info_msg("Mnesia Init"),
     error_logger:info_msg("Mnesia Init"),
     mnesia:create_schema([node()]),
     mnesia:create_schema([node()]),
-    ?CREATE_TAB(payment),
-    ?CREATE_TAB(acl),
-    ?CREATE_TAB(acl_entry),
-    ?CREATE_TAB(feed),
-    ?CREATE_TAB(team),
-    ?CREATE_TAB(entry),
-    ?CREATE_TAB(comment),
-    ?CREATE_TAB(user),
-    ?CREATE_TAB(user_product),
-    ?CREATE_TAB(user_payment),
-    ?CREATE_TAB(user_status),
-    ?CREATE_TAB(membership),
-    ?CREATE_TAB(account),
-    ?CREATE_TAB(subscription),
-    ?CREATE_TAB(group_subscription),
-    ?CREATE_TAB(group),
-    ?CREATE_TAB(id_seq),
-    ?CREATE_TAB(transaction),
-    ?CREATE_TAB(product),
-    ?CREATE_TAB(product_category),
+    [ Module:init(store_mnesia) || Module <- kvs:modules() ],
     wait_for_tables(),
     wait_for_tables(),
-    add_indexes(),
     ok.
     ok.
 
 
 wait_for_tables() ->
 wait_for_tables() ->

+ 2 - 0
src/store_riak.erl

@@ -18,6 +18,8 @@
 start() -> ok.
 start() -> ok.
 stop() -> ok.
 stop() -> ok.
 version() -> {version,"KVS RIAK 1.3.2-voxoz"}.
 version() -> {version,"KVS RIAK 1.3.2-voxoz"}.
+join() -> initialize(), ok.
+join(Node) -> initialize(), ok.
 
 
 initialize() ->
 initialize() ->
     C = riak:client_connect(node()),
     C = riak:client_connect(node()),