This patch is the first of a serie which merge all the action structs. The
function "tcp-request content", "tcp-response-content", "http-request" and
"http-response" have the same values and the same process for some defined
actions, but the struct and the prototype of the declared function are
different.
This patch try to unify all of these entries.
The union name "data" is a little bit heavy while we read the source
code because we can read "data.data.sint". The rename from "data" to "u"
makes the read easiest like "data.u.sint".
This patch remove the struct information stored both in the struct
sample_data and in the striuct sample. Now, only thestruct sample_data
contains data, and the struct sample use the struct sample_data for storing
his own data.
test conf:
global
tune.lua.session-timeout 0
lua-load lol.lua
debug
maxconn 4096
listen test
bind 0.0.0.0:10010
mode tcp
tcp-request content lua act_test
balance roundrobin
server test 127.0.0.1:3304
lua test:
function act_test(txn)
while true do
core.Alert("TEST")
end
end
The function "act_test()" is not executed because a zero timeout is not
considered as TICK_ETERNITY, but is considered as 0.
This path fix this behavior. This is the same problem than the bugfix
685c014e99.
I've been trying out 1.6 dev3 with lua support, and trying to start
lua tasks seems to not be working.
Using this configuration
global
lua-load /lua/lol.lua
debug
maxconn 4096
backend shard_b
server db01 mysql_shard_b:3306
backend shard_a
server db01 mysql_shard_a:3306
listen mysql-cluster
bind 0.0.0.0:8001
mode tcp
balance roundrobin
use_backend shard_b
And this lua function
core.register_task(function()
while true do
core.Alert("LOLOLOLOLOL")
end
end)
I'd always get a timeout error starting the registered function.
The problem lies as far as I can tell in the fact that is possible for
now_ms to not change (is this maybe a problem on my config/system?)
until the expiration check happens, in the resume function that
actually kickstarts the lua task, making HAProxy think that expiration
time for the task is up, if I understand correctly tasks are meant to
never really timeout.
These ones are considered safe as they have already been reused.
They will be useful in "aggressive" and "always" http-reuse modes
in order to place the first request of a connection with the least
risk.
For now it's not populated but we have the list entry. It will carry
all idle connections that sessions don't want to share. They may be
used later to reclaim connections upon socket shortage for example.
Since we now always call this function with the reuse parameter cleared,
let's simplify the function's logic as it cannot return the existing
connection anymore. The savings on this inline function are appreciable
(240 bytes) :
$ size haproxy.old haproxy.new
text data bss dec hex filename
1020383 40816 36928 1098127 10c18f haproxy.old
1020143 40816 36928 1097887 10c09f haproxy.new
This patch removes the 32 bits unsigned integer and the 32 bit signed
integer. It replaces these types by a unique type 64 bit signed.
This makes easy the usage of integer and clarify signed and unsigned use.
With the previous version, signed and unsigned are used ones in place of
others, and sometimes the converter loose the sign. For example, divisions
are processed with "unsigned", if one entry is negative, the result is
wrong.
Note that the integer pattern matching and dotted version pattern matching
are already working with signed 64 bits integer values.
There is one user-visible change : the "uint()" and "sint()" sample fetch
functions which used to return a constant integer have been replaced with
a new more natural, unified "int()" function. These functions were only
introduced in the latest 1.6-dev2 so there's no impact on regular
deployments.
Dmitry Sivachenko reported the following build warning using Clang,
though it's harmless :
src/hlua.c:1911:13: warning: variable '_socket_info_expanded_form' is not needed
and will not be emitted [-Wunneeded-internal-declaration]
static char _socket_info_expanded_form[] = SOCKET_INFO_EXPANDED_FORM;
^
Indeed, the variable is not used except to compute a sizeof which is
taken from the string it is initialized from. It probably is a leftover
after various code refactorings. Let's get rid of it now since it's not
used anymore.
No backport is needed.
Actually, the registered lua actions with "tcp-request lua" and
"tcp-response lua" are final actions. This patch change the action
type type and permit to continue the evaluation of tcp-* processing
after the evaluation of the lua actions.
First, findproxy() was renamed proxy_find_by_name() so that its explicit
that a name is required for the lookup. Second, we give this function
the ability to search for tables if needed. Third we now provide inline
wrappers to pass the appropriate PR_CAP_* flags and to explicitly look
up a frontend, backend or table.
Options are relative to the sample. Each sample fetched is associated with
fetch options or fetch flags.
This patch adds the 'opt' vaue in the sample struct. This permits to reduce
the sample-fetch function prototype. In other way, the converters will have
more detail about the origin of the sample.
This patch removes the structs "session", "stream" and "proxy" from
the sample-fetches and converters function prototypes.
This permits to remove some weight in the prototype call.
Some sample analyzer (sample-fetch or converters) needs to known the proxy,
session and stream attached to the sampel. The sample-fetches and the converters
function pointers cannot be called without these 3 pointers filled.
This patch permits to reduce the sample-fetch and the converters called
prototypes, and provides a new mean to add information for this type of
functions.
It's much easier to centralize this call into the I/O handler than to
do it everywhere with the risk to miss it. Applets are not allowed to
unregister themselves anyway so their SI is still present and it is
possible to update all the context.
The applet I/O handlers now rely on si_applet_done() which itself decides
to wake up or sleep the appctx. Now it becomes critical that applte handlers
properly call this on every exit path so that the appctx is removed from the
active list after I/O have been handled. One such call was added to the Lua
socket handler. It used to work without it probably because the main task is
woken up by the parent task but now it's needed.
Now that applet's functions only take an appctx in argument, not a
stream interface. This slightly simplifies the code and will be needed
to take the appctx out of the stream interface.
We don't pass sess->origin anymore but the pointer to the previous step. Now
it should be much easier to chain elements together once applets are moved out
of streams. Indeed, the session is only used for configuration and not for the
dynamic chaining anymore.
This patch cretes a new Map class that permits to do some lookup in
HAProxy maps. This Map class is integration in the HAProxy update
system, so we can modify the map throught the socket.
the functions (req|res)_get_headers() return only the last entry
for each header with the same name. This patch fix this behavior.
Each header name contain an array of values.
The stick counters in the session will be used for everything not related
to contents, hence the connections / concurrent sessions / etc. They will
be usable by "tcp-request connection" rules even without a stream. For now
they're just allocated and initialized.
Doing so ensures we don't need to use the stream anymore to prepare the
log information to report a failed handshake on an embryonic session.
Thus, prepare_mini_sess_log_prefix() now takes a session in argument.
Many such function need a session, and till now they used to dereference
the stream. Once we remove the stream from the embryonic session, this
will not be possible anymore.
So as of now, sample fetch functions will be called with this :
- sess = NULL, strm = NULL : never
- sess = valid, strm = NULL : tcp-req connection
- sess = valid, strm = valid, strm->txn = NULL : tcp-req content
- sess = valid, strm = valid, strm->txn = valid : http-req / http-res
The registerable http_req_rules / http_res_rules used to require a
struct http_txn at the end. It's redundant with struct stream and
propagates very deep into some parts (ie: it was the reason for lua
requiring l7). Let's remove it now.
All of them can now retrieve the HTTP transaction *if it exists* from
the stream and be sure to get NULL there when called with an embryonic
session.
The patch is a bit large because many locations were touched (all fetch
functions had to have their prototype adjusted). The opportunity was
taken to also uniformize the call names (the stream is now always "strm"
instead of "l4") and to fix indent where it was broken. This way when
we later introduce the session here there will be less confusion.
Now this one is dynamically allocated. It means that 280 bytes of memory
are saved per TCP stream, but more importantly that it will become
possible to remove the l7 pointer from fetches and converters since
it will be deduced from the stream and will support being null.
A lot of care was taken because it's easy to forget a test somewhere,
and the previous code used to always trust s->txn for being valid, but
all places seem to have been visited.
All HTTP fetch functions check the txn first so we shouldn't have any
issue there even when called from TCP. When branching from a TCP frontend
to an HTTP backend, the txn is properly allocated at the same time as the
hdr_idx.
The header captures are now general purpose captures since tcp rules
can use them to capture various contents. That removes a dependency
on http_txn that appeared in some sample fetch functions and in the
order by which captures and http_txn were allocated.
Interestingly the reset of the header captures were done at too many
places as http_init_txn() used to do it while it was done previously
in every call place.
When s->si[0].end was dereferenced as a connection or anything in
order to retrieve information about the originating session, we'll
now use sess->origin instead so that when we have to chain multiple
streams in HTTP/2, we'll keep accessing the same origin.
Just like for the listener, the frontend is session-wide so let's move
it to the session. There are a lot of places which were changed but the
changes are minimal in fact.
There is now a pointer to the session in the stream, which is NULL
for now. The session pool is created as well. Some parts will move
from the stream to the session now.
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
These ones were found in the actions to set the query/path/method/uri.
Where it's used, "s" makes one think about session or something like
this, especially when mixed with http_txn.
hlua_run_sample_fetch() uses "struct hlua_smp *s" which starts to become
confusing when "s->s" is used, then hlua_txn_close() uses this for struct
hlua_txn with the same "s->s" everywhere. Let's uniformize everything with
htxn and hsmp as in other places.
Struct hlua_txn is called "htxn" or "ht" everywhere, while here it's
called "hs" which is the name used everywhere for struct "hlua_smp".
Such confusion participate to the dangers of copy-pasting code, so
let's fix the name here.
Last bug was an example of a side effect of abuse of copy-paste, but
there are other places at risk, so better fix all occurrences of sizeof
to really reference the object size in order to limit the risks in the
future.
In hlua_converters_new(), we used to allocate the size of an hlua_txn
instead of hlua_smp, resulting in random crashes with one integer being
randomly overwritten at the end, even when no converter is being used.
Lua supports a memory allocator. This is very important as it's the
only way we can control the amount of memory allocatable by Lua scripts.
That avoids prevents bogus scripts from eating all of the system's memory.
The value can be enforced using tune.lua.maxmem in the global section.
Thispatch adds global log function. Each log message is writed on
the stderr and is sent to the default syslog server. These two
actions are done according the configuration.
This class is accessible via the TXN object. It is created only if
the attached proxy have HTTP mode. It contain all the HTTP
manipulation functions:
- req_get_headers
- req_del_header
- req_rep_header
- req_rep_value
- req_add_header
- req_set_header
- req_set_method
- req_set_path
- req_set_query
- req_set_uri
- res_get_headers
- res_del_header
- res_rep_header
- res_rep_value
- res_add_header
- res_set_header
If the Lua code causes an infinite loop without yield possible, the
clock is not updated. This patch check the clock when the Lua control
code cannot yield.
When we explicitly write si[0] or si[1], we know whether we're working
with s->req or s->res, so better use that instead of si_ic/si_oc(), to
make the code simpler and more readable.
Some fetches uses a proxy name as first parameter. This is used to identify
frontend, backend or table. This first argument is declared as mandatory,
but the documentation says that is optional.
The behavior of the function smp_resolve_args() is to use the current proxy
if it match the required argument.
This patch implements the same behavior in the Lua argument checker for
sample-fetches and sample-converters.
The first argument in the stack is 1 and not 0. So the analyzer
starts at bad argument number, and the error message contains
also bad argument number.
It was inappropriate to put this flag on every failed write into an
input buffer because it depends where it happens. When it's in the
context of an analyser (eg: hlua) it makes sense. When it's in the
context of an applet (eg: dumpstats), it does not make sense, and
it only happens to work because currently applets are scheduled by
the sessions. The proper solution for applets would be to add the
flag SI_FL_WAIT_ROOM on the stream interface.
Thus, we now don't set any flag anymore in bi_put* and it's up to the
caller to either set CF_WAKE_WRITE on the channel or SI_FL_WAIT_ROOM
on the stream interface. Changes were applied to hlua, peers and
dumpstats.
This struct used to carry only a sample fetch function. Thanks to
lua_pushuserdata(), we don't need to have the Lua engine allocate
that struct for us and we can simply push our pointer onto the stack.
This makes the code more readable by removing several occurrences of
"f->f->". Just like the previous patch, it comes with the nice effect
of saving about 1.3% of performance when fetching samples from Lua.
Since last cleanups, this one was only used to carry a struct channel.
Removing it makes the code a bit cleaner (no more chn->chn) and easier
to follow (no more abstraction for a common type). Interestingly it
happens to also make the Lua code slightly faster (about 1.5%) when
using channels, probably thanks to less pointer dereferences and maybe
the use of lua_pushlightuserdata().
Now that we can get the session from the channel, let's simplify the
prototype of session_alloc_recv_buffer() to only require the channel.
Both the caller and the function are now simplified.
These 4 combinations are needlessly complicated since the session already
has direct access to the associated stream interfaces without having to
check an indirect pointer.
The purpose of these two macros will be to pass via the session to
find the relevant stream interfaces so that we don't need to store
the ->cons nor ->prod pointers anymore. Currently they're only defined
so that all references could be removed.
Note that many places need a second pass of clean up so that we don't
have any chn_prod(&s->req) anymore and only &s->si[0] instead, and
conversely for the 3 other cases.
At a few places we need to find one stream interface from the other one.
Instead of passing via the channel, we simply use the session as an
intermediary, which simply results in applying an offset to the pointer.
This new flag "SI_FL_ISBACK" is set only on the back SI and is cleared
on the front SI. That way it's possible only by looking at the SI to
know what side it is.
We'll soon remove direct references to the channels from the stream
interface since everything belongs to the same session, so let's
first not dereference si->ib / si->ob anymore and use macros instead.
The channels were pointers to outside structs and this is not needed
anymore since the buffers have moved, but this complicates operations.
Move them back into the session so that both channels and stream interfaces
are always allocated for a session. Some places (some early sample fetch
functions) used to validate that a channel was NULL prior to dereferencing
it. Now instead we check if chn->buf is NULL and we force it to remain NULL
until the channel is initialized.
In some cases we don't want to known if a fetch or converter
fails. We just want a valid string. After this patch, we
have two sets of fetches and two sets of converters. There are:
txn.f, txn.sf, txn.c, txn.sc. The version prefixed by 's' always
returns strings for any type, and returns an empty string in the
error case or when the data are not available. This is particularly
useful when manipulating headers or cookies.
To add data in channel, it is necessary to process in two times.
First time, get the channel object, and after send data:
local req = txn:req_channel()
req:send("data\n")
Now, the function is converted as a variable containing the req
and res aobject. We can process as following:
txn.req:send("data\n")
This patch implements a wrapper to give access to the converters
in the Lua code. The converters are used with the transaction.
The automatically created function are prefixed by "conv_".
HAProxy proposes many sample fetches. It is possible that the
automatic registration of the sample fetches causes a collision
with an existing Lua function. This patch sets a namespace for
the sample fetches.
Actually an object is just a userdata value with a metatable.
This mode causes some problems like I can't add lua own data.
This new model uses an array as object base, and affect the
userdata at the index 0.
The core entry is just a collection of function, it doesn't depends on
special variable. This patch just converts an object contained in a
metatable in object contained in a normal table.
A few function names in Lua had underscores which did not appear in their
C counterpart. Since almost all of them already had similar names, better
uniformize the naming convention.
For now we don't perform any operation on IP addresses, so at least
we'd like to be able to pass them as strings so that we can log them
or whatever in Lua. Without this patch txn.src(txn) returns "nil" and
now it returns the correct IP address.
Lua 5.3 provides an opaque space associated with each
coroutine stack. This patch uses this lot of memory to
store the "struct hlua *" associated pointer.
This patch makes the retrieval of the "struct hlua *"
associated struct faster because it replace a lookup in
a tree by an immediate access to the data.
This reverts commit cd9084f776.
This commit introduced a regression making it impossible to leave
process_session() during a forced yield because the analyser was always
set on the response even if not needed. The result was a busy loop
making haproxy spin at 100% without even polling anymore in case a
forced yield was performed.
The problem it tried to address (intercept response data from a request
analyser before forwarding) is not a trivial issue to address since
wakeups based on reads will not necessarily happen unless there's write
activity.
Anyway, if functions are attached specifically to a request or to a
response, it's for a reason. So for now let's be clear about the fact
that it's unreliable to try to process data from the opposite channel
until a better solution is found.
This patch fix the Lua library check. Only the version
5.3 or later is allowed.
This bug is added by the patch "MEDIUM: lua: use the
Lua-5.3 version of the library" with commit id
f90838b71a
Specs says that the receive() function with an argument "*l"
must return a line without the final "\n" ( or without "\r\n").
This patch removes these two final bytes.
When we try to write data in a session from another session, the "req"
buffer is not allowed. This patch try to allocate the buffer. The session
wait if the buffer is not yet avalaible.
When a socket is initilized in the body context, a segfaut is generated
because the memory pools are not initilized. This atch check if these
memory pool are initialized.
The function buffer_contig_space() returns the contiguous space avalaible
to add data (at the end of the input side) while the function
hlua_channel_send_yield() needs to insert data starting at p. Here we
introduce a new function bi_space_for_replace() which returns the amount
of space that can be inserted at the head of the input side with one of
the buffer_replace* functions.
This patch proposes a function that returns the space avalaible after buf->p.
The request action can't handle the reponse trafic because its
automatically forwarded. The forard with CHN_INFINITE_FORWARD
is set because any anamizers are registered on the response
channel.
This patch automatically register the request analyzer on the
reponse channel when its yield. This prevent the automatic
tranfer of the response bytes.
The hook function called each nth Lua instructions just
do a yield. Sometimes this yield is not allowed, because
some functions are not compatible.
The Lua-5.3 permits to known if the yield is avalaible with
the function lua_isyieldable().
If the processing is interrupted in non yieldable state,
we try to execute a yield asap. The yield will be may
available at the end of the non-yieldable currently
executed function. So, we require interrupt at the end
of the current function.
But, Lua cannot yield when its returning from a function,
so, we can fix the interrupt hook to 1 instruction,
expecting that the function is finnished.
During this time, the execution timeout is always checked.
The Lua-5.3 version of the library adds a required function to fix
a bug with the forced-yield system.
This patch permits to build with the Lua-5.3 library. Main changes
are:
- "unsigned" type disappear to be replaced by signed type,
- prototype of the yield function callback changes.
First we allow to use the reserved size to write the data that
will be sent. The reserved size remain guaranty because the
writed data will be sent quickly and the reserved room we be
again avalaible.
This permits to guaranty that the function send always have
avalaible space to send data (except if it cannot connect to
the server).
The function buffer_replace2 works only on contiguous buffer.
This patch also detects if the required size is contiguous.
If it not the case we realign the buffer.
If we are writing in the request buffer, we are not waked up
when the data are forwarded because it is useles. The request
analyzers are waked up only when data is incoming. So, if the
request buffer is full, we set the WAKE_ON_WRITE flag.
Before this patch, each yield in a Lua action set a flags to be
waked up when some activity were detected on the response channel.
This behavior causes loop in the analyzer process.
This patch set the wake up on response buffer activity only if we
really want to be waked up on this activity.
This patch reset the flags except th run flag before resuming
the Lua execution. If this initialisation is not done, some
flags can remain at the end of the Lua execution and give bad
informations.
Check if the buffer is avalaible because HAProxy doesn't allocate
the request buffer if its not required. Sometimes, the Lua need to
write some data to the server before that the client send his data.
This patch check the expiration of the execution timeout for each
yield source, and test also the execution timeout before resuming
the execution of the Lua code.
This patch permits to interrupt the Lua execution each n# of
instructions. It is useful for controling the execution time
of an Lua code, and permits at the HAProxy schedule to process
some others tasks waiting execution.
This flag indicate that the current yield is returned by the Lua
execution task control. If this flag is set, the current task may
quit but will be set in the run queue to be re-executed immediatly.
This patch modify the "hlua_yieldk()" function, it adds an argument
that contain a field containing yield options.
This is used to ensure that the task doesn't become a zombie
when the Lua returns a yield. The yield wrapper ensure that an
timer used for waking up the task will be set.
The timer is reseted to TICK_ETERNITY if the Lua execution is
done.
This first patch permits to cofigure the Lua execution exipiration.
This expiration is configured but it is not yet avalaible, it will
be add in a future patch.
In the future, the lua execution must return scheduling informations.
We want more than one flag, so I convert an integer used with an
enum into an interer used as bitfield.
In some cases the Lua "send" function fails. This is caused by the
return of "buffer_replace2()" is not tested. I checked avalaible space
in the buffer and I supposed than "buffer_replace2()" took all the
data. In some cases, "buffer_replace2()" cannot take the incoming
data, it returns the amount of data copied.
This patch check the amount of data really copied by "buffer_replace2()"
and advance the buffer with taking this value in account.
When a Lua script calls an internal haproxy sample fetch, it may segfault in
some conditions :
- when a fetch has no argument,
- when there is no room left to store the special type ARGT_STOP in the argument
list (this one shouldn't happen currently as there isn't any sample fetch with
enough arguments to fill the allocated buffer).
Example of Lua code which reproduces a segfault :
core.register_fetches("segfault", function(txn, ...)
return txn.req_ver(txn)
end)
haproxy Lua support begins with Lua 5.2. In order to ease the diagnostic on
compilation error, a preprocessor error is added when an incompatible version
is used.
The compatibility is determined by the presence of LUA_VERSION_NUM and its
magic value (502 for Lua 5.2.x).
Actually, the Lua context is always initilized in each
session, even if the session doesn't use Lua. This
behavior cause 5% performances loss.
This patch initilize the Lua only if it is use by the
session. The initialization is now on demand.
The code was a bit of a pain to follow because of this, especially
when some of it heavily relies on longjmp... This refreshing makes
it slightly easier to read.
This patch provides a yield function. This function permits to
give back the hand at the HAProxy scheduler. It is used when the
lua processing consumes a lot of time.
The channel class permits manipulation of channels. A channel is
an FIFO buffer between the client and the server. This class provides
function to read, write, forward, destroy and alter data between
the input and the ouput of the buffer.
This patch adds the TCP I/O functionnality. The class implemented
provides the same functions than the "lua socket" project. This
make network compatibility with another LUA project. The documentation
is located here:
http://w3.impa.br/~diego/software/luasocket/tcp.html
This version of sleep is based on a coroutine. A sleeping
task is started and a signal is registered. This sleep version
must disapear to be replaced by a version using the internal
timers.
This patch permits to write LUA converters. Note that
all the converters declared trough LUA are automatically
prefixed by "lua.".
The Lua converters needs the current session to be executed,
but the writed and executed Lua code must be static and
contextless. The TXN object is not created for the converters.
This patch adds the browsing of all the HAProxy fetches and
create associated LUA functions. The HAProxy internal fetches
can be used in LUA trough the class "TXN".
Note that the symbols "-", "+" and "." in the name of current
sample fetch are rewrited as "_" in LUA because ".", "-" and "+"
are operators.
The shared context is a global reference dedicated to one Lua stack.
Even if the TXN is not required, the shared context it is associated
with a TXN object. In fact, the shared has no sense outside a TXN
context
This class of functions permit to access to all the functions
associated with the transaction like http header, HAProxy internal
fetches, etc ...
This patch puts the skeleton of this class. The class will be
enhanced later.
This system permits to execute some lua function after than HAProxy
complete his initialisation. These functions are executed between
the end of the configuration parsing and check and the begin of the
scheduler.
This system permits to send signals between lua tasks. A main lua stack can
register the signal in a coprocess. When the coprocess finish his job, it
send a signal, and the associated task is wakes. If the main lua execution
stack stop (with or without errors), the list or pending signals is purged.
This is the first step of the lua integration. We add the useful
files in the HAProxy project. These files contains the main
includes, the Makefile options and empty initialisation function.
Is is the LUA skeleton.