Browse Source

Merge pull request #15 from m-2k/master

Redis Implementation
Namdak Tonpa 10 years ago
parent
commit
bd93a60404
2 changed files with 92 additions and 2 deletions
  1. 12 2
      README.md
  2. 80 0
      src/store_redis.erl

+ 12 - 2
README.md

@@ -8,7 +8,7 @@ Features
 
 
 * Polymorphic Tuples
 * Polymorphic Tuples
 * Managing Linked-Lists
 * Managing Linked-Lists
-* Various Backends Support: KAI, Mnesia, Riak, CouchDB
+* Various Backends Support: Mnesia, Riak, KAI, Redis
 * Sequential Consistency via Feed Server
 * Sequential Consistency via Feed Server
 * Basic Schema for Social Sites and Accounting
 * Basic Schema for Social Sites and Accounting
 * Extendable Schema
 * Extendable Schema
@@ -22,7 +22,14 @@ Usage
 
 
 In rebar.config:
 In rebar.config:
 
 
+```erlang
     {kvs, ".*", {git, "git://github.com/synrc/kvs", "HEAD"}}
     {kvs, ".*", {git, "git://github.com/synrc/kvs", "HEAD"}}
+```
+
+Redis also need to add:
+```erlang
+    {eredis, ".*", {git, "git://github.com/wooga/eredis", {tag, "v1.0.6"} }}
+```
 
 
 Overview
 Overview
 --------
 --------
@@ -64,6 +71,7 @@ Currently kvs includes following store backends:
 * Mnesia
 * Mnesia
 * Riak
 * Riak
 * KAI
 * KAI
+* Redis
 
 
 Configuring
 Configuring
 -----------
 -----------
@@ -90,6 +98,7 @@ Create database for single node:
 3> kvs:join().
 3> kvs:join().
 [kvs] Mnesia Init
 [kvs] Mnesia Init
 ok
 ok
+```
 
 
 You can also create database by joining to existing cluster:
 You can also create database by joining to existing cluster:
 
 
@@ -209,7 +218,7 @@ Extending Schema
 ----------------
 ----------------
 
 
 Usually you need only specify custom mnesia indexes and tables tuning.
 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
+Riak, KAI and Redis backends don't need it. Group you table into table packages
 represented as modules with handle_notice API.
 represented as modules with handle_notice API.
 
 
 ```erlang
 ```erlang
@@ -298,5 +307,6 @@ Credits
 * Vladimir Kirillov
 * Vladimir Kirillov
 * Alex Kalenuk
 * Alex Kalenuk
 * Sergey Polkovnikov
 * Sergey Polkovnikov
+* Andrey Martemyanov
 
 
 OM A HUM
 OM A HUM

+ 80 - 0
src/store_redis.erl

@@ -0,0 +1,80 @@
+-module(store_redis).
+-author('Andrey Martemyanov').
+-copyright('Synrc Research Center s.r.o.').
+-include("config.hrl").
+-include("kvs.hrl").
+-include("metainfo.hrl").
+-compile(export_all).
+
+start() -> erase(eredis_pid), {ok,C}=eredis:start_link(), put(eredis_pid,C), ok.
+stop() -> P=erase(eredis_pid), eredis:stop(P), ok.
+c() -> case get(eredis_pid) of
+    P when is_pid(P) ->
+        case is_process_alive(P) of true -> P; _ -> start(), get(eredis_pid) end;
+    _ -> start(), get(eredis_pid) end.
+destroy() -> ok.
+version() -> {version,"KVS REDIS"}.
+dir() -> [{table,T}||T<-kvs:modules()].
+join() -> initialize(), ok.
+join(_Node) -> initialize(), ok.
+change_storage(_Table,_Type) -> ok.
+initialize() -> ok.
+
+b2i(B) -> list_to_integer(binary_to_list(B)).
+redis_table(RecordName) ->
+    list_to_binary(atom_to_list(RecordName)).
+redis_key(RecordName,Key) ->
+    <<(redis_table(RecordName))/binary,$:,(term_to_binary(Key))/binary>>.
+redis_keys(RecordName) ->
+    case eredis:q(c(), ["keys", <<(redis_table(RecordName))/binary,$:,$*>> ]) of
+        {ok,KeyList} when is_list(KeyList) -> KeyList;
+        _ -> [] end.
+redis_put(#id_seq{thing=Thing,id=Incr}) when is_integer(Incr)->
+    eredis:q(c(), ["SET", redis_key(id_seq,Thing), Incr]);
+redis_put(Record) ->
+    Key = redis_key(element(1,Record),element(2,Record)),
+    Value = term_to_binary(Record),
+    eredis:q(c(), ["SET", Key, Value]).
+redis_get(Key, Fun) ->
+    case eredis:q(c(), ["GET", Key]) of
+        {ok, undefined} -> {error,not_found};
+        {ok, <<"QUEUED">>} -> transaction;
+        {ok, Value} ->
+            if is_function(Fun) -> {ok,Fun(Value)};
+                true -> {ok,binary_to_term(Value)} end;
+        E -> {error, E} end.
+redis_get(Key) -> redis_get(Key, undefined).
+redis_transaction(Fun) ->
+    {ok, <<"OK">>} = eredis:q(c(), ["MULTI"]),
+    Fun(),
+    {ok,List} = eredis:q(c(), ["EXEC"]),
+    List.
+
+index(_RecordName,_Key,_Value) -> not_implemented.
+get(id_seq,Key) ->
+    redis_get(redis_key(id_seq,Key), fun(Value) ->
+        #id_seq{thing=Key,id=b2i(Value)} end);
+get(RecordName,Key) -> redis_get(redis_key(RecordName,Key)).
+put(Records) when is_list(Records) ->
+    redis_transaction(fun() -> lists:foreach(fun put/1, Records) end);
+put(Record) -> redis_put(Record).
+delete(RecordName,Key) ->
+    case eredis:q(c(), ["DEL", redis_key(RecordName,Key)]) of
+        {ok,<<"1">>} -> ok;
+        E -> {error, E} end.
+count(RecordName) -> length(redis_keys(RecordName)).
+all(RecordName) -> 
+    Keys = redis_keys(RecordName),
+    List = redis_transaction(fun() -> [redis_get(Key) || Key <- Keys] end),
+    case RecordName of
+        id_seq ->
+            lists:zipwith(fun(K,R) ->
+                #id_seq{thing=binary_to_term(binary_part(K,7,size(K)-7)),id=b2i(R)}
+                end, Keys, List);
+        _ -> [ binary_to_term(R) || R <- List ] end.
+next_id(RecordName,Incr) ->
+    Key = redis_key(id_seq,RecordName),
+    {ok, Value} = eredis:q(c(), ["INCRBY", Key, Incr]),
+    b2i(Value).
+create_table(_Name,_Options) -> ok.
+add_table_index(_Record,_Field) -> not_implemented.