[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2 Server Assumptions About the Database

There are a small number of circumstances under which the server directly and specifically accesses a particular verb or property in the database. This section gives a complete list of such circumstances.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.1 Server Options Set in the Database

Many optional behaviors of the server can be controlled from within the database by creating the property $server_options (i.e., #0.server_options), assigning as its value a valid object number, and then defining various properties on that object. At a number of times, the server checks for whether the property $server_options exists and has an object number as its value. If so, then the server looks for a variety of other properties on that $server_options object and, if they exist, uses their values to control how the server operates.

Note that for some options, you will need to call load_server_options() in order for any changes in their values to take effect. See the description of that function for more information on this.

The specific properties searched for are each described in the appropriate section below, but here is a brief list of all of the relevant properties for ease of reference:

bg_seconds

The number of seconds allotted to background tasks.

bg_ticks

The number of ticks allotted to background tasks.

connect_timeout

The maximum number of seconds to allow an un-logged-in in-bound connection to remain open. (This option is listener-specific.)

default_flush_command

The initial setting of each new connection's flush command.

fg_seconds

The number of seconds allotted to foreground tasks.

fg_ticks

The number of ticks allotted to foreground tasks.

max_concat_catchable

Cause value size limit violations to raise an error instead of abort the task.

max_list_concat

The maximum size list value that may be constructed

max_string_concat

The maximum size string value that may be constructed

max_stack_depth

The maximum number of levels of nested verb calls.

name_lookup_timeout

The maximum number of seconds to wait for a network hostname/address lookup.

outbound_connect_timeout

The maximum number of seconds to wait for an outbound network connection to successfully open.

protect_property

Restrict reading of built-in property to wizards.

protect_function

Restrict use of built-in function to wizards.

queued_task_limit

The maximum number of tasks a player can have.

support_numeric_verbname_strings

Enables use of an obsolete verb-naming mechanism.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.2 Server Messages Set in the Database

There are a number of circumstances under which the server itself generates messages on network connections. Most of these can be customized or even eliminated from within the database. In each such case, a property on $server_options is checked at the time the message would be printed. If the property does not exist, a default message is printed. If the property exists and its value is not a string or a list containing strings, then no message is printed at all. Otherwise, the string(s) are printed in place of the default message, one string per line. None of these messages are ever printed on an outbound network connection created by the function open_network_connection().

The following list covers all of the customizable messages, showing for each the name of the relevant property on $server_options, the default message, and the circumstances under which the message is printed:

boot_msg = "*** Disconnected ***"

The function boot_player() was called on this connection.

connect_msg = "*** Connected ***"

The user object that just logged in on this connection existed before $do_login_command() was called.

create_msg = "*** Created ***"

The user object that just logged in on this connection did not exist before $do_login_command() was called.

recycle_msg = "*** Recycled ***"

The logged-in user of this connection has been recycled or renumbered (via the renumber() function).

redirect_from_msg = "*** Redirecting connection to new port ***"

The logged-in user of this connection has just logged in on some other connection.

redirect_to_msg = "*** Redirecting old connection to this port ***"

The user who just logged in on this connection was already logged in on some other connection.

server_full_msg = {

"*** Sorry, but the server cannot accept any more connections right now.",
"*** Please try again later."}

This connection arrived when the server really couldn't accept any more connections, due to running out of a critical operating system resource.

timeout_msg = "*** Timed-out waiting for login. ***"

This in-bound network connection was idle and un-logged-in for too long. The actual time limit is $server_options.connect_timeout.

Fine point: If the network connection in question was received at a listening point (established by the ‘listen()’ function) handled by an object obj other than #0, then system messages for that connection are looked for on obj.server_options; if that property does not exist, then the corresponding property on $server_options is used instead. This also applies to the connect_timeout option.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.3 Checkpointing the Database

The server maintains the entire MOO database in main memory, not on disk. It is therefore necessary for it to dump the database to disk if it is to persist beyond the lifetime of any particular server execution. The server is careful to dump the database just before shutting down, of course, but it is also prudent for it to do so at regular intervals, just in case something untoward happens.

To determine how often to make these checkpoints of the database, the server consults the value of $dump_interval. If it exists and its value is an integer greater than or equal to 60, then it is taken as the number of seconds to wait between checkpoints; otherwise, the server makes a new checkpoint every 3600 seconds (one hour). If the value of $dump_interval implies that the next checkpoint should be scheduled at a time after 3:14:07 a.m. on Tuesday, January 19, 2038, then the server instead uses the default value of 3600 seconds in the future.

The decision about how long to wait between checkpoints is made again immediately after each one begins. Thus, changes to $dump_interval will take effect after the next checkpoint happens.

Whenever the server begins to make a checkpoint, it makes the following verb call:

 
$checkpoint_started()

When the checkpointing process is complete, the server makes the following verb call:

 
$checkpoint_finished(success)

where success is true if and only if the checkpoint was successfully written on the disk. Checkpointing can fail for a number of reasons, usually due to exhaustion of various operating system resources such as virtual memory or disk space. It is not an error if either of these verbs does not exist; the corresponding call is simply skipped.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.4 Accepting and Initiating Network Connections

When the server first accepts a new, incoming network connection, it is given the low-level network address of computer on the other end. It immediately attempts to convert this address into the human-readable host name that will be entered in the server log and returned by the connection_name() function. This conversion can, for the TCP/IP networking configurations, involve a certain amount of communication with remote name servers, which can take quite a long time and/or fail entirely. While the server is doing this conversion, it is not doing anything else at all; in particular, it it not responding to user commands or executing MOO tasks.

By default, the server will wait no more than 5 seconds for such a name lookup to succeed; after that, it behaves as if the conversion had failed, using instead a printable representation of the low-level address. If the property name_lookup_timeout exists on $server_options and has an integer as its value, that integer is used instead as the timeout interval.

When the open_network_connection() function is used, the server must again do a conversion, this time from the host name given as an argument into the low-level address necessary for actually opening the connection. This conversion is subject to the same timeout as in the in-bound case; if the conversion does not succeed before the timeout expires, the connection attempt is aborted and open_network_connection() raises E_QUOTA.

After a successful conversion, though, the server must still wait for the actual connection to be accepted by the remote computer. As before, this can take a long time during which the server is again doing nothing else. Also as before, the server will by default wait no more than 5 seconds for the connection attempt to succeed; if the timeout expires, open_network_connection() again raises E_QUOTA. This default timeout interval can also be overridden from within the database, by defining the property outbound_connect_timeout on $server_options with an integer as its value.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.5 Associating Network Connections with Players

When a network connection is first made to the MOO, it is identified by a unique, negative object number. Such a connection is said to be un-logged-in and is not yet associated with any MOO player object.

Each line of input on an un-logged-in connection that is not a flush command and is not consumed by out-of-band processing is parsed into words in the usual way (see the chapter on command parsing for details) and then these words are passed as the arguments in a call to the verb $do_login_command(). For example, the input line

 
connect Munchkin frebblebit

would result in the following call being made:

 
$do_login_command("connect", "Munchkin", "frebblebit")

In that call, the variable player will have as its value the negative object number associated with the appropriate network connection. The functions notify() and boot_player() can be used with such object numbers to send output to and disconnect un-logged-in connections. Also, the variable argstr will have as its value the unparsed command line as received on the network connection.

If $do_login_command() returns a valid player object and the connection is still open, then the connection is considered to have logged into that player. The server then makes one of the following verbs calls, depending on the player object that was returned:

 
$user_created(player)
$user_connected(player)
$user_reconnected(player)

The first of these is used if the returned object number is greater than the value returned by the max_object() function before $do_login_command() was invoked, that is, it is called if the returned object appears to have been freshly created. If this is not the case, then one of the other two verb calls is used. The $user_connected() call is used if there was no existing active connection for the returned player object. Otherwise, the $user_reconnected() call is used instead.

Fine point: If a user reconnects and the user's old and new connections are on two different listening points being handled by different objects (see the description of the listen() function for more details), then user_client_disconnected is called for the old connection and user_connected for the new one.

If an in-bound network connection does not successfully log in within a certain period of time, the server will automatically shut down the connection, thereby freeing up the resources associated with maintaining it. Let L be the object handling the listening point on which the connection was received (or #0 if the connection came in on the initial listening point). To discover the timeout period, the server checks on L.server_options or, if it doesn't exist, on $server_options for a connect_timeout property. If one is found and its value is a positive integer, then that's the number of seconds the server will use for the timeout period. If the connect_timeout property exists but its value isn't a positive integer, then there is no timeout at all. If the property doesn't exist, then the default timeout is 300 seconds.

When any network connection (even an un-logged-in or outbound one) is terminated, by either the server or the client, then one of the following two verb calls is made:

 
$user_disconnected(player)
$user_client_disconnected(player)

The first is used if the disconnection is due to actions taken by the server (e.g., a use of the boot_player() function or the un-logged-in timeout described above) and the second if the disconnection was initiated by the client side.

It is not an error if any of these five verbs do not exist; the corresponding call is simply skipped.

Note: Only one network connection can be controlling a given player object at a given time; should a second connection attempt to log in as that player, the first connection is unceremoniously closed (and $user_reconnected() called, as described above). This makes it easy to recover from various kinds of network problems that leave connections open but inaccessible.

When the network connection is first established, the null command is automatically entered by the server, resulting in an initial call to $do_login_command() with no arguments. This signal can be used by the verb to print out a welcome message, for example.

Warning: If there is no $do_login_command() verb defined, then lines of input from un-logged-in connections are simply discarded. Thus, it is necessary for any database to include a suitable definition for this verb.

Note that a database with a missing or broken $do_login_command may still be accessed (and perhaps repaired) by running the server with the -e command line option. See section Emergency Wizard Mode.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.6 Player Input Handlers

$do_out_of_band_command

On any connection for which the connection-option disable-oob has not been set, any unflushed incoming lines that begin with the out-of-band prefix will be treated as out-of-band commands, meaning that if the verb $do_out_of_band_command() exists and is executable, it will be called for each such line. For more on this, see Out-of-band Processing.

$do_command

As we previously described in The Built-in Command Parser, on any logged-in connection that

any incoming line that

will result in a call to $do_command() provided that verb exists and is executable. If this verb suspends or returns a true value, then processing of that line ends at this point, otherwise, whether the verb returned false or did not exist in the first place, the remainder of the builtin parsing process is invoked.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.7 The First Tasks Run By the Server

Whenever the server is booted, there are a few tasks it runs right at the beginning, before accepting connections or getting the value of $dump_interval to schedule the first checkpoint (see below for more information on checkpoint scheduling).

First, the server calls $user_disconnected() once for each user who was connected at the time the database file was written; this allows for any cleaning up that's usually done when users disconnect (e.g., moving their player objects back to some `home' location, etc.).

Next, it checks for the existence of the verb $server_started(). If there is such a verb, then the server runs a task invoking that verb with no arguments and with player equal to #-1. This is useful for carefully scheduling checkpoints and for re-initializing any state that is not properly represented in the database file (e.g., re-opening certain outbound network connections, clearing out certain tables, etc.).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.8 Controlling the Execution of Tasks

As described earlier, in the section describing MOO tasks, the server places limits on the number of seconds for which any task may run continuously and the number of “ticks,” or low-level operations, any task may execute in one unbroken period. By default, foreground tasks may use 30,000 ticks and five seconds, and background tasks may use 15,000 ticks and three seconds.

The server also places a limit on the number of levels of nested verb calls, raising E_MAXREC from a verb-call expression if the limit is exceeded. The limit is 50 levels by default.

In addition, the server limits the size of list and string values that may be constructed to 16,777,216 elements by default.

Finally, the server can limit the number of forked or suspended tasks a given programmer can have queued at a given time; by default there is no limit.

All of these limits can be overridden from within the database by defining any or all of the following properties on $server_options and giving them integer values:

bg_seconds

The number of seconds allotted to background tasks.

bg_ticks

The number of ticks allotted to background tasks.

fg_seconds

The number of seconds allotted to foreground tasks.

fg_ticks

The number of ticks allotted to foreground tasks.

max_stack_depth

The maximum number of levels of nested verb calls.

max_list_concat

The maximum size list value that may be constructed

max_string_concat

The maximum size string value that may be constructed

queued_task_limit

The maximum number of tasks a player can have.

The server ignores the values of fg_ticks and bg_ticks if they are less than 100 and similarly ignores fg_seconds and bg_seconds if their values are less than 1. A value of max_stack_depth less than 50 is likewise ignored. This may help prevent utter disaster should you accidentally give these options uselessly-small values.

Recall that command tasks and server tasks are deemed foreground tasks, while forked, suspended, and reading tasks are defined as background tasks. The respective ticks and seconds limits take effect only at the beginning of execution or upon resumption of execution after suspending or reading. The maximum stack depth is set at the time that task is created and cannot be changed thereafter, even after being saved in and restored from the DB.

The limit on number of queued tasks is consulted upon attempts to execute a fork statement, a call to suspend(), or a blocking call to read. If the programmer already has a number of queued tasks that is greater than or equal to the limit, E_QUOTA is raised instead. A property on the programmer named queued_task_limit that is set to a non-negative integer takes precedence over $server_options.queued_task_limit. If both the programmer-specific and server properties are nonexistent or negative, then there is no limit.

Limits on list and string sizes are not task-specific and may change at any time, though these are amongst the options that require load_server_options in order to take effect. Attempting to create an value of size beyond the limit immediately aborts the task in the same manner as when the seconds limit is exceeded. This behavior can be changed by setting $server_options.max_concat_catchable to a true value, in which case E_QUOTA is raised instead.

The value size limits may be removed by setting max_list_concat and/or max_string_concat to zero or negative values. Note that removing these limits or setting them too large relative to the memory available on the server host will cause the server to crash if an overly large value construction is attempted.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.9 Controlling the Handling of Aborted Tasks

The server will abort the execution of tasks for either of two reasons:

  1. an error was raised within the task but not caught, or
  2. the task exceeded the limits on ticks and/or seconds.

In each case, after aborting the task, the server attempts to call a particular handler verb within the database to allow code there to handle this mishap in some appropriate way. If this verb call suspends or returns a true value, then it is considered to have handled the situation completely and no further processing will be done by the server. On the other hand, if the handler verb does not exist, or if the call either returns a false value without suspending or itself is aborted, the server takes matters into its own hands.

First, an error message and a MOO verb-call stack traceback are printed to the player who typed the command that created the original aborted task, explaining why the task was aborted and where in the task the problem occurred. Then, if the call to the handler verb was itself aborted, a second error message and traceback are printed, describing that problem as well. Note that if the handler-verb call itself is aborted, no further `nested' handler calls are made; this policy prevents what might otherwise be quite a vicious little cycle.

The specific handler verb, and the set of arguments it is passed, differs for the two causes of aborted tasks.

If an error is raised and not caught, then the verb-call

 
$handle_uncaught_error(code, msg, value, traceback, formatted)

is made, where code, msg, value, and traceback are the values that would have been passed to a handler in a try-except statement and formatted is a list of strings being the lines of error and traceback output that will be printed to the player if $handle_uncaught_error returns false without suspending.

If a task runs out of ticks or seconds, then the verb-call

 
$handle_task_timeout(resource, traceback, formatted)

is made, where resource is the appropriate one of the strings "ticks" or "seconds", and traceback and formatted are as above.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.10 Matching in Command Parsing

In the process of matching the direct and indirect object strings in a command to actual objects, the server uses the value of the aliases property, if any, on each object in the contents of the player and the player's location. For complete details, see the chapter on command parsing.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.11 Restricting Access to Built-in Properties and Functions

Protected Properties

A built-in property prop is deemed protected if $server_options.protect_prop exists and has a true value. However, no such property protections are recognized if the compilation option IGNORE_PROP_PROTECTED (see section Server Compilation Options) was set when building the server. (It should be noted that enabling property protection has significant performance costs).

Whenever verb code attempts to read (on any object) the value of a built-in property that is protected in this way, the server raises E_PERM if the programmer is not a wizard.

Protected Built-in Functions

A built-in function func() is deemed protected if $server_options.protect_func exists and has a true value. If, for a given protected built-in function, a corresponding verb $bf_func() exists and its ‘x’ bit is set, then that built-in function is also considered overridden, meaning that any call to func() from any object other than #0 will be treated as a call to $bf_func() with the same arguments, returning or raising whatever that verb returns or raises.

A call to a protected built-in function that is not overridden proceeds normally as long as either the caller is #0 or has wizard permissions; otherwise the server raises E_PERM.

Note that you must call load_server_options() in order to ensure that changes made in $server_options take effect.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.12 Creating and Recycling Objects

Whenever the create() function is used to create a new object, that object's initialize verb, if any, is called with no arguments. The call is simply skipped if no such verb is defined on the object.

Symmetrically, just before the recycle() function actually destroys an object, the object's recycle verb, if any, is called with no arguments. Again, the call is simply skipped if no such verb is defined on the object.

Both create() and recycle() check for the existence of an ownership_quota property on the owner of the newly-created or -destroyed object. If such a property exists and its value is an integer, then it is treated as a quota on object ownership. Otherwise, the following two paragraphs do not apply.

The create() function checks whether or not the quota is positive; if so, it is reduced by one and stored back into the ownership_quota property on the owner. If the quota is zero or negative, the quota is considered to be exhausted and create() raises E_QUOTA.

The recycle() function increases the quota by one and stores it back into the ownership_quota property on the owner.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.13 Object Movement

During evaluation of a call to the move() function, the server can make calls on the accept and enterfunc verbs defined on the destination of the move and on the exitfunc verb defined on the source. The rules and circumstances are somewhat complicated and are given in detail in the description of the move() function.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.14 Temporarily Enabling Obsolete Server Features

If the property $server_options.support_numeric_verbname_strings exists and has a true value, then the server supports a obsolete mechanism for less ambiguously referring to specific verbs in various built-in functions. For more details, see the discussion given just following the description of the verbs() function.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated by Roger Crew on March, 27 2010 using texi2html 1.78.