From d8b9dba47ba67c6019d81795067e18076b471de5 Mon Sep 17 00:00:00 2001 From: ocelot-inc <pgulutzan@ocelot.ca> Date: Mon, 9 Dec 2013 15:18:34 -0700 Subject: [PATCH] stored-procedures.xml box.fiber example --- doc/user/stored-procedures.xml | 129 ++++++++++++++++++++++----------- 1 file changed, 86 insertions(+), 43 deletions(-) diff --git a/doc/user/stored-procedures.xml b/doc/user/stored-procedures.xml index f884cbeada..47db2fdd32 100644 --- a/doc/user/stored-procedures.xml +++ b/doc/user/stored-procedures.xml @@ -1898,32 +1898,29 @@ error: 'Iterator type is not supported' <section xml:id="sp-box-fiber"> <title>Package <code>box.fiber</code></title> - <para>Functions in this package allow you to create, run and - manage existing <emphasis>fibers</emphasis>. + <para>Functions in this package allow for creating, running and + managing <emphasis>fibers</emphasis>. </para> <para> -A fiber is an independent execution thread implemented -using a mechanism of cooperative multitasking. +A fiber is a set of instructions which are executed +with cooperative multitasking. Fibers managed by the +box.fiber library are associated with a user-supplied function +called the <emphasis>fiber function</emphasis>. A fiber has three possible states: running, suspended or dead. -When a fiber is created with <code>box.fiber.create()</code>, -it is suspended. +When a fiber is created with <code>box.fiber.create()</code>, it is suspended. When a fiber is started with <code>box.fiber.resume()</code>, it is running. -When a fiber's control is yielded back to the caller with -<code>box.fiber.yield()</code>, it is suspended. -When a fiber ends (due to <code>return</code> or by reaching the -end of the fiber function), it is dead. +When a fiber yields control with <code>box.fiber.yield()</code>, it is suspended. +When a fiber ends (because the fiber function ends), it is dead. </para> <para> A fiber can also be attached or detached. An attached fiber is a child of the creator, and is running only if the creator has called <code>box.fiber.resume()</code>. A detached fiber is a child of -Tarantool internal <quote>sched</quote> fiber, and gets +the Tarantool internal <quote>sched</quote> fiber, and gets scheduled only if there is a libev event associated with it. - </para> - <para> To detach, a running fiber must invoke <code>box.fiber.detach()</code>. A detached fiber loses connection with its parent forever. </para> @@ -1935,22 +1932,14 @@ which is a string. If there is more than one fiber with the given name, the first fiber that matches is returned. </para> <para> -Once fiber function is done or calls <code>return</code>, -the fiber is considered dead. Its carcass is put into -a fiber pool, and can be reused when another fiber is -created. - </para> - <para> A runaway fiber can be stopped with <code>box.fiber.cancel()</code>. However, <code>box.fiber.cancel()</code> is advisory — it works only if the runaway fiber calls <code>box.fiber.testcancel()</code> once in a while. Most <code>box.*</code> hooks, such as <code>box.delete()</code> or <code>box.update()</code>, do call <code>box.fiber.testcancel()</code>. -<code>box.select()</code> doesn't. - </para> - <para> +<code>box.select()</code> does not. In practice, a runaway fiber can only become unresponsive -if it does a lot of computations and doesn't check +if it does many computations and does not check whether it's been canceled. <!-- In addition to the advisory cancellation, configuration parameter @@ -1968,9 +1957,11 @@ sends an asynchronous wakeup event to the fiber, and <code>box.fiber.testcancel()</code> is checked whenever such an event occurs. </para> <para>Like all Lua objects, dead fibers are - garbage collected: the garbage collector frees pool allocator + garbage collected. The garbage collector frees pool allocator memory owned by the fiber, resets all fiber data, and returns - the fiber to the fiber pool.</para> + the fiber (now called a fiber carcass) to the fiber pool. + The carcass can be reused when another fiber is created. + </para> <variablelist xml:id="box.fiber"> <varlistentry> <term> @@ -1999,10 +1990,8 @@ and <code>box.fiber.testcancel()</code> is checked whenever such an event occurs <emphasis role="lua" xml:id="box.fiber.create">box.fiber.create(function) </emphasis> </term> <listitem><simpara> - Create a fiber for a <code>function</code>. + Create a fiber for a <code>function</code>. There will be an error if the function does not exist or if a recursion limit is hit. </simpara> - <bridgehead renderas="sect4">Errors</bridgehead> - <simpara>Can hit a recursion limit.</simpara> </listitem> </varlistentry> @@ -2016,19 +2005,17 @@ and <code>box.fiber.testcancel()</code> is checked whenever such an event occurs <varlistentry> <term> - <emphasis role="lua" xml:id="box.fiber.yield" xreflabel="box.fiber.yield(...)">box.fiber.yield(...) </emphasis> + <emphasis role="lua" xml:id="box.fiber.yield" xreflabel="box.fiber.yield([arguments])">box.fiber.yield(...) </emphasis> </term> - <listitem><para> - Yield control to the calling fiber, if the fiber - is attached, or to sched otherwise. - </para> - <para> - If the fiber is attached, whatever arguments are passed - to this call, are passed on to the calling fiber. + <listitem><simpara> + If the fiber is attached, yield control to the calling fiber if the fiber + is attached; otherwise, yield to sched. + If the fiber is attached, arguments passed + to box.fiber.yield are passed on to the calling fiber. If the fiber is detached, <code>box.fiber.yield()</code> - returns back everything passed into it after temporarily + arguments passed to box.fiber.yield are returned after temporarily yielding control back to the scheduler. - </para></listitem> + </simpara></listitem> </varlistentry> <varlistentry> @@ -2067,11 +2054,11 @@ and <code>box.fiber.testcancel()</code> is checked whenever such an event occurs <emphasis role="lua" xml:id="box.fiber.status">box.fiber.status(fiber)</emphasis> </term> <listitem><simpara> - Returns the status of the fiber. If no argument is - provided, the current fiber's status is returned. The - status can be either <quote>dead</quote>, - <quote>suspended</quote>, <quote>attached</quote> - or <quote>running</quote>. + Returns the status of <code>fiber</code>. If no argument is + provided, the current fiber's status is returned. The + status can be one of: <quote>dead</quote>, + <quote>suspended</quote>, <quote>attached</quote> + or <quote>running</quote>. </simpara></listitem> </varlistentry> @@ -2096,6 +2083,62 @@ and <code>box.fiber.testcancel()</code> is checked whenever such an event occurs </simpara></listitem> </varlistentry> </variablelist> + +<para> +<bridgehead renderas="sect4">Example</bridgehead> +Make the function which will be associated with the fiber. +When this function gets invoked, it will immediately "detach" +so it will be running independently of the caller, and then +will enter an infinite loop ("while 0 == 0" is an infinite +loop). Each iteration of the loop adds 1 to a global variable +named gvar, then goes to sleep for 2 seconds, +then yields. The sleep causes an implicit box.fiber.yield().<programlisting> +<prompt>localhost></prompt><userinput> setopt delimiter = '!'</userinput> +<prompt>localhost></prompt><userinput> lua function function_x ()</userinput> +<prompt> -></prompt><userinput> box.fiber.detach()</userinput> +<prompt> -></prompt><userinput> gvar = 0</userinput> +<prompt> -></prompt><userinput> while 0 == 0 do</userinput> +<prompt> -></prompt><userinput> gvar = gvar + 1</userinput> +<prompt> -></prompt><userinput> box.fiber.sleep(2)</userinput> +<prompt> -></prompt><userinput> end</userinput> +<prompt> -></prompt><userinput> end!</userinput> +--- +... +<prompt>localhost></prompt><userinput> setopt delimiter = ''!</userinput></programlisting> +Make the fiber and associate the function with it. + Get the id of the fiber (fid), to be used in later displays.<programlisting> +<prompt>localhost></prompt><userinput> lua fiber_of_x = box.fiber.create(function_x)</userinput> +--- +... +<prompt>localhost></prompt><userinput> lua fid = box.fiber.id(fiber_of_x)</userinput> +--- +...</programlisting> +"Resume" the fiber. This causes invocation of the function.<programlisting> +<prompt>localhost></prompt><userinput> lua box.fiber.resume(fiber_of_x)</userinput> +--- +...</programlisting> +Pause for a while, while the detached function runs. Then ... +Display the fiber id, the fiber status, and gvar (gvar will have +gone up a bit depending how long the pause lasted). The status is +suspended because the fiber spends almost all its time sleeping or yielding.<programlisting> +<prompt>localhost></prompt><userinput> lua print("fiber=",fid,". ",box.fiber.status(fiber_of_x),". gvar=",gvar)</userinput> +--- +fiber=104. suspended. gvar=9 +...</programlisting> +Pause for a while, while the detached function runs. Then ... +Cancel the fiber. Then, once again ... +Display the fiber id, the fiber status, and gvar (gvar will have +gone up a bit more depending how long pause lasted). This time +the status is dead because the cancel worked.<programlisting> +<prompt>localhost></prompt><userinput> lua box.fiber.cancel(fiber_of_x)</userinput> +--- +... +<prompt>localhost></prompt><userinput> lua print("fiber=",fid,". ",box.fiber.status(fiber_of_x),". gvar=",gvar)</userinput> +--- +fiber=104. dead. gvar=22 +...</programlisting> +</para> + </section> <!-- end of lib --> -- GitLab