From 68c3447ea739e3222c21b0fd6b5fd6270e6c49bc Mon Sep 17 00:00:00 2001
From: ocelot-inc <pgulutzan@ocelot.ca>
Date: Thu, 26 Jun 2014 16:00:10 -0600
Subject: [PATCH] stored-procedures.xml expirationd

---
 doc/user/stored-procedures.xml | 143 +++++++++++++++++++++++++--------
 1 file changed, 109 insertions(+), 34 deletions(-)

diff --git a/doc/user/stored-procedures.xml b/doc/user/stored-procedures.xml
index 00379b6a8b..e247f60c18 100644
--- a/doc/user/stored-procedures.xml
+++ b/doc/user/stored-procedures.xml
@@ -69,40 +69,8 @@ tarantool> <userinput>'hello' .. ' world' -- '..' means 'concatenate'</userinput
       using a dedicated <filename xml:id="init.lua" xreflabel="init.lua">init.lua</filename> script,
       located in 
       <olink targetptr="script_dir"><filename>script_dir</filename></olink>.
-
-      An example of such a script is given below:
-    <programlisting>
-    <![CDATA[
--- Importing expirationd module
-dofile("expirationd.lua")
-
-function is_expired(args, tuple)
-   if tuple == nil then
-       return true
-   end
-
-   if #tuple <= args.field_no then
-       return true
-   end
-
-   field = tuple[args.field_no]
-   if field == nil or #field ~= 4 then
-       return true
-   end
-
-   local current_time = os.time()
-   local tuple_ts = pickle.unpack("i", field)
-   return current_time >= tuple_ts + args.ttl
-end
-function purge(args, tuple)
-    box.space.space0:delete(tuple[1])
-end
-
--- Run task
-expirationd.run_task("exprd space 0", 0, is_expired, purge,
-                    { field_no = 2, ttl = 30 * 60 })
-]]>
-    </programlisting>
+    An example and discussion of such a script will appear later in section
+    <link linkend="sp-expirationd">expirationd</link>.
     </para>
     <para>
       The initialization script can select and modify data. However,
@@ -334,7 +302,114 @@ tarantool&gt; <userinput>session.delimiter('')!</userinput>
     
 </variablelist>
 
+<section xml:id="sp-expirationd">
+ <title>expirationd -- the daemon that shifts expired tuples to a long-term archive</title>
+
+<para>
+For a commercial-grade example of a Lua rock that works with Tarantool,
+let us look at expirationd, which Tarantool supplies on
+<link xlink:href="https://github.com/tarantool/expirationd/blob/master/expirationd.lua">GitHub</link>
+with an Artistic license. The expirationd.lua program is
+lengthy (about 500 lines), so here we will only highlight
+the matters that will be enhanced by studying the full source later.
+<programlisting>
+            task.worker_fiber = fiber.create(worker_loop)
+            task.worker_fiber:resume(task)
+            log.info("expiration: task %q restarted", task.name)
+            ...
+            fiber.sleep(expirationd.constants.check_interval)
+            ...
+</programlisting>
+Whenever one hears "daemon" in Tarantool, one should suspect it's
+being done with <olink targetptr="sp-box-fiber">fibers</olink>. The program is making a fiber
+and turning control over to it so it runs occasionally, goes to
+sleep, then comes back for more.
+<programlisting>
+    for _, tuple in scan_space.index[0]:pairs(nil, {iterator = box.index.ALL}) do
+    ...
+            if task.is_tuple_expired(task.args, tuple) then
+            task.expired_tuples_count = task.expired_tuples_count + 1
+            task.process_expired_tuple(task.space_id, task.args, tuple)
+    ...
+</programlisting>
+The "for" instruction can be translated as "iterate through the index of
+the space that is being scanned", and within it, if the tuple is "expired"
+(that is, if the tuple has a timestamp field which is less than the current
+time), process the tuple as an expired tuple.
+<programlisting>
+-- put expired tuple in archive
+local function put_tuple_to_archive(space_id, args, tuple)
+    -- delete expired tuple
+    box.space[space_id]:delete{tuple[0]}
+    local email = get_field(tuple, 1)
+    if args.archive_space_id ~= nil and email ~= nil then
+        box.space[args.archive_space_id]:replace{email, os.time()}
+    end
+end
+</programlisting>
+Ultimately the tuple-expiry process leads to put_tuple_to_archive()
+which does a "delete" of a tuple from its original space, and an
+"insert" of the same tuple into another space. Tarantool's "replace"
+function is the same as an "insert" function without an error message
+if a tuple with the same content already exists in the target space.
+<programlisting>
+function expirationd.do_test(space_id, archive_space_id)
+...
+</programlisting>
+At this point, if the above explanation is worthwhile, it's clear that
+expirationd.lua starts a background routine (fiber) which iterates
+through all the tuples in a space, sleeps cooperatively so that other
+fibers can operate at the same time, and -- whenever it finds a tuple
+that has expired -- deletes it from this space and puts it in another
+space. Now the "do_test()" function can be used to create some sample
+spaces, let the daemon run for a while, and print results.
+</para>
+<para>
+For those who like to see things run, here are the exact steps to
+get expirationd through the test.
+</para>
+<para>
+1. Get expirationd.lua.
+   There are standard ways -- it is after all part of a standard rock --
+   but for this purpose just copy the contents of
+   <link xlink:href="https://github.com/tarantool/expirationd/blob/master/expirationd.lua">https://github.com/tarantool/expirationd/blob/master/expirationd.lua</link>
+   to a default directory.
+</para>
+<para>
+2. Start the Tarantool server as described <olink targetptr="getting-started-start-stop">before</olink>.
+</para>
+<para>
+3. Execute these requests:
+<programlisting>
+     box.cfg{}
+     a = box.schema.create_space('origin')
+     a:create_index('first', {type = 'tree', parts = {0, 'NUM'}})
+     b = box.schema.create_space('archive')
+     b:create_index('first', {type = 'tree', parts = {0, 'STR'}})
+     expd = require('expirationd')
+     expd._debug = true
+     expd.do_test('origin', 'archive')
+     os.exit()
+</programlisting>
+The database-specific requests (cfg, create_space, create_index)
+should already be familiar. The key for getting the rock rolling is
+<code>expd = require('expirationd')</code>.
+The "require" function is what reads in the program; it will appear
+in many later examples in this manual, when it's necessary to get a
+package that's not part of the Tarantool kernel. After the Lua
+variable expd has been assigned the value of the expirationd package,
+it's possible to invoke the package's <code>do_test()</code> function.
+</para>
+<para>
+After a while, when the task has had time to do its iterations through
+the spaces, do_test() will print out a report showing the tuples that
+were originally in the original space, the tuples that have now been
+moved to the archive space, and some statistics. Of course, expirationd
+can be customized to do different things by passing different parameters,
+which will be evident after looking in more detail at the source code.  
+</para> 
 
+</section>
 
 <section xml:id="sp-pickle">
     <title>Package <code>pickle</code></title>
-- 
GitLab