GZOCHID MANUAL-EDITION 0.7

Table of Contents

Next: , Up: (dir)   [Contents][Index]

The gzochid Manual

This manual describes gzochid, the gzochi server.

Copyright © 22 August 2014 Julian Graham.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled “GNU Free Documentation License”.

This reference manual documents gzochid, the server component of the gzochi massively multiplayer online game development framework.

Table of Contents


Next: , Previous: , Up: Top   [Contents][Index]

1 Introduction

gzochid is the server component for the gzochi massively multiplayer online game development framework. It is responsible for hosting the server-side portions of game applications developed against the framework, for managing the data persisted by these applications and provisioning computing resources for their needs at run-time, and for exposing a set of container services that are especially useful for online game development.

gzochid is a container for game server applications the same way that a web container is a container for web applications: It manages the lifecycles of the applications it hosts, routes client requests to application endpoints, and provides services to ease the interaction of the applications with external resources.

This manual expects a familiarity with the Scheme programming language, which is the language used to write applications that can be hosted by gzochid. gzochid uses the GNU GUile extension language platform to provide its Scheme run-time environment; the Guile manual is an excellent resource for users who are new to Scheme or to functional programming in general.

New users of gzochi may wish to pay special attention to the following section of this manual, “Conceptual overview,” which explores some of the rationale for the design of the gzochi framework and the services it provides.


Next: , Previous: , Up: Top   [Contents][Index]

2 Conceptual overview

Developing games that are played over a computer network poses challenges distinct from those that arise from games whose extent is limited to a single process or a single machine. The characteristics of the network link that connects the machines involved the game give rise, by necessity, to some primary constraints on the design of the game: To create a dynamic model of the game state that is shared between the client and the server, those systems must exchange messages, and this process is naturally limited by the rate of message delivery. Will messages be delivered reliably? Is message order guaranteed to be preserved? Answers to these questions will also have an impact on game server architecture.

When multiple players are allowed to interact with a networked game system simultaneously, an additional set of difficulties emerges. How can their interactions with components of the game system be properly synchronized such that each player receives a fair and consistent view of the world? How can this synchronization be scaled to maintain a responsive user interface for up to thousands of simultaneously connected clients?

Some additional background is presented in the following sections. To address these issues, gzochid provides a unified set of software tools, which are described in a subsequent chapter (see Application services).


Next: , Up: Conceptual overview   [Contents][Index]

2.1 Data persistence

If the state of a game is to “outlive” the server process that manages it, the data that makes up the state must be written to non-volatile storage, such as a hard disk. There are many reasons for a server process to terminate. Some shutdowns, such as those performed for system maintenance or upgrades; others are spontaneous—software bugs are inevitable, and whether they cause the server process to terminate outright or leave the game system in an unplayable state, the net effect is the same. When a player’s commitment to an online game can span months or even years, losing their play history can be quite disheartening.

Several questions must be answered in order for persistence to be implemented: How often must data be persisted? If players are notified of changes to game state before these changes are made persistent, then the potential exists for a recovered game state to “erase” progress made by players between the last persistence event and the shutdown of the game. On the other hand, non-volatile storage media are often quite a bit slower than random-access memory, and thus forcing persistence too often can create a bottleneck on game performance. How much of the game state must be persisted at each persistence point to ensure that the entire state can be reconstituted at some later date? For large, complex games, the game state may be so large that persisting the entire state takes so long that even infrequent persistence events must cause the game to “pause.” If only portions of the game state are persisted, then care must be taken to ensure that enough state is persisted to ensure logical consistency between entities within the game.

gzochid addresses these issues with an automatic persistence mechanism that treats game state as an object graph in which updates are tracked and persisted transparently, with full transactional semantics. See Managed records, for more information.


Next: , Previous: , Up: Conceptual overview   [Contents][Index]

2.2 Transactions and atomicity

It is often important that certain sequences of events occur as a unit, such that either every event in the sequence takes place (and players receive notification) or, in the event of an error, none of the events take place—no matter where in the sequence the error arises. One example of this is transferring an object from one the inventory of one player to the inventory of another. Depending on how the transfer is implemented, there may be an interval between the object being taken from the first player but before it is given to the second player. If the execution of game code is interrupted at this point, the object may be destroyed. A similar problem arises if a reference to the object is given to the second player before being removed from the first.

Even when errors are detected, recovery can difficult: It may not be possible to determine what the state of individual connected clients is once they have lost consistency with the server’s model of the game world, and enabling clients to resolve conflicting updates to game state presents significant architectural challenges. In general, once the side effects—e.g, client notifications or persistent changes to data—have been committed, they cannot easily be undone.

gzochid executes all game application code in a transactional context, meaning that the side effects produced by a portion of code are delayed until its successful completion, at which point all of them guaranteed to take effect together; or the side effects are “rolled back” and the block of code is either retried, with no indication to the client that an error occurred, or abandoned. And other portions of code that are concurrently accessing the same bits of data are guaranteed a consistent view of that data for the duration of their execution.


Next: , Previous: , Up: Conceptual overview   [Contents][Index]

2.3 Network communication

The reliable delivery of messages between clients and the server is fundamental to the operation of an online game, but the network communication services provided by most programming languages and operating systems expose game applications to nuanced, unpredictable behaviors. Some communication channels do not guarantee packet delivery; nor is in-order delivery alway ensured. Even if a system promises ordered and reliable ordered delivery of packets, it is difficult to predict their time of delivery.

When a packet of data arrives on the client or server, the bytes it contains must be interpreted, a process that is governed by a shared protocol. The set of possible communications between hosts in an online game is naturally dependent upon the specific mechanics of that game, but some types of messages are likely common to all games: Clients need to establish their identities with the server; the server needs to respond to authentication attempts. The client and server may need messages representing attempts to disconnect or log out of the game gracefully. Some types of messages, which trigger transitions in the state of a client’s connection to the server, are only valid when the connection is in a particular state. What should be the response from the server if it receives a login request from an already-authenticated client in the course of regular gameplay? If there are multiple points in the flow of game execution at which messages can be received, does semantic validation of message content have to be applied at all of them?

Because the state of a network connection is dependent on the state of multiple independent hosts and their operators, it is inherently asynchronous with game state. In the likely case that a protocol message is larger than a single packet, an entire message may not become available all at once, and thus participants in the communication will need to keep a buffer of partial messages while they wait for the remaining bytes. A connection may be interrupted before all of the message’s consituent packets have been delivered, and if the processing of network data is mixed in with the processing of game application logic, recovery from a network failure may be complicated.

There are aspects of multiplayer games for which it is not very important that every player have a view of the world that is consistent with that of every other player. For example, depending on the context, it may not be critical that every player have the same information about the scenery in a particular region—this is information that is related to the game world, but has no bearing on the outcome of the game. There are other elements of gameplay for which it is necessary that all involved players are kept in a consistent state. If some but not all players receive notification of a change that does affect the outcome of the game, not only are they at a strategic disadvantage, but losing synchronization with the server’s model of the world may make it difficult for them to interpet subsequent notifications.

gzochid provides a network management layer and a low-level client-server protocol that work in concert to hide the tricky details of message deliery. Reasonably large messages may be transactionally queued for delivery to the server or its clients, and messages can be addressed to individual clients or to arbitrarily large groups of clients with a single procedure invocation. See Client session management, for information on gzochid’s representation of client connections; See Channel management, for a description of efficient message broadcast services.


Previous: , Up: Conceptual overview   [Contents][Index]

2.4 Concurrent execution

While some portions of a game can be driven entirely by client-generated events, there are often flows of execution that are best managed as “background processes” that proceed independent of any action by a client. Some examples of this type of processing include: Time and weather systems, in which regular changes to the game world take place at scheduled intervals; or the actions of non-player characters that act as autonomous agents within the game world, with a flow of logic that determines their behavior based on various dynamic game states.

As you can infer from these examples, different modes of scheduling and execution are possible for tasks within the same application. Some tasks need to begin executing at predetermined points in the future. Others need to run as soon as CPU time can be allocated to them. Certain tasks, such as those implementing an in-game timer tick, for example, may need to execute on a repeating basis.

This type of asynchronous parallelism could be implemented using a an explicitly threaded execution model, but this approach has some significant limitations. For one, allocating a new thread for every asynchronous bit of processing to be done consumes valuable process memory and CPU cycles, and effectively constrains the amount of work that can be . A thread pool can some of these issues, but few low-level thread libraries include time-based scheduling as part of their thread management APIs—you can specify that some bit of code should run in a separate thread but, but you usually can’t control when it runs or how often it repeats without building some abstractions around the system’s thread primitives.

gzochid provides scheduling and execution services that allow tasks to be queued for immediate or deferred processing, either one time only or repeating on a configurable interval. Furthermore, gzochid provides durability guarantees about scheduled tasks to the effect that tasks that fail with a recoverable error can be retried, and that the universe of scheduled tasks can survive a failure and restart of the application server. See Task scheduling, for more information.


Next: , Previous: , Up: Top   [Contents][Index]

3 Installation

See the INSTALL file included in the gzochid distribution for detailed instructions on how to build gzochid. In most cases, if you have the requisite toolchain and dependences in place, you should simply be able to run

./configure
make
make install

This will install the gzochid executable gzochid (as well as the database tools gzochi-dump, gzochi-load, and gzochi-migrate) to a standard location, depending on the installation prefix—on most Unix-like systems, this will be /usr/local, with executable files being copied to /usr/local/bin. A server configuration file with the default settings will be installed to the /etc directory under the installation prefix—by default, /usr/local/etc.

This configuration file will be processed prior to installation to set references to the gzochid deployment and data directories—where the server looks for deployed games and where it stores game state data, respectively—to locations relative to the installation prefix. See The server configuration file, for more information.


Next: , Previous: , Up: Top   [Contents][Index]

4 Running gzochid

The format for running the gzochid program is:

gzochid option

With no options, gzochid scans its deployment directory looking for game applications, each of which is configured and initialized or restarted depending on its state, and then begins listening for client connections. By default, the monitoring web application is also started.

In the absence of command line arguments, the port numbers on which these servers listen for connections, as well as other aspects of their behavior, are modifiable via a configuration file (see below).

gzochid supports the following options:

--config
-c

Specify an alternate location for the server configuration file.

--help
-h

Print an informative help message on standard output and exit successfully.

--version
-v

Print the version number and licensing information of gzochid on standard output and then exit successfully.


Up: Running gzochid   [Contents][Index]

4.1 The server configuration file

The gzochid server configuration file is usually named gzochid.conf and is installed (and searched for) by default in the /etc/ directory of the installation prefix. It is an .ini-style configuration file, meaning it consists of several named sections of key-value pairs, like so:

[section]

key1 = value1
key2 = value2

The configuration options currently understood by gzochid are as follows, organized by section.

admin

These settings control various aspects of gzochid’s administrative and monitoring functionality.

context.enabled

Set to true to enable the administrative context, which is responsible for collecting and reporting on a variety of statistics about the state of a running gzochid server and its hosted games. Disabling this feature (by setting this key to false) will net a small improvement in process memory consumption and CPU performance.

module.debug.enabled

Set to true to enable the debugging server. Has no effect if ‘context.enabled’ is not true.

module.debug.port

The local port on which the debugging server should listen for incoming telnet connections.

module.httpd.enabled

Set to true to enable the monitoring web server. Has no effect if ‘context.enabled’ is not true.

module.httpd.port

The local port on which the monitoring web server should listen for incoming HTTP connections.

game

These settings control the primary game server module of gzochid.

server.port

The local port on which to listen for incoming TCP connections from gzochi clients.

server.fs.data

The filesystem directory in which to store game state data for hosted game applications. The user associated with the gzochid process must have read and write access to this directory, as the server will attempt to create sub-directories rooted at this location for each game, and will read and write data files in those sub-directories.

server.fs.apps

The filesystem directory to search for deployed game applications. The user associated with the gzochid process must have read and execute access to this directory—but it does not need to be able to write files here.

tx.timeout

The maximum duration, in milliseconds, for time-limited transactions executed on behalf of a game application. Any task or callback whose execution time exceeds this value will fail and be retried (if it has not used up its maximum retries). This setting also bounds the amount of time the container’s data services will wait to obtain a lock for exclusive access to any single datum such as a managed reference; if the wait time expires, the transaction attempting to access the data will be marked for rollback.

By design, this setting has an impact on the task execution throughput of game applications. The longer a task takes to execute, and the more data it accesses as part of its execution, the more constraints it places on the transactional work that can be done concurrent with its execution. As a corollary, the shorter a task’s duration and the less data it accesses, the less risk there is that it will conflict with other tasks. Before increasing this value beyond its default, consider refactoring a failing task to perform fewer operations and access less data.

Certain lifecycle events, such as application initialization, are executed in transactions without time limits; this setting has no effect on the processing of those events.

log

These settings control the system-wide logging behavior of gzochid.

priority.threshold

The lowest severity of log message that will be recorded in the logs (both to console and to the server’s log file). Valid values of this settings are, in order of decreasing severity: ERR, WARNING, NOTICE, INFO, and DEBUG.


Next: , Previous: , Up: Top   [Contents][Index]

5 Application deployment

Game applications hosted by gzochid are discovered by the server when it scans its deployment directory for sub-directories containing game application descriptor files, which are discussed in the following section. If gzochid’s game deployment directory is “/var/gzochid/deploy” (the default), then the server will scan and discover the game descriptor file “/var/gzochid/deploy/my-game/game.xml” on startup.

The other required components of a game application are the Guile Scheme modules that contain the game logic and callbacks. These are typically included in sub-directory trees rooted in the game application directory, but alternate locations to search for modules can be specified in the game application descriptor file.


Up: Application deployment   [Contents][Index]

5.1 The game application descriptor

“game.xml,” the game application descriptor, is an XML document that is deployed as part of a game application and provides game configuration information and metadata to gzochid. It is a rough analog to the “web.xml” descriptor file that accompanies Java web applications. Like “web.xml,” “game.xml” is used by the server to find the locations of the application’s code libraries and the entry points to the application. The game descriptor file must appear in the deployed application’s root directory.

A DTD that can be used to validate the structure of your application descriptors is included in the gzochid source distribution. Some explanation of the semantics of the descriptor file follows.

The application descriptor’s document element is game, and it must include a name attribute that specifies a unique “short name” for the application; among other things, this name will be used to identifier your application in log messages.

The description element allows you to specify as its content some longer, more descriptive text to identify your game. (This text will be displayed in the gzochid monitoring console.)

The load-paths element is a wrapper element for zero or more load-path element, each of which specifies as its content an absolute or relative path to be (temporarily) added to the default Guile %load-path variable, which contains the locations that are searched during module resolution. Note that the game application root directory is always added to the load path, so you can leave the load-paths element empty if your application library tree is rooted at the application root.

Next there are two “lifecycle callbacks” that must be specified, procedures for handling the “initialization” and “logged in” events. Callbacks are specified via a callback element, which has no content but requires the procedure and module arguments which specify a publicly-visible Scheme procedure to be used to handle an event. For example, the following XML snippet:

<callback procedure="handler" module="my-code app handlers" />

...identifies the handler procedure exported from the Guile module (my-code app handlers). Modules are resolved via the configured load paths.

Initialization occurs once per application—even across server restarts—and the initialization callback is passed an R6RS hashtable containing application properties. (In the current release, this table will always be empty.) The logged in callback will be called when a client connects and successfully authenticates, and it will be passed a client session record that can be used to communicate with the connected client.


Next: , Previous: , Up: Top   [Contents][Index]

6 Application services

The follow sections describe the services that gzochid exposes to the applications it hosts. As an application author, you are free to employ or ignore them in whatever proportion you choose, but the expectation is that most non-trivial games will depend heavily on all of the services the container provides.


Next: , Up: Application services   [Contents][Index]

6.1 Transaction management

All game application code that executes within the gzochid container executes in the context of a transaction, meaning that all of its side effects, such as sending messages or modifying data, have the four ACID properties: Atomicity, consistency, isolation, and durability. The services described in the following sections are the primary means by which side effects are achieved in a gzochi application, and all of them participate in the container’s two-phase commit protocol, which verifies that each participant is prepared to commit before issuing the request to do so.

When a transaction commits, the side effects requested from each service by application code are made permanent: Messages are sent to clients, changes to data are saved to the data store. When a transaction fails to commit, each service participating in the commit rolls back any transaction-local state that was created during the lifetime of the transaction.

A transaction may fail to commit for any of several reasons: It may have exceeded the maximum running specified by the tx.timeout setting; it may have attempted to access data in a way that brought it into conflict with another currently-executing transaction; an external resource (such as a network connection) required by the transaction may be unavailable; code executing in a transactional context may exit non-locally. If a transactional task or callback fails to commit but the container determines that it is safe and desirable to re-attempt it, it will automatically be returned to the queue of items eligible for execution. A transactional unit of work that fails in a “retryable” way will be retried up to a configured maximum number of times (3, by default) before being abandoned.


Next: , Previous: , Up: Application services   [Contents][Index]

6.2 Managed records

gzochid exposes its transactional persistence services via flexible, user-defined data structures called “managed records.” A managed record is just like an R6RS record—in fact, a managed record is an R6RS record that has the record-type gzochi:managed-record as its parent—with a few additional rules.

First of all, the fields of a managed record must be annotated to assist the container in persisting them to the data store. This is done via a serialization clause added to every field sub-clause in the managed record definition. The serialization clause gives a reference to the serialization to use to convert the field value to and from a stream of bytes as it is written to and read from the data store. A serialization is a record that provides serializer and deserializer procedures that are called by the container during the persistence phrase for managed records that have been modified in a transaction. The serialization clause may be omitted for fields whose value will always be a managed record. In this case, a built-in managed record serialization will be used. See gzochi io, for more information on serialization.

Second, managed record-type definitions must be nongenerative (unique) with respect to their serialized type. Every managed record type is associated with a symbol (called a “serial UID”) that identifies it to the serialization system, and no two managed record types may share the same serial UID. A record type’s serial UID may be given explicitly, via the serial-uid keyword argument or clause, or one will be selected automatically: By taking the record type’s R6RS uid (if the type is nongenerative) or by taking the record type name.

All managed record types definitions are added to a type registry, from which they are looked up by their serial UIDs during serialization and deserialization. Record types that do not specify a target type registry via the type-registry keyword argument or clause will be added to a default type registry. The (gzochi data) data module exports procedures that allow developers to create new type registries, but this is not typically useful outside the scope of a database migration, since during normal operation of the gzochid container, only the default type registry is used. See Migrating data, for more information on data migration.

For parity with the R6RS record libraries, the gzochid Scheme API provides both syntactic and procedural facilities for working with managed records. See gzochi data, for more information on creating managed records.


Next: , Previous: , Up: Application services   [Contents][Index]

6.3 Data binding and storage

gzochid provides a few different ways of accessing data persisted as managed records. You can access persistent data implicitly, in the form of a managed record used as a callback for a lifecycle event (e.g., client messages); or you can bind managed objects to names for explicitly retrieval. In either case, the container will also manage the persistence of managed records reachable from the root record—that is to say, gzochid knows when a field in one managed record contains a reference to another managed record and only persists the portions of the object graph that change during the execution of application code.

Like the rest of the operations provided by the container, access to data follows transactional semantics. Any single flow of execution within an application is guaranteed a consistent view of data over the lifetime of its execution, and the set of changes it makes to data during this lifetime will be persisted together or not at all. These operations are also subject to transactional constraints, such as the requirement that they complete within a configured timeout and that they not conflict with operations accessing the same data in other transactions. If these constraints are violated, the operation will fail and the task will be retried or abandoned.

Bindings can be manipulated using the gzochid:set-binding!, gzochid:get-binding and gzochid:remove-binding! procedures. For example, the following code snippet introduces a new binding that refers to a field of the managed record obj:

(define obj (gzochi:get-binding "my-object"))
(gzochi:set-binding! "f" (my-object-field obj))

Note that the container tracks references to managed records such that at any subsequent point (provided the bindings above are not mutated), the following expression will evaluate to #t:

(eq? (my-object-field (gzochi:get-binding "my-object"))
     (gzochi:get-binding "f"))

See gzochi data, for more information.


Next: , Previous: , Up: Application services   [Contents][Index]

6.4 Client session management

A connected and authenticated user is exposed to game code in the form of a client session, a managed record that can be used to manipulate the state of that user. Messages may be queued transactionally for delivery to individual client sessions or to groups of sessions (see below); sessions can be explicitly disconnected; and handlers may be registered for session-related events, such as incoming messages and client-side disconnections.

Because client sessions are managed records, they can be used any place in game application code that managed records may be used, such as automatically serialized fields of other managed records or as the data for an event handler. See gzochi client, for more information.


Next: , Previous: , Up: Application services   [Contents][Index]

6.5 Channel management

Message broadcasting is a pattern that appears frequently in massively multiplayer game development. There may be a logical set of players that should be managed and addressed by the server as a group for the purposes of messaging. This group may include every player in the game, in the case of system notifications that need to be sent globally; or it may correspond to a logical grouping arising from game logic, such as broadcasting messages only to players gathered in a particular room or region.

gzochid addresses this case by providing an abstraction for managing communication with arbitrarily large numbers of grouped client sessions. gzochid “channels” are managed records, and, like client sessions, can be used any place in game application code that supports managed records. See gzochi channel, for more information.


Next: , Previous: , Up: Application services   [Contents][Index]

6.6 Task scheduling

gzochid provides an explicit task scheduling API that is used in place of other mechanisms for asynchronous processing, such as threads. A task in gzochid is a callback similar to the ones invoked for application lifecycle events, such as initialization; it specifies a procedure to execute (qualified by a Guile module name), accompanied optionally by an arbitrary managed record to supply contextual information.

The task API provides several options for task scheduling. Scheduling is a transactional operation with respect to the code doing the scheduling, so the earliest a scheduled task can run is following a successful commit of the transactional code (a task or a lifecycle callback) that scheduled it. Additionally, the execution of a task may be delayed by a user-specified number of milliseconds. If a task needs to run more than once, you can reschedule it explicitly as part of its execution, or you can schedule it as a periodic task. Periodic tasks are automatically rescheduled to run on a repeating basis with each execution following the previous one after a specified number of milliseconds.

Task scheduling is persistent, such that the schedule of pending tasks will survive a restart of the gzochid container. See gzochi task, for more information.


Previous: , Up: Application services   [Contents][Index]

6.7 Transactional logging

Because gzochid executes application code transactionally, any side effects (e.g., queued messages, scheduled tasks) will be rolled back if the enclosing transaction fails to commit. And a single task may be executed several times before committing successfully if there is heavy contention for data or other resources. As such, if log messages are written non-transactionally, it can be difficult to use them to trace application events.

The gzochid container provides an API for writing log messages that will only be flushed on a successful commit. For example, if the following segment of transactional code is attempted and rolled back twice before committing:

(display "A log message.") (newline)
(gzochi:log-info "A transactional log message.")

...the output might include:

A log message.
A log message.
A log message.
A transactional log message.

See gzochi log, for more information.


Next: , Previous: , Up: Top   [Contents][Index]

7 Communication protocol

The protocol used for gzochi client-server communication is documented below. Note that this description is provided merely for the curious; the responsibility of gzochi game developers is to handle the messages that this underlying protocol delivers—in the form of byte arrays—to the client or server. The format and encoding of these byte arrays is left up to game developers to determine.

The low-level protocol described below conforms to a general pattern of a two-byte prefix encoding the length of the message payload, if any, followed by an “opcode” indicating the purpose of the message. (The opcode byte is not included in the length prefix.) The maximum size of a message body sent between components in a gzochi game is thus 65535. Note that this is not necessarily the size of the packet that delivers the message; the client and server may break a larger protocol up into smaller packets that are re-assembled by the recipient. (Naturally, this behavior is transparent to gzochi game developers.)

The following table lists the message types and structures that make up the low-level gzochi byte protocol.

LOGIN_REQUEST (0x10)

A request from a client to login to a gzochid application endpoint. The message payload must include the UTF-8-encoded endpoint name followed by a null byte (0x0), followed by a byte sequence that will be passed uninterpreted to the authentication plugin configured for the specified endpoint.

LOGIN_SUCCESS (0x11)

A message from the server indicating that a LOGIN_REQUEST was received and that authentication was successful. There is no message payload for this message.

LOGIN_FAILURE (0x12)

A message from the server indicating that a LOGIN_REQUEST was received but that the login could not be completed successfully.

LOGOUT_REQUEST (0x20)

A request from an authenticated client to perform a graceful disconnect from a gzochid server. There is no message payload for this message.

LOGOUT_SUCCESS (0x21)

A message from the server indicating that a LOGOUT_REQUEST message was received. There is no message payload for this message. Following the dispatch of this message, the server will close the client’s socket connection.

SESSION_DISCONNECTED (0x30)

A message from the server notifying the client that the server will be immediately closing the client’s socket connection. There is no message payload for this message.

SESSION_MESSAGE (0x31)

A message that may be sent from the server or the client that carries a message to be delivered, respectively, to a gzochid game application endpoint or to client application code. The message payload follows the opcode as a byte sequence that will be passed uninterpreted to a handler registered by game code.


Next: , Previous: , Up: Top   [Contents][Index]

8 User authentication

gzochid employs a pluggable authentication mechanism to allow each game application endpoint to specify an authentication scheme that meets its security requirements. Authentication plugins are built and distributed as shared libraries and installed to the “gzochid” directory under the library directory of the installation prefix; for example, ‘/usr/local/lib/gzochid’. This directory is scanned on server startup and any discovered plugins are dynamically loaded. Plugins are configured for use by individual game applications via the auth element in the game descriptor file. Nested property elements can be used pass application-specific configuration to the plugin like so:

  <auth type="password_file">
    <property name="path" value="/path/to/passwords.txt" />
  </auth>

The plugins currently available are described in the following sections.


Next: , Up: User authentication   [Contents][Index]

8.1 Pass-thru authentication

The pass-thru authentication plugin performs no actual authentication—all login requests are accepted—and the contents of the byte sequence included as part of the login request are interpeted as a UTF-8-encoded text string and are used as the name portion of the identity for the resulting client sessions.

Note that pass-thru authentication is built into the gzochid server container and does not need to be loaded or otherwise configured. This scheme is what will be used by applications that do not explicitly specify another authentication plugin.


Next: , Previous: , Up: User authentication   [Contents][Index]

8.2 Password file authentication

The password file authentication plugin allows a game application to authenticate users against a list defined in a text file. The location of this file is given by the required “path” property described below. Each row of the password file gives a username, followed by the equals (“=”) character, followed by a password, and terminated by a newline.

testuser=password123

This plugin interprets the byte string passed by the client during authentication as follows: All characters up to (but not including) a NULL byte (0x00) are interpreted as a username and are used as the name portion of the identity for the client session following successful authentication; all characters following this NULL byte are interpreted as a password and must match the password component of the row corresponding to the username in the password file.

To use the password file plugin to authenticate clients of an application, specify “password_file” as the value of the type attribute in an auth element in the application’s game descriptor file. This plugin accepts the following configuration properties.

PropertyRequired?Description
pathtrueThe absolute path to the password file.

Previous: , Up: User authentication   [Contents][Index]

8.3 Kerberos v5 authentication

The Kerberos v5 authentication plugin allows a game application to act as a host-based service in a Kerberos authentication realm, and verify tickets generated for a user by a ticket granting server. The contents of the byte sequence included as part of the login request are interpeted as an AP-REQ request and passed to the krb5_rd_req Kerberos API function. The name portion of the identity created for the resulting client session is obtained by calling the krb5_unparse_name function on the parsed request ticket.

See the README file included in the gzochi source distribution for instructions for building the Kerberos authentication plugin and linking with the Kerberos libraries. To use the Kerberos plugin to authenticate the users of an application, specify “krb5” as the value of the type attribute in an auth element in the application’s game descriptor file. This plugin accepts the following configuration properties.

PropertyRequired?Description
service_namefalseThe service principal name to use (defaults to “gzochi”).
keytab_filefalseThe absolute path to the keytab file to be used by the service.

The configured service principal name must match the target service principal for which the client generated the ticket. The following sample code extracts the credentials for the current user principal from a local credentials cache and encodes a request that can be read by the Kerberos authentication plugin. It may be useful as a basis for building clients of applications that use this plugin.

#include <krb5.h>
#include <stddef.h>

void
authenticate ()
{
  krb5_auth_context auth_context;
  krb5_ccache ccache;
  krb5_context k5_ctx;
  krb5_data outbuf;

  krb5_init_context (&k5_ctx);  
  krb5_cc_default (k5_ctx, &ccache);
  krb5_auth_con_init (k5_ctx, &auth_context);
  krb5_mk_req (k5_ctx, &auth_context, 0, "gzochi", 
               "localhost.localdomain", NULL, ccache, &outbuf);

  /* The contents of outbuf.data should be sent as the payload of an
     authentication request to the gzochid server. */

  ...
}

Note that because of the one-way nature of the gzochi client authentication protocol, game applications cannot prove their identity to an authenticating client, and the AP_OPTS_MUTUAL_REQUIRED flag should not be used by clients.


Next: , Previous: , Up: Top   [Contents][Index]

9 Monitoring

When enabled, the gzochid administrative module collect various bits of statistical information and makes resources related to active game applications available for reporting. The module’s architecture supports the registration of sub-modules—described below—that expose this information in different ways.

The monitoring web server

When the monitoring web server is enabled, it listens for HTTP connections on its configured port (8080 by default) and serves HTML pages with information about the server and the games it runs. In particular, a browser for the game applications’ data stores is provided, which renders the contents of the store in a format similar to a “hex editor” application. There are two ways of accessing the data store through the monitoring web server. The binding list can be accessed by visiting the following URL in a web browser:

http://localhost:8080/app/my-game/names/

Provided the server is running on the local machine and listening on port 8080, the URL above will return a list of bound names in the data store for ‘my-game’, with links to the data bound to each name. For a lower-level view of the store, you can visit the URL:

http://localhost:8080/app/my-game/oids/

...which serves a list of all of the managed records in the store, indexed by the internal object identifiers the container uses to track them.

Future plans for the monitoring web server include per-game statistical reporting on data such as transactional throughput and client session volume.


Next: , Previous: , Up: Top   [Contents][Index]

10 Remote debugging

Application code deployed to gzochid executes in a context with fairly unique characteristics. Even when unit tests—which should be the primary means of detecting and preventing bugs—have been written, situations present themselves in which inspecting the state of a running application is the most effective way to troubleshoot an error or incorrect behavior. To this end, gzochid offers a remote debugging interface that allows a developer to connect to a running gzochid instance using a telnet client and to evaluate Scheme code within the context of an application hosted by that instance.

The debugging server listens on the port specified by the module.debug.port setting in the server configuration file. When a client connects to the debug port, a new Scheme REPL (Read Evaluate Print Loop) is launched and associated with a fresh “sandbox” environment in which the (guile), (gzochi), and (gzochi admin) modules have been pre-loaded. A user can interact with the debugger using the full complement of Scheme syntax and Guile REPL commands (e.g., ,pretty-print). A typical debugging session might have the form:

julian@navigator:~$ telnet localhost 37146
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GNU Guile 2.0.6.31-2446f
Copyright (C) 1995-2012 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@(#{ g109}#)> (gzochi:applications)
$1 = (#<r6rs:record:gzochi:application-context>)
scheme@(#{ g109}#)> (gzochi:with-application (car $1) 
  (lambda () (gzochi:get-binding "scoreboard")))
$2 = #<r6rs:record:my-game:scoreboard>

Next: , Previous: , Up: Top   [Contents][Index]

11 Application design with gzochid

As the introduction to this manual explains, gzochid is a server container for gzochi game applications. To take full advantage of this architecture, it may be useful to understand the way gzochid interacts with your application.

There are several entry points to a game application. When an application is started for the first time, its initialization procedure is invoked. This procedure is responsible for setting up any global state required by the game and creating any managed record bindings that must be present before client connections can be accepted. The game application descriptor also registers a callback procedure that is invoked when a new, authenticated client connection is established. See the

The following paragraphs are describe some best practices for game programming in gzochid.

Avoid top-level Scheme bindings for application state.

Modifications to data accessed via bindings in the top-level module environment (i.e., variables created using define) cannot be tracked by gzochid, whether the data is part of a managed record or not. To share mutable state between different execution paths in a game application, bind the state to a name with the gzochid binding API and retrieve and modify its value—creating a local definition via a let form, perhaps—within the scope of the code that needs it. There is no need to synchronize access to data managed by gzochid; the container will prevent race conditions by rolling back task execution as necessary.

Express concurrency through task scheduling.

Likewise, you should never need to explicitly launch a thread to handle a bit of application work. Scheduling work via gzochid’s task API ensures that it is executed in the proper transactional context and that it will be transparently rescheduled following a non-fatal error and that its status will survive the failure and restart of the container.

Limit task scope.

The longer a task runs and the more resources it accesses, the more likely it is to disrupt the behavior of other simultaneously-executing tasks, and the less likely its transaction will be able to commit successfully—tasks whose execution time exceeds the configured value of tx.timeout will be aborted or otherwise prevented from committing. If there is a lot of work to be done or there are many objects to be modified, try breaking a large task into a series of smaller tasks, each of which does a portion of the work and then schedules the next portion to run as soon as possible.

Avoid external side effects.

Because application tasks are executed within the scope of a transaction that may be rolled back and re-attempted arbitrarily many times, any side effects these tasks have that are not managed by gzochid may be “played back” multiple times along with the rest of the task’s execution, possibly duplicating their impact.


Next: , Previous: , Up: Top   [Contents][Index]

12 Scheme API reference

The following sections describe the Scheme API exposed to the server-side components of gzochi applications by the gzochid container. The API consists of a set of use-specific R6RS libraries that can be imported independently or all together via the (gzochi) composite library.


Next: , Up: Scheme API reference   [Contents][Index]

12.1 gzochi admin

The (gzochi admin) module exports procedures and data types that enable introspection of game application state and the execution of Scheme code within the context of a running game application.

These functions are intended for use with the remote debugging interface provided by the gzochid container. Because their use cases as part of deployed application code are not well defined, they are not exported from the (gzochi) composite library.

Scheme Procedure: gzochi:applications

Returns a list of application context objects representing the set of applications running in the container.

Scheme Procedure: gzochi:current-application

Returns an application context representing the “current” application, e.g. as set by gzochi:with-application, or #f if the current application has not been set.

Scheme Procedure: gzochi:application-context? obj

Returns #t if obj is an application context object (as returned by gzochi:applications or gzochi:current-application, #f otherwise.

Scheme Procedure: gzochi:application-context-name context

Returns the name of the application represented by the application context object context.

Scheme Procedure: gzochi:with-application context thunk

Calls the zero-argument procedure thunk with the current application set temporarily to the application represented by the application context object context. The value yielded by thunk is returned.

The application that was current before calling gzochi:with-application (or #f if there was none) will be restored when thunk exits locally or non-locally.


Next: , Previous: , Up: Scheme API reference   [Contents][Index]

12.2 gzochi app

The (gzochi app) module exports procedures and data types common to other components of the API.

Callbacks are serializable references to Scheme procedures with some optionally associated data. They are used in several places to indicate actions to be taken by game application code upon notification of an asynchronous event such as a new autheticated client connection. Procedures are represented within callbacks as Scheme symbols; the modules that export them are represented as lists of symbols. The data associated with a callback—if any—must take the form of a managed record, so that its lifecycle may be managed by the container.

Scheme Procedure: gzochi:make-callback procedure module [data]

Constructs a new gzochi:callback with the specified procedure, module, and optional data.

Scheme Syntax: g:  (module ...) procedure [data]
Scheme Syntax: g:  procedure [data]

Expands to an invocation of gzochi:make-callback with the specified procedure, module, and optional data. If module is omitted, the module in which procedure is defined will be used.

Scheme Procedure: gzochi:callback? obj

Returns #t if obj is a gzochi:callback, #f otherwise.

Scheme Procedure: gzochi:callback-module callback

Returns the module specification for the gzochi:callback callback as a list of symbols.

Scheme Procedure: gzochi:callback-procedure callback

Returns the procedure name for the gzochi:callback callback as a symbol.

Scheme Procedure: gzochi:callback-data callback

Returns the managed record that encapsulates the data for the gzochi:callback callback or #f if the callback was created without any.

Scheme Variable: %gzochi:application-root

The value of this fluid is set to the root deployment directory of the application to which the currently executing code belongs. (By default, this is “/var/gzochid/deploy/[application name]”.)


Next: , Previous: , Up: Scheme API reference   [Contents][Index]

12.3 gzochi channel

The (gzochi channel) library exports procedures that are useful for managing client communication channels.

Scheme Procedure: gzochi:create-channel name

Creates and returns a new channel bound to the string specified by name. A &gzochi:name-exists condition will be raised if there is already a channel with that name.

Scheme Procedure: gzochi:get-channel name

Returns the channel bound to the specified string name, which must have been created previously via a call to gzochi:create-channel. A &gzochi:name-not-bound condition will be raised if there is no channel wit

Scheme Procedure: gzochi:channel? obj

Returns #t if obj is a channel, #f otherwise.

Scheme Procedure: gzochi:channel-name channel

Returns the name of the channel channel as a string.

Scheme Procedure: gzochi:join-channel channel session

Adds the client session session to the channel channel. session is guaranteed to receive any messages successfully committed following the successful commit of the join operation.

Scheme Procedure: gzochi:leave-channel channel session

Removes the client session session from the channel channel. session is guaranteed not to receive any messages committed following the successful commit of the leave operation.

Scheme Procedure: gzochi:send-channel-message channel msg

Enqueues a message to be sent, in the form of the bytevector msg, to all client sessions that are members of the channel channel at the time this procedure is called.

Scheme Procedure: gzochi:close-channel channel

Destroys the channel channel, unbinding its associated name and removing all constituent client sessions.


Next: , Previous: , Up: Scheme API reference   [Contents][Index]

12.4 gzochi client

The (gzochi client) library provides procedures that are useful for working with individual client sessions. See (gzochi channel), for functionality related to groups of client sessions.

Client sessions are managed records; as such, you may store a session as the value of fields in other managed records or as the data for tasks or other callbacks. When a client is disconnected, the session record is removed from the data store, and attempts to access it will result in a &gzochi:object-removed condition being raised.

Scheme Procedure: gzochi:client-session? obj

Returns #t if obj is a client session record, #f otherwise.

Scheme Procedure: gzochi:client-session-name session

Returns the identity associated with the session session as a string. The game’s authentication plugin is responsible for setting the session’s identity.

Scheme Procedure: gzochi:send-message session msg

Enqueues a message to be sent, in the form of the bytevector msg, to the client session session.

Client session listeners are managed records that are used by the gzochid container to notify game application code of events related to client sessions. A listener is returned from the callback for the logged in event to indicate a successful login handshake (#f may be returned instead to signal a login failure.) This listener must in turn be configured with two gzochi:callback objects, one to be invoked when a new message is received from the spcified session, the other to be invoked when the session disconnects from the server.

Managed Record Type: gzochi:client-session-listener

The record type, for introspection or use as a base type.

Scheme Procedure: gzochi:make-client-session-listener received-message disconnected

Constructs a new gzochi:client-session-listener with the specified gzochi:callback objects received-message and disconnected, which will be invoked, respectively, when a message is received from a client and when a client disconnects from the server.

Scheme Procedure: gzochi:client-session-listener? obj

Returns #t if obj is a gzochi:client-session-listener, #f otherwise.

Scheme Procedure: gzochi:client-session-listener-received-message listener

Returns the gzochi:callback registered with the gzochi:client-session-listener listener for handling received messages.

Scheme Procedure: gzochi:client-session-listener-disconnected listener

Returns the gzochi:callback registered with the gzochi:client-session-listener listener for handling session disconnection.


Next: , Previous: , Up: Scheme API reference   [Contents][Index]

12.5 gzochi conditions

The (gzochi conditions) library exposes condition types and related procedures for conditions that may be raised during the execution of game application code.

A &gzochi:name-exists condition is raised in contexts in which an attempt is being made to introduce a new binding, but the target name is already bound.

Condition Type: &gzochi:name-exists

The condition type, for introspection or use as a base type for other conditions.

Scheme Procedure: gzochi:make-name-exists-condition name

Contructs a new &gzochi:name-exists condition for the specified name string name.

Scheme Procedure: gzochi:name-exists-condition? obj

Returns #t of obj is a &gzochi:name-exists condition, #f otherwise.

Scheme Procedure: gzochi:name-exists-condition-name cond

Returns the name associated with the specified &gzochi:name-exists condition cond.

A &gzochi:name-not-bound condition is raised in contexts in which a non-existent named binding is looked up.

Condition Type: &gzochi:name-not-bound

The condition type, for introspection or use as a base type for other conditions.

Scheme Procedure: gzochi:make-name-not-bound-condition name

Contructs a new &gzochi:name-not-bound condition for the specified name string name.

Scheme Procedure: gzochi:name-not-bound-condition?

Returns #t of obj is a &gzochi:name-not-bound condition, #f otherwise.

Scheme Procedure: gzochi:name-not-bound-condition-name cond

Returns the name associated with the specified &gzochi:name-not-bound condition cond.

A &gzochi:object-removed condition is raised in contexts when a reference to a managed record is accessed after the record has been removed. This may happen for a number of reasons: A client session record used as a field value or binding and which is subsequently disconnected; a named binding whose target value is explicitly removed; or a managed record used as a value that is accessed after it is has been explicitly removed.

Condition Type: &gzochi:object-removed

The condition type, for introspection or use as a base type for other conditions.

Scheme Procedure: gzochi:make-object-removed-condition

Contructs a new &gzochi:object-removed condition.

Scheme Procedure: gzochi:object-removed-condition? obj

Returns #t of obj is a &gzochi:object-removed condition, #f otherwise.

A &gzochi:no-current-application condition is raised when an operation requiring an application context is attempted and none is present. This happens most frequently because of user error in an interactive remote debugging session—for example, a call to a transaction-aware API function that is not wrapped in an invocation of gzochi:with-application.

Condition Type: &gzochi:no-current-application

The condition type, for introspection or use as a base type for other conditions.

Scheme Procedure: gzochi:make-no-current-application-condition

Contructs a new &gzochi:no-current-application condition.

Scheme Procedure: gzochi:no-current-application-condition?

Returns #t of obj is a &gzochi:no-current-application condition, #f otherwise.

A &gzochi:transaction-aborted condition is raised when a transactional operation is attempted and the transaction bound to the current thread has been found to be in an inconsistent state—that is to say, it has been rolled back or marked for rollback.

Although this condition will almost aways be raised in a non-continuable way, aborted transactions are an expected part of the control flow of a gzochi game application. A transaction may be aborted for a number of reasons; the code executing as part of the transaction may have accessed data in a way that brought it into conflict with code executing as part of another transaction, or its execution time may have exceeded a configured threshold and the scheduler has pre-emptively aborted its transaction to prevent it from interfering with other transactions.

A &gzochi:transaction-aborted condition does not typically require explicit handling. Rather, it is best to allow the code that triggered the condition to exit non-locally; gzochid’s task scheduler will observe the state of the transaction upon exit and reschedule the task or callback accordingly.

Condition Type: &gzochi:transaction-aborted

The condition type, for introspection or use as a base type for other conditions.

Scheme Procedure: gzochi:make-transaction-aborted-condition

Contructs a new &gzochi:transaction-aborted condition.

Scheme Procedure: gzochi:transaction-aborted-condition?

Returns #t if obj is a &gzochi:transaction-aborted condition, #f otherwise.

A &gzochi:transaction-retry condition is raised when a transactional operation or an interaction with the gzochi API fails but is safe to retry and worth retrying because it might succeed on a subsequent execution attempt. This condition is often raised as a composite condition with a &gzochi:transaction-timeout condition when a task’s execution times out. The container’s Scheme interface recognizes this condition type, and the container uses it as part of determining whether to reschedule or abandon a task.

Application code may raise this condition explicitly, so as to release resources if it can determine ahead of time that the current transaction will not be able to commit.

Condition Type: &gzochi:transaction-retry

The condition type, for introspection or use as a base type for other conditions.

Scheme Procedure: gzochi:make-transaction-retry-condition

Constructs a new &gzochi:transaction-retry condition.

Scheme Procedure: gzochi:transaction-retry-condition?

Returns #t if obj is a &gzochi:transaction-retry condition, #f otherwise.

A &gzochi:transaction-timeout condition is raised when a transactional operation takes longer than the time remaining for the current transaction to run, or when the current transaction attempts a transactional operation after its allotted running time has elapsed.

Condition Type: &gzochi:transaction-timeout

The condition type, for introspection or use as a base type for other conditions.

Scheme Procedure: gzochi:make-transaction-timeout-condition

Constructs a new &gzochi:transaction-timeout condition.

Scheme Procedure: gzochi:transaction-timeout-condition?

Returns #t if obj is a &gzochi:transaction-timeout condition, #f otherwise.


Next: , Previous: , Up: Scheme API reference   [Contents][Index]

12.6 gzochi data

The (gzochi data) library exports the data structures and procedures that make up gzochid’s data storage and serialization API. As discussed in a previous section, managed records are the foundation of any game application’s interaction with container’s data services. The syntactic and procedural APIs for managed records are discussed below.

Note that because managed records are implemented on top of R6RS records, they may be treated as such for the purposes of the procedures in the (rnrs records inspection) library.

Scheme Syntax: gzochi:define-managed-record-type name-spec record-clause*

Defines a new managed record type, introducing bindings for a record-type descriptor, a record constructor descriptor, a constructor procedure, a record predicate, and managed accessor and mutator procedures for the new managed record type’s fields.

The structure of name-spec and the record-clause sub-forms are the same as in the R6RS define-record-type, with the following exceptions:

First, each field definition that appears in a fields declaration of a record-clause sub-form of a managed record definition may include a serialization specification that provides the serialization to use for the field when it is marshalled to or from persistent storage. This specification has the form (serialization s), where s is a gzochi:serialization record. If the serialization specification is omitted, the container will use a default serialization that requires all field values to be managed records themselves or #f.

A custom serial UID may be specified by adding a serial-uid clause as one of the record-clause sub-forms. This UID will be used to register the record type definition in the default type registry, or in the registry specified by the type-registry clause, if one is provided. Custom serial UIDs and non-default type registries are mainly useful when implementing migration processes. See Migrating data, for more information.

Scheme Syntax: gzochi:managed-record-type-descriptor record-name

Evaluates to the managed record-type descriptor associated with the type specified by record-name.

Scheme Syntax: gzochi:managed-record-constructor-descriptor record-name

Evaluates to the managed record-constructor descriptor associated with the type specified by record-name.

Scheme Procedure: gzochi:make-managed-record-type-descriptor name parent uid sealed? opaque? fields #:serial-uid serial-uid #:type-registry type-registry

Returns a new record-type descriptor for the managed record with the specified properties, which have the same semantics as they do when passed to R6RS’s make-record-type-descriptor, with the exceptions that the field descriptors in fields may contain serialization specifiers as described above, and that the optional keyword arguments #:serial-uid and #:type-registry may be present and have the effect described above.

Scheme Procedure: gzochi:managed-record-accessor mrtd k

Returns the managed record field accessor procedure for the kth field of the managed record-type descriptor mrtd.

Scheme Procedure: gzochi:managed-record-mutator mrtd k

Returns the managed record field mutator procedure for the kth field of the managed record-type descriptor mrtd. An &assertion condition will be raised if this field is not mutable.

Scheme Procedure: gzochi:managed-record-constructor mrcd

Returns a constructor procedure for the managed record constructor descriptor mrcd. This procedure returns the same value as the record-constructor procedure in the (rnrs records procedural) library.

Scheme Procedure: gzochi:managed-record-predicate mrtd
Scheme Procedure: gzochi:managed-record-type-name mrtd
Scheme Procedure: gzochi:managed-record-type-parent mrtd
Scheme Procedure: gzochi:managed-record-type-uid mrtd

These procedures return the same values as their counterparts in the (rnrs records procedural) library.

Scheme Procedure: gzochi:make-managed-record-type-registry
Scheme Procedure: gzochi:managed-record-type-registry?

A constructor and type predicate for managed record type registries, which can be used to control the visibility of managed record types in different contexts; in particular, across different schemas during a database migration. gzochi:make-managed-record-type-registry constructs a new type registry object. gzochi:managed-record-type-registry? returns #t if obj is a managed record type registry, #f otherwise.

Scheme Procedure: gzochi:managed-record? obj

Returns #t if obj is a managed record, #f otherwise.

Scheme Procedure: gzochi:managed-record-rtd mr

Returns the record-type descriptor for mr. This procedure returns the same value as the record-rtd procedure in the (rnrs records procedural) library.

References to managed records within an object graph of other managed records will be tracked transparently by the container. The following procedures can be used to explicitly store and retrieve references to managed records by name.

Scheme Procedure: gzochi:get-binding name

Returns the managed record associated with the strig name name. A &gzochi:name-not-bound condition will be raised if there is no binding for name.

Scheme Procedure: gzochi:set-binding! name object

Creates an association between the string name and object, which must be a managed record, replacing any previous binding that may exist for name.

Scheme Procedure: gzochi:remove-binding! name

Removes the binding for the string name. A &gzochi:name-not-bound condition will be raised if there is no binding for name. Note that this procedure only removes the association between name and a managed record; to remove the record itself, you must call gzochi:remove-record!.

Many of the operations provided by (gzochi data) are supported only for managed records. For example, you cannot use gzochi:set-binding! to store a primitive value; you must first “wrap” that value as a field in a managed record type that includes information about how it should be serialized. In lieu of creating distinct managed record types to wrap every unmanaged type that needs to be stored, the procedures below are provided to support the use of the generic gzochi:managed-serializable type that encapsulates the serialization information for unmanaged types.

Scheme Procedure: gzochi:make-managed-serializable value serializer-callback deserializer-callback

Constructs a new gzochi:managed-serializable object with the specified value. The serializer-callback and deserializer-callback arguments must be gzochi:callback instances specifying procedures to be used or serialization and deserialization, respectively.

Scheme Procedure: gzochi:managed-serializable? obj

Returns #t if obj is a managed serializable record, #f otherwise.

Scheme Procedure: gzochi:managed-serializable-value ms

Returns the value wrapped by the managed serializable record ms.

Compound data types such as vectors and hash tables are necessary components of any non-trivial application, but designing structures that support highly concurrent access to and modification of their contents is challenging. The following API describes “managed” implementations of R6RS vectors and hash tables, which partition their elements such that conflicts between transactions accessing different elements of the same container are minimized. For applications that require access to sequentially-ordered elements and need the container to resize itself as elements are added or removed, a managed sequence type is provided which features an API based on the SRFI-44 collections proposal (http://srf.schemers.org/srfi-44/srfi-44.html).

Scheme Procedure: gzochi:make-managed-vector len

Returns a newly allocated managed vector of len elements. The initial contents of each position is set to #f.

Scheme Procedure: gzochi:managed-vector #:key serializer deserializer #:rest arg ...

Returns a newly allocated managed vector composed of the given arguments. If any vector element is not a managed record, the keyword arguments #:serializer and #:deserializer must be given (in the form of gzochi:callback records), and managed serializable wrappers will be generated to hold any unmanaged elements.

Scheme Procedure: gzochi:managed-vector?

Returns #t if obj is a managed vector, #f otherwise.

Scheme Procedure: gzochi:managed-vector-ref vec k

Returns the contents of position k of vec. k must be a valid index of vec.

Scheme Procedure: gzochi:managed-vector-set! vec k obj #:key serializer deserializer

Stores obj at position k of vec. k must be a valid index of vec. The value returned by gzochi:managed-vector-set! is unspecified. If obj is not a managed record, the keyword arguments #:serializer and #:deserializer must be given (in the form of gzochi:callback records), and a managed serializable wrapper will be generated to hold obj.

Scheme Procedure: gzochi:managed-vector-length vector

Returns the number of elements in vector as an exact integer.

Scheme Procedure: gzochi:managed-vector->list v

Return a newly allocated list composed of the contents of v.

Scheme Procedure: gzochi:make-managed-hashtable hash-callback equiv-callback

Constructs a new hash table that uses the procedure specified by the gzochi:callback arguments equiv-callback to compare keys and hash-callback as a hash function. equiv-callback must specify a procedure that accepts two arguments and returns a true value if the are equivalent, #f otherwise, hash-callback a procedure that accepts one argument and returns a non-negative integer.

Scheme Procedure: gzochi:managed-hashtable?

Returns #t if obj is a managed hash table, #f otherwise.

Scheme Procedure: gzochi:managed-hashtable-size hashtable

Returns the number of keys currently in the managed hash table hashtable.

Scheme Procedure: gzochi:managed-hashtable-ref hashtable key default

Returns the value associated with key in the the managed hash table hashtable or default if none is found.

Scheme Procedure: gzochi:managed-hashtable-set! hashtable key obj #:key key-serializer key-deserializer value-serializer value-deserializer

Associates the key key wth the value obj in the managed hash table hashtable, and returns an unspecified value.

If key is not a managed record, the keyword arguments #:key-serializer and #:key-deserializer must be given (in the form of gzochi:callback records), and a managed serializable wrapper will be generated to hold key. Likewise, if obj is not a managed record, #:value-serializer and #:value-deserializer must be provided.

Scheme Procedure: gzochi:managed-hashtable-delete! hashtable key

Removes any association found for the key key in the hash table hashtable, and returns an unspecified value.

Scheme Procedure: gzochi:managed-hashtable-contains? hashtable key

Returns #t if the managed hash table hashtable contains an association for the key key, #f otherwise.

Scheme Procedure: gzochi:managed-hashtable-update! hashtable key proc default #:key key-serializer key-deserializer value-serializer value-deserializer

Associates with key in the managed hash table hashtable the result of calling proc, which must be a procedure that takes one argument, on the value currently associated with key in hashtable—or on default if no such association exists.

If key is not a managed record, the keyword arguments #:key-serializer and #:key-deserializer must be given. If proc returns something that is not a managed record—or if default becomes the value of the association—then #:value-serializer and #:value-deserializer must be provided.

Scheme Procedure: gzochi:managed-hashtable-clear! hashtable

Removes all of the associations from the managed hash table hashtable.

Scheme Procedure: gzochi:managed-hashtable-keys hashtable

Returns a managed vector of the keys with associations in the managed hash table hashtable, in an unspecified order.

Scheme Procedure: gzochi:managed-hashtable-entries hashtable

Returns two values—a managed vector of the keys with associations in the managed hash table hashtable, and a managed vector of the values to which these keys are mapped, in corresponding but unspecified order.

Scheme Procedure: gzochi:managed-hashtable-hash-function hashtable

Returns a gzochi:callback record that represents the equivalence predicate used by hashtable.

Scheme Procedure: gzochi:managed-hashtable-equivalence-function hashtable

Returns a gzochi:callback record that represents the hash function used by hashtable

Scheme Procedure: gzochi:make-managed-sequence

Returns a newly allocated managed sequence.

Scheme Procedure: gzochi:managed-sequence? obj

Returns #t if obj is a managed sequence, #f otherwise.

Scheme Procedure: gzochi:managed-sequence->list seq

Return a newly allocated list composed of the contents of seq.

Scheme Procedure: gzochi:managed-sequence-add! seq obj #:key serializer deserializer

Appends obj to the end of seq. The value returned by gzochi:managed-sequence-add! is unspecified. If obj is not a managed record, the keyword arguments #:serializer and #:deserializer must be given (in the form of gzochi:callback records), and a managed serializable wrapper will be generated to hold obj.

Scheme Procedure: gzochi:managed-sequence-contains? seq obj [pred]

Returns #t if seq contains at least one element equivalent to obj as determined by the equivalence procedure pred, #f otherwise. If pred is not specified, eq? will be used to check equivalence.

Scheme Procedure: gzochi:managed-sequence-delete! seq obj [pred]

Removes the first element of seq equivalent to obj, as determined by the equivalence procedure pred. If pred is not specified eq? will be use to check equivalence. The positions of all elements that come after the removed element are decreased by one. The value returned by gzochi:managed-sequence-delete! is unspecified.

Scheme Procedure: gzochi:managed-sequence-delete-at! seq i

Removes the element at position i of seq. The positions of all elements that come after i are decreased by one. The value returned by gzochi:managed-sequence-delete-at! is unspecified.

Scheme Procedure: gzochi:managed-sequence-fold-left seq fold-fn . seeds
Scheme Procedure: gzochi:managed-sequence-fold-right seq fold-fn . seeds

Applies fold-fn to each element in seq. fold-fn should accept a single element from the sequence as its first argument, and the values passed as seeds as its remaining arguments. The function must return either #f, indicating that the folding iteration should halt; or the values to passed as seed values on the next invocation of fold-fn. The fold completes when fold-fn has been applied to every element of seq, or when fold-fn returns #f. gzochi:managed-sequence-fold-left applies fold-fn to every element in seq starting with position 0; gzochi:managed-sequence-fold-right begins with the element at the end of the sequence and works backwards to the first. These procedures return the final set of seed values returned by fold-fn as the values of the fold.

Scheme Procedure: gzochi:managed-sequence-insert! seq i obj #:key serializer deserializer

Inserts obj into seq at position i, which must be between zero and the nunber of elements currently in the sequence, inclusive. The positions of all elements that come after i are increased by one. The value returned by gzochi:managed-sequence-insert! is unspecified. If obj is not a managed record, the keyword arguments #:serializer and #:deserializer must be given (in the form of gzochi:callback records), and a managed serializable wrapper will be generated to hold obj.

Scheme Procedure: gzochi:managed-sequence-ref seq i

Returns the element at position i in seq.

Scheme Procedure: gzochi:managed-sequence-set! seq i obj #:key serializer deserializer

Replaces the element in seq at position i, which must be between zero and the number of elements currently in the sequence, with obj. The value returned by gzochi:managed-sequence-set! is unspecified. If obj is not a managed record, the keyword arguments #:serializer and #:deserializer must be given (in the form of gzochi:callback records), and a managed serializable wrapper will be generated to hold obj.

Scheme Procedure: gzochi:managed-sequence-size seq

Returns the number of entities currently in the managed sequence seq.


Next: , Previous: , Up: Scheme API reference   [Contents][Index]

12.7 gzochi io

The (gzochi io) library exports structures and procedures useful for building serializations, which are used by the data management features of the gzochid container for storing and retrieving application data. The serializations described below may be used directly as field serializations for a managed record-type descriptor or composed to form serializations for more complex types.

A serialization is an R6RS record with fields for a serialization procedure and a deserialization procedure. Serialization procedures should take two arguments, an output port and the value to be serialized, and should write the serialized form of the value to the port as a sequence of bytes; deserialization procedures will be passed an input port and should read the bytes necessary to return a value of the required type.

No type or length information—or delimiters—other than what the serializers themselves add to the output will be persisted. In particular, deserializer procedures should take care not to read more bytes than necessary from the port, as doing so will disrupt the operation of subsequent deserializers.

Variable: Record Type gzochi:serialization
Scheme Procedure: gzochi:make-serialization serializer deserializer
Scheme Procedure: gzochi:serialization? obj
Scheme Procedure: gzochi:serialization-serializer serialization
Scheme Procedure: gzochi:serialization-deserializer serialization

The base serialization record-type, constructor, predicate, and field accessors.

Variable: Scheme Variable gzochi:integer-serialization
Scheme Procedure: gzochi:write-integer port int
Scheme Procedure: gzochi:read-integer port

A serialization that uses an efficient, variable-length encoding format to read and write integer values of arbitrary size.

Variable: Scheme Variable gzochi:boolean-serialization
Scheme Procedure: gzochi:write-boolean port bool
Scheme Procedure: gzochi:read-boolean port

A serialization that encodes boolean values as integers, with 1 representing true and 0 representing false. Note that the deserializer procedure will treat any non-zero value as encoding true.

Variable: Scheme Variable gzochi:string-serialization
Scheme Procedure: gzochi:write-string port str
Scheme Procedure: gzochi:read-string port

A serialization that reads and writes text strings using the UTF-8 encoding, with an integer prefix giving the number of characters in the original string.

Scheme Variable: gzochi:symbol-serialization
Scheme Procedure: gzochi:write-symbol port sym
Scheme Procedure: gzochi:read-symbol port

A serialization that reads and writes symbols by converting them to and from strings and delegating to the procedures in gzochi:string-serialization.

Scheme Variable: gzochi:bytevector-serialization
Scheme Procedure: gzochi:write-bytevector port bv
Scheme Procedure: gzochi:read-bytevector port

A serialization that reads and writes R6RS bytevectors as sequences of bytes with encoded integer prefixes giving the lengths of the original vectors.

Scheme Procedure: gzochi:make-uniform-list-serialization ser

Returns a new gzochi:serialization record that can be used as a serialization for a list of arbitrary length in which every car of the list has its serialization performed by the serialization ser.


Next: , Previous: , Up: Scheme API reference   [Contents][Index]

12.8 gzochi log

The (gzochi log) library provides procedures for performing application-level message logging, at various levels of priority. All of the procedures in this library do their writes transactionally, which means that the messages will only be persisted (to the console and/or a file on disk, depending on configuration) if the current transaction commits.

These procedures interpret their “rest” arguments as values with which to replace escapes in the message string. Formatting and replacement is done according to the rules of Guile’s simple-format procedure.

Scheme Procedure: gzochi:log priority msg . args

Writes a transactional message at the priority level priority, a symbol that must be one of err, warning, notice, info, and debug.

Scheme Procedure: gzochi:log-err msg . args
Scheme Procedure: gzochi:log-warning msg . args
Scheme Procedure: gzochi:log-notice msg . args
Scheme Procedure: gzochi:log-info msg . args
Scheme Procedure: gzochi:log-debug msg . args

Each of these convenience procedures delegates to gzochi:log, passing a respective priority value.


Next: , Previous: , Up: Scheme API reference   [Contents][Index]

12.9 gzochi task

The (gzochi task) library provides procedures for creating and scheduling transactional tasks. Tasks are gzochi:callback records, and represent blocks of code to be executed on behalf of a game application. All tasks are executed in a fully transactional context, meaning that their side effects enjoy guarantees of atomicity.

Scheme Procedure: gzochi:schedule-task callback [delay] [period]

Transactionally schedules the gzochi:callback callback for future execution. If delay is specified, it must be a non-negative integer giving the number of milliseconds by which the execution of callback should be delayed. If period is also specified, the execution of callback will be executed repeatedly, and period must be a non-negative integer giving the number of milliseconds that must elapse between executions of callback.

If period is specified, this procedure futhermore returns a “perodic task handle,” an opaque managed record that can be used to control the scheduling behavior of the resulting task.

Note that the execution delay of a scheduled task, as well as the period of a periodic task, is “best effort.” The task will not be eligible for execution until at least the specified number of milliseconds have elapsed, but may be delayed further depending on the current state of the server.

Scheme Procedure: gzochi:task-handle? obj

Returns #t if obj is a task handle, #f otherwise.

Scheme Procedure: gzochi:cancel-task handle

Cancels the periodic task associated with the periodic task handle handle. Note that depending on the state of the container’s task execution schedule, the task may still be eligible for execution for a short period of time following its cancellation.

After this procedure returns, handle will be removed from the data store.


Previous: , Up: Scheme API reference   [Contents][Index]

12.10 gzochi

The (gzochi) library is a composite of all of the other public gzochi libraries, with the exception of ‘(gzochi admin)’. It imports and re-exports all of their exported procedures and syntactic forms.


Next: , Previous: , Up: Top   [Contents][Index]

13 An example application

The following sample code is a complete gzochid application that implements a simple “Hello, world!” behavior. Authenticated clients receive a simple greeting and may send a single message to the server before being disconnected.

#!r6rs

(library (gzochi example hello-world)
  (export initialize-hello-world 
          hello-client 

          client-message
          client-disconnected)

  (import (gzochi) (rnrs))

  (define (initialize-hello-world properties)
    (gzochi:notice "Hello, world!"))

  (define (hello-client session)
    (gzochi:client-session-send session 
     (string->utf8 
      (string-append "Hello, " (gzochi:client-session-name session) "!")))
    (gzochi:make-client-session-listener
     (gzochi:make-callback 'client-message '(gzochi example hello-world))
     (gzochi:make-callback 'client-disconnected 
                           '(gzochi example hello-world))))

  (define (client-message session msg)
    (let ((name (gzochi:client-session-name session)))
      (gzochi:notice "~a: ~a" name (utf8->string msg))
      (gzochi:client-session-send session
        (string->utf8 (simple-format "Goodbye, ~a!" name))))
    (gzochi:disconnect session))

  (define (client-disconnected session) (if #f #f))
)

To launch this application, copy and paste the code above into a file named “hello-world.scm” and copy it to a sub-directory named “hello-world/gzochi/example” below your gzochid application deployment root directory. For example, the default deployment root is “/var/gzochid/deploy,” so the full path in the default case would be “/var/gzochid/deploy/hello-world/gzochi/example/hello-world.scm.” You’ll also need to copy and paste the following game descriptor XML to a file named “game.xml” in the top-level “hello-world” directory.

<?xml version="1.0"?>
<game name="hello-world">
  <description>Hello, world!</description>
  <load-paths />

  <initialized>
    <callback module="gzochi example hello-world" 
              procedure="initialize-hello-world" />
  </initialized>

  <logged-in>
    <callback module="gzochi example hello-world" 
              procedure="hello-client" />
  </logged-in>
</game>

The descriptor begins by giving the application’s short name and a description. The load-paths element is a list of additional locations the system should look for Scheme modules when module dependencies are being resolved. The application’s deployment directory is implicitly on the load path, so this element is empty in the descriptor for “hello-world.”

Next there are declarations for the two primary callbacks, initialization and client connection. This game descriptor file sets the initialization callback to the initialize-hello-world procedure in the module (gzochi example hello-world) and sets the connection callback to the procedure hello-client in that same module.

The Scheme implementation of initialize-hello-world gets passed a hash table with the game properties (which will be empty in this case) and doesn’t do anything except log a message. The hello-client callback is a bit more interesting—it sends a greeting to the newly-connected session and then constructs and returns a new client session listener, which includes two additional callbacks that will be used to handle events related specifically to the new session. The first listener callback will be called when a message is received from a client session; in this case, the client-message procedure is used. The other callback (client-disconneted in the example above) will be called when the session disconnects.


Next: , Previous: , Up: Top   [Contents][Index]

14 Database tools

The data for a gzochi game application is stored in three separate databases: Names, which binds names to object identifiers; oids, which stores the serialized objects that encode the state of the game; and meta, which tracks necessary metadata about the object identifier key space. Tools for manipulating these databases are described in the following sections.


Next: , Up: Database tools   [Contents][Index]

14.1 Exporting data

Making a copy of a gzochi game application database is a wise thing to do. Although the transactional storage layer of the server works to prevent inconsistent writes and catastrophic loss of data, it is unable to guard against “application-level” corruption of data resulting from software bugs. Creating a backup at strategic intervals lets you create rollback points before major releases, and also gives you access to “scratch” versions of real game state that you can use to test new or experimental code. Copying the contents of the game databases is not as simple as copying the game’s data directory. The files and formats used to store game data are not compatible across storage engine implementations, and so a game database created by an instance of gzochid compiled against one storage engine is not readable by an instance of gzochid compiled against another. And depending on the capabilities of the storage engine, the contents of the files on disk may not fully capture the transactional state of a database being modified by a running gzochid server, nor provide enough context for an independent server instance to successfully reconstruct it.

The gzochi-dump utility allows you to perform a transactional export of the contents of any (or all) of the gzochi game databases in a portable, storage engine-independent format.

To export all of the three databases for a game application (“names,” “oids,” and “meta”), run the gzochi-dump command on the data directory of the target game application, or just give it the name of the application, and it will “guess” its data directory based on the server’s storage configuration.

gzochi-dump /var/gzochid/data/mygame

The files names.dump, oids.dump, and meta.dump will be created in the current directory. To export a single game database, qualify the target (path or application name) with the name of the database.

gzochi-dump /var/gzochid/data/mygame:names

The contents of the specified database will be written to standard output. See the gzochi-dump man page for more information on the flags understood by the tool.

The gzochi-dump utility produces output in a portable flat-text format very similar to the format used by the db_dump tool distributed with Berkeley DB—though the output of gzochi-dump is the same no matter what storage engine the server is built against. The format is as follows:

First, a header section is written, as a series of name=value pairs. The first line is always the version specifier, “VERSION=N”, where N is the version of the dump output format. The header section ends with the line “HEADER=END”.

Next, a data section is written, as a series of pairs of keys and values, with each key and each value on its own line. Each line begins with one character of whitespace, followed by the hexadecimal representation of the bytes of the key or value in a two-character, zero-padded format—effectively the output of printf with the %.2hhx conversion specifier. The data section ends with the line “DATA=END”.

Here is some example output written as the result of dumping the “names” database of one of the example games included in the gzochi source distribution:

VERSION=3
format=bytevalue
type=btree
HEADER=END
 6f2e6d617a6500
 33643000
 732e6368616e6e656c2e6d61696e00
 33643100
 732e696e697469616c697a657200
 3000
DATA=END

Next: , Previous: , Up: Database tools   [Contents][Index]

14.2 Importing data

The gzochi-load utility rebuilds a game database from the contents of a database dumped by gzochi-dump in the format described in the previous section, read from standard input.

As with gzochi-dump, you may specify the target of the gzochi-load command as either a path to an application’s data directory, or as the name of an application hosted by the gzochid container. The target database must also be given; gzochi-load can only load data into a single database at a time. The database will be created if it does not already exist—gzochi-load will complain and halt if the target database does exist, since its majority use case is rebuilding a complete database from scratch. This behavior can be overridden by running gzochi-load with the --force argument, but note that doing so runs the risk of corrupting existing game state, and so this option should be used with care.

The following example shows how to use the gzochi-load command to rebuild the “oids” database for the application “mygame2.” (gzochi-load will resolve the data directory for this application by reading the server configuration file and scanning the application deployment directory.)

cat oids.dump | gzochi-load mygame2:oids

To make a complete clone of a game application’s databases, dump all three databases transactionally with gzochi-dump, then load each dump file into the corresponding database in the target application data directory as per the shell script included below.

#!/bin/sh

DUMPDIR=`mktemp -d`

gzochi-dump -o $DUMPDIR $1
gzochi-load $2:meta < $DUMPDIR/meta.dump \
    && gzochi-load $2:oids < $DUMPDIR/oids.dump \
    && gzochi-load $2:names < $DUMPDIR/names.dump

rm -rf $DUMPDIR

Previous: , Up: Database tools   [Contents][Index]

14.3 Migrating data

It is unusual that a single version of a piece of software serves its users for the duration of their experience of it. Game application software is no different; delivering bug-fixes, performance enhancements, and new features may require that you deploy updates to the game application code running in the gzochid container. Sometimes, this new code may depend on additions or modifications to the structure of the records that describe the persistent state of the game; and these modifications will usually need to be applied to instances of these records that have already been stored in the database.

The gzochi-migrate utility allows you to transform the contents of a gzochi game application database by visiting and optionally re-writing (or removing parts of) the persisted game object graph. A migration to be executed by gzochi-migrate is described in an XML migration descriptor file; the logic for processing the objects in the database being migrated is defined by the migration visitor, a procedure written in Guile Scheme.

gzochi-migrate reads the descriptor, resolves the type registries and visitor procedure, and then traverses the application-visible keyspace of the names database (that is, the set of keys that begin with “o.”) to identify the roots of the game object graph and enqueue them for visiting. For each object identifier in the migrator’s queue, the corresponding record is deserialized from the oids database and passed as an argument to the visitor procedure. Any references to other managed records held by the record being migrated are enqueued for subsequent visit. In this way, every managed record that is reachable from a named binding is visited exactly once.


Next: , Up: Migrating data   [Contents][Index]

14.3.1 The migration visitor procedure

The migration visitor is a Scheme procedure invoked by gzochi-migrate on each reachable object in the game database. It is the responsibility of the migration visitor procedure to provide a disposition for each object it is given, and it does so via the value it returns. If the visitor returns:

#f

the object is removed from the object graph.

a managed record

the object is replaced by this value.

an unspecified value

the object is left unmodified.

any other value

an error is signaled.

The simplest implementation of a migration visitor is a bijective function over managed records: A procedure that accepts a managed record and returns one of the values listed above. Visitor procedures may have side effects, too, though, and may achieve them through interactions with the object graph or explicit calls to the data management functions. A visitor procedure may call gzochi:remove-object! on its argument or on a record to which its argument has a field reference. However, named bindings should not be modified while a migration is in progress; in particular, the effect of gzochi:set-binding! is undefined. gzochi API functionality related to network communication and task scheduling is not supported during migrations, and the effects of calling procedures in those modules is also undefined.


Next: , Previous: , Up: Migrating data   [Contents][Index]

14.3.2 The migration descriptor

The XML migration descriptor has the schema described in the following paragraphs. A DTD that can be used to validate the structure of your migration descriptors is included in the gzochid source distribution.

The migration descriptor’s document element is migration, and it must include a target attribute giving the name of the deployed game application to be migrated. (The directories containing the game database files are computed using the gzochid.conf file and the conventions of the storage engine against which the server and database toolchain were built.)

The input-registry and output-registry elements specify managed record type registries to push onto the type resolution stack when an object in the graph is deserialized and when it is serialized, respectively. Controlling the behavior of type resolution during these lifecycle phases is crucial to implementing a migration that mutates the structure of a declared type while preserving its name. Both of these migration descriptor elements require a module attribute, which gives the name (as a whitespace-delimited list of symbols) of the module exporting the type registry; and the name attribute, which gives the name of the type registry within that module. Type registries may be defined using the gzochi:make-managed-record-type-registry procedure in the (gzochi data) API.

The callback element gives the procedure name and module (via the procedure and module attributes, respectively) of the migration visitor procedure.

The load-paths element is a wrapper element for zero or more load-path element, each of which specifies as its content an absolute or relative path to be added to the default Guile %load-path variable when the input and output type registries are resolved, and when the visitor procedure is resolved. Note that the game application root directory is added to the load path by default.


Previous: , Up: Migrating data   [Contents][Index]

14.3.3 A sample migration

The following migration adds a new mutable field named “experience-points” to the managed record with the serial UID player. The version of the player structure persisted to the database without the new field is captured by the managed record type definition for from-player below, which registers the type in the input-registry type registry. The version of the player structure that includes the new field and will be serialized back to the database is declared as to-player and is registered in the output-registry type registry.

After running this migration, the server administrator would need to deploy a new version of the “my-game” application that includes a type definition for the player structure that includes the field added by to-player.

Note that while the re-use of the player UID allows this migration to modify the structure of a record without changing its type this migration is not strictly idempotent. Re-executing the migration on an already-migrated database will cause serialized form of the version of the player structure that includes the “experience-points” field to be deserialized “into” a version of the player structure that does not contain that field. The gzochi object system cannot natively detect this kind of serialization mismatch; its outcome depends on the behavior of the serializer and deserializer procedures.

Here is the Scheme module containing the type registries and visitor procedure:

#!r6rs

(library (my-game migration player)
  (export input-registry output-registry migrate-player)
  (import (gzochi) (rnrs))

  (define input-registry (gzochi:make-managed-record-type-registry))
  (define output-registry (gzochi:make-managed-record-type-registry))

  (gzochi:define-managed-record-type from-player
    (fields (immutable name (serialization gzochi:string-serialization))
            (mutable hit-points (serialization gzochi:integer-serialization)))
    (serial-uid player)
    (type-registry input-registry)
    (protocol (lambda (p)
                (lambda (name)
                  (p name 0)))))

  (gzochi:define-managed-record-type to-player
    (fields (immutable name (serialization gzochi:string-serialization))
            (mutable hit-points (serialization gzochi:integer-serialization))
            (mutable experience-points
                     (serialization gzochi:integer-serialization)))
    (serial-uid player)
    (type-registry output-registry)
    (protocol (lambda (p)
                (lambda (name hit-points)
                  (p name hit-points 0)))))

  (define (migrate-player obj)
    (if (from-player? obj)
        (make-to-player (from-player-name obj) 
                        (from-player-hit-points obj))))
)

The migration descriptor for this migration:

<?xml version="1.0"?>
<migration target="my-game">
  <input-registry module="my-game migration player" name="input-registry" />
  <output-registry module="my-game migration player" name="output-registry" />
  <callback module="my-game migration player" procedure="migrate-player" />
</migration>

Next: , Previous: , Up: Top   [Contents][Index]

Appendix A GNU Free Documentation License

Version 1.3, 3 November 2008
Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
http://fsf.org/

Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
  1. PREAMBLE

    The purpose of this License is to make a manual, textbook, or other functional and useful document free in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.

    This License is a kind of “copyleft”, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.

    We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.

  2. APPLICABILITY AND DEFINITIONS

    This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The “Document”, below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as “you”. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.

    A “Modified Version” of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.

    A “Secondary Section” is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document’s overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.

    The “Invariant Sections” are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.

    The “Cover Texts” are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.

    A “Transparent” copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not “Transparent” is called “Opaque”.

    Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.

    The “Title Page” means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, “Title Page” means the text near the most prominent appearance of the work’s title, preceding the beginning of the body of the text.

    The “publisher” means any person or entity that distributes copies of the Document to the public.

    A section “Entitled XYZ” means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of such a section when you modify the Document means that it remains a section “Entitled XYZ” according to this definition.

    The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.

  3. VERBATIM COPYING

    You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.

    You may also lend copies, under the same conditions stated above, and you may publicly display copies.

  4. COPYING IN QUANTITY

    If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document’s license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.

    If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.

    If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.

    It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.

  5. MODIFICATIONS

    You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:

    1. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission.
    2. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement.
    3. State on the Title page the name of the publisher of the Modified Version, as the publisher.
    4. Preserve all the copyright notices of the Document.
    5. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices.
    6. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below.
    7. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document’s license notice.
    8. Include an unaltered copy of this License.
    9. Preserve the section Entitled “History”, Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled “History” in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence.
    10. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the “History” section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission.
    11. For any section Entitled “Acknowledgements” or “Dedications”, Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein.
    12. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles.
    13. Delete any section Entitled “Endorsements”. Such a section may not be included in the Modified Version.
    14. Do not retitle any existing section to be Entitled “Endorsements” or to conflict in title with any Invariant Section.
    15. Preserve any Warranty Disclaimers.

    If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version’s license notice. These titles must be distinct from any other section titles.

    You may add a section Entitled “Endorsements”, provided it contains nothing but endorsements of your Modified Version by various parties—for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.

    You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.

    The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.

  6. COMBINING DOCUMENTS

    You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.

    The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.

    In the combination, you must combine any sections Entitled “History” in the various original documents, forming one section Entitled “History”; likewise combine any sections Entitled “Acknowledgements”, and any sections Entitled “Dedications”. You must delete all sections Entitled “Endorsements.”

  7. COLLECTIONS OF DOCUMENTS

    You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.

    You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.

  8. AGGREGATION WITH INDEPENDENT WORKS

    A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an “aggregate” if the copyright resulting from the compilation is not used to limit the legal rights of the compilation’s users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.

    If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document’s Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.

  9. TRANSLATION

    Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.

    If a section in the Document is Entitled “Acknowledgements”, “Dedications”, or “History”, the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.

  10. TERMINATION

    You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License.

    However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.

    Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.

    Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, receipt of a copy of some or all of the same material does not give you any rights to use it.

  11. FUTURE REVISIONS OF THIS LICENSE

    The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See http://www.gnu.org/copyleft/.

    Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License “or any later version” applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Document.

  12. RELICENSING

    “Massive Multiauthor Collaboration Site” (or “MMC Site”) means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A “Massive Multiauthor Collaboration” (or “MMC”) contained in the site means any set of copyrightable works thus published on the MMC site.

    “CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization.

    “Incorporate” means to publish or republish a Document, in whole or in part, as part of another Document.

    An MMC is “eligible for relicensing” if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008.

    The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing.

ADDENDUM: How to use this License for your documents

To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page:

  Copyright (C)  year  your name.
  Permission is granted to copy, distribute and/or modify this document
  under the terms of the GNU Free Documentation License, Version 1.3
  or any later version published by the Free Software Foundation;
  with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
  Texts.  A copy of the license is included in the section entitled ``GNU
  Free Documentation License''.

If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the “with…Texts.” line with this:

    with the Invariant Sections being list their titles, with
    the Front-Cover Texts being list, and with the Back-Cover Texts
    being list.

If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation.

If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.


Next: , Previous: , Up: Top   [Contents][Index]

Concept index


Previous: , Up: Top   [Contents][Index]

Procedure index

Jump to:   &  
G  
Index Entry  Section

&
&gzochi:name-exists: gzochi conditions
&gzochi:name-not-bound: gzochi conditions
&gzochi:no-current-application: gzochi conditions
&gzochi:object-removed: gzochi conditions
&gzochi:transaction-aborted: gzochi conditions
&gzochi:transaction-retry: gzochi conditions
&gzochi:transaction-timeout: gzochi conditions

G
g:: gzochi app
g:: gzochi app
gzochi:application-context-name: gzochi admin
gzochi:application-context?: gzochi admin
gzochi:applications: gzochi admin
gzochi:bytevector-serialization: gzochi io
gzochi:callback-data: gzochi app
gzochi:callback-module: gzochi app
gzochi:callback-procedure: gzochi app
gzochi:callback?: gzochi app
gzochi:cancel-task: gzochi task
gzochi:channel-name: gzochi channel
gzochi:channel?: gzochi channel
gzochi:client-session-listener: gzochi client
gzochi:client-session-listener-disconnected: gzochi client
gzochi:client-session-listener-received-message: gzochi client
gzochi:client-session-listener?: gzochi client
gzochi:client-session-name: gzochi client
gzochi:client-session?: gzochi client
gzochi:close-channel: gzochi channel
gzochi:create-channel: gzochi channel
gzochi:current-application: gzochi admin
gzochi:define-managed-record-type: gzochi data
gzochi:get-binding: gzochi data
gzochi:get-channel: gzochi channel
gzochi:join-channel: gzochi channel
gzochi:leave-channel: gzochi channel
gzochi:log: gzochi log
gzochi:log-debug: gzochi log
gzochi:log-err: gzochi log
gzochi:log-info: gzochi log
gzochi:log-notice: gzochi log
gzochi:log-warning: gzochi log
gzochi:make-callback: gzochi app
gzochi:make-client-session-listener: gzochi client
gzochi:make-managed-hashtable: gzochi data
gzochi:make-managed-record-type-descriptor: gzochi data
gzochi:make-managed-record-type-registry: gzochi data
gzochi:make-managed-sequence: gzochi data
gzochi:make-managed-serializable: gzochi data
gzochi:make-managed-vector: gzochi data
gzochi:make-name-exists-condition: gzochi conditions
gzochi:make-name-not-bound-condition: gzochi conditions
gzochi:make-no-current-application-condition: gzochi conditions
gzochi:make-object-removed-condition: gzochi conditions
gzochi:make-serialization: gzochi io
gzochi:make-transaction-aborted-condition: gzochi conditions
gzochi:make-transaction-retry-condition: gzochi conditions
gzochi:make-transaction-timeout-condition: gzochi conditions
gzochi:make-uniform-list-serialization: gzochi io
gzochi:managed-hashtable-clear!: gzochi data
gzochi:managed-hashtable-contains?: gzochi data
gzochi:managed-hashtable-delete!: gzochi data
gzochi:managed-hashtable-entries: gzochi data
gzochi:managed-hashtable-equivalence-function: gzochi data
gzochi:managed-hashtable-hash-function: gzochi data
gzochi:managed-hashtable-keys: gzochi data
gzochi:managed-hashtable-ref: gzochi data
gzochi:managed-hashtable-set!: gzochi data
gzochi:managed-hashtable-size: gzochi data
gzochi:managed-hashtable-update!: gzochi data
gzochi:managed-hashtable?: gzochi data
gzochi:managed-record-accessor: gzochi data
gzochi:managed-record-constructor: gzochi data
gzochi:managed-record-constructor-descriptor: gzochi data
gzochi:managed-record-mutator: gzochi data
gzochi:managed-record-predicate: gzochi data
gzochi:managed-record-rtd: gzochi data
gzochi:managed-record-type-descriptor: gzochi data
gzochi:managed-record-type-name: gzochi data
gzochi:managed-record-type-parent: gzochi data
gzochi:managed-record-type-registry?: gzochi data
gzochi:managed-record-type-uid: gzochi data
gzochi:managed-record?: gzochi data
gzochi:managed-sequence->list: gzochi data
gzochi:managed-sequence-add!: gzochi data
gzochi:managed-sequence-contains?: gzochi data
gzochi:managed-sequence-delete!: gzochi data
gzochi:managed-sequence-delete-at!: gzochi data
gzochi:managed-sequence-fold-left: gzochi data
gzochi:managed-sequence-fold-right: gzochi data
gzochi:managed-sequence-insert!: gzochi data
gzochi:managed-sequence-ref: gzochi data
gzochi:managed-sequence-set!: gzochi data
gzochi:managed-sequence-size: gzochi data
gzochi:managed-sequence?: gzochi data
gzochi:managed-serializable-value: gzochi data
gzochi:managed-serializable?: gzochi data
gzochi:managed-vector: gzochi data
gzochi:managed-vector->list: gzochi data
gzochi:managed-vector-length: gzochi data
gzochi:managed-vector-ref: gzochi data
gzochi:managed-vector-set!: gzochi data
gzochi:managed-vector?: gzochi data
gzochi:name-exists-condition-name: gzochi conditions
gzochi:name-exists-condition?: gzochi conditions
gzochi:name-not-bound-condition-name: gzochi conditions
gzochi:name-not-bound-condition?: gzochi conditions
gzochi:no-current-application-condition?: gzochi conditions
gzochi:object-removed-condition?: gzochi conditions
gzochi:read-boolean: gzochi io
gzochi:read-bytevector: gzochi io
gzochi:read-integer: gzochi io
gzochi:read-string: gzochi io
gzochi:read-symbol: gzochi io
gzochi:remove-binding!: gzochi data
gzochi:schedule-task: gzochi task
gzochi:send-channel-message: gzochi channel
gzochi:send-message: gzochi client
gzochi:serialization-deserializer: gzochi io
gzochi:serialization-serializer: gzochi io
gzochi:serialization?: gzochi io
gzochi:set-binding!: gzochi data
gzochi:symbol-serialization: gzochi io
gzochi:task-handle?: gzochi task
gzochi:transaction-aborted-condition?: gzochi conditions
gzochi:transaction-retry-condition?: gzochi conditions
gzochi:transaction-timeout-condition?: gzochi conditions
gzochi:with-application: gzochi admin
gzochi:write-boolean: gzochi io
gzochi:write-bytevector: gzochi io
gzochi:write-integer: gzochi io
gzochi:write-string: gzochi io
gzochi:write-symbol: gzochi io

Jump to:   &  
G