Previous Table of Contents Next


The Half-sync/Half-async pattern (Schmidt & Cranor, 1996) decouples synchronous I/O from asynchronous I/O in a system to simplify concurrent programming effort without degrading execution efficiency. Figure 2.10 illustrates the structure of the Half-sync/Half-async pattern in the context of the queue-based Thread Pool model in section 2.4.4.3. In this design, the Reactor is responsible for reading HTTP requests from clients and enqueueing valid requests on a message queue. This message queue feeds the pool of active objects that process the requests concurrently.


FIGURE 2.10.  The structure of the Half-sync/Half-async pattern.

2.4.3.2. Tactical Patterns

Web servers also utilize many tactical patterns. In contrast to the strategic patterns described earlier, tactical patterns are domain independent and have a relatively localized impact on a software design. For instance, Singleton is a tactical pattern that often is used to consolidate all option processing used to configure a Web server. Although this pattern is domain independent and thus widely applicable, the problem it addresses does not affect Web server software architecture as pervasively as strategic patterns such as the Active Object and Reactor patterns. A thorough understanding of tactical patterns is essential, however, to implement highly flexible software that is resilient to changes in application requirements and platform environments.

The following tactical patterns are widely used in ACE and JAWS:

  The Strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. JAWS uses this pattern extensively to configure different concurrency and event dispatching strategies without affecting the core software architecture of the Web server.
  The Adapter pattern transforms a nonconforming interface into one that can be used by a client. ACE uses this pattern in its OS adaptation layer to encapsulate the accidental complexity of the myriad native OS APIs in a uniform manner.
  The State pattern defines a composite object whose behavior depends on its state. The event dispatcher in JAWS uses the State pattern to seamlessly support both synchronous and asynchronous I/O.
  The Singleton pattern ensures that a class has only one instance and provides a global point of access to it. JAWS uses a Singleton to ensure that only one copy of its caching virtual filesystem exists in the Web server.

2.4.4. Implementing Web Server Concurrency Models with ACE

Existing Web servers use a wide range of concurrency strategies to implement the role of the event dispatcher. These strategies include single-threaded concurrency (e.g., Roxen), multiprocess concurrency (e.g., Apache), and multithread concurrency (e.g., PHTTPD, Zeus, JAWS). This section examines common Web concurrency models, including single-threaded Reactive, Thread-per-Request, Thread Pool, and Thread-per-Session. Each of these models is discussed below, focusing on the patterns they use and outlining how they can be implemented using ACE components.

Note how each concurrency model reuses most of the same patterns (e.g., Reactor, Acceptor, and Active Object) and ACE components (e.g., ACE Reactor, HTTP Acceptor, and HTTP Handler) simply by restructuring these core architectural building blocks in different configurations. This high degree of consistency is common in applications and frameworks that are explicitly built using patterns. When patterns are used to structure and document applications and frameworks, nearly every class plays a well-defined role and collaborates effectively with its related classes.

2.4.4.1. The Single-Threaded Reactive Web Server Model

In the Single-Threaded Reactive model, all connections and HTTP requests are handled by the same thread of control. This thread is responsible for demultiplexing requests from different clients and dispatching event handlers to perform HTTP processing. If each request is processed in its entirety, the Reactive Web server is deemed iterative. If the processing of each request is split into chunks that are performed separately, the Reactive Web server is deemed a single-threaded concurrent server.

The Single-Threaded Reactive model is a highly portable model for implementing the event dispatcher role in a Web server. This model runs on any OS platform that supports event demultiplexing mechanisms such as select or WaitForMultipleObjects. The structure of a Reactive Web server based on the ACE Reactor is shown in Figure 2.11. The ACE Reactor is an OO implementation of the Reactor pattern that waits synchronously in a single thread of control for the occurrence of various types of events (such as socket data, signals, or timeouts). When these events occur, the ACE Reactor demultiplexes the event to a pre-registered ACE Event Handler object and then dispatches the appropriate upcall method (e.g., handle_input, handle_signal, handle_timeout) on the object.


FIGURE 2.11.  The Single-Threaded Reactive Web server model.

Figure 2.12 illustrates how the Reactor pattern is used to trigger the acceptance of HTTP connections from clients. When a connection event arrives from a client, the ACE Reactor invokes the handle_input factory method hook on the HTTP Acceptor. This hook accepts the connection and creates a new HTTP Handler object that processes the client request. Because this model is single-threaded and driven entirely by reactive I/O, each HTTP Handler must register with the ACE Reactor. The Reactor can then trigger the processing of HTTP requests from clients. When an HTTP GET request arrives, the ACE Reactor invokes the handle_input hook method on the HTTP handler. This hook processes the request by retrieving the URI from the HTTP GET request and transferring the specified file to the client.


FIGURE 2.12.  Accepting connections and processing HTTP requests with the Reactor.


Previous Table of Contents Next