kvs_stream.htm 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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>STREAM</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 databases through its backends:
  21. redis, mongo, mnesia, riak, kai, fs.
  22. The main KVS cursor consist of two main parts (reader and writer).
  23. Writer holds the cached value of the top or bottom of the stream.
  24. Reader holds the cached valus 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. </section>
  34. <section>
  35. <h3>RECORDS</h3>
  36. <figure><figcaption>KVS CORE</figcaption><code>
  37. #ok { data= [] :: term() }.
  38. #error { data= [] :: term() }.
  39. #cur { id= [] :: term(),
  40. top= [] :: [] | integer(),
  41. bot= [] :: [] | integer(),
  42. dir= 0 :: 0 | 1,
  43. pos= [] :: [] | tuple(),
  44. val= [] :: [] | tuple() }.
  45. #iter { id= [] :: [] | integer(),
  46. prev= [] :: [] | integer(),
  47. next= [] :: [] | integer()).
  48. </code></figure>
  49. <p><ul>
  50. <li>id &mdash; Unique key of the cursor</li>
  51. <li>val &mdash; Writer cursor.</li>
  52. <li>pos &mdash; Reader cursor.</li>
  53. <li>dir=0 &mdash; Adding to top, reading up from bottom (default).</li>
  54. <li>dir=1 &mdash; Adding to bottom, reading down from top.</li>
  55. <li>top &mdash; The top of the list</li>
  56. <li>bot &mdash; The bottom of the list</li>
  57. </ul></p>
  58. <p><ul>
  59. <li>id &mdash; Unique key of the record in the list</li>
  60. <li>next &mdash; The next element of the list</li>
  61. <li>prev &mdash; The prev element of the list</li>
  62. </ul></p>
  63. </section>
  64. <section>
  65. <h3>EXAMPLE</h3>
  66. <figure><code>
  67. -module(test).
  68. -include_lib("kvs/include/kvs.hrl").
  69. -include_lib("kvs/include/user.hrl").
  70. -compile(export_all).
  71. check() ->
  72. Cur = kvs_stream:new(),
  73. [A,B,C,D] = [ kvs:next_id(person,1)
  74. || _ <- lists:seq(1,4) ],
  75. R = kvs_stream:save(
  76. kvs_stream:add(#person{id=A},
  77. kvs_stream:add(#person{id=B},
  78. kvs_stream:add(#person{id=C},
  79. kvs_stream:add(#person{id=D}, Cur ))))),
  80. X = kvs_stream:take(-1,
  81. kvs_stream:down(
  82. kvs_stream:top(R))),
  83. Y = kvs_stream:take(-1,
  84. kvs_stream:up(
  85. kvs_stream:bot(R))),
  86. X = lists:reverse(Y),
  87. L = length(X).
  88. > test:check().
  89. 4
  90. > kvs:all(cur).
  91. [{cur,1,{user2,1,3,[],[],[],[],[],[]},0,1,2}]
  92. > kvs_stream:take(-1,
  93. kvs_stream:top(kvs:get(cur,1))).
  94. [{user2,2,[],4,[],[],[],[],[]},
  95. {user2,4,2,3,[],[],[],[],[]},
  96. {user2,3,4,1,[],[],[],[],[]},
  97. {user2,1,3,[],[],[],[],[],[]}]
  98. </code></figure>
  99. </section>
  100. <section>
  101. <h3>API</h3>
  102. <p>We prepared for you sequential steps manual.
  103. Just enter the erlang commands in shell in right order
  104. and check the results.
  105. <h4>new() -> #cur{}.</h4>
  106. <p>Creates a KVS cursor.</p>
  107. <figure><code>
  108. > kvs_stream:new().
  109. {cur,1,[],0,[],[]}
  110. > kvs:get(id_seq,"cur").
  111. {ok,{id_seq,"cur",1}}
  112. > kvs_stream:new().
  113. {cur,2,[],0,[],[]}
  114. > kvs:get(id_seq,"cur").
  115. {ok,{id_seq,"cur",2}}
  116. </code></figure>
  117. <h4>save(#cur{}) -> #cur{}.</h4>
  118. <p>Saves the cursor to database.<?p>
  119. <figure><code>
  120. > kvs:all(cur).
  121. []
  122. > kvs_stream:save(kvs_stream:new()).
  123. {cur,3,[],0,[],[]}
  124. > kvs:all(cur).
  125. [{cur,3,[],0,[],[]}]
  126. </code></figure>
  127. <h4>load(Id) -> #ok{data::#cur{}} | #error{}.</h4>
  128. <p>Gets a cursor from database.</p>
  129. <figure><code>
  130. > S = 3, kvs_stream:load(S).
  131. {cur,3,[],[],0,[]}
  132. </code></figure>
  133. <h4>add(Message,#cur{}) -> #cur{}.</h4>
  134. <p>Adds message to datatabase and update cursor to new data.
  135. Message is linked on next prev fields with existed data under cursor.
  136. If cursor doesn't contain top or bottom value the additional
  137. seek to the end is performed according to cursor direction.</p>
  138. <figure><code>
  139. > rr(kvs_stream).
  140. [block,container,cur,id_seq,iter,iterator,kvs,log,operation]
  141. > P = {user2,[],[],[],[],[],[],[],[]},
  142. kvs_stream:save(kvs_stream:add(P,kvs_stream:load(S))).
  143. #cur{id = 3,top = 1,bot = 1,dir = 0,
  144. pos = {user2,1,[],[],[],[],[],[],[]},
  145. val = {user2,1,[],[],[],[],[],[],[]},
  146. left = 0,right = 0}
  147. </code></figure>
  148. <h4>prev(#cur{}) -> #cur{} | #error{}.</h4>
  149. <p>Moves cursor to prev. Consume data bottom up.
  150. Reutrn error if lists is empty, otherwise next element or last.</p>
  151. <figure><code>
  152. > kvs_stream:prev(kvs_stream:load(S)).
  153. {error,not_found}
  154. </code></figure>
  155. <h4>next(#cur{}) -> #cur{} | #error{}.</h4>
  156. <p>Moves cursor to next. Consume data top down.
  157. Reutrn error if lists is empty, otherwise next element or last.</p>
  158. <figure><code>
  159. > kvs_stream:next(kvs_stream:top(
  160. kvs_stream:save(kvs_stream:add(P,kvs_stream:load(S))))).
  161. #cur{id = 3,top = 2,bot = 1,dir = 1,
  162. pos = {user2,1,[],2,[],[],[],[],[]},
  163. val = {user2,2,1,[],[],[],[],[],[]},
  164. left = 0,right = 1}
  165. </code></figure>
  166. <h4>seek(#cur{}) -> #cur{} | #error{}.</h4>
  167. <p>Moves cursor to begin or end of the list depending of cursor order.
  168. If cursor has no cached value then function returns error.</p>
  169. <figure><code>
  170. > Stream = kvs_stream:save(kvs_stream:add(P,kvs_stream:load(S))),
  171. kvs_stream:seek(kvs_stream:up(Stream)).
  172. #cur{id = 3,top = 3,bot = 1,dir = 0,
  173. pos = {user2,1,[],2,[],[],[],[],[]},
  174. val = {user2,3,2,[],[],[],[],[],[]},
  175. left = 2,right = 0}
  176. </code></figure>
  177. <h4>top(#cur{}) -> #cur{} | #error{}.</h4>
  178. <p>Moves cursor to top of the list.</p>
  179. <figure><code>
  180. > kvs_stream:top(kvs_stream:load(S)).
  181. #cur{id = 3,top = 3,bot = 1,dir = 1,
  182. pos = {user2,3,2,[],[],[],[],[],[]},
  183. val = {user2,3,2,[],[],[],[],[],[]},
  184. left = 2,right = 0}
  185. </code></figure>
  186. <h4>bot(#cur{}) -> #cur{} | #error{}.</h4>
  187. <p>Moves cursor to bottom of the list.</p>
  188. <figure><code>
  189. > kvs_stream:bot(kvs_stream:load(S)).
  190. #cur{id = 3,top = 3,bot = 1,dir = 0,
  191. pos = {user2,1,[],2,[],[],[],[],[]},
  192. val = {user2,3,2,[],[],[],[],[],[]},
  193. left = 2,right = 0}
  194. </code></figure>
  195. <h4>take(N,#cur{}) -> list().</h4>
  196. <p>Trying to consume N records from stream using its current value and direction.
  197. Returns consumed data. Usually you seek to some position and then consume some data.</p>
  198. <figure><code>
  199. > kvs_stream:take(-1,kvs_stream:load(S)).
  200. [{user2,3,2,[],[],[],[],[],[]},
  201. {user2,2,1,3,[],[],[],[],[]},
  202. {user2,1,[],2,[],[],[],[],[]}]
  203. </code></figure>
  204. <h4>down(#cur{}) -> #cur{}.</h4>
  205. <p>Changes the cursor direction.</p>
  206. <h4>up(#cur{}) -> #cur{}.</h4>
  207. <p>Changes the cursor direction.</p>
  208. <h4>remove(Id,#cur{}) -> #cur{} | #error{}.</h4>
  209. <p>Removes record by id from database and unlink it from list.
  210. If cursor has no cached value then function returns error.
  211. Please do not use remove, keep your data immutable :-)</p>
  212. <figure><code>
  213. > kvs_stream:take(-1,kvs_stream:top(kvs_stream:save(
  214. kvs_stream:remove(Stream#cur.top-1,kvs_stream:load(S))))).
  215. [{user2,1,[],3,[],[],[],[],[]},
  216. {user2,3,1,[],[],[],[],[],[]}]
  217. </code></figure>
  218. </section>
  219. <section>
  220. <h3>CONFIG</h3>
  221. <p>In sys.config you should specify kvs backend and list of modules
  222. containing <b>metainfo/0</b> exported function.</p>
  223. <figure><code>
  224. [{kvs, [{dba, store_mnesia},
  225. {schema, [kvs]} ]}].
  226. </code></figure>
  227. </section>
  228. <section>
  229. <p>This module may refer to:
  230. <a href="http://erlang.org/doc/man/mnesia.html">mnesia</a></b>,
  231. <a href="kvs.htm"><b>kvs</b></a>.
  232. </p>
  233. </section>
  234. </main>
  235. <footer>
  236. 2005&mdash;2017 &copy; Synrc Research Center
  237. </footer>
  238. </body>
  239. </html>