The API supports modules executing in several formats, including processes, threads, and callbacks. The module sees the same interfaces in all cases, but the underlying implementations may differ. Since all of the models present the same interface, module developers are free to change the model used as the performance or flexibility needs of their modules change.
Processes - The most flexible model for an API module is to use a
(Unix) process. In this manner, all module processing takes place in a
separate address space from the proxy core, and the module is at
liberty to use any operating system interfaces, run other programs,
communicate across the network, perform disk operations, or undertake other
slow or resource-intensive operations. A process may be
single-threaded or multi-threaded. Using the process model
enables the trivial use of multiprocessors and, with
appropriately written modules, the ability to harness clusters of
machines in a network. The flexibility of the process model implies
more overhead in the operating system, including extra memory for
storing the process state and more CPU overhead when the OS-supplied
interprocess communication mechanisms are invoked to exchange
information between the proxy core and the module. However, these communication
costs are relatively minor for modules that perform significant processing.
Threads - Threads provide a higher-performance alternative to
processes. In this model, the
module spawns multiple threads in the proxy's address
space. Each thread requires less overhead than a full process
and the use of shared memory allows higher performance
communication between the module and the proxy cache. Like the process
model, threads can also trivially take advantage of
multiprocessors. However, since the threads share the address space
with the proxy cache, they must be careful not to corrupt memory or
invoke system calls that affect the state of the proxy itself.
Callbacks - Callbacks are the lowest overhead mechanism for content
adaptation, since the module is directly linked into the proxy cache's
address space and invoked by the proxy cache state machine.
As a result, callback overhead is comparable to a
single function call. Since callbacks are performed synchronously in
the proxy, the module's routines should not
perform any blocking operation such as opening files, waiting on
network operations, or synchronously loading data from disk. Nevertheless,
callbacks may invoke nonblocking network socket operations and use
polling functions provided by the API to determine when data is
available for them. Modules that fit these criteria may use callbacks for
the highest performance. Modules using
callbacks should also be careful to avoid corrupting memory or
performing stray pointer accesses, since corrupting memory can affect
the running of the proxy cache.