DOC: LUA: fix some typos and syntax errors

This fix must be backported to 1.6.

Signed-off-by: Godbach <nylzhaowei@gmail.com>
This commit is contained in:
Godbach 2016-02-16 11:59:17 +08:00 committed by Willy Tarreau
parent 3724da1261
commit 06c8099922

View File

@ -10,7 +10,7 @@
HAProxy is a powerful load balancer. It embeds many options and many HAProxy is a powerful load balancer. It embeds many options and many
configuration styles in order to give a solution to many load balancing configuration styles in order to give a solution to many load balancing
problems. However, HAProxy is not universal and some special or specific problems. However, HAProxy is not universal and some special or specific
problems doesn't have solution with the native software. problems do not have solution with the native software.
This text is not a full explanation of the Lua syntax. This text is not a full explanation of the Lua syntax.
@ -25,7 +25,7 @@ Why a scripting language in HAProxy
=================================== ===================================
HAProxy 1.5 makes at possible to do many things using samples, but some people HAProxy 1.5 makes at possible to do many things using samples, but some people
wants to more combining results of samples fetches, programming conditions and want to more combining results of samples fetches, programming conditions and
loops which is not possible. Sometimes people implement these functionnalities loops which is not possible. Sometimes people implement these functionnalities
in patches which have no meaning outside their network. These people must in patches which have no meaning outside their network. These people must
maintain these patches, or worse we must integrate them in the HAProxy maintain these patches, or worse we must integrate them in the HAProxy
@ -44,7 +44,7 @@ between samples and patterns. The samples are extracted using fetch functions
easily extensible, and are used by actions which are also extensible. It seems easily extensible, and are used by actions which are also extensible. It seems
natural to allow Lua to give samples, modify them, and to be an action target. natural to allow Lua to give samples, modify them, and to be an action target.
So, Lua uses the same entities as the configuration language. This is the most So, Lua uses the same entities as the configuration language. This is the most
natural and reliable way fir the Lua integration. So, the Lua engine allow one natural and reliable way for the Lua integration. So, the Lua engine allows one
to add new sample fetch functions, new converter functions and new actions. to add new sample fetch functions, new converter functions and new actions.
These new entities can access the existing samples fetches and converters These new entities can access the existing samples fetches and converters
allowing to extend them without rewriting them. allowing to extend them without rewriting them.
@ -52,7 +52,7 @@ allowing to extend them without rewriting them.
The writing of the first Lua functions shows that implementing complex concepts The writing of the first Lua functions shows that implementing complex concepts
like protocol analysers is easy and can be extended to full services. It appears like protocol analysers is easy and can be extended to full services. It appears
that these services are not easy to implement with the HAProxy configuration that these services are not easy to implement with the HAProxy configuration
model which is base on four steps: fetch, convert, compare and action. HAProxy model which is based on four steps: fetch, convert, compare and action. HAProxy
is extended with a notion of services which are a formalisation of the existing is extended with a notion of services which are a formalisation of the existing
services like stats, cli and peers. The service is an autonomous entity with a services like stats, cli and peers. The service is an autonomous entity with a
behaviour pattern close to that of an external client or server. The Lua engine behaviour pattern close to that of an external client or server. The Lua engine
@ -63,7 +63,7 @@ This scripting language is useful for testing new features as proof of concept.
Later, if there is general interest, the proof of concept could be integrated Later, if there is general interest, the proof of concept could be integrated
with C language in the HAProxy core. with C language in the HAProxy core.
The HAProxy Lua integration also provides also a simple way for distributing Lua The HAProxy Lua integration also provides a simple way for distributing Lua
packages. The final user needs only to install the Lua file, load it in HAProxy packages. The final user needs only to install the Lua file, load it in HAProxy
and follow the attached documentation. and follow the attached documentation.
@ -92,8 +92,8 @@ more about Lua choice
--------------------- ---------------------
Lua language is very simple to extend. It is easy to add new functions written Lua language is very simple to extend. It is easy to add new functions written
in C in the core language. It not require to embed very intrusive libraries, and in C in the core language. It is not required to embed very intrusive libraries,
we do not change compilation processes. and we do not change compilation processes.
The amount of memory consumed can be controlled, and the issues due to lack of The amount of memory consumed can be controlled, and the issues due to lack of
memory are perfectly caught. The maximum amount of memory allowed for the Lua memory are perfectly caught. The maximum amount of memory allowed for the Lua
@ -172,7 +172,7 @@ Some other functions are prohibited:
- os.execute(), waits for the end of the required execution blocking HAProxy. - os.execute(), waits for the end of the required execution blocking HAProxy.
- os.exit(), is not really dangerous for the process, but its not the good way - os.exit(), is not really dangerous for the process, but it's not the good way
for exiting the HAProxy process. for exiting the HAProxy process.
- print(), writes data on stdout. In some cases these writes are blocking, the - print(), writes data on stdout. In some cases these writes are blocking, the
@ -188,7 +188,7 @@ there are compatible with the non blocking design. These functions are:
Responsive design Responsive design
----------------- -----------------
HAProxy must process connexions accept, forwarding data and processing timeouts HAProxy must process connections accept, forwarding data and processing timeouts
as soon as possible. The first thing is to believe that a Lua script with a long as soon as possible. The first thing is to believe that a Lua script with a long
execution time should impact the expected responsive behaviour. execution time should impact the expected responsive behaviour.
@ -200,12 +200,12 @@ configured with the following "tune" option:
tune.lua.forced-yield <nb> tune.lua.forced-yield <nb>
The default value is 10 000. For determining it, I ran benchmark on my laptop. The default value is 10 000. For determining it, I ran benchmark on my laptop.
I executed a Lua loop between 10 seconds with differents values for the I executed a Lua loop between 10 seconds with different values for the
"tune.lua.forced-yield" option, and I noted the results: "tune.lua.forced-yield" option, and I noted the results:
configured | Number of configured | Number of
instructions | loops executed instructions | loops executed
between two | in milions between two | in millions
forced yields | forced yields |
---------------+--------------- ---------------+---------------
10 | 160 10 | 160
@ -242,7 +242,7 @@ services.
Execution time Execution time
-------------- --------------
The Lua execution time is measured and limited. Each group of functions have its The Lua execution time is measured and limited. Each group of functions has its
own timeout configured. The time measured is the real Lua execution time, and own timeout configured. The time measured is the real Lua execution time, and
not the difference between the end time and the start time. The groups are: not the difference between the end time and the start time. The groups are:
@ -251,20 +251,20 @@ not the difference between the end time and the start time. The groups are:
- task, by default does not have timeout, - task, by default does not have timeout,
- service have a default timeout of 4s. - service have a default timeout of 4s.
The corresponding tune option are: The corresponding tune options are:
- tune.lua.session-timeout (fetches, converters and action) - tune.lua.session-timeout (fetches, converters and action)
- tune.lua.task-timeout (task) - tune.lua.task-timeout (task)
- tune.lua.service-timeout (services) - tune.lua.service-timeout (services)
The tasks does not have a timeout because it runs in background along the The task does not have a timeout because it runs in background along the
HAProxy process life. HAProxy process life.
For example, if an Lua script is executed during 1,1s and the script executes a For example, if an Lua script is executed during 1.1s and the script executes a
sleep of 1 second, the effective measured running time is 0,1s. sleep of 1 second, the effective measured running time is 0.1s.
This timeout is useful for preventing infinite loops. During the runtime, it This timeout is useful for preventing infinite loops. During the runtime, it
should never triggered. should be never triggered.
The stack and the coprocess The stack and the coprocess
--------------------------- ---------------------------
@ -284,11 +284,11 @@ Some examples follows. This first one, is a simple addition:
lua_pushnumber(L, 2) lua_pushnumber(L, 2)
lua_arith(L, LUA_OPADD) lua_arith(L, LUA_OPADD)
Its easy, we push 1 on the stack, after, we push 2, and finally, we perform an It's easy, we push 1 on the stack, after, we push 2, and finally, we perform an
addition. The two top entries of the stack are added, poped, and the result is addition. The two top entries of the stack are added, poped, and the result is
pushed. It is a classic way with a stack. pushed. It is a classic way with a stack.
Now an example for constructing array and objects. Its little bit more Now an example for constructing array and objects. It's a little bit more
complicated. The difficult consist to keep in mind the state of the stack while complicated. The difficult consist to keep in mind the state of the stack while
we write the code. The goal is to create the entity described below. Note that we write the code. The goal is to create the entity described below. Note that
the notation "*1" is a metatable reference. The metatable will be explained the notation "*1" is a metatable reference. The metatable will be explained
@ -333,7 +333,7 @@ So, coding for Lua in C, is not complex, but it needs some mental gymnastic.
The object concept and the HAProxy format The object concept and the HAProxy format
----------------------------------------- -----------------------------------------
The objects seems to not be a native concept. An Lua object is a table. We can The object seems to be not a native concept. An Lua object is a table. We can
note that the table notation accept three forms: note that the table notation accept three forms:
1. mytable["entry"](mytable, "param") 1. mytable["entry"](mytable, "param")
@ -341,7 +341,7 @@ note that the table notation accept three forms:
3. mytable:entry("param") 3. mytable:entry("param")
These three notation have the same behaviour pattern: a function is executed These three notation have the same behaviour pattern: a function is executed
with the itself table as first parameter and string "param" as second parameter with the table itself as first parameter and string "param" as second parameter
The notation with [] is commonly used for storing data in a hash table, and the The notation with [] is commonly used for storing data in a hash table, and the
dotted notation is used for objects. The notation with ":" indicates that the dotted notation is used for objects. The notation with ":" indicates that the
first parameter is the element at the left of the symbol ":". first parameter is the element at the left of the symbol ":".
@ -376,8 +376,8 @@ the global part of the main Lua stack, and it is called with the case sensitive
class name. A great part of these class must not be used directly because it class name. A great part of these class must not be used directly because it
requires an initialisation using the HAProxy internal structs. requires an initialisation using the HAProxy internal structs.
The HAProxy objects uses unified conventions. An Lua object is always a table. The HAProxy objects use unified conventions. An Lua object is always a table.
In most cases, an HAProxy Lua object need some private data. These are always In most cases, an HAProxy Lua object needs some private data. These are always
set in the index [0] of the array. The metatable entry "__tostring" returns the set in the index [0] of the array. The metatable entry "__tostring" returns the
object name. object name.
@ -405,7 +405,7 @@ specially useful with embedded environments.
When the memory limit is reached, HAProxy refuses to give more memory to the Lua When the memory limit is reached, HAProxy refuses to give more memory to the Lua
scripts. The current Lua execution is terminated with an error and HAProxy scripts. The current Lua execution is terminated with an error and HAProxy
continue its processing. continues its processing.
The max amount of memory is configured with the option: The max amount of memory is configured with the option:
@ -419,21 +419,21 @@ from C part or Lua part.
Sometimes, objects using lightuserdata or userdata requires to free some memory Sometimes, objects using lightuserdata or userdata requires to free some memory
block or close filedescriptor not controlled by the Lua. A dedicated garbage block or close filedescriptor not controlled by the Lua. A dedicated garbage
collection function is providedthrought the metatable. It is referenced with the collection function is provided through the metatable. It is referenced with the
special entry "__gc". special entry "__gc".
Generally, in HAProxy, the garbage collector does this job without any Generally, in HAProxy, the garbage collector does this job without any
intervention. However some object uses a great amount of memory, and we want to intervention. However some objects use a great amount of memory, and we want to
release as quick as possible. The problem is that only the GC knows if the object release as quickly as possible. The problem is that only the GC knows if the
is in use or not. The reason is simple variable containing objects can be shared object is in use or not. The reason is simple variable containing objects can be
between coroutines and the main thread, so an object can used everywhere in shared between coroutines and the main thread, so an object can be used
HAProxy. everywhere in HAProxy.
The only one example is the HAProxy sockets. These are explained later, just for The only one example is the HAProxy sockets. These are explained later, just for
understanding the GC issues, a quick overview of the socket follows. The HAProxy understanding the GC issues, a quick overview of the socket follows. The HAProxy
socket uses an internal session and stream, these sessions uses resources like socket uses an internal session and stream, the session uses resources like
memory and file descriptor and in some cases keeps a socket open while it is no memory and file descriptor and in some cases keeps a socket open while it is no
loner used by Lua. longer used by Lua.
If the HAProxy socket is used, we forcing a garbage collector cycle after the If the HAProxy socket is used, we forcing a garbage collector cycle after the
end of each function using HAProxy socket. The reason is simple: if the socket end of each function using HAProxy socket. The reason is simple: if the socket
@ -449,42 +449,42 @@ The yield concept / longjmp issues
The "yield" is an action which does some Lua processing in pause and give back The "yield" is an action which does some Lua processing in pause and give back
the hand to the HAProxy core. This action is do when the Lua needs to wait about the hand to the HAProxy core. This action is do when the Lua needs to wait about
data or other things. The most basically example is the sleep() function. In a data or other things. The most basically example is the sleep() function. In an
event driven software the code must not process blocking systems call, so the event driven software the code must not process blocking systems call, so the
sleep blocks the software between a lot of time. In HAProxy, an Lua sleep does a sleep blocks the software between a lot of time. In HAProxy, an Lua sleep does a
yield, and ask to the scheduler to be waked up in a required sleep time. yield, and ask to the scheduler to be woken up in a required sleep time.
Meanwhile, the HAProxy scheduler dos other things, like accepting new connection Meanwhile, the HAProxy scheduler does other things, like accepting new
or forwarding data. connection or forwarding data.
A yield is also executed regularly, after a lot of Lua instruction processed. A yield is also executed regularly, after a lot of Lua instructions processed.
This yield permits to control the effective execution time, and also give back This yield permits to control the effective execution time, and also give back
the hand to the haproxy core. When HAProxy finish to process the pending jobs, the hand to the HAProxy core. When HAProxy finishes to process the pending jobs,
the Lua execution continue. the Lua execution continues.
This special "yield" uses the Lua "debug" functions. Lua provides a debug method This special "yield" uses the Lua "debug" functions. Lua provides a debug method
called "lua_sethook()" which permits to interrupt the execution after some called "lua_sethook()" which permits to interrupt the execution after some
configured condition and call a function. This condition used in HAProxy is configured condition and call a function. This condition used in HAProxy is
a number of instruction processed and when a function returns. The function a number of instructions processed and when a function returns. The function
called controls the effective execution time, and if it is possible send a called controls the effective execution time, and if it is possible to send a
"yield". "yield".
The yield system is based on a couple setjmp/longjmp. In brief, the setjmp() The yield system is based on a couple setjmp/longjmp. In brief, the setjmp()
stores a stack state, and the longjmp restores the stack in its state which had stores a stack state, and the longjmp restores the stack in its state which had
before the last Lua execution. before the last Lua execution.
Lua can immediately stop is execution if an error occurs. This system uses also Lua can immediately stop its execution if an error occurs. This system uses also
the longjmp system. In HAProxy, we try to use this sytem only for unrecoverable the longjmp system. In HAProxy, we try to use this sytem only for unrecoverable
errors. Maybe some trivial errors targets an exception, but we try to remove it. errors. Maybe some trivial errors target an exception, but we try to remove it.
It seems that Lua uses the longjmp system for having a behaviour like the java It seems that Lua uses the longjmp system for having a behaviour like the java
try / catch. We can use the function pcall() to executes some code. The function try / catch. We can use the function pcall() to execute some code. The function
pcall() run a setjmp(). So, if any error occurs while the Lua code execution, pcall() run a setjmp(). So, if any error occurs while the Lua code execution,
the flow immediately return from the pcall() with an error. the flow immediately returns from the pcall() with an error.
The big issue of this behaviour is that we cannot do a yield. So if some Lua code The big issue of this behaviour is that we cannot do a yield. So if some Lua code
executes a library using pcall for catching errors, HAProxy must be wait for the executes a library using pcall for catching errors, HAProxy must be wait for the
end of execution without processing any accept or any stream. The cause is the end of execution without processing any accept or any stream. The cause is the
yield must be jump to the root of execution. The intermediate setjmp() avoid yield must be jump to the root of execution. The intermediate setjmp() avoids
this behaviour. this behaviour.
@ -502,7 +502,7 @@ Another issue with the processing of strong errors is the manipulation of the
Lua stack outside of an Lua processing. If one of the functions called occurs a Lua stack outside of an Lua processing. If one of the functions called occurs a
strong error, the default behaviour is an abort(). It is not acceptable when strong error, the default behaviour is an abort(). It is not acceptable when
HAProxy is in runtime mode. The Lua documentation propose to use another HAProxy is in runtime mode. The Lua documentation propose to use another
setjmp/longjmp to avoid the abort(). The goal is to puts a setjmp between setjmp/longjmp to avoid the abort(). The goal is to put a setjmp between
manipulating the Lua stack and using an alternative "panic" function which jumps manipulating the Lua stack and using an alternative "panic" function which jumps
to the setjmp() in error case. to the setjmp() in error case.
@ -510,10 +510,10 @@ All of these behaviours are very dangerous for the stability, and the internal
HAProxy code must be modified with many precautions. HAProxy code must be modified with many precautions.
For preserving a good behaviour of HAProxy, the yield is mandatory. For preserving a good behaviour of HAProxy, the yield is mandatory.
Unfortunately, some HAProxy part are not adapted for resuming an execution after Unfortunately, some HAProxy parts are not adapted for resuming an execution
a yield. These part are the sample fetches and the sample converters. So, the after a yield. These parts are the sample fetches and the sample converters. So,
Lua code written in these parts of HAProxy must be quickly executed, and can not the Lua code written in these parts of HAProxy must be quickly executed, and can
do actions which require yield like TCP connection or simple sleep. not do actions which require yield like TCP connection or simple sleep.
HAproxy socket object HAproxy socket object
--------------------- ---------------------
@ -523,7 +523,7 @@ server, and processing the many errors which can occurs during these exchanges.
HAProxy is not designed for having a third connection established to a third HAProxy is not designed for having a third connection established to a third
party server. party server.
The solution consist to puts the main stream in pause waiting for the end of the The solution consist to put the main stream in pause waiting for the end of the
exchanges with the third connection. This is completed by a signal between exchanges with the third connection. This is completed by a signal between
internal tasks. The following graph shows the HAProxy Lua socket: internal tasks. The following graph shows the HAProxy Lua socket:
@ -557,12 +557,12 @@ A more detailed graph is available in the "doc/internals" directory.
The HAProxy Lua socket uses a full HAProxy session / stream for establishing the The HAProxy Lua socket uses a full HAProxy session / stream for establishing the
connection. This mechanism provides all the facilities and HAProxy features, connection. This mechanism provides all the facilities and HAProxy features,
like the SSL stack, many socket type, and support for namespaces. like the SSL stack, many socket type, and support for namespaces.
Technically it support the proxy protocol, but there are no way to enable it. Technically it supports the proxy protocol, but there are no way to enable it.
How compiling HAProxy with Lua How compiling HAProxy with Lua
============================== ==============================
HAProxy 1.6 requires Lua 5.3. Lua 5.3 offers some features which makes easy the HAProxy 1.6 requires Lua 5.3. Lua 5.3 offers some features which make easy the
integration. Lua 5.3 is young, and some distros do not distribute it. Luckily, integration. Lua 5.3 is young, and some distros do not distribute it. Luckily,
Lua is a great product because it does not require exotic dependencies, and its Lua is a great product because it does not require exotic dependencies, and its
build process is really easy. build process is really easy.
@ -582,7 +582,7 @@ The compilation process for linux is easy:
make linux make linux
- install it: - install it:
sudo make INSTALL_TOP=/opt/lua-5.3.1 sudo make INSTALL_TOP=/opt/lua-5.3.1 install
HAProxy builds with your favourite options, plus the following options for HAProxy builds with your favourite options, plus the following options for
embedding the Lua script language: embedding the Lua script language:
@ -609,16 +609,16 @@ embedding the Lua script language:
First steps with Lua First steps with Lua
==================== ====================
Now, its time to using Lua in HAProxy. Now, it's time to use Lua in HAProxy.
Start point Start point
----------- -----------
The HAProxy global directive "lua-load <file>" allow to load an lua file. This The HAProxy global directive "lua-load <file>" allows to load an Lua file. This
is the entry point. This load become during the configuration parsing, and the is the entry point. This load become during the configuration parsing, and the
Lua file is immediately executed. Lua file is immediately executed.
All the register_*() function must be called at this time because there are used All the register_*() functions must be called at this time because they are used
just after the processing of the global section, in the frontend/backend/listen just after the processing of the global section, in the frontend/backend/listen
sections. sections.
@ -626,7 +626,7 @@ The most simple "Hello world !" is the following line a loaded Lua file:
core.Alert("Hello World !"); core.Alert("Hello World !");
It display a log during the HAProxy startup: It displays a log during the HAProxy startup:
[alert] 285/083533 (14465) : Hello World ! [alert] 285/083533 (14465) : Hello World !
@ -634,8 +634,8 @@ Default path and libraries
-------------------------- --------------------------
Lua can embed some libraries. These libraries can be included from different Lua can embed some libraries. These libraries can be included from different
paths. It seems that Lua doesn't like subdirectories. In the following example, I paths. It seems that Lua doesn't like subdirectories. In the following example,
try to load a compiled library, so the first line is Lua code, the second line I try to load a compiled library, so the first line is Lua code, the second line
is an 'strace' extract proving that the library was opened. The next lines are is an 'strace' extract proving that the library was opened. The next lines are
the associated error. the associated error.
@ -657,7 +657,7 @@ The variable "<libname>" is defined using the content of the variable
/usr/local/lib/lua/5.3/?.so;/usr/local/lib/lua/5.3/loadall.so;./?.so /usr/local/lib/lua/5.3/?.so;/usr/local/lib/lua/5.3/loadall.so;./?.so
The "<libname>" is the content which replaces the symbol "<?>". In th previous The "<libname>" is the content which replaces the symbol "<?>". In the previous
example, its "luac/concat", and obviously the Lua core try to load the function example, its "luac/concat", and obviously the Lua core try to load the function
associated with the symbol "luaopen_luac/concat". associated with the symbol "luaopen_luac/concat".
@ -677,7 +677,7 @@ First useful example
return txn.sc:sdbm(salt .. txn.sf:req_fhdr("host") .. txn.sf:path() .. txn.sf:src(), 1) return txn.sc:sdbm(salt .. txn.sf:req_fhdr("host") .. txn.sf:path() .. txn.sf:src(), 1)
end) end)
You will see that these 3 line can generate a lot of explanations :) You will see that these 3 lines can generate a lot of explanations :)
Core.register_fetches() is executed during the processing of the global section Core.register_fetches() is executed during the processing of the global section
by the HAProxy configuration parser. A new sample fetch is declared with name by the HAProxy configuration parser. A new sample fetch is declared with name
@ -686,16 +686,16 @@ sample fetch will be used calling "lua.my-hash" in the HAProxy configuration
file. file.
The second parameter is an inline declared anonymous function. Note the closed The second parameter is an inline declared anonymous function. Note the closed
parenthesis after the keyword "end" which end the function. The first parameter parenthesis after the keyword "end" which ends the function. The first parameter
of these anonymous function is "txn". It an object of class TXN. It provides of this anonymous function is "txn". It is an object of class TXN. It provides
access functions. The second parameter is an arbitrary value provided by the access functions. The second parameter is an arbitrary value provided by the
HAProxy configuration file. This parameter is optional, the developer must HAProxy configuration file. This parameter is optional, the developer must
check if its present. check if it is present.
The anonymous function registration is executed when the HAProxy backend or The anonymous function registration is executed when the HAProxy backend or
frontend configuration references the sample fetch "lua.my-hash". frontend configuration references the sample fetch "lua.my-hash".
This example can writed with an other style, like below: This example can be written with another style, like below:
function my_hash(txn, salt) function my_hash(txn, salt)
return txn.sc:sdbm(salt .. txn.sf:req_fhdr("host") .. txn.sf:path() .. txn.sf:src(), 1) return txn.sc:sdbm(salt .. txn.sf:req_fhdr("host") .. txn.sf:path() .. txn.sf:src(), 1)
@ -705,7 +705,7 @@ This example can writed with an other style, like below:
This second form is clearer, but the first one is compact. This second form is clearer, but the first one is compact.
The operator ".." is a string concatenation. If one of the two operands are not a The operator ".." is a string concatenation. If one of the two operands is not a
string, an error occurs and the execution is immediately stopped. This is string, an error occurs and the execution is immediately stopped. This is
important to keep in mind for the following things. important to keep in mind for the following things.
@ -732,22 +732,22 @@ understand that the function "my_hash" will be called for each HAProxy request
using the declared sample fetch. So, this function can be executed many times in using the declared sample fetch. So, this function can be executed many times in
parallel. parallel.
By default, Lua uses global variables. so in this example, il the variable "str" By default, Lua uses global variables. So in this example, if the variable "str"
is declared without the keyword "local", it will be shared by all the parallel is declared without the keyword "local", it will be shared by all the parallel
executions of the function and obviously, the content of the requests will be executions of the function and obviously, the content of the requests will be
shared. shared.
This warning is very important. I tried to write useful Lua code like a rewrite This warning is very important. I tried to write useful Lua code like a rewrite
of the statistics page, and its very hard to thing to declare each variable as of the statistics page, and it is very hard thing to declare each variable as
"local". "local".
I guess than this behaviour will be the cause of many trouble on the mailing I guess that this behaviour will be the cause of many troubles on the mailing
list. list.
str = str .. str = str ..
~~~~~~~~~~~~ ~~~~~~~~~~~~
Now a parenthesis about the form "str = str ..". This form allow to do string Now a parenthesis about the form "str = str ..". This form allows to do string
concatenations. Remember that Lua uses a garbage collector, so what happens when concatenations. Remember that Lua uses a garbage collector, so what happens when
we do "str = str .. 'another string'" ? we do "str = str .. 'another string'" ?
@ -755,10 +755,10 @@ we do "str = str .. 'another string'" ?
^ ^ ^ ^ ^ ^ ^ ^
1 2 3 4 1 2 3 4
Lua execute first the concatenation operator (3), it allocates memory for the Lua executes first the concatenation operator (3), it allocates memory for the
resulting string and fill this memory with the concatenation of the operands 2 resulting string and fill this memory with the concatenation of the operands 2
and 4. Next, it free the variable 1, now the old content of 1 can be garbage and 4. Next, it frees the variable 1, now the old content of 1 can be garbage
collected. and finally, the new content of 1 is the concatenation. collected. And finally, the new content of 1 is the concatenation.
what the matter ? when we do this operation many times, we consume a lot of what the matter ? when we do this operation many times, we consume a lot of
memory, and the string data is duplicated and move many times. So, this practice memory, and the string data is duplicated and move many times. So, this practice
@ -779,41 +779,41 @@ sample fetches and converters. The object txn contains 2 members dedicated to
the sample fetches and 2 members dedicated to the converters. the sample fetches and 2 members dedicated to the converters.
The sample fetches members are "f" (as sample-Fetch) and "sf" (as String The sample fetches members are "f" (as sample-Fetch) and "sf" (as String
sample-Fetch). These two members contains exactly the same functions. All the sample-Fetch). These two members contain exactly the same functions. All the
HAProxy native sample fetches are available, obviously, the Lua registered sample HAProxy native sample fetches are available, obviously, the Lua registered sample
fetches are not available. Unfortunately, HAProxy sample fetches names are not fetches are not available. Unfortunately, HAProxy sample fetches names are not
compatible with the Lua function names, and they are renames. The rename compatible with the Lua function names, and they are renamed. The rename
convention is simple, we replace all the '.', '+' and '-' by '_'. The '.' is the convention is simple, we replace all the '.', '+' and '-' by '_'. The '.' is the
object member separator, and the "-" and "+" is math operator. object member separator, and the "-" and "+" is math operator.
Now, that I'm writing this article, I known the Lua better than I wrote the Now, that I'm writing this article, I know the Lua better than I wrote the
sample-fetches wrapper. The original HAProxy sample-fetches name should be used sample-fetches wrapper. The original HAProxy sample-fetches name should be used
using alternative manner to call an object member, so the sample-fetch using alternative manner to call an object member, so the sample-fetch
"req.fhdr" (actually renamed req_fhdr") is should be used like this: "req.fhdr" (actually renamed req_fhdr") should be used like this:
txn.f["req.fhdr"](txn.f, ...) txn.f["req.fhdr"](txn.f, ...)
However, I think that this form is not elegant. However, I think that this form is not elegant.
The "s" collection return a data with a type near to the original returned type. The "s" collection return a data with a type near to the original returned type.
A string return an Lua string, an integer returns an Lua integer and an IP A string returns an Lua string, an integer returns an Lua integer and an IP
address returns an Lua string. Sometime the data is not or not yet available, in address returns an Lua string. Sometime the data is not or not yet available, in
this case it returns the Lua nil value. this case it returns the Lua nil value.
The "sf" collection guarantee that a string will be always returned. If the data The "sf" collection guarantees that a string will be always returned. If the data
is not available, an empty string is returned. The main usage of these collection is not available, an empty string is returned. The main usage of these collection
is to concatenate the returned sample-fetches without testing each function. is to concatenate the returned sample-fetches without testing each function.
The parameters of the sample-fetches are according with the haproxy The parameters of the sample-fetches are according with the HAProxy
documentation. documentation.
The converters runs exactly with the same manner as the sample fetches. The The converters run exactly with the same manner as the sample fetches. The
only one difference is that the fist parameter is the converter entry element. only one difference is that the first parameter is the converter entry element.
The "c" collection returns a precise result, and the "sc" collection returns The "c" collection returns a precise result, and the "sc" collection returns
always a string. always a string.
The sample-fetches used in the example function are "txn.sf:req_fhdr()", The sample-fetches used in the example function are "txn.sf:req_fhdr()",
"txn.sf:path()" and "txn.sf:src()". The converter are "txn.sc:sdbm()". The same "txn.sf:path()" and "txn.sf:src()". The converter is "txn.sc:sdbm()". The same
function with the "s" collection of sample-fetches and the "c" collection of function with the "s" collection of sample-fetches and the "c" collection of
converter should be written like this: converter should be written like this:
@ -832,7 +832,7 @@ converter should be written like this:
tostring tostring
~~~~~~~~ ~~~~~~~~
The function tostring ensure that its parameter is returned as a string. If the The function tostring ensures that its parameter is returned as a string. If the
parameter is a table or a thread or anything that will not have any sense as a parameter is a table or a thread or anything that will not have any sense as a
string, a form like the typename followed by a pointer is returned. For example: string, a form like the typename followed by a pointer is returned. For example:
@ -845,7 +845,7 @@ returns:
For objects, if the special function __tostring() is registered in the attached For objects, if the special function __tostring() is registered in the attached
metatable, it will be called with the table itself as first argument. The metatable, it will be called with the table itself as first argument. The
HAProxy objects returns its own type. HAProxy object returns its own type.
About the converters entry point About the converters entry point
-------------------------------- --------------------------------
@ -854,12 +854,12 @@ In HAProxy, a converter is a stateless function that takes a data as entry and
returns a transformation of this data as output. In Lua it is exactly the same returns a transformation of this data as output. In Lua it is exactly the same
behaviour. behaviour.
So, the registered Lua function doesn't have any special parameters, juste a So, the registered Lua function doesn't have any special parameters, just a
variable as input which contains the value to convert, and it must return data. variable as input which contains the value to convert, and it must return data.
The data required as input by the Lua converter is a string. So HAProxy will The data required as input by the Lua converter is a string. So HAProxy will
always provide a string as input. If the native sample fetch is not a string it always provide a string as input. If the native sample fetch is not a string it
will ne converted in best effort. will be converted in best effort.
The returned value will have anything type, it will be converted as sample of The returned value will have anything type, it will be converted as sample of
the near HAProxy type. The conversion rules from Lua variables to HAProxy the near HAProxy type. The conversion rules from Lua variables to HAProxy
@ -885,7 +885,7 @@ The task entry point
The function "core.register_task(fcn)" executes once the function "fcn" when the The function "core.register_task(fcn)" executes once the function "fcn" when the
scheduler starts. This way is used for executing background task. For example, scheduler starts. This way is used for executing background task. For example,
you can use this functionnality for periodically checking the health of an other you can use this functionnality for periodically checking the health of another
service, and giving the result to each proxy needing it. service, and giving the result to each proxy needing it.
The task is started once, if you want periodic actions, you can use the The task is started once, if you want periodic actions, you can use the
@ -895,7 +895,7 @@ Storing Lua variable between function in the same session
--------------------------------------------------------- ---------------------------------------------------------
All the functions registered as action or sample fetch can share an Lua context. All the functions registered as action or sample fetch can share an Lua context.
This context is a memory zone in the stack. sample fetch and action uses the This context is a memory zone in the stack. sample fetch and action use the
same stack, so both can access to the context. same stack, so both can access to the context.
The context is accessible via the function get_priv and set_priv provided by an The context is accessible via the function get_priv and set_priv provided by an
@ -922,7 +922,7 @@ HTTP actions
Lua is fast, but my service require more execution speed Lua is fast, but my service require more execution speed
======================================================== ========================================================
We can wrote C modules for Lua. These modules must run with HAProxy while they We can write C modules for Lua. These modules must run with HAProxy while they
are compliant with the HAProxy Lua version. A simple example is the "concat" are compliant with the HAProxy Lua version. A simple example is the "concat"
module. module.
@ -949,7 +949,7 @@ The build
--------- ---------
The compilation of the source file requires the Lua "include" directory. The The compilation of the source file requires the Lua "include" directory. The
compilation and the link of the object file requires the -fPIC option. Thats compilation and the link of the object file requires the -fPIC option. That's
all. all.
cc -I/opt/lua/include -fPIC -shared -o mymod.so mymod.c cc -I/opt/lua/include -fPIC -shared -o mymod.so mymod.c
@ -961,7 +961,7 @@ You can load this module with the following Lua syntax:
require("mymod") require("mymod")
When you start HAProxy, this module just print "Hello world" when its loaded. When you start HAProxy, this module just print "Hello world" when it is loaded.
Please, remember that HAProxy doesn't allow blocking method, so if you write a Please, remember that HAProxy doesn't allow blocking method, so if you write a
function doing filesystem access or synchronous network access, all the HAProxy function doing filesystem access or synchronous network access, all the HAProxy
process will fail. process will fail.