Common Lua Globals
Service Global Variables
The following true-global and thread-private global variables are pre-loaded for a Lua Service state. All of these variables
are visible in the Lua _ENV
environment which contains “free scope” (non-local) variable names.
Further below is discussion of the difference between true-global and thread-private global variables.
First, here are the true-globals (as per the following discussion. Their value is shared across all threads using that Lua state. Modifying them within one thread will affect the value within other threads.
Variable | Type | Description |
---|---|---|
SCRIPT_KEY
|
String | The key used by the loader to identify which Lua script content to execute. |
SCRIPT_MTIME
|
Number | The modification time (epoch) of the script which was loaded to return this Lua. |
APPLICATION_IDX
|
Integer |
The unique index within n2svcd of the n2svcd application which is executing this Lua.
|
APPLICATION_NAME
|
String |
The name of the n2svcd application which is executing this Lua.
|
APPLICATION_PID
|
Integer |
The process ID of the n2svcd application which is executing this Lua.
|
HOSTNAME
|
String | The hostname of the machine which is executing this Lua. |
SERVICE_MODULE
|
String |
The class of the LuaService module which initiated this Lua.
|
LOADER_MODULE
|
String |
The class of the LuaLoader module which loaded this Lua.
|
REQUIRE_LIST
|
List of Table |
The list of internally-satisfiable require modules given to the LuaLoader
to be used in conjunction with this script name. Most Loaders will not provide any require modules,
in which case this global variable will be nil .
|
[]
|
Table | Anonymous table. |
.name
|
String |
The module name which will be internally satisfied by a require .
|
.lua_chunk
|
String |
The Lua content (compiled or non-compiled) which satisfies the require .
|
.version
|
Integer | An associated version number provided by the loader logic. |
Additionally the following thread-private globals are pre-defined for each thread.
Variable | Type | Description |
---|---|---|
INSTANCE_IDX
|
Hex String |
The instance_idx of the LuaInstance currently executing this Lua.
|
INSTANCE_GID
|
String |
The instance_gid of the LuaInstance currently executing this Lua.
|
TRACE_LEVEL
|
0 - 3
|
An integer value indicating if trace-level debugging is currently enabled.0 = none, 1 = DEBUG, 2 = DUMP, 3 = SPAM.This can be used to avoid needless computation overhead when tracing is not activated. |
CHAIN_COUNT
|
Integer |
The number of times that this processing has chained to a follow-on script. The initial value for this counter is 0 .
|
In addition, each
See the Lua Services configuration within the LogicApp.
Notes on Global Variables
As described above, there is a subtle but important distinction between “true-global” and “thread-private global” when running Lua scripts inside LogicApp.
In many cases this distinction will not be visible to the service script writer. However,
there are specific situations where this distinction can become very important, specifically
in relation to the use of top-level variables inside a chunk loaded using require
.
The remainder of this page describes when and how this distinction becomes important.
Shared State & Script Key
The distinction between true-global and thread-private global becomes relevant when the same “script key” is loaded more than once within a single LogicApp process. In this case the LogicApp will create a single Lua state (with a single Lua memory space) and re-use that state multiple times by creating individual execution threads within that single state/memory space.
This approach provides very significant efficiency gains, since it avoids the CPU and memory overhead of re-compiling and loading the Lua state into memory repeatedly.
In practice, this approach is relevant to nearly all services, as nearly all Lua-based services are based around a small number of common script keys, including:
- Number Portability, N2IWF (for Voice, SMS), N2TTG, etc.
- Performance Test Runs which run the same script multiple times, e.g.
--total
is specified.
The exceptions will be:
- Services such as N2ACD which execute many different scripts.
- Functional Test Runs which are only executing each script once.
Internal Implementation
The Lua framework uses a shared-state mechanism to reduce memory usage in applications where multiple services load the same script_key.
In Lua terms, each instance of the running script is a Lua “thread”, which is a separate stack within a common, shared Lua state. Each of these threads shares a single Lua memory space.
However, in general these threads will not be aware of each other’s existence because most variables will not be shared.
Specifically:
- Any
local
variables within a function are private to that function, and - The
_G
global environment is backed by a “private global variables” table.
In detail: Whenever each thread starts/resumes execution, the standard _G
global variables
table is adjusted so that it is backed by a “thread-private global variables table”.
Note: See the caveat relating to top-level local
variables inside modules loaded using require
.
Relationship with _ENV
A “free” variable is a variable which is not defined as a local
variable, or is not defined as
a function-owned upvalue by any other mechanism e.g. the C Lua API.
Any free (non-local) variable named _ENV.<varname>
where _ENV
is the function’s “environment” table. For scripts running within
LogicApp, the _ENV
has its default value which is _ENV
= _G
.
To reiterate. The LogicApp does not modify _ENV
when executing threads. The LogicApp modifies
_G
directly which affects free (non-scoped) variables because Lua by default sets its environment
_ENV
to be = _G
.
True Globals
The real _G
table contains the truly-shared global values, this contains:
_G
(itself)_VERSION
the Lua version- Base Lua classes:
bit32
,coroutine
,debug
,io
,math
,os
,package
,string
,table
. - Default service true-global variables listed at the top of this page.
- Other default service-specific true-global variables (if any).
- Custom service global variables configured in the LogicApp Service “globals”.
Thread-Private Globals
The thread-private globals are stored in a separate table which at thread-runtime is attached to
the _G
table. When executing the thread, the following changes are made to _G
prior to resuming
the script execution.
- The
__index
metatable value for_G
is set to be the thread-private globals table. - The
__newindex
metatable value for_G
is set to be the thread-private globals table.
This means that for getting and setting free-scope (non-local) variables in Lua scripts run within LogicApp:
- When used as an r-value (getting) if the variable exists in
_G
then the true-global value is got. - When used as an r-value (getting) if the variable does not exist in
_G
then the thread-private global value is got. - When used as an l-value (setting) if the variable exists in
_G
then the true-global value is set. - When used as an l-value (setting) if the variable does not exist in
_G
then the thread-private global value is set.
Effectively, unless your free-variable name already exists as a key in the true-global table, then the thread-private global table is used for reading and writing variables.
The following thread-private global variables are defined prior to starting each thread.
- Default thread-private true-global variables listed at the top of this page.
- Other default service-specific thread-private global variables (if any).
Direct Access to True Globals
To modify an existing true-global value, it is sufficient just to assign the new value.
To create a new true-global value, use the Lua rawset
method which will bypass the metatable mechanism.
-- Set BSTATE = 'stateA' as a true-global value visable across all threads.
rawset (_G, 'BSTATE', 'stateA')
Note that because the LogicApp will periodically create a new Lua state. A global variable change will be seen by all other threads sharing your Lua state. But there will be more than one Lua state even for a single script key.
The Lua rawget
function also exists although will not typically be useful.
Direct Access to Thread-Private Globals
To access the underlying thread-private globals table, use the n2svcd.thread_globals
method.
local tgvars = n2svcd.thread_globals ()
Internally this method accesses the __index
metatable value for _G
.
Iterating _G with Pairs
The pairs
iterator on the _G table has been modified so that it will:
- First iterate all the keys of the true-global _G table.
- Then iterate all the keys of the thread-private globals table.
Variables Inside “require”
There is some non-intuitive behavior in regards to top-level variables inside Lua chunks which are loaded
with a call to require
. This affects top-level variables only, not variables which are inside functions
defined within that require
chunk.
- Firstly. A top-level
local
variable inside a chunk loaded byrequire
will be visible to all threads.
This is because the chunk loaded by require
is loaded only once, and so the “closure” is created only once.
Any local
variable is part of that singleton closure and hence is common to all threads which share that Lua state.
- Secondly. A top-level “free” (global scope) variable inside a chunk loaded by
require
will be thread-private to the first thread which loads it, and absent for all other threads.
This is because the chunk loaded by require
is loaded only once and hence the assignment statement setting that variable is executed only once.
The first thread to load that require will execute the assignment, and the variable will be placed in that thread’s thread-private global table.
Any subsequent thread will receive a copy of the require
object but will not re-execute the code contained
in the required chunk. Hence it will not have any entry in its thread-private global table - i.e. the free
variable does not exist.