kvs.erl 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. -module(kvs).
  2. -copyright('Synrc Research Center s.r.o.').
  3. -compile(export_all).
  4. -include_lib("stdlib/include/qlc.hrl").
  5. -include("config.hrl").
  6. -include("metainfo.hrl").
  7. -include("kvs.hrl").
  8. -include("api.hrl").
  9. % Public Main Backend is given in sys.config and
  10. % could be obtained with application:get_env(kvs,dba,store_mnesia).
  11. delete(Table,Key) -> delete (Table, Key, #kvs{mod=?DBA}).
  12. remove(Table,Key) -> remove (Table, Key, #kvs{mod=?DBA}).
  13. get(Table,Key) -> get (Table, Key, #kvs{mod=?DBA}).
  14. index(Table,K,V) -> index (Table, K,V, #kvs{mod=?DBA}).
  15. change_storage(Table,Type) -> change_storage(Table,Type, #kvs{mod=?DBA}).
  16. entries(A,B,C) -> entries (A,B,C, #kvs{mod=?DBA}).
  17. join() -> join ([], #kvs{mod=?DBA}).
  18. join(Node) -> join (Node, #kvs{mod=?DBA}).
  19. count(Table) -> count (Table, #kvs{mod=?DBA}).
  20. add(Table) -> add (Table, #kvs{mod=?DBA}).
  21. all(Table) -> all (Table, #kvs{mod=?DBA}).
  22. put(Table) -> put (Table, #kvs{mod=?DBA}).
  23. link(Table) -> link (Table, #kvs{mod=?DBA}).
  24. traversal(T,S,C,D) -> traversal(T,S,C,D, #kvs{mod=?DBA}).
  25. info(T) -> info (T, #kvs{mod=?DBA}).
  26. start() -> start (#kvs{mod=?DBA}).
  27. stop() -> stop (#kvs{mod=?DBA}).
  28. destroy() -> destroy (#kvs{mod=?DBA}).
  29. version() -> version (#kvs{mod=?DBA}).
  30. dir() -> dir (#kvs{mod=?DBA}).
  31. next_id(Table,DX) -> next_id(Table, DX, #kvs{mod=?DBA}).
  32. generation(Table,Key) ->
  33. case Key - topleft(Table,Key) < application:get_env(kvs,generation,250000) of
  34. true -> skip;
  35. false -> kvs:rotate(Table) end.
  36. % Implementation
  37. init(Backend, Module) ->
  38. [ begin
  39. Backend:create_table(T#table.name, [{attributes,T#table.fields},{T#table.copy_type, [node()]}]),
  40. [ Backend:add_table_index(T#table.name, Key) || Key <- T#table.keys ],
  41. T
  42. end || T <- (Module:metainfo())#schema.tables ].
  43. start(#kvs{mod=DBA}) -> DBA:start().
  44. stop(#kvs{mod=DBA}) -> DBA:stop().
  45. change_storage(Type) -> [ change_storage(Name,Type) || #table{name=Name} <- kvs:tables() ].
  46. change_storage(Table,Type,#kvs{mod=DBA}) -> DBA:change_storage(Table,Type).
  47. destroy(#kvs{mod=DBA}) -> DBA:destroy().
  48. join(Node,#kvs{mod=DBA}) -> DBA:join(Node), rotate_new(), load_partitions().
  49. version(#kvs{mod=DBA}) -> DBA:version().
  50. tables() -> lists:flatten([ (M:metainfo())#schema.tables || M <- modules() ]).
  51. table(Name) -> lists:keyfind(Name,#table.name,tables()).
  52. dir(#kvs{mod=DBA}) -> DBA:dir().
  53. info(T,#kvs{mod=DBA}) -> DBA:info(T).
  54. modules() -> kvs:config(schema).
  55. containers() ->
  56. lists:flatten([ [ {T#table.name,T#table.fields}
  57. || T=#table{container=true} <- (M:metainfo())#schema.tables ]
  58. || M <- modules() ]).
  59. create(ContainerName) -> create(ContainerName, kvs:next_id(atom_to_list(ContainerName), 1), #kvs{mod=?DBA}).
  60. create(ContainerName, Id, Driver) ->
  61. kvs:info(?MODULE,"Create: ~p",[ContainerName]),
  62. Instance = list_to_tuple([ContainerName|proplists:get_value(ContainerName, kvs:containers())]),
  63. Top = setelement(#container.id,Instance,Id),
  64. Top2 = setelement(#container.top,Top,undefined),
  65. Top3 = setelement(#container.count,Top2,0),
  66. ok = kvs:put(Top3, Driver),
  67. Id.
  68. ensure_link(Record, #kvs{mod=_Store}=Driver) ->
  69. Id = element(2,Record),
  70. Type = rname(element(1,Record)),
  71. CName = element(#iterator.container, Record),
  72. Cid = case element(#iterator.feed_id, Record) of
  73. undefined -> rname(element(1,Record));
  74. Fid -> Fid end,
  75. Container = case kvs:get(CName, Cid, Driver) of
  76. {ok,Res} -> Res;
  77. {error, _} when Cid /= undefined ->
  78. NC = setelement(#container.id,
  79. list_to_tuple([CName|
  80. proplists:get_value(CName, kvs:containers())]), Cid),
  81. NC1 = setelement(#container.count, NC, 0),
  82. NC1;
  83. _Error -> error end,
  84. case Container of
  85. error -> {error, no_container};
  86. _ when element(#container.top,Container) == Id -> {error,just_added};
  87. _ ->
  88. Top = case element(#container.top, Container) of
  89. undefined -> undefined;
  90. Tid -> case kvs:get(Type, Tid, Driver) of
  91. {error, _} -> undefined;
  92. {ok, T} -> setelement(#iterator.next, T, Id) end end,
  93. Prev = case Top of undefined -> undefined; E -> element(#iterator.id, E) end,
  94. Next = undefined,
  95. C1 = setelement(#container.top, Container, Id),
  96. C2 = setelement(#container.count, C1,
  97. element(#container.count, Container)+1),
  98. R = setelement(#iterator.feeds, Record,
  99. [ case F1 of
  100. {FN, Fd} -> {FN, Fd};
  101. _-> {F1, kvs:create(CName,{F1,element(#iterator.id,Record)},Driver)}
  102. end || F1 <- element(#iterator.feeds, Record)]),
  103. R1 = setelement(#iterator.next, R, Next),
  104. R2 = setelement(#iterator.prev, R1, Prev),
  105. R3 = setelement(#iterator.feed_id, R2, element(#container.id, Container)),
  106. case {kvs:put(R3, Driver),Top} of % Iterator
  107. {ok,undefined} -> kvs:put(C2, Driver); % Container
  108. {ok,Top} -> kvs:put(C2, Driver),
  109. kvs:put(Top, Driver);
  110. __ -> kvs:error(?MODULE,"Error Updating Iterator: ~p~n",
  111. [element(#container.id,R3)]) end,
  112. kvs:info(?MODULE,"Put: ~p~n", [element(#container.id,R3)]),
  113. {ok, R3}
  114. end.
  115. link(Record,#kvs{mod=_Store}=Driver) ->
  116. Id = element(#iterator.id, Record),
  117. case kvs:get(rname(element(1,Record)), Id, Driver) of
  118. {ok, Exists} -> ensure_link(Exists, Driver);
  119. {error, not_found} -> {error, not_found} end.
  120. add(Record, #kvs{mod=store_mnesia}=Driver) when is_tuple(Record) -> store_mnesia:add(Record);
  121. add(Record, #kvs{mod=Store}=Driver) when is_tuple(Record) -> append(Record,Driver).
  122. append(Record, #kvs{mod=_Store}=Driver) when is_tuple(Record) ->
  123. Id = element(#iterator.id, Record),
  124. Name = rname(element(1,Record)),
  125. generation(Name, Id),
  126. case kvs:get(Name, Id, Driver) of
  127. {error, _} -> ensure_link(Record, Driver);
  128. {aborted, Reason} -> {aborted, Reason};
  129. {ok, _} -> {error, exist} end.
  130. reverse(#iterator.prev) -> #iterator.next;
  131. reverse(#iterator.next) -> #iterator.prev.
  132. relink(Container, E, Driver) ->
  133. Id = element(#iterator.id, E),
  134. Next = element(#iterator.next, E),
  135. Prev = element(#iterator.prev, E),
  136. Top = element(#container.top, Container),
  137. case kvs:get(element(1,E), Prev, Driver) of
  138. {ok, PE} -> kvs:put(setelement(#iterator.next, PE, Next), Driver);
  139. _ -> ok end,
  140. case kvs:get(element(1,E), Next, Driver) of
  141. {ok, NE} -> kvs:put(setelement(#iterator.prev, NE, Prev), Driver);
  142. _ -> ok end,
  143. C = case Top of
  144. Id -> setelement(#container.top, Container, Prev);
  145. _ -> Container end,
  146. case element(#container.top,C) of
  147. undefined -> kvs:delete(element(1,C),element(#container.id,C));
  148. _ -> kvs:put(setelement(#container.count,C,element(#container.count,C)-1), Driver) end.
  149. delete(Tab, Key, #kvs{mod=Mod}) ->
  150. case range(Tab,Key) of
  151. [] -> Mod:delete(Tab, Key);
  152. T -> Mod:delete(T, Key) end.
  153. remove(Record,Id,#kvs{mod=Mod}=Driver) ->
  154. case get(Record,Id) of
  155. {error, not_found} -> kvs:error(?MODULE,"Can't remove ~p~n",[{Record,Id}]);
  156. {ok,R} -> do_remove(R,Driver) end.
  157. do_remove(E,#kvs{mod=Mod}=Driver) ->
  158. case get(element(#iterator.container,E),element(#iterator.feed_id,E)) of
  159. {ok, C} -> relink(C,E,Driver);
  160. _ -> skip end,
  161. kvs:info(?MODULE,"Delete: ~p", [E]),
  162. kvs:delete(element(1,E),element(2,E), Driver).
  163. traversal(Table, Start, Count, Direction, Driver)->
  164. fold(fun(A,Acc) -> [A|Acc] end,[],Table,Start,Count,Direction,Driver).
  165. % kvs:fold(fun(X,A)->[X|A]end,[],process,2152,-1,#iterator.next,#kvs{mod=store_mnesia}).
  166. fold(___,___,_,undefined,_,_,_) -> [];
  167. fold(___,Acc,_,_,0,_,_) -> Acc;
  168. fold(Fun,Acc,Table,Start,Count,Direction,Driver) ->
  169. %io:format("fold: ~p~n",[{rname(Table), Start, Driver}]),
  170. case kvs:get(rname(Table), Start, Driver) of
  171. {ok, R} -> Prev = element(Direction, R),
  172. Count1 = case Count of C when is_integer(C) -> C - 1; _-> Count end,
  173. fold(Fun, Fun(R,Acc), Table, Prev, Count1, Direction, Driver);
  174. Error -> %kvs:error(?MODULE,"Error: ~p~n",[Error]),
  175. Acc end.
  176. entries({error,_},_,_,_) -> [];
  177. entries({ok,Container},N,C,Driver) -> entries(Container,N,C,Driver);
  178. entries(T,N,C,Driver) -> traversal(N,element(#container.top,T),C,#iterator.prev,Driver).
  179. entries(N, Start, Count, Direction, Driver) ->
  180. E = traversal(N, Start, Count, Direction, Driver),
  181. case Direction of #iterator.next -> lists:reverse(E);
  182. #iterator.prev -> E end.
  183. add_seq_ids() ->
  184. Init = fun(Key) ->
  185. case kvs:get(id_seq, Key) of
  186. {error, _} -> {Key,kvs:put(#id_seq{thing = Key, id = 0})};
  187. {ok, _} -> {Key,skip} end end,
  188. [ Init(atom_to_list(Name)) || {Name,_Fields} <- containers() ].
  189. put(Record,#kvs{mod=Mod}) ->
  190. case range(element(1,Record),element(2,Record)) of
  191. [] -> Mod:put(Record);
  192. Name -> Mod:put(setelement(1,Record,Name)) end.
  193. get(RecordName, Key, #kvs{mod=Mod}) ->
  194. case range(RecordName,Key) of
  195. [] -> Mod:get(RecordName, Key);
  196. Name -> case Mod:get(Name, Key) of
  197. {ok,Record} -> {ok,setelement(1,Record,kvs:last(RecordName,Key))};
  198. Else -> Else end end.
  199. count(RecordName,#kvs{mod=DBA}) -> DBA:count(RecordName).
  200. all(RecordName,#kvs{mod=DBA}) -> DBA:all(RecordName).
  201. index(RecordName, Key, Value,#kvs{mod=DBA}) -> DBA:index(RecordName, Key, Value).
  202. next_id(RecordName, Incr,#kvs{mod=DBA}) -> DBA:next_id(RecordName, Incr).
  203. save_db(Path) ->
  204. Data = lists:append([all(B) || B <- [list_to_atom(Name) || {table,Name} <- kvs:dir()] ]),
  205. kvs:save(Path, Data).
  206. load_db(Path) ->
  207. add_seq_ids(),
  208. AllEntries = kvs:load(Path),
  209. [kvs:put(E) || E <- lists:filter(fun(E) -> is_tuple(E) end ,AllEntries)].
  210. save(Dir, Value) ->
  211. filelib:ensure_dir(Dir),
  212. file:write_file(Dir, term_to_binary(Value)).
  213. load(Key) ->
  214. {ok, Bin} = file:read_file(Key),
  215. binary_to_term(Bin).
  216. notify(_EventPath, _Data) -> skip.
  217. config(Key) -> config(kvs, Key, "").
  218. config(App,Key) -> config(App,Key, "").
  219. config(App, Key, Default) -> case application:get_env(App,Key) of
  220. undefined -> Default;
  221. {ok,V} -> V end.
  222. log_modules() -> [].
  223. -define(ALLOWED, (config(kvs,log_modules,kvs))).
  224. log(Module, String, Args, Fun) ->
  225. case lists:member(Module,?ALLOWED:log_modules()) of
  226. true -> error_logger:Fun("~p:"++String, [Module|Args]);
  227. false -> skip end.
  228. info(Module, String, Args) -> log(Module, String, Args, info_msg).
  229. warning(Module,String, Args) -> log(Module, String, Args, warning_msg).
  230. error(Module, String, Args) -> log(Module, String, Args, error_msg).
  231. dump() ->
  232. io:format("~20w ~20w ~10w ~10w~n",[name,storage_type,memory,size]),
  233. [ io:format("~20w ~20w ~10w ~10w~n",[Name,
  234. mnesia:table_info(Name,storage_type),
  235. mnesia:table_info(Name,memory),
  236. mnesia:table_info(Name,size)]) || #table{name=Name} <- kvs:tables()],
  237. io:format("Snapshot taken: ~p~n",[calendar:now_to_datetime(os:timestamp())]).
  238. % Table Partitions
  239. range(RecordName,Id) -> (find(kvs:config(kvs:rname(RecordName)),RecordName,Id))#interval.name.
  240. topleft(RecordName,Id) -> (find(kvs:config(kvs:rname(RecordName)),RecordName,Id))#interval.left.
  241. last(RecordName,Id) -> (find(kvs:config(kvs:rname(RecordName)),RecordName,Id))#interval.last.
  242. find([],_,_Id) -> #interval{left=1,right=infinity,name=[],last=[]};
  243. find([Range|T],RecordName,Id) ->
  244. case lookup(Range,Id) of
  245. [] -> find(T,RecordName,Id);
  246. Interval -> Interval end.
  247. lookup(#interval{left=Left,right=Right,name=Name}=I,Id) when Id =< Right, Id >= Left -> I;
  248. lookup(#interval{},_) -> [].
  249. rotate_new() -> N = [ kvs:rotate(kvs:table(T)) || {T,_} <- fold_tables(),
  250. length(proplists:get_value(attributes,kvs:info(last_disc(T)),[])) /=
  251. length((kvs:table(kvs:last_table(rname(T))))#table.fields)
  252. ], io:format("Nonexistent: ~p~n",[N]), N.
  253. rotate(#table{}=T) -> Name = name(rname(T#table.name)),
  254. init(setelement(#table.name,kvs:table(kvs:last_table(T#table.name)),Name)),
  255. update_config(rname(T#table.name),Name);
  256. rotate(Table) -> rotate(kvs:table(Table)).
  257. load_partitions() -> [ case kvs:get(config,Table) of
  258. {ok,{config,_,List}} -> application:set_env(kvs,Table,List);
  259. Else -> ok end || {table,Table} <- kvs:dir() ].
  260. omitone(1) -> [];
  261. omitone(X) -> X.
  262. limit() -> infinity.
  263. store(Table,X) -> application:set_env(kvs,Table,X), X.
  264. rname(Table) -> list_to_atom(lists:filter(fun(X) -> not lists:member(X,"1234567890") end, atom_to_list(Table))).
  265. nname(Table) -> list_to_integer(case lists:filter(fun(X) -> lists:member(X,"1234567890") end, atom_to_list(Table)) of [] -> "1"; E -> E end).
  266. fold(N) -> kvs:fold(fun(X,A)->[X|A]end,[],process,N,-1,#iterator.next,#kvs{mod=store_mnesia}).
  267. top(Table) -> id_seq(Table).
  268. name(T) -> list_to_atom(lists:concat([T,omitone(kvs:next_id(lists:concat([T,".tables"]),1))])).
  269. init(T) -> store_mnesia:create_table(T#table.name, [{attributes,T#table.fields},{T#table.copy_type, [node()]}]),
  270. [ store_mnesia:add_table_index(T#table.name, Key) || Key <- T#table.keys ].
  271. id_seq(Tab) -> T = atom_to_list(Tab), case kvs:get(id_seq,T) of {ok,#id_seq{id=Id}} -> Id; _ -> kvs:next_id(T,1) end.
  272. last_disc(T) -> list_to_atom(lists:concat([T,omitone(kvs:id_seq(list_to_atom(lists:concat([T,".tables"]))))])).
  273. last_table(T) -> list_to_atom(lists:concat([T,omitone(lists:max(proplists:get_value(T,fold_tables(),[1])))])).
  274. fold_tables() -> lists:foldl(fun(#table{name=X},Acc) ->
  275. wf:setkey(kvs:rname(X),1,Acc,{kvs:rname(X),[kvs:nname(X)|proplists:get_value(kvs:rname(X),Acc,[])]}) end,
  276. [], kvs:tables()).
  277. interval(L,R,Name) -> #interval{left=L,right=R,name=Name,last=last_table(rname(Name))}.
  278. update_config(Table,Name) ->
  279. kvs:put(#config{key = Table,
  280. value = store(Table,case kvs:get(config,Table) of
  281. {error,not_found} -> update_list(Table,[],Name);
  282. {ok,#config{value=List}} -> update_list(Table,List,Name) end)}).
  283. update_list(Table,[],Name) -> [ interval(top(Table)+1,limit(),Name) ];
  284. update_list(Table,[#interval{}=CI|Tail],Name) -> [ interval(top(Table)+1,limit(),Name) ] ++
  285. [ CI#interval{right=top(Table)} ] ++ Tail.