• No results found

Chapter 3 The Apache Portable Runtime

3.5 Selected APR Topics

3.5.4 Data Structs

Apache provides four data struct modules: • apr_tableprovides tables and arrays.

apr_hashprovides hash tables.

apr_queueprovides first in, first out (FIFO) queues.

apr_ring provides a ring struct, which is also the basis for APR bucket

brigades.

3.5.4.1 Arrays

APR arrays are provided by the apr_array_header_t type, and can hold either

objects or pointers. The array data type also serves as a stack. An array has a default size that is set when the array is created. Although it works most efficiently when it

remains within that size, the array can grow as required. The most common opera- tions supported are append (push) and iteration:

/* Allocate an array of type my_type */

apr_array_header_t* arr = apr_array_make(pool, sz, sizeof(my_type));

/* Allocate an uninitialized element on the array*/ my_type* newelt = apr_array_push(arr) ;

/* Now fill in the values of elt */ newelt->foo = abc ;

newelt->bar = "foo" ;

/* Pop the last-in element */

my_type* oldelt = apr_array_pop(arr) ;

/* Iterate over all elements */ for (i = 0; i < arr->nelts; i++) {

/* A C++ reference is the clearest way to show this */ my_type& elt = arr->elts[i] ;

}

Other array operations include the pop stack operation, copying (shallow copy), lazy copy, concatenation, append, and conversion to a string value (the latter is obviously meaningful only when the contents of the array are string values).

3.5.4.2 Tables

Theapr_table_tis an intuitive, higher-level data type built on the array for stor-

ing key/value pairs. It supports adding elements (several variants), deleting elements (not efficient), lookup, iteration, and clearing an entire table. It also supports merge and overlay operations, and merging or elimination of duplicate entries.

Table keys are always case insensitive (in contrast to the keys in APR hash tables).

/* Allocate a new table */

apr_table_t* table = apr_table_make(pool, sz) ;

/* Set a key/value pair */

apr_table_setn(table, key, val) ;

Variants on apr_table_set include apr_table_setn, apr_table_add, apr_table_addn,apr_table_merge, and apr_table_mergen:

apr_table_setnsets a value, overwriting any existing value for the key.

apr_table_addn adds a new value, leaving duplicate keys if there was an

existing value for the key.

apr_table_mergenadds a new value, merging it with any existing value for

the key.

apr_table_set copies the data as they are entered in the table; apr_table_setndoesn’t (and is therefore more efficient when the values are

persistent or allocated on the same pool as the table). The same applies to the other functions.

/* Retrieve an entry */

val = apr_table_get(table, key) ;

/* Iterate over the table (see Chapter 5) */ apr_table_do(func, rec, table, NULL) ;

/* Clear the table */ apr_table_clear(table) ;

/* Merge tables */

newtable = apr_table_overlay(pool, table1, table2) ;

/* Prune duplicate entries */ apr_table_compress(table, flags) ;

The high-level API and the availability of functions such as apr_table_mergeand apr_table_overlap provide the ideal foundations for manipulation of HTTP

headers and environment variables in Apache.

3.5.4.3 Hash Tables

apr_hash_t also stores key/value pairs, but is a lower-level data type than apr_table_t. It has two advantages:

1. Keys and values can be of any data type (and, unlike with tables, are case sensitive).

2. Hash tables scale more efficiently as the number of elements grows.

Unlike the array and table, the hash table has no initial size. The most commonly used operations are insertion and lookup. Other operations supported include iter- ation, copy, overlay, and merge.

apr_hash_t* hash = apr_hash_make(pool) ;

/* key and value are pointers to arbitrary data types */ apr_hash_set(hash, key, sizeof(*key), value) ;

value = apr_hash_get(hash, key, sizeof(*key)) ;

There is one special case we commonly encounter: where the key is a character string. To ensure the proper string comparison semantics are used, we should use the macro APR_HASH_KEY_STRING in place of the sizeargument.

3.5.4.4 Queues

The apr_queue_t is a thread-safe, FIFO bounded queue. It is available only in

threaded APR builds, and it enables multiple threads to cooperate in handling jobs. A queue has a fixed capacity, as set in apr_queue_create. The main queue oper-

ations are blocking and nonblocking push and pop.

3.5.4.5 Rings

APR_RINGis not, in fact, a data type, but rather a collection of macros somewhat like

a C++ template; these macros implement cyclic, doubly linked lists. The main ring example in Apache is the bucket brigade, which we’ll introduce in Section 3.5.5 and discuss at length in Chapter 8. The bucket is an element in the ring, while the brigade is the ring structure itself. The following declarations implement the ring structure:

struct apr_bucket {

/** Links to the rest of the brigade */ APR_RING_ENTRY(apr_bucket) link;

/** and, of course, the bucket's data fields */ };

/** A list of buckets */ struct apr_bucket_brigade {

/** The pool to associate the brigade with. The data is not allocated out * of the pool, but a cleanup is registered with this pool. If the * brigade is destroyed by some mechanism other than pool destruction, * the destroying function is responsible for killing the cleanup. */

apr_pool_t *p;

/** The buckets in the brigade are on this list. */ /*

* The apr_bucket_list structure doesn't actually need a name tag

* because it has no existence independent of the struct apr_bucket_brigade. * The ring macros are designed so that you can leave the name tag

* argument empty in this situation, but apparently the Windows compiler * doesn't like that.

*/

APR_RING_HEAD(apr_bucket_list, apr_bucket) list;

/** The freelist from which this bucket was allocated */ apr_bucket_alloc_t *bucket_alloc;

};