kvs_stream.htm 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. <html>
  2. <head>
  3. <meta charset="utf-8" />
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <meta name="description" content="" />
  7. <meta name="author" content="Maxim Sokhatsky" />
  8. <title>KVS</title>
  9. <link rel="stylesheet" href="https://n2o.space/n2o.css" />
  10. </head>
  11. <body>
  12. <header>
  13. <a href="../index.html"><img src="https://n2o.space/img/Synrc Neo.svg"></a>
  14. <h1>STREAM</h1>
  15. </header>
  16. <main>
  17. <section>
  18. <h3>INTRO</h3>
  19. <p>The <b>kvs_stream</b> is intended to store and retrieve doubly-linked lists
  20. using simple key-value access to different KV databases through its backends:
  21. redis, mongo, mnesia, riak, kai, fs.
  22. The descriptor of the cursor consist mainly of two parts (reader and writer).
  23. Writer holds the cached value of the top or bottom of the stream.
  24. Reader holds the cached value of current cursor position.
  25. Descriptor also tracks moving direction and distances to both ends,
  26. which are updated during reader cursor repositioning.
  27. Cursor should be stored in databse.
  28. If there is no cursor for some data then this data is not alive yet.
  29. The data could be added only to list ends using writer cursor.
  30. The data in list could be removed only by record id.
  31. The list could not contain duplicates or even records with the same id.
  32. When you consume the stream, the data is not deleted.</p>
  33. <p>This module could be used to manage different kinds of lists
  34. including doubly-linked lists on top of any KV storage.
  35. The possible applications are: public and private feeds, FIFO queues,
  36. unread messages, chat applications, blockchain applications, etc.</p>
  37. <p>You can download <a style="margin-bottom:30px;" href="https://raw.githubusercontent.com/synrc/kvs/master/src/kvs_stream.erl">kvs_stream</a> as it's a self-containing module.
  38. &nbsp; <br><br>
  39. <img src="https://n2o.space/img/Erlang.png" width=50>
  40. </p>
  41. </section>
  42. <section>
  43. <h3>RECORDS</h3>
  44. <figure><figcaption>KVS CORE</figcaption><code>
  45. #ok { data= [] :: term() }.
  46. #error { data= [] :: term() }.
  47. #cur { id= [] :: term(),
  48. top= [] :: [] | integer(),
  49. bot= [] :: [] | integer(),
  50. dir= 0 :: 0 | 1,
  51. reader= [] :: [] | tuple(),
  52. writer= [] :: [] | tuple() }.
  53. #iter { id= [] :: [] | integer(),
  54. prev= [] :: [] | integer(),
  55. next= [] :: [] | integer()).
  56. </code></figure>
  57. <p><ul>
  58. <li>id &mdash; Unique key of the cursor.</li>
  59. <li>writer &mdash; Append writes to one of the two ends of the list.</li>
  60. <li>reader &mdash; Reader cursor tracks distances to edges.</li>
  61. <li>dir=0 &mdash; Adding to top, reading up from bottom (default).</li>
  62. <li>dir=1 &mdash; Adding to bottom, reading down from top.</li>
  63. <li>top &mdash; The top of the list.</li>
  64. <li>bot &mdash; The bottom of the list.</li>
  65. </ul></p>
  66. <p><ul>
  67. <li>id &mdash; Unique key of the record in the list.</li>
  68. <li>next &mdash; The next element of the list.</li>
  69. <li>prev &mdash; The prev element of the list.</li>
  70. </ul></p>
  71. </section>
  72. <section>
  73. <h3>EXAMPLE</h3>
  74. <figure><code>
  75. -module(test).
  76. -include_lib("kvs/include/kvs.hrl").
  77. -include_lib("kvs/include/user.hrl").
  78. -compile(export_all).
  79. check() ->
  80. Cur = kvs_stream:new(),
  81. [A,B,C,D] = [ kvs:next_id(person,1)
  82. || _ <- lists:seq(1,4) ],
  83. R = kvs_stream:save(
  84. kvs_stream:add(#person{id=A},
  85. kvs_stream:add(#person{id=B},
  86. kvs_stream:add(#person{id=C},
  87. kvs_stream:add(#person{id=D}, Cur ))))),
  88. X = kvs_stream:take(-1,
  89. kvs_stream:down(
  90. kvs_stream:top(R))),
  91. Y = kvs_stream:take(-1,
  92. kvs_stream:up(
  93. kvs_stream:bot(R))),
  94. X = lists:reverse(Y),
  95. L = length(X).
  96. > test:check().
  97. 4
  98. > kvs:all(cur).
  99. [{cur,1,{user2,1,3,[],[],[],[],[],[]},0,1,2}]
  100. > kvs_stream:take(-1,
  101. kvs_stream:top(kvs:get(cur,1))).
  102. [{user2,2,[],4,[],[],[],[],[]},
  103. {user2,4,2,3,[],[],[],[],[]},
  104. {user2,3,4,1,[],[],[],[],[]},
  105. {user2,1,3,[],[],[],[],[],[]}]
  106. </code></figure>
  107. </section>
  108. <section>
  109. <h3>API</h3>
  110. <p>We prepared for you sequential steps manual.
  111. Just enter one by one the erlang commands
  112. in shell in right order and check the results.</p>
  113. <h4>new() -> #cur{}.</h4>
  114. <p>Creates a KVS cursor.</p>
  115. <figure><code>
  116. > kvs_stream:new().
  117. {cur,1,[],0,[],[]}
  118. > kvs:get(id_seq,"cur").
  119. {ok,{id_seq,"cur",1}}
  120. > kvs_stream:new().
  121. {cur,2,[],0,[],[]}
  122. > kvs:get(id_seq,"cur").
  123. {ok,{id_seq,"cur",2}}
  124. </code></figure>
  125. <h4>save(#cur{}) -> #cur{}.</h4>
  126. <p>Saves the cursor to database.<?p>
  127. <figure><code>
  128. > kvs:all(cur).
  129. []
  130. > kvs_stream:save(kvs_stream:new()).
  131. {cur,3,[],0,[],[]}
  132. > kvs:all(cur).
  133. [{cur,3,[],0,[],[]}]
  134. </code></figure>
  135. <h4>load(Id) -> #ok{data::#cur{}} | #error{}.</h4>
  136. <p>Gets a cursor from database.</p>
  137. <figure><code>
  138. > S = 3, kvs_stream:load(S).
  139. {cur,3,[],[],0,[]}
  140. </code></figure>
  141. <h4>add(Object::tuple(),#cur{}) -> #cur{}.</h4>
  142. <p>Adds any object to datatabase and update writer cursor.
  143. Object is linked on next prev fields with existed data under cursor.
  144. If cursor doesn't contain top or bottom value the additional
  145. seek to the end is performed according to cursor direction.</p>
  146. <figure><code>
  147. > rr(kvs_stream).
  148. [block,container,cur,id_seq,iter,iterator,kvs,log,operation]
  149. > P = {user2,[],[],[],[],[],[],[],[]},
  150. kvs_stream:save(kvs_stream:add(P,kvs_stream:load(S))).
  151. #cur{id = 3,top = 1,bot = 1,dir = 0,
  152. reader = {user2,1,[],[],[],[],[],[],[]},
  153. writer = {user2,1,[],[],[],[],[],[],[]},
  154. left = 0,right = 0}
  155. </code></figure>
  156. <h4>prev(#cur{}) -> #cur{} | #error{}.</h4>
  157. <p>Moves cursor to prev. Consume data up from bottom.
  158. Reutrn error if lists is empty, otherwise next element or last.</p>
  159. <figure><code>
  160. > kvs_stream:prev(kvs_stream:load(S)).
  161. {error,not_found}
  162. </code></figure>
  163. <h4>next(#cur{}) -> #cur{} | #error{}.</h4>
  164. <p>Moves cursor to next. Consume data down from top.
  165. Reutrn error if lists is empty, otherwise next element or last.</p>
  166. <figure><code>
  167. > kvs_stream:next(kvs_stream:top(
  168. kvs_stream:save(kvs_stream:add(P,kvs_stream:load(S))))).
  169. #cur{id = 3,top = 2,bot = 1,dir = 1,
  170. reader = {user2,1,[],2,[],[],[],[],[]},
  171. writer = {user2,2,1,[],[],[],[],[],[]},
  172. left = 0,right = 1}
  173. </code></figure>
  174. <h4>seek(#cur{}) -> #cur{} | #error{}.</h4>
  175. <p>Moves cursor to begin or end of the list depending of cursor order.
  176. If cursor has no cached value then function returns error.</p>
  177. <figure><code>
  178. > Stream = kvs_stream:save(kvs_stream:add(P,kvs_stream:load(S))),
  179. kvs_stream:seek(kvs_stream:up(Stream)).
  180. #cur{id = 3,top = 3,bot = 1,dir = 0,
  181. reader = {user2,1,[],2,[],[],[],[],[]},
  182. writer = {user2,3,2,[],[],[],[],[],[]},
  183. left = 2,right = 0}
  184. </code></figure>
  185. <h4>top(#cur{}) -> #cur{} | #error{}.</h4>
  186. <p>Moves cursor to top of the list.</p>
  187. <figure><code>
  188. > kvs_stream:top(kvs_stream:load(S)).
  189. #cur{id = 3,top = 3,bot = 1,dir = 1,
  190. reader = {user2,3,2,[],[],[],[],[],[]},
  191. writer = {user2,3,2,[],[],[],[],[],[]},
  192. left = 2,right = 0}
  193. </code></figure>
  194. <h4>bot(#cur{}) -> #cur{} | #error{}.</h4>
  195. <p>Moves cursor to bottom of the list.</p>
  196. <figure><code>
  197. > kvs_stream:bot(kvs_stream:load(S)).
  198. #cur{id = 3,top = 3,bot = 1,dir = 0,
  199. reader = {user2,1,[],2,[],[],[],[],[]},
  200. writer = {user2,3,2,[],[],[],[],[],[]},
  201. left = 2,right = 0}
  202. </code></figure>
  203. <h4>take(N,#cur{}) -> list().</h4>
  204. <p>Trying to consume N records from stream using its current value and direction.
  205. Returns consumed data. Usually you seek to some position and then consume some data.</p>
  206. <figure><code>
  207. > kvs_stream:take(-1,kvs_stream:load(S)).
  208. [{user2,3,2,[],[],[],[],[],[]},
  209. {user2,2,1,3,[],[],[],[],[]},
  210. {user2,1,[],2,[],[],[],[],[]}]
  211. </code></figure>
  212. <h4>down(#cur{}) -> #cur{}.</h4>
  213. <p>Changes the cursor direction.</p>
  214. <h4>up(#cur{}) -> #cur{}.</h4>
  215. <p>Changes the cursor direction (default).</p>
  216. <h4>remove(Id,#cur{}) -> #cur{} | #error{}.</h4>
  217. <p>Removes record by id from database and unlink it from list.
  218. If cursor has no cached value then function returns error.
  219. Please do not use remove, keep your data immutable :-)</p>
  220. <figure><code>
  221. > kvs_stream:take(-1,kvs_stream:top(kvs_stream:save(
  222. kvs_stream:remove(Stream#cur.top-1,kvs_stream:load(S))))).
  223. [{user2,1,[],3,[],[],[],[],[]},
  224. {user2,3,1,[],[],[],[],[],[]}]
  225. </code></figure>
  226. </section>
  227. <section>
  228. <h3>CONFIG</h3>
  229. <p>In sys.config you should specify kvs backend and list of modules
  230. containing <b>metainfo/0</b> exported function.</p>
  231. <figure><code>
  232. [{kvs, [{dba, store_mnesia},
  233. {schema, [kvs]} ]}].
  234. </code></figure>
  235. </section>
  236. <section>
  237. <p>This module may refer to:
  238. <a href="http://erlang.org/doc/man/mnesia.html">mnesia</a></b>,
  239. <a href="kvs.htm"><b>kvs</b></a>.
  240. </p>
  241. </section>
  242. </main>
  243. <footer>
  244. 2005&mdash;2017 &copy; Synrc Research Center
  245. </footer>
  246. </body>
  247. </html>