转载注明出处!
《The Apache Modules Book:Application Development with Apache》Nick Kew
第一版 2007-05-19
翻译难免有错误,因此把英文原文贴上.有翻译错误请与我联系,非常谢谢!
版权所有,yacsha(wangcheng711@gmail.com)
第3章 Apache可移植运行期库(翻译)
The Apache Portable Runtime (APR) and Utilities (APR-UTILS or APU) are a pair
of libraries used by the Apache httpd, but autonomously developed and maintained
within the ASF. Although many core developers are involved in both httpd
(the webserver) and APR, the projects are separate. These libraries provide core
functions that are not specific to webserving but are also useful in more general
applications.
Apache可移植运行期库(APR)和实用库(APR-UTILS或者APU)是被Apache httpd使用的一对库文件,但是由ASF(Apache Software Foundation)开发和维护.尽管很多核心开发人员都在httpd(web服务器)和APR项目中,但是这两个项目还是独立的.这些库文件提供的核心功能不仅仅为web服务器也为更多普通的应用程序.
Apart from the webserver, the best-known APR application is Subversion, a revision
and change control management system. Another is Site Valet, a suite of software
for QA and accessibility audit on the Web; Site Valet was developed by this book
’
s
author.
除web服务器之外,大家都知道的APR程序采用的是Subversion版本控制系统.另一个是Site Valet软件,用来在web上进行质量和访问控制.Site Valet由本书的作者开发.
This chapter discusses the APR as it applies to Apache modules. It does not go into
subjects such as application initialization, which are necessary but are handled
internally by the Apache core code. For developers working outside the webserver
context, this usage is documented clearly within APR itself, and it is covered in
the tutorial at http://dev.ariel-networks.com/apr/apr-tutorial/html/
apr-tutorial.html.
本章讨论APR对Apache模块的应用.不会探究诸如程序初始化之类的话题, 程序初始化是必须的,但是已经被Apache内部核心代码处理了.在web服务器之外进行开发,这个库的使用在APR自身的文档有清晰的说明.在http://dev.ariel-networks.com/apr/apr-tutorial/html/
apr-tutorial.html上也有谈到.
3.1 APR
The main purpose of APR is to provide a portable, platform-independent layer for
applications. Functions such as filesystem access, network programming, process
and thread management, and shared memory are supported in a low-level, crossplatform
library. Apache modules that use exclusively APR instead of native system
functions are portable across platforms and can expect to compile cleanly
—
or at
worst with a trivial amount of tidying up
—
on all platforms supported by Apache.
APR的主要目的是为应用程序提供可移植的,平台独立的层.像诸如文件系统的访问,网络编程,进程线程管理和共享内存的功能由底层的,跨平台的库支持. 使用APR库函数代替本地系统函数的Apache模块能在apache支持的平台间移植,也能按期望顺利编译一一或者最坏也只需要一点点的处理.
Each APR module comprises an application programming interface (API) shared
between all platforms, together with implementations of the functions defined in
the API. The implementations are often wholly or partly platform-specific,
although this issue is of no concern to applications.
每一个APR模块由应用编程接口(API)加上这些API的实现组成,这些API在所有平台共享.这些API实现经常是全部的或者部分和平台相关,尽管这个问题对应用程序无关紧要.
At the core of APR is Apache
’
s resource management (pools), which are discussed in
more detail later in this chapter. Table 3-1 provides a full list of the APR modules.
APR的核心是Apache的资源管理(pools),在这个章节的稍后详细讨论.表3-1提供了一个完整的APR模块列表.
TABLE 3-1
APR Modules
Name Purpose
apr_allocator Used internally for memory allocation
apr_atomic Atomic operations
apr_dso Dynamic loading of code (.so/.dll)
apr_env Reading/setting environment variables
apr_errno Defines error conditions and macros
apr_file_info Properties of filesystem objects and paths
apr_file_io Filesystem I/O
apr_fnmatch Filesystem pattern matching
apr_general Initialization/termination; useful macros
apr_getopt Command arguments
apr_global_mutex Global locking routines
apr_hash Hash tables
apr_inherit File handle inheritance helpers
apr_lib Odds and ends
apr_mmap Memory mapping
apr_network_io Network I/O (sockets)
apr_poll Poll routines
apr_pools Resource management
apr_portable APR to native mapping conversion
apr_proc_mutex Process locking routines
apr_random Random numbers
apr_ring Ring data struct and macros
apr_shm Shared memory
apr_signal Signal handling
apr_strings String operations
apr_support Internal support function
apr_tables Table and array functions
apr_thread_cond Thread conditions
apr_thread_mutex Thread mutex routines
apr_thread_proc Threads and process functions
apr_thread_rwlock Reader/writer locking routines
apr_time Time/date functions
apr_user User and group ID services
apr_version APR version
apr_want Standard header support
表3-1
APR模块
名字
功能
apr_allocator
用来内部内存分配
apr_atomic
原子操作
apr_dso
动态加载 (.so/.dll)
apr_env
读取和设置环境变量
apr_errno
定义错误条件和宏
apr_file_info
文件和路径的属性
apr_file_io
文件系统 I/O
apr_fnmatch
文件系统格式匹配
apr_general
初始化/结束; 有用的宏
apr_getopt
命令行参数
apr_global_mutex
全局锁例程
apr_hash
哈希表
apr_inherit
File handle inheritance helpers
apr_lib
零碎的东西
apr_mmap
内存映射
apr_network_io
网络I/O (sockets)
apr_poll
询问例程
apr_pools
资源管理
apr_portable
APR到本地映射的转换
apr_proc_mutex
进程锁例程
apr_random
随机数
apr_ring
令牌环数据结构和宏
apr_shm
共享内存
apr_signal
信号处理
apr_strings
字符串操作
apr_support
内部支持函数
apr_tables
表和数组函数
apr_thread_cond
线程环境
apr_thread_mutex
线程互斥例程
apr_thread_proc
线程和进程函数
apr_thread_rwlock
读写锁例程
apr_time
时间日期函数
apr_user
用户和组ID服务
apr_version
APR 版本
apr_want
Standard header support
3.2 APR-UTIL
3.2 APR-UTIL
APR-UTIL (also known as APU) is a second library in the APR project. It provides
a small set of utilities, based on the APR and with a unified programming interface.
APU doesn
’
t have separate per-platform modules, but it does adopt a similar
approach to some other commonly used resources, such as databases.
Table 3-2 provides a complete list of APU modules.
APR-UTIL(也叫APU)是APR工程的第二个项目.它基于APR和统一的编程接口提供了小集合的实用功能.APU模块在每个平台是同一个,但是它采用了一个相似的方法,被作为其它一些使用的通用的资源.
表3-2提供了一个完整的APU模块列表:
TABLE 3-2
APU Modules
Name Purpose
apr_anylock Transparent any lock flavor wrapper
apr_base64 Base-64 encoding
apr_buckets Buckets/bucket brigades
apr_date Date string parsing
apr_dbd Common API for SQL databases
apr_dbm Common API for DBM databases
apr_hooks Hook implementation macros
apr_ldap LDAP authentication APIs
apr_ldap_init LDAP initialization APIs used mainly when initializing
secure connections to the LDAP server
apr_ldap_option APIs for setting LDAP options
apr_ldap_url APIs for parsing and handling the LDAP URL
apr_md4 MD4 encoding
apr_md5 MD5 encoding
apr_optional Optional functions
apr_optional_hooks Optional hooks
apr_queue Thread-safe FIFO queues
apr_reslist Pooled resources
apr_rmm Relocatable managed memory
apr_sdbm SDBM library
apr_sha1 SHA1 encoding
apr_strmatch String pattern matching
apr_uri URI parsing/construction
apr_uuid User identification
apr_xlate Charset conversion (I18N)
apr_xml XML parsing
表 3-2
APU 模块
名字
功能
apr_anylock
Transparent any lock flavor wrapper
apr_base64
Base-64 编码
apr_buckets
Buckets/bucket brigades
apr_date
日期字符串解析
apr_dbd
SQL 数据库通用API
apr_dbm
数据库管理的常用API
apr_hooks
拦截实现宏
apr_ldap
LDAP 认证 API
apr_ldap_init
在初始和LDAP 服务器进行安全连接的时候主要使用的LDAP
初始化API
apr_ldap_option
设置LDAP 选项的API
apr_ldap_url
解析处理LDAP URL的API
apr_md4
MD4 编码
apr_md5
MD5 编码
apr_optional
可选函数
apr_optional_hooks
可选拦截
apr_queue
线程安全FIFO 队列
apr_reslist
缓冲池资源
apr_rmm
可重定位的被管理资源
apr_sdbm
SDBM 库
apr_sha1
SHA1 编码
apr_strmatch
字符串样式匹配
apr_uri
URI 解析/构造
apr_uuid
用户识别
apr_xlate
字符集转换 (I18N)
apr_xml
XML解析
3.3 Basic Conventions
3.3 基本协定
APR and APR-UTIL adopt a number of conventions that give them a homogenous
API and make them easy to work with.
APR和APR-UTIL采用了一系列的协定,有着一致的API和是他们很容易被使用.
3.3.1
Reference Manual: API Documentation and Doxygen
3.3.1 参考手册:API文档和Doxygen
All of APR/APU is very well documented at the code level. Every public function
and data type is documented in the header file that defines it, in doxygen1-friendly
format. The header files themselves, or the doxygen-generated documentation, provide
a full API reference for programmers. If you have doxygen installed, you can
generate your own copy of the APR reference manual from the source code with the
command make dox.
所有的APR/APU有着很好的代码注释.每一个公共函数和数据类型在定义的头文件中有着注释,注释按照Doxygen格式.头文件自身或者Doxygen生成的文档为程序员提供了一个完整的API参考.如果你安装了Doxygen,能用它从源代码中生成一份自己的APR参考手册.
3.3.2
Namespacing
3.3.2 命名空间
All APR/APU public interfaces are prefixed with the string
“
apr_
”
(data types and
functions) or
“
APR_
”
(macros). This defines APR
’
s
“
reserved
”
namespace.
Within the APR namespace, most of the APR and APU modules use secondary
namespacing. This convention is often based on the name of the module in question.
For example, all functions in module apr_dbd are prefixed with the string
“
apr_dbd_
”
. Sometimes an obviously descriptive secondary namespace is used. For
example, socket operations in module apr_network_io are prefixed with
“
apr_socket_
”
.
所有的APR/APU公共接口有着”apr”(数据类型和函数)或”APR”(宏)的前缀.这个定义了APR的”保留”命名空间.在APR的命名空间里,大多数APR和APU模块使用第二级命名空间.这个协定常常基于模块名字.例如,apr_dbd模块中的所有函数有着”apr_dbd_”的前缀.有时使用有着明显说明的二级命名空间.例如, 操作socket 的模块有着apr_network_io前缀.
3.3.3
Declaration Macros
3.3.3宏的声明
Public functions in APR/APU are declared using macros such as APR_DECLARE,
APU_DECLARE, and APR_DECLARE_NONSTD. For example:
APR_DECLARE(apr_status_t) apr_initialize(void);
On most platforms, this is a null declaration and expands to
apr_status_t apr_initialize(void);
On platforms such as Windows with Visual C++, which require their own nonstandard
keywords such as _dllexport to enable other modules to use a function,
these macros will expand to the required keywords.
APR/APU中的公共函数使用宏来声明,例如APR_DECLARE,
APU_DECLARE,和APR_DECLARE_NONSTD.例如:
APR_DECLARE(apr_status_t) apr_initialize(void);
在大多数平台,这是一个空声明,展开如下
apr_status_t apr_initialize(void);
在如windows平台的Visual C++,需要用他们自己的非标准关键字,如_dllexport,来让其他模块使用这个函数,这些宏会被替换为需要的关键字.
3.3.4 a
pr_status_t and Return Values
3.3.4 apr_status_t和返回值
A convention widely adopted in APR/APU is that functions return a status value
indicating success or an error code to the caller. The type is apr_status_t, which
takes integer values defined in apr_errno.h. Thus the usual prototype for an APR
function is
APR_DECLARE(apr_status_t) apr_do_something(...function args...);
Return values should routinely be tested, and error handling (recovery or graceful
failure) should be implemented. The return value APR_SUCCESS indicates success,
and we can commonly handle errors using constructs such as
apr_status_t rv;
...
rv = apr_do_something(... args ...);
if (rv != APR_SUCCESS) {
/* log an error */
return rv;
}
函数返回状态值这个协定在APR/APU中被广泛的采用,这个状态值用来告诉调用者是否成功或者错误代号.类型是apr_status_t,在apr_errno.h中定义为整型.因此常用的APR函数原型是
APR_DECLARE(apr_status_t) apr_do_something(...function args...);
返回值应该在调用之后被检查,应该有错误处理(恢复或者优雅的报错). APR_SUCCESS返回值表示成功,我们能够用下面这个结构通用的处理错误
apr_status_t rv;
...
rv = apr_do_something(... args ...);
if (rv != APR_SUCCESS) {
/* log an error */
return rv;
}
Sometimes we may do more. For example, if do_something was a nonblocking I/O
operation and returned APR_EAGAIN, we will probably want to retry the operation.
Some functions return a string value (char* or const char*), a void*, or void.
These functions are assumed to have no failure conditions or to return a null
pointer on failure as appropriate.
有时候我们需要做更多的工作.例如,做的事情是非阻塞的I/O操作,返回一个APR_EAGAIN,这样我们可能希望在重试一次.有些函数返回字符串(char* 或者 const char*), void *, 或者void.这些函数被认为不会发生错误或者返回一个空指针表示失败.
3.3.5
Conditional Compilation
3.3.5 条件编译
By their very nature, a number of features of APR may not be supported on every
platform. For example, prior to version 5.x, FreeBSD had no native thread implementation
considered suitable for Apache; hence threads were not supported in
APR (unless the relevant options were set manually for compilation).
由于现实环境,一些APR的功能不可能在每一个平台都支持.例如,
FreeBSD 5.x以前的版本不支持线程,为了适合Apache,因此APR中也不支持线程(除非在编译的时候手动修改相关的选项).
To enable applications to work around this issue, APR provides APR_HAS_* macros
for such features. When an application is concerned with such a feature, it should
use conditional compilation based on these macros. For example, a module performing
an operation that could lead to a race condition in a multithreaded environment
might want to use something like this:
为了让程序能在这种情况下工作,APR提供了APR_HAS_*宏来支持这个特性.当程序需要考虑这个特性的时候,应该用这些宏进行条件编译.例如,当一个模块在多线程环境下执行一个可能会导致竞争操作的时候,可能会像下面这样使用:
#if APR_HAS_THREADS
rv = apr_thread_mutex_lock(mutex);
if (rv != APR_SUCCESS) {
/* Log an error */
/* Abandon critical operation */
}
#endif
/* ... Execute critical section of code here ... */
#if APR_HAS_THREAD
apr_thread_mutex_unlock(mutex);
#endif
3.4 Resource Management: APR Pools
3.4 资源管理:APR池
The APR pools are a fundamental building block that lie at the heart of APR and
Apache; they serve as the basis for all resource management. The pools allocate
memory, either directly (in a malloc-like manner) or indirectly (e.g., in string
manipulation), and, crucially, ensure that memory is freed at the appropriate time.
But they extend much further, to ensure that other resources such as files or mutexes
can be allocated and will always be properly cleaned up. They can even deal with
resources managed opaquely by third-party libraries.
NOTE It is common practice in Apache to assume that pool
memory allocation never fails. The rationale for this assumption
is that if the allocation does fail, then the system is not recoverable,
and any error handling will fail, too.
APR池是位于APR和Apache心脏部位的基础构建部分;为所有的资源管理提供基本服务. APR池直接地(像malloc形式的)或者间接地(例如字符串的操作)分配内存,最重要地确保了在适当的时候释放内存.除此之外,它们还进一步的确保文件或互斥量这类资源的分配和正确的释放.它们甚至也能处理被第三方库不透明管理的资源.
提示: 我们通常假设在Apache中内存分配不会失败.因为如果内存分配失败,系统已经是不稳定的了,错误处理也是无用的.
3.4.1
The Problem of Resource Management
3.4.1 资源管理的问题
Every programmer knows that when you allocate a resource, you must ensure that
it is released again when you
’
ve finished with it. For example:
char* buf = malloc(n) ;
... check buf is non null ...
... do something with buf ...
free(buf) ;
or
FILE* f = fopen(path, "r") ;
... check f is non null ...
... read from f ....
fclose(f) ;
每一个程序员都知道,你分配资源,当你完成相应的任务后应该再次把它释放.例如:
char* buf = malloc(n) ;
... check buf is non null ...
... do something with buf ...
free(buf) ;
或
FILE* f = fopen(path, "r") ;
... check f is non null ...
... read from f ....
fclose(f) ;
Clearly, failure to free buf or to close f is a bug. In the context of a long-lasting program
such as Apache, it would have serious consequences, up to and including
bringing the entire system down. Obviously, it is important to get resource management
right.
这是很清楚的,释放buf或者关闭句柄f失败是一个bug.在持久运行的程序里,像Apache,会有很很严重的后果,最终导致系统瘫痪.让资源管理器工作正确显得非常重要.
In trivial cases, this is straightforward. In a more complex case with multiple error
paths, in which even the scope of a resource is uncertain at the time it is allocated,
ensuring that cleanup takes place in every execution path is much more challenging.
In such circumstances, we need a better way to manage resources.
在简单情况下,这是简单明了的.在有着多个错误处理块的更复杂环境里面,甚至连资源分配代码的位置都不能确定,确保资源释放操作的被执行是非常有难度的.在这种情况下,我们需要一个好方式来管理资源.
Constructor/Destructor Model
构造/析构模式
One method of resource management is exemplified by the C++ concept of objects
having a constructor and a destructor. Many C++ programmers make the destructor
responsible for cleanup of all resources allocated by the object. This approach
works well provided all dynamic resources are clearly made the responsibility of an
object. But, as with the simple C approach, it requires a good deal of care and attention
to detail
—
for example, where resources are conditionally allocated or shared
between many different objects
—
and it is vulnerable to programming bugs.
资源管理的一种方法是模仿C++中的对象概念,有一个构造器和析构器.许多C++程序员用析构器来负责清除对象分配的资源.这种方法工作的很好,
provided all dynamic resources are clearly made the responsibility of an object.但是,对简单的C语言,需要关注大量的细节一一例如,资源在哪儿有条件的分配或者不同对象间的共享一一这会使程序容易产生一些bug.
Garbage Collection Model
垃圾回收模式
A high-level method of resource management, typified by Lisp and Java, is garbage
collection. This approach has the advantage of taking the problem away from the
programmer and transferring it to the language itself, thereby completely removing
the danger of crippling programming errors. The drawback is that garbage collection
incurs a substantial overhead even where it isn
’
t necessary, and it deprives the
programmer of useful levels of control, such as the ability to control the lifetime of
a resource. It also requires that all program components
—
including third-party
libraries
—
be built on the same system, which is clearly not possible in an open system
written in C.
一种更高级别的资源管理方法是垃圾回收机制,Lisp和Java是其代表.这种方法的好处是让程序员远离这些麻烦,把麻烦交给语言自身.因此完全规避了这种难查错误的编程错误风险.缺点是这种垃圾回收机制带来了一些不必要的额外负担,剥夺了程序员的一些有用控制,像控制一个资源的生命周期.它也需要所有的编程组件一一包括第三方库文件一一在相同系统上构建,在一个用C语言编写的开放系统中这是明显不可能的.
3.4.2 A
PR Pools
3.4.2 APR池
The APR pools provide an alternative model for resource management. Like
garbage collection, they liberate the programmer from the complexities of dealing
with cleanups in all possible cases. In addition, they offer several other advantages,
including full control over the lifetime of resources and the ability to manage heterogeneous
resources.
APR池为资源管理提供了一个可供选择的模式,像垃圾回收,它们把程序员从处理所有可能情况下的资源释放的复杂问题中解放了出来.除此之外,它们还提供了一些其他的好处,包括可以完成控制资源的生命周期和有能力去管理不同类的资源.
The basic concept goes like this: Whenever you allocate a resource that requires
cleanup, you register it with a pool. The pool then takes responsibility for the
cleanup, which will happen when the pool itself is cleaned. In this way, the problem
is reduced to one of allocating and cleaning up a single resource: the pool itself.
Given that the Apache pools are managed by the server itself, the complexity is,
therefore, removed from applications programming. All the programmer has to do
is select the appropriate pool for the required lifetime of a resource.
基本概念像这样:无论何时你分配一个需要被释放的资源,你注册它为pool类型,在这个资源被销毁的时候,pool会负责进行清除操作.在这种方式下,问题是分配和清除一个单一资源是pool自身了.假设Apache的pool由服务器自身管理,因此,应用编程中的复杂问题没有了.所有的程序员必须根据资源的生命周期去选择一个适当的pool.
Basic Memory Management
基本内存管理
The most basic application of pools is for memory management. Instead of
mytype* myvar = malloc(sizeof(mytype)) ;
/* make sure it gets freed later in every possible execution path */
we use
mytype* myvar = apr_palloc(pool, sizeof(mytype)) ;
最基本的pool应用是内存管理.取代
mytype* myvar = malloc(sizeof(mytype)) ;
/* 在每一可能的执行路径中确保它被释放 */
我们使用
mytype* myvar = apr_palloc(pool, sizeof(mytype)) ;
The pool automatically takes responsibility for freeing this resource, regardless of
what may happen in the meantime. A secondary benefit is that pool allocation is
faster than malloc on most platforms!
pool自动的负责资源的释放,不用考虑与此同时发生了什么.第二个好处是在大多数平台上pool的分配要比malloc快!
Basic memory management takes many forms in APR and Apache, where memory
is allocated within another function. Examples include string-manipulation functions
and logging, where we gain the immediate benefit of being able to use
constructs such as the APR version of sprintf() without having to know the size
of a string in advance:
char* result = apr_psprintf(pool, fmt, ...) ;
APR also provides higher-level abstractions of pool memory
—
for example, in the
buckets used to pass data down the filter chain.
在APR和Apache中基本内存管理有多种形式,分配内存发生在其他函数里.如字符串处理函数和日志,我们能从使用构造中获得立即的好处,像APR版本的sprintf(),不需要预先知道字符串的大小.
char* result = apr_psprintf(pool, fmt, ...) ;
APR也提供了更高级别抽象的pool内存一一例如,在桶中传递数据到过滤链.
Generalized Memory Management
一般化的内存管理
APR provides built-in functions for managing memory, as well as a few other basic
resources such as files, sockets, and mutexes. However, programmers are not
required to use these functions and resources. An alternative is to use native allocation
functions and explicitly register a cleanup with the pool:
mytype* myvar = malloc(sizeof(mytype)) ;
apr_pool_cleanup_register(pool, myvar, free,
apr_pool_cleanup_null) ;
or
FILE* f = fopen(filename, "r") ;
apr_pool_cleanup_register(pool, f, fclose, apr_pool_cleanup_null) ;
APR为内存管理提供了内建的函数,也包括其它的基本资源如文件,套接字和互斥量.可是,程序员不需要使用这些函数和资源.我们可以选择使用本地系统分配函数和明确的在pool上注册一个清除操作:
mytype* myvar = malloc(sizeof(mytype)) ;
apr_pool_cleanup_register(pool, myvar, free,
apr_pool_cleanup_null) ;
或者
FILE* f = fopen(filename, "r") ;
apr_pool_cleanup_register(pool, f, fclose, apr_pool_cleanup_null) ;
This code delegates responsibility for cleanup to the pool, so that no further action
from the programmer is required. However, native functions may be less portable
than the APR equivalents from apr_pools and apr_file_io, respectively, and
malloc on most systems will be slower than using the pool.
这个代码代表了pool的清除职责,因此不需要程序员的更进一步的处理.但是本地系统函数比APR中等价的apr_pools和apr_file_io缺少移植性,在大多数系统上malloc要比使用pool慢.
This method of memory management generalizes to resources opaque to Apache
and APR. For example, to open a MySQL database connection and ensure it is
closed after use, you would write the following code:
MYSQL* sql = NULL ;
sql = mysql_init(sql) ;
if ( sql == NULL ) { log error and return failure ; }
apr_pool_cleanup_register(pool, sql, mysql_close,
apr_pool_cleanup_null) ;
sql = mysql_real_connect(sql, host, user, pass,
dbname, port, sock, 0) ;
if ( sql == NULL ) { log error and return failure ; }
这种内存管理方法使得资源对Apache和APR不透明.例如,打开MySQL数据库,确保在使用后被关闭,你可能会编写如下代码:
MYSQL* sql = NULL ;
sql = mysql_init(sql) ;
if ( sql == NULL ) { log error and return failure ; }
apr_pool_cleanup_register(pool, sql, mysql_close,
apr_pool_cleanup_null) ;
sql = mysql_real_connect(sql, host, user, pass,
dbname, port, sock, 0) ;
if ( sql == NULL ) { log error and return failure ; }
Note that apr_dbd (which is discussed in Chapter 11) provides an altogether better
method for managing database connections.
提示:apr_dbd(第11章讨论)为管理数据库连接提供了一个更好的方法.
As a second example, consider XML processing:
xmlDocPtr doc = xmlReadFile(filename);
apr_pool_cleanup_register(pool, doc, xmlFreeDoc,
apr_pool_cleanup_null) ;
/* Now we do things with doc, which may allocate further memory
* managed by the XML library but will be cleaned by xmlFreeDoc
*/
Integrating C++ destructor-cleanup code provides yet another example. Suppose
we have
class myclass {
public:
virtual ~myclass() { do cleanup ; }
// ....
} ;
We define a C wrapper:
void myclassCleanup(void* ptr) { delete (myclass*)ptr ; }
We then register this wrapper with the pool when we allocate myclass:
myclass* myobj = new myclass(...) ;
apr_pool_cleanup_register(pool, (void*)myobj, myclassCleanup,
apr_pool_cleanup_null) ;
// Now we've hooked our existing resource management from C++
// into Apache and never need to delete myobj;
// pool cleanup will do the job for us
第二个例子,考虑XML的处理:
xmlDocPtr doc = xmlReadFile(filename);
apr_pool_cleanup_register(pool, doc, xmlFreeDoc,
apr_pool_cleanup_null) ;
/* 现在开始使用 doc, XML库可能还会在doc中分配内存,但是都会被 xmlFreeDoc释放
*/
另一个例子整合了C++的析构函数.假设我们这样
class myclass {
public:
virtual ~myclass() { do cleanup ; }
// ....
} ;
定义一个C wrapper:
void myclassCleanup(void* ptr) { delete (myclass*)ptr ; }
当我们分配myclass的时候,向pool注册这个wrapper:
myclass* myobj = new myclass(...) ;
apr_pool_cleanup_register(pool, (void*)myobj, myclassCleanup,
apr_pool_cleanup_null) ;
//现在我们用Apache接管了原先的C++资源管理,在不需要去调用delete myobj;pool会
//为我们做这个工作
Implicit and Explicit Cleanup
内在的和清楚的清除操作
Suppose we want to free our resource explicitly before the end of the request
—
for
example, because we
’
re doing something memory intensive but have objects we can
free. We may want to do everything according to normal scoping rules and just use
pool-based cleanup as a fallback to deal with error paths. However, because we registered
the cleanup, it will run regardless of our intentions. In the worst-case scenario,
it could possibly lead to a double-free and a segfault.
我们想在处理请求结束之前就明确的释放我们的资源一一例如,因为我们在做及其需要内存的操作但是又有对象能被释放.我们可能想根据正常范围规则来做事情, 在错误处理通路上仅仅使用基于pool清除作为一个可靠的处理.可是,因为我们注册了清除操作,它的运行操作不会考虑我们的目的.在最坏的情况下,这个可能导致二次释放和段错误.
Another pool function, apr_pool_cleanup_kill, is provided to deal with this
situation. When we run the explicit cleanup, we unregister the cleanup from the
pool. Of course, we can be a little more clever about how we go about this task.
另一个pool函数apr_pool_cleanup_kill,为这种情况提供了处理.当我们运行明确的清除操作的时候,我们从pool中反注册清除操作.当然,我们也能够更灵活的处理这种情况.
Here
’
s the outline of a C++ class that manages itself based on a pool, regardless of
whether it is explicitly deleted:
这里有基于pool的C++类资源管理的原则,不用明确的考虑是否被delete:
class poolclass {
private:
apr_pool_t* pool ;
public:
poolclass(apr_pool_t* p) : pool(p) {
apr_pool_cleanup_register(pool, (void*)this,
myclassCleanup, apr_pool_cleanup_null) ;
}
virtual ~poolclass() {
apr_pool_cleanup_kill(pool, (void*)this, myclassCleanup) ;
}
} ;
If you use C++ with Apache (or APR), you can derive any class from poolclass.
Most APR functions do something equivalent to this, conducting register and kill
operations whenever resources are allocated or cleaned up.
如果你在Apache(或者APR)中使用C++,你能够从poolclass派生任何类.大多数APR函数做的事情和这个一样,管理注册和解除注册操作,无论资源何时被分配或者清除.
In simple C, we would use the following generic form:
在简单C语言中,我们能使用下面这种通用形式:
/* Allocate something */
my_type* my_res = my_res_alloc(args) ;
/* Handle errors */
if (my_res == NULL) {
/* Log error and bail out */
}
/* Ensure it won't leak by registering a cleanup */
apr_pool_cleanup_register(pool, my_res,
my_res_free, apr_pool_cleanup_null) ;
/* ... Now use it as required ... */
/* OK, we're done with it, and we'd like to release it ASAP */
rv = my_res_free(my_res) ;
/* Since we freed it, we want to kill the cleanup */
apr_pool_cleanup_kill(pool, my_res, my_res_free) ;
/* Now handle errors and continue */
if (rv != APR_SUCCESS) { /* or whatever test may be appropriate */
/* ... Log error and bail out or attempt recovery ... */
}
We can also streamline this form by running the cleanup and unregistering it with
the pool using a single function:
apr_pool_cleanup_run(pool, my_res, my_res_free) ;
我们也可以简化这种形式,在pool上运行清除和反注册使用一个单一的函数:
apr_pool_cleanup_run(pool, my_res, my_res_free) ;
3.4.3
Resource Lifetime
3.4.3 资源生命周期
When we allocate resources by using a pool, we automatically ensure that they get
cleaned up at some point. But when? We need to make sure the cleanup happens at
the right time
—
that is, neither while the resource is still in use, nor long after the
resource is no longer required.
当我们使用pool分配资源的时候,在某种程度上能自动确保资源被释放.但是何时?我们需要确定在正确的时间执行清除操作一一既不能在资源还在被使用,也不能在资源长期不被需要之后.
Apache Pools
Apache Pools
Fortunately, Apache makes this process quite easy, by providing different pools for
different types of resource. These pools are associated with relevant structures of the
httpd, and they have the lifetime of the corresponding struct. Four general-purpose
pools are always available in Apache:
•
The request pool, with the lifetime of an HTTP request
•
The process pool, with the lifetime of a server process
•
The connection pool, with the lifetime of a TCP connection
•
The configuration pool
幸运地,Apache十分容易的确保这个过程,通过为不同类型的资源提供不同pools.这些pools绑定在httpd的相关结构,它们有着相应结构的生命周期.在Apache中总是可用的四个一般目的的pools:
• 请求pool,一个HTTP请求的生命周期
• 进程pool,服务器进程的生命周期
• 连接pool,一次TCP连接的生命周期
• 配置pool
The first three, which are associated with the relevant Apache structs, are accessed
as request->pool, connection->pool, and process->pool, respectively. The
fourth, process->pconf, is also associated with the process, but differs from the
process pool in that it is cleared whenever Apache rereads its configuration.
头三个绑定在Apache的相关结构,能各自通过request->pool, connection->pool, and process->pool访问.第四个,
process->pconf,绑定在进程上,和进程pool不同的是在Apache读取它的配置的时候被清除.
The process pool is suitable for long-lived resources, such as those that are initialized
at server start-up. The request pool is suitable for transient resources used to
process a single request.
进程pool适合长期存在的资源,例如在服务器初始化的时候被初始化的资源.请求pool适合处理一个请求的短暂资源.
The connection pool has the lifetime of a connection, which normally consists of
one or more requests. This pool is useful for transient resources that cannot be associated
with a request
—
most notably, in a connection-level filter, where the
request_rec structure is undefined, or in a non-HTTP protocol handler.
连接pool有着一次连接的生命周期,一次连接包括一个或者更多请求.对不只在一个请求有效的短暂资源是有用的一一在没有request_rec数据的连接层过滤器中是特别显著的或者一个非HTTP协议的处理器中.
In addition to these standard pools, special-purpose pools may be created for other
purposes, such as configuration and logging, or may be created privately by modules
for their own use.
除这些标准的pools之外,一些特别其他目的的pools也可以被创建,例如配置和日志,或者为模块自己使用的,也能被创建.
Using Pools in Apache: Processing a Request
在Apache中使用Pools:处理一个请求
All request-processing hooks take the form
所有请求处理拦截像这样
int my_func(request_rec* r) {
/* implement the request processing hook here */
}
This hook puts the request pool r->pool at our disposal. As discussed earlier, the
request pool is appropriate for the vast majority of operations involved in processing
a request. We pass it to Apache and APR functions that need a pool argument
as well as our own.
这个拦截传入请求pool r->pool由我们支配,已经在前面谈到,请求pool适合在处理一个请求过程中的大量操作.我们为需要pool参数的Apache和APR函数也为我们自己传入这个参数.
The process pool is available as r->server->process->pool for operations that
need to allocate long-lived resources
—
for example, caching a resource that should
be computed once and subsequently reused in other requests. However, this process
is a little more complex, and it is generally preferable to derive a subpool from the
process pool, as discussed in Chapters 4 and 10.
The connection pool is r->connection->pool.
通过r->server->process->pool能得到进程pool,对那些需要分配长久资源的操作,进程pool是有效的一一例如,缓存一个资源,应该只被计算一次,能被接下来其他的请求重用.可是,这个过程是有一点复杂的,一般更好的办法是从进程pool继存一个子pool,在第4章和第10章中讨论.
连接pool是r->connection->pool
Using Pools in Apache: Initialization and Configuration
在Apache中使用Pools:初始化和配置
The internal workings of Apache
’
s initialization are complex. As far as modules are
concerned, however, the initialization can normally be treated as a simple procedure:
Just set up a configuration, and everything is permanent. Apache makes that
easy, because most of the relevant hooks have prototypes that pass the relevant pool
as their first argument.
Apache初始化的内部工作是复杂的.可是作为模块关心的,初始化能被简单的看成一个仅仅设置配置的过程,每件事情都是一层不变的.Apache让这个变的容易,因为大多数相关的拦截已经有原型,把相关的pool作为第一个参数传入.
Configuration Handlers
配置处理器
static const char* my_cfg(cmd_parms* cmd, void* cfg, /* args */ )
Use the configuration pool, cmd->pool, to give a configuration the lifetime of the
directive.
static const char* my_cfg(cmd_parms* cmd, void* cfg, /* args */ )
使用配置pool,cmd->pool,来给配置有着指令的生命周期.
Pre-configuration and Post-configuration Hooks
配置前和配置后的拦截
These hooks are unusual in having several pools passed:
static int my_pre_config(apr_pool_t* pool,
apr_pool_t* plog, apr_pool_t* ptemp)
For most purposes, just use the first pool argument. ptemp is suitable for resources
used during configuration, but will be destroyed before Apache goes into operational
mode. plog remains active for the lifetime of the server, but is cleaned up each time
the configuration is read.
传入多个pools参数的这些拦截不常见:
static int my_pre_config(apr_pool_t* pool,
apr_pool_t* plog, apr_pool_t* ptemp)
对大多数情况,仅仅使用第一个pool参数就够了.
ptemp适合配置阶段的资源使用,但是在Apache进入运行模式之前会被销毁.
plog在整个服务的阶段都是有效的,但是在每一次配置被读取的时候被清除.
Child init
子pool
的初始化
static void my_child_init(apr_pool_t* pool, server_rec* s).
The child pool is the first argument.
static void my_child_init(apr_pool_t* pool, server_rec* s).
第一个参数是子pool.
Monitor
监视器
static int my_monitor(apr_pool_t* pool)
The monitor is a special case: It runs in the parent process and is not tied to any
time-limited structure. For this reason, resources allocated in a monitor function
should be explicitly freed. If necessary, a monitor may create and free its own subpool
and manage it as discussed in Chapter 4. Few applications will need to use the
monitor hook.
static int my_monitor(apr_pool_t* pool)
监视器是一个特别的例子:它运行在父进程中,不依赖任何有时效性的结构.因为这个,在监视器函数中分配的资源应该被显示释放.如果可能,监视器可以创建和释放自己的子pool,然后管理这个子pool,在第4章中讨论.很少有程序会需要使用这个监视器拦截.
Using Pools in Apache: Other Cases
在Apache中使用Pools:其他情况
Most Apache modules involve the initialization and request processing we have
already discussed. There are two other cases to deal with, however: connection functions
and filter functions.
大多数Apache模块中涉及的初始化和请求处理过程我们已经讨论过了.可是,这里有两个其它情况需要处理:链接函数和过滤函数
Connection Functions
连接函数
The pre_connection and process_connection connection-level hooks pass a
conn_rec object as their first argument; they are directly analogous to request functions
as far as pool resources are concerned. The create_connection connectioninitialization
hook passes the pool as its first argument. Any module implementing
this hook takes responsibility for setting up the connection.
连接前和连接处理中的连接层拦截传入了一个conn_rec对象作为他们的第一个参数;至于关心的pool资源,它们和请求函数是直接相似的.创建连接时的连接初始化拦截以第一个参数传递pool.任何实现这个拦截的模块负责连接的设置.
Filter Functions
过滤器函数
Filter functions receive an ap_filter_t as their first argument. This object
ambiguously contains both a request_rec and a conn_rec as members, regardless
of whether it is a request-level or a connection-level filter. Content filters should
normally use the request pool. Connection-level filters will get a junk pointer in
f->r (the request doesn
’
t exist outside the protocol layer; see Chapter 8) and must
use the connection pool. Be careful: This can be a trap for the unwary.
过滤器函数接受ap_filter_t作为第一个参数.这个对象模糊地包含request_rec和conn_rec成员,很少考虑是否是请求级别或者连接级别的过滤器.内容过滤器适应正常地使用请求pool.连接级别的过滤器将会得到一个垃圾指针f->r(超出协议层,请求不存在,见第8章),必须使用连接pool.当心:不留意就会掉入这个陷进.
3.4.4
Limitations of Pools
3.4.4 Pools的限制
So far, we have seen the advantages of using pools for resource management.
Naturally, there are also some limitations:
•
Managing resources that have a lifetime that doesn
’
t correspond to any of
Apache
’
s main objects requires more work. This issue is discussed further in
Chapter 4.
•
Allocating resources from a pool is not thread safe. This is rarely an issue,
because most pool allocation by modules when Apache is running on a multithreaded
basis uses a pool owned by an object (HTTP request or TCP connection)
that is thread private at the time of use. Chapter 4 discusses some
cases where thread safety is an issue.
•
APR pools never return memory to the operating system until they are
destroyed (they do, of course, reuse memory, so pool-based applications don
’
t
grow indefinitely). Thus it may sometimes make sense to use malloc rather
than pools when allocating very large blocks of memory. Conversely, using
malloc
in your code may affect binary compatibility. On Windows, it may
prevent your code from being linked with a binary compiled using a different
version of Visual C++, due to incompatibilities in the runtime libraries.
到目前为止,我们已经看到使用pools管理资源的好处.实际中,这里也有一些限制:
• 管理生命周期和Apache主要对象不一直的资源需要更多工作.在第4章中进一步讨论这个情况.
• 从pool分配的资源不是线程安全的.在很少情况下会有问题,因为当Apache运行在一个多线程环境下,在模块大多数pool分配的操作中,基本只有一个对象(HTTP请求或者TCP连接)使用pool,也只在一个线程内部.第4章讨论一些有线程安全问题的一些情况.
• APR pools从不释放内存给操作系统直到它们被销毁(当然,他们这样做,让基于pool的应用程序不会无限制的消耗内存).因此在分配非常大块的内存的时候,我们使用
malloc要比pool好.相反,在你的代码中使用
malloc可能会影响二进制文件的兼容性.在Windows上,由于不兼容的运行期库,这个可以阻止你的代码被链接到使用不同Visual C++版本编译的二进制文件上.
3.5 Selected APR Topics
3.5 谈到的APR话题
APR provides a direct alternative to functions that are familiar and almost certain
to be available on your system without any need for APR. Nevertheless, there are
good reasons to use the APR versions of these functions:
•
APR functions are platform independent and provide for better portability.
•
APR functions get the benefit of APR
’
s pool-based resource management
for free.
APR提供了一个直接可选择的调用函数, 在你的系统上没有APR几乎也是可以的.然而,这里有很好理由去使用APR版本的这些函数:
• APR函数是平台独立的,提供了更好的可以移植性.
• APR函数能从基于pool的资源管理获得免费的好处.
We won
’
t go into detail here. For more information, see the excellent documentation
in the header files.
我们这里不会详细描述.从非常棒的头文件中获取更多信息.
3.5.1
Strings and Formats
3.5.1 字符串和格式化
The apr_strings module provides APR implementations of
•
Common string functions: comparisons, substring matches, copying, and
concatenation
•
stdio-like functions: sprintf and family, including vformatters
•
Parsing, including thread-safe strtok
•
Conversion to and from other data types (e.g., atoi)
apr_strings模块为APR提供了
• 通用字符串函数:比较,子串匹配,拷贝和联接.
• 像stdio函数:
sprintf和同一样的一类,包括v格式.
• 解析,包括线程安全的strtok.
• 和其他数据类型的互转(例如atoi).
APR string handling is based on pools. This scheme brings with it a substantial simplification,
as we very rarely need to worry about the size of a buffer. For example,
to concatenate an arbitrary number of strings, we can use
result = apr_pstrcat(pool, str1, str2, str3, ..., NULL);
without the need to compute the length of result and allocate a buffer in advance.
APR字符串的处理基于pools.这种策略带来了着实的简单,因为我们非常少的需要去考虑缓冲区的大小.例如,去联接一个任意长度的字符串,我们能这样使用
result = apr_pstrcat(pool, str1, str2, str3, ..., NULL);
不需要计算结果的长度,预先分配内存.
Similarly,
result = apr_psprintf(pool, fmt, ...) ;
requires altogether less tedious housekeeping than
length = [compute length here] ;
buf = malloc(length) ;
sprintf(buf, fmt, ...) ;
相似的,
result = apr_psprintf(pool, fmt, ...) ;
一次完成没有下面冗长乏味
length = [compute length here] ;
buf = malloc(length) ;
sprintf(buf, fmt, ...) ;
There is no regular expression support in APR (although there is in Apache), but
the apr_strmatch module provides fast string matching that deals with the issues
of case-insensitive (as well as case-sensitive) searches and non-null-terminated
strings.
在APR中不支持正则表达式(在Apache中支持),但是
apr_strmatch模块提供了一个字符串快速匹配,用来处理大小写不敏感(同样,大小写敏感)的字符串搜索和非null结束的字符串.
3.5.2
Internationalization
3.5.2 国际化
The apr_xlate module provides conversion between different character sets.
At the time of this book
’
s writing, apr_xlate on the Windows platform relies on
a third APR library, apr_iconv, because Windows lacks (or lacked) native internationalization
support. This dependency is expected to be removed in the future.
apr_xlate模块为不同字符集间提供了转换.在本书编写期间, windows平台的apr_xlate依靠一个第三库apr_iconv,因为windows本地的国际化支持.希望将来这个依赖被去掉.
3.5.3
Time and Date
3.5.3 时间和日期
The apr_time module provides a microsecond timer and clock. Because APR
works in microseconds, its fundamental data type apr_time_t is a 64-bit integer
and is not interchangeable with time_t. Macros provided for conversion include
the following:
apr_time模块提供了微秒级时钟.因为APR工作在微秒级,它的基础数据结构apr_time_t是一个64位整型,和time_t不可互换.宏提供的转换包括下面:
/** @return apr_time_t as a second */
#define apr_time_sec(time) ((time) / APR_USEC_PER_SEC)
/** @return a second as an apr_time_t */
#define apr_time_from_sec(sec) ((apr_time_t)(sec) * APR_USEC_PER_SEC)
Other data types include time intervals and a
“
struct tm
”
-like type apr_time_exp_t.
APR time functions include
•
Time now
•
Any time as Greenwich Mean Time (GMT), local time, or a selected time zone
•
Time arithmetic
•
Sleep
•
Time formatted as a ctime or RFC822 string
The apr_date module provides additional functions for parsing commonly used
time and date formats.
其它时间类型包括时间间隔和像”
struct tm”类型的apr_time_exp_t.
APR时间函数包括:
• 现在时间
• 格林威治时间(GMT),当地时间,或者被选择的时区
• 时间计算
• 休眠
• ctime形式的时间格式或者RFC822中规定的字符串
3.5.4
Data Structs
3.5.4 数据结构
Apache provides four data struct modules:
•
apr_table provides tables and arrays.
•
apr_hash provides hash tables.
•
apr_queue provides first in, first out (FIFO) queues.
•
apr_ring provides a ring struct, which is also the basis for APR bucket
brigades.
Apache提供了四个数据类型模块:
•
apr_table提供了表和数组
•
apr_hash提供了哈希表
•
apr_queue提供了先进先出队列(FIFO)
•
apr_ring提供了一个环结构, 环结构也是APR bucket brigade的基础结构.
3.5.4
.1 Arrays
3.5.4.1 数组
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 operations
supported are append (push) and iteration:
APR数组是apr_array_header_t类型,既可以使用对象也可以使用指针.数组类型也可以堆栈形式使用.在数组创建的时候有一个默认的大小.大多数情况下,这个大小是足够的,数组大小也能按照需要增长.支持最常用的操作是追加(压栈)和遍历.
/* 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
3.5.4.2 表
The apr_table_t is an intuitive, higher-level data type built on the array for storing
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.
apr_table_t是直观的,更高级别的数据类型, 构建在存储key/value对的数组之上.它支持增加元素(多个变量),删除元素(没有效率),查找,遍历和清除整个表.它也支持合并和覆盖操作,合并或者清除重复元素.
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) ;
表的key常常是大小写不敏感的(和APR哈希表中的key相反).
/* 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_setn sets 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_mergen adds 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_setn
doesn
’
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) ;
apr_table_set包括apr_table_setn,
apr_table_add,apr_table_addn,apr_table_merge和apr_table_mergen:
•
apr_table_setn 设置一个值,修改key对应的值.
•
apr_table_addn 增加一个新值,如果key已经有对应的值的话,就不处理.
•
apr_table_mergen 增加一个新值,覆盖key已经对应的值.
•
apr_table_set从表中已有的数据条目拷贝;
apr_table_setn没有这个功能(因此当数据是
永久的或者在同一个pool中分配的表是高效的).同样应用到其它函数.
/* 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_merge and
apr_table_overlap provide the ideal foundations for manipulation of HTTP
headers and environment variables in Apache.
更高级别的API和可用的函数像apr_table_merge,
apr_table_overlap提供了漂亮的HTTP的操作.
3.5.4
.3 Hash Tables
3.5.4.3 哈希表
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.
apr_hash_t也存储了key/value对,但是是比apr_table_t更低一级别的数据类型,它有两个优点:
1. key和value可以是随意的数据类型(不像表是大小写敏感的).
2.哈希表随着元素数量的增加有着更好的效率.
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 iteration,
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 size argument.
不像数组和表,哈希表没有初始的大小.最常用的操作是插入和查询.其它操作也包括遍历,拷贝,覆盖和合并.
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)) ;
我们经常遇到的一个特定情况:key是一个字符串.为了确保正确使用字符串语义比较,我们应该使用APR_HASH_KEY_STRING宏取代参数的大小.
3.5.4
.4 Queues
3.5.4.4 队列
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 operations
are blocking and nonblocking push and pop.
apr_queue_t是一个线程安全,有边界的FIFO队列.它也只在支持线程的APR库中有效,它允许多个线程协作处理任务.队列有确定的容量,也能在apr_queue_create中设置.队列主要操作是阻塞和非阻塞的进队和出队.
3.5.4
.5 Rings
3.5.4.5 环
APR_RING is 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;
};
事实上APR_RING不是一个数据类型,是一系列的宏,有些像C++模板;这些宏实现了循环链表和双向链表.Apache中主要的环例子是bucket brigade,我们将在3.5.5节介绍,在第8章中详细讨论.
bucket是环中的一个元素,同时brigade是环结构自身.下面是环结构的声明:
struct apr_bucket {
/**指向brigade 的其他部分*/
APR_RING_ENTRY(apr_bucket) link;
/** bucket的数据字段 */
};
/** 一系列bucket */
struct apr_bucket_brigade {
/** brigade的pool. 数据分配不超出pool,但是会注册pool清除.如果通过一些方法销毁
* brigade,除了pool析构,销毁函数负责解除清除过程.
*/
apr_pool_t *p;
/**brigade中的buckets在这个链表上. */
/*
* apr_bucket_list结构不需要一个实际的名字,因为独立于apr_bucket_brigade结构,它就不
* 存在.环的宏被设计成在这样情况下你可以不用名字参数,但是显然的,Windows编译器
* 不希望那样.
*/
APR_RING_HEAD(apr_bucket_list, apr_bucket) list;
/** bucket从这个链表上分配 */
apr_bucket_alloc_t *bucket_alloc;
};
3.5.5
Buckets and Brigades
3.5.5 Buckets和Brigades
Here
’
s a one-sentence, buzzword-laden overview: Bucket brigades represent a complex
data stream that can be passed through a layered I/O system without unnecessary
copying.
这里有一句很烦恼的话,Bucket Brigades代表复杂的数据流,这个数据流能在系统I/O层传递,没有不必要拷贝操作.
Buckets and brigades form the basis of Apache
’
s data handling, I/O, and filter chain
(which are really three ways of saying the same thing). Use and manipulation of
these is fundamental to filter modules, as is discussed in detail in Chapter 8.
Buckets和brigades形成了Apache数据处理,I/O和过滤链的基础(这三种方式都是在讲同一个东西).使用和操作这些是过滤模块的基础,在第8章中详细讨论.
A bucket brigade is a doubly linked list (ring) of buckets, so we aren
’
t limited to
inserting elements at the front and removing them at the end. Buckets are passed
around only as members of a brigade, although singleton buckets can occur for
short periods of time.
bucket brigade是buckets的一个双向链表(环),因此我们不被限制只在链表前面插入元素和在链表尾部删除元素.
Buckets仅仅以brigade的成员传递,尽管单一的buckets能短时间的存在.
Buckets are data stores of various types. They can refer to data in memory, or part
of a file or mmap area, or the output of a process, among other things. Buckets also
have some type-dependent accessor functions:
The read function returns the address and size of the data in the bucket. If the
data isn
’
t in memory, then it is read in and the bucket changes type so that it
can refer to the new location of the data. If all of the data cannot fit in the
bucket, then a new bucket is inserted into the brigade to hold the rest of it.
The split function divides the data in a bucket into two regions. After a split,
the original bucket refers to the first part of the data and a new bucket inserted
into the brigade after the original bucket refers to the second part of the data.
Reference counts are maintained as necessary.
The setaside function ensures that the data in the bucket has an adequate lifetime.
For example, sometimes it is convenient to create a bucket referring
to data on the stack in the expectation that it will be consumed (e.g., output to
the network) before the stack is unwound. If that expectation turns out not
to be valid, the setaside function is called to move the data somewhere safer.
The copy function makes a duplicate of the bucket structure as long as it
’
s possible
to have multiple references to a single copy of the data itself. Not all
bucket types can be copied.
The destroy function maintains the reference counts on the resources used by
a bucket and frees them if necessary.
Buckets用来多种数据类型的存储.涉及内存中的数据,或者文件的一部分或内存映射,或进程输出,还有一些其它东西.
Buckets也有一些和类型相关的访问函数:
Read函数,返回Buckets中的数据地址和大小.如果数据不在内存中,它将会把数据读到
内存中来,
Buckets会去修改数据类型来保证它能引用新的数据地址.如果在一个Buckets
中装不下所有数据,新的Buckets会被插入到brigade来保留多余的数据.
Split函数,把一个bucket中的数据分成两部分.在分割以后,原始的bucket指向数据的第
一部分,在原始bucket之后插入的新bucket指向数据的第二部分.引用计数被有必要的维
护
Setaside函数,确保bucket中的数据有适当的生存周期.例如,有时我们非常方便的去创建
一个bucket来引用栈上的数据,希望在栈回收前bucket能被销毁(例如,向网络输出).如果
这个希望不是有效的,
setaside函数在某个安全地方被调用来销毁这些数据.
Copy函数,制作一份bucket结构的拷贝,只要可能对一份数据自身拷贝有多重引用.不是
所有的bucket类型都能被拷贝.
Destroy函数,在被bucket使用的资源上维护引用计数,在需要的时候释放它们.
NOTE All of these functions have wrapper macros
[apr_bucket_read(), apr_bucket_destroy(), and so on]. The
wrapper macros should be used rather than using the function
pointers directly.
注意:所有这些函数有封装的宏[apr_bucket_read(),apr_bucket_destroy()等等].应该使用这些封装的宏,不去直接的使用函数指针.
To write a bucket brigade, we first turn the data into an iovec, so that we don
’
t
write too little data at one time. If we really want good performance, then we need
to compact the buckets before we convert the data to an iovec, or possibly while
we are converting to an iovec.
向bucket brigade中写数据,我们必须先把数据转成iovec,因此我们不会在一次写太少的数据.如果我们真正想要好的性能,在我们转换数据到iovec之前或者可能的话,在我们正在转换的时候,我们需要紧密的buckets.
The following bucket types are supported natively in APR:
•
File
—
bucket contents are a file. Commonly used when serving a static file.
•
Pipe
—
bucket contents are a pipe (filesystem FIFO).
•
Socket
—
bucket contents are a socket. Most commonly used by the network
filters.
•
Heap
—
bucket contents are heap memory. Used for stdio-like buffered I/O.
•
Mmap
—
bucket contents are an mmapped file.
•
Immortal
—
bucket contents are memory, which is guaranteed to be valid for
at least the lifetime of the bucket.
•
Pool
—
bucket contents are allocated on a pool.
•
Transient
—
bucket contents may go out of scope and disappear.
•
Flush (metadata)
—
the brigade
’
s contents should be flushed before continuing.
In Apache, that means passing whatever data is available to the next filter in
the chain.
•
EOS (metadata)
—
end of data.
Other types may also be implemented
—
indeed, additional metadata types are used
internally in Apache. This author has implemented bucket types for SQL queries
(using apr_dbd) and for script fragments; both of these types execute and convert
data to another bucket type when read. A third-party library implementing a wide
range of bucket types is serf.2
APR支持下面bucket类型:
•
File
—bucket内容是文件.通常在服务一个静态文件时候使用.
•
Pipe
—bucket内容是管道(文件系统FIFO).
•
Socket
—bucket内容是套接字.通常被网络过滤器使用.
•
Heap
—bucket内容是堆内存.被像stdio缓冲区I/O使用.
•
Mmap
—bucket内容是内存映射文件.
•
Immortal
—bucket内容是内存,保证这个内存最少在一个bucket的生命周期中有效.
•
Pool
—bucket内容是在pool上分配.
•
Transient
—bucket内容可能超出作用域,消失.
•
Flush(元数据)
—brigade的内容应该在继续前被刷新.
在Apache中,那意味着向过滤链中下一个过滤器传递任何可用的数据.
•
EOS (元数据)
—数据的结束.
也能实现其它的数据类型
——
事实上,附加的元数据类型在Apache内部使用.作者已经实现了SQL查询和脚本片段的bucket类型(使用apr_dbd);这两个类型在读取的时候转换数据到其它bucket类型.一个第三方库正在实现一个更宽泛的bucket类型,
serf
2. http://svn.webdav.org/repos/projects/serf/trunk
3.5.6
Filesystem
3.5.6 文件系统
APR modules related to filesystems include the following:
•
apr_file_io provides standard file operations: open/close, stdio-style
read/write operations, locking, and create/delete/copy/rename/chmod. This
module supports ordinary files, temporary files, directories, and pipes.
•
apr_file_info provides filesystem information (stat), directory manipulation
functions (e.g., open, close, read), file path manipulation, and relative
path resolution.
•
apr_fnmatch provides pattern matching for the filesystem, to support wildcard
operations.
•
apr_mmap mmaps a file.
We will see examples of these modules in later chapters.
A third-party extension is apvfs,3 a library that implements a common, APR-based
front end to a wide range of different (virtual) filesystems such as standard files,
APR buckets, archives IPC, and databases.
和文件系统相关的APR模块包括下面:
•
apr_file_io提供标准的文件操作:打开/关闭,stdio样式的读/写,锁定,和创建/删除/拷贝/重命名/权限设置.这个模块提供了原始文件,临时文件,目录和管道.
•
apr_file_info提供文件系统信息(stat),目录管理函数(例如,打开,关闭,读),文件路径操作,和相对路径解析.
•
apr_fnmatch为文件系统提供了样式匹配,来支持通配符的操作.
•
apr_mmap内存映射文件.
我们将在后面章节看到这些模块的例子.
一个第三方的扩展,
apvfs实现了一个通用的,基于APR的从头到尾不同的文件系统(虚拟)例如标准文件,APRbuckets,IPC存档和数据库.
3.5.7
Network
3.5.7 网络
APR provides two modules related to networks:
•
apr_network_io is a socket layer supporting IPv4, IPv6, and the TCP, UDP,
and SCTP protocols. It supports a number of features subject to underlying
operating system support, and will emulate them where not available. These
features include send file, accept filters, and multicast.
•
apr_poll provides functions for polling a socket (or other descriptor).
和网络相关的,APR提供了两个模块:
•
apr_network_io在socket层支持IPv4,IPv6和TCP,UDP和SCTP协议.它支持一系列的特征,由于操作系统的限制,在不可用的情况下会被模拟出来.这些特征包括发送文件,接受过滤器和多播.
•
apr_poll提供socket轮询(或者其它描述符).
3.5.8
Encoding and Cryptography
3.5.8 编码和加密
APR does not provide a cryptographic library, and Apache
’
s mod_ssl relies on the
external OpenSSL package for implementation of transport-level security. APR
APR
不提供加密库
,Apache
的
mod_ssl
依赖外部的
OpenSSL
包来实现传输层的安全
.
3. http://apvfs.sourceforge.net/
does support a number of data encoding and hashing techniques in its
apr_base64
, apr_md4, apr_md5, and apr_sha1 modules.
APR提供数据编码和在
apr_base64,
apr_md4,
apr_md5, 和
apr_sha1中的哈希技术.
3.5.9
URI Handling
3.5.9 URI处理
The apr_uri module defines a struct for URIs/URLs, and provides parsing and
unparsing functions:
apr_uri模块为URI/URL定义了一个结构,提供解析和反解析功能:
/**
* A structure to encompass all of the fields in a URI
*/
struct apr_uri_t {
/** Scheme ("http"/"ftp"/...) */
char *scheme;
/** Combined [user[:password]/@]host[:port] */
char *hostinfo;
/** User name, as in http://user:passwd/@host:port/ */
char *user;
/** Password, as in http://user:passwd/@host:port/ */
char *password;
/** Hostname from URI (or from Host: header) */
char *hostname;
/** Port string (integer representation is in "port") */
char *port_str;
/** The request path (or "/" if only scheme://host was given) */
char *path;
/** Everything after a '?' in the path, if present */
char *query;
/** Trailing "#fragment" string, if present */
char *fragment;
/** Structure returned from gethostbyname() */
struct hostent *hostent;
/** The port number, numeric, valid only if port_str != NULL */
apr_port_t port;
/** Has the structure been initialized? */
unsigned is_initialized:1;
/** Has the DNS been looked up yet? */
unsigned dns_looked_up:1;
/** Has the DNS been resolved yet? */
unsigned dns_resolved:1;
};
The main functions provided are apr_uri_parse and apr_uri_unparse, which
convert between a string and the apr_uri struct.
提供的主要函数是apr_uri_parse 和 apr_uri_unparse,用来在字符串和apr_uri结构之间转换.
3.5.10 P
rocesses and Threads
3.5.10 进程和线程
•
apr_thread_proc provides process and thread management functions: creation,
parent
–
child relationships including environment propagation, pipes,
rendezvous, and wait.
•
apr_signal provides basic signal handling.
•
apr_global_mutex provides global locks that protect the calling thread bothfrom
other threads and processes.
•
apr_thread_proc提供进程和线程管理:创建,父子关系包括环境变量的继承,管道,集合,和等待
•
apr_signal提供基本信号处理.
•
apr_global_mutex提供全局锁,从其它线程进程中保护被执行的线程.
Processes
•
apr_proc_mutex provides locks for the calling process against other
processes.
•
apr_shm provides shared memory segments.
进程
•
apr_proc_mutex 提供当前执行进程锁,阻止其它进程
•
apr_shm 提供共享内存段.
Threads
•
apr_thread_mutex and apr_thread_rwlock provide thread locks/mutexes.
•
apr_thread_cond provides thread conditions for synchronization of different
threads in a process.
线程
•
apr_thread_mutex 和
apr_thread_rwlock 提供线程锁和互斥量.
•
apr_thread_cond 提供同一进程中的线程同步条件.
Modules should be able to run in a multiprocess and/or multithreaded environment.
Although they will rarely need to create a new thread, they may need to use
mutexes, shared memory, or other techniques to share resources and avoid race conditions.
Techniques for working with threads and processes in Apache are discussed
in Chapter 4.
模块应该能在多进程和多线程环境下运行.尽管它们很少需要创建新的线程,可能需要使用互斥量,共享内存,或其它共享资源的方法,避免竞争.在第4章中讨论线程和进程的操作技巧.
3.5.11
Resource Pooling
3.5.11 资源缓存
The apr_reslist module manages a pool of persistent resources.
A database is a fundamental component of many web applications. Unfortunately,
connecting to it incurs an overhead that affects traditional application architectures
such as CGI and the environment commonly known as LAMP (Linux, Apache,
MySQL, [Perl|PHP|Python]). Using apr_reslist (APR
’
s resource pooling module)
with Apache 2’s threaded MPMs, we can achieve significant improvements in
performance and scalability in applications using
“
expensive
”
resources such as databases,
or back-end connections when proxying an application server.
Chapter 11 presents the DBD framework, which is one of the main applications of
connection pooling.
apr_reslist模块管理一个永久存在的资源池.数据库是许多web程序的基础部件.不幸地,连接数据库招致负载,影响传统应用程序结构例如CGI和环境,普遍知道的LAMP (Linux,Apache,MySQL,[Perl|PHP|Python]).使用Apache2线程模式MPM的apr_reslist(APR的资源缓存模块),在使用”昂贵”资源,例如数据库,或者代理应用程序服务的后端连接,的应用程序中,我们能达到显著的性能和平衡性的提升.
第11章展现一个DBD框架,是一个连接池的主要应用程序.
3.5.12 A
PI Extensions
3.5.12 API扩展
The following modules serve to enable new APIs:
•
apr_hooks provides Apache
’
s hooks, a mechanism for exporting an API where
an extension (module) can insert its own processing
•
apr_optional_hooks provides optional hooks, enabling different modules
to use each other
’
s APIs when both are present without creating a dependency.
•
apr_optional provides optional functions, so that a module can use functions
exported by another module without creating a dependency.
These extensions are discussed in depth in Chapter 10.
下面这些模块服务新的API:
•
apr_hooks 提供Apache拦截,导出API的一种方法,扩展(模块)能够插入自己的处理过程.
•
apr_optional_hooks 提供可选的拦截,允许不同的模块相互使用各自的API,当这些没有显示的创建依赖.
•
apr_optional提供可选函数,因此模块能使用其它模块导出的函数,在没有创建依赖的时候.
这个扩展在第10章中深入讨论..
3.6 Databases in APR/Apache
3.6 APR/Apache中的数据库
Readers of a certain age will recollect a time in the 1980s when every application
for the PC came bundled with hundreds of different printer drivers on ever-growing
piles of floppy disks. Eventually, the operating system implemented the sensible
solution: a unified printing API, so that each printer had a single driver, and each
application had a single print function that works with any driver.
The history of database support in Apache echoes this evolutionary path. At first,
Apache had no database support, so every module needing it had to implement it.
Apache 1.3 offered separate, yet virtually identical modules for authentication with
NDBM and Berkeley DB, and a whole slew of different (third-party) authentication
modules for popular SQL databases such as MySQL. Similarly, every scripting
language
—
such as Perl, PHP and Python
—
had its own database management.
In time for the release of Apache 2.0, the apr_dbm module was developed to provide
a unified interface for the DBM (simple key/value lookup) class of databases.
Most recently, the apr_dbd module has been introduced, providing an analogous
API for SQL databases. Just as with the printer drivers, the APR database classes
eliminate the need for duplication and, as such, are the preferred means of database
support for new applications in APR and Apache.
有一定年龄的读者会想起1980年代,PC的每一个应用程序有着许许多多的不同打印机驱动,用大堆的软盘装着.最后,操作系统实现了一个明智的方案:统一打印API,因此每一个打印机有单一的驱动,每一个应用程序有单一的打印函数,这个函数能和任何打印驱动工作.
Apache的数据库支持有着同样的进化过程.首先,Apache没有数据库支持,因此每一个需要数据库的模块不得不自己来实现.Apache1.3提供了独立的,事实上一样的模块来和NDBM,伯克利DB连接,为流行的SQL数据库例如MySQL,又是另一个完全不同的连接模块(第三方).相似的,每个脚本语言,例如Perl,PHP和Python,有这个自己的数据库管理.
在Apache2.0发布时候,apr_dbm模块被开发出来,为DBM(简单的key/value查询)类的数据库提供一个统一的接口.最近,apr_dbd模块也被开发出来,为SQL数据库提供相似的API.正像打印机驱动,APR数据库结束了重复的需要,为开发APR和Apache中的新程序,也同样是首选的数据库支持.
3.6.1
DBMs and apr_dbm
3.6.1 DBM和apr_dbm
DBMs have been with us since the early days of computing, when the need for fast
keyed lookups was recognized. The original DBM is a UNIX-based library and file
format for fast, highly scalable, keyed access to data. It was followed (in order) by
NDBM (
“
new DBM
”
), GDBM (
“
GNU DBM
”
), and the Berkeley DB. This last is
by far the most advanced, and the only DBM under active development today.
Nevertheless, all of the DBMs from NDBM onward provide the same core functionality
used by most programs, including Apache. A minimal-implementation
SDBM is also bundled with APR, and is available to applications along with the
other DBMs.
在早期,当我们需要快速的基于key查询,我们已经有DBM.原始的DBM是一个基于UNIX的库和格式化文件,这个文件有着快速,高平衡性,通过关键词访问数据的能力.依次是NDBM(“新DBM”),GDBM(“GNU DBM”)和伯克利DB.最后一个是至今最先进的,也是今天仅有的一个还在继续开发.不过,所有从NDBM发展出来的DBM向前提供了一样的核心功能, 被大多数程序员使用,包括Apache.有着最小化实现的SDBM也被捆绑在APR中,连同其他DBM一起都是对应用程序可用的.
Although NDBM is now old
—
like the city named New Town (
“
Neapolis
”
) by the
Greeks in about 600 B.C. and still called Naples today
—
it remains the baseline
DBM. NDBM was used by early Apache modules such as the Apache 1.x versions
of mod_auth_dbm and mod_rewrite. Both GDBM and Berkeley DB provide
NDBM emulations, and Linux distributions ship with one or other of those emulations
in place of the
“
real
”
NDBM, which is excluded for licensing reasons.
Unfortunately, the various file formats are totally incompatible, and there are subtle
differences in behavior concerning database locking. These issues led a steady
stream of Linux users to report problems with DBMs in Apache 1.x.
尽管NDBM现在落后了,像
Apache 2 replaces direct access to a DBM with a unified wrapper layer, apr_dbm.
There can be one or more underlying databases; this determination is made at build
time, either through a configuration option or by being detected automatically by
the build scripts (the default behavior). The database to be used by an application
may be passed as a parameter whenever a DBM is opened, so it is under direct programmer
control (or administrator control, if the database is configurable) and can
be trivially switched if that ever becomes necessary. Alternatively, for cases like
authentication that are known to work well with any DBM, it can use a system
default. Apache has to support only a single DBM interface, so, for example, a single
DBM authentication module serves regardless of the underlying DBM used.
The apr_dbm layer, which is similar to the DBM APIs, is documented in
apr_dbm.h. When programming with it, one should not assume any locking,
although update operations are safe if the DBM is either GDBM or the original
NDBM. Using a mutex for critical updates makes it safe in all cases.
The DBM functions supported in APR are basically the same as those common to
all of the DBMs
—
namely, an API essentially equivalent to NDBM, GDBM, and
early versions of Berkeley DB. Advanced capabilities of recent Berkeley DB versions,
such as transactions, are not supported, so applications requiring them have
to access DB directly.
Example
The function fetch_dbm_value in mod_authn_dbm looks up a value in a DBM
database.
static apr_status_t fetch_dbm_value(const char *dbmtype,
const char *dbmfile,
const char *user, char **value,
apr_pool_t *pool)
{
apr_dbm_t *f;
apr_datum_t key, val;
apr_status_t rv;
rv = apr_dbm_open_ex(&f, dbmtype, dbmfile, APR_DBM_READONLY,
APR_OS_DEFAULT, pool);
if (rv != APR_SUCCESS) {
return rv;
}
key.dptr = (char*)user;
#ifndef NETSCAPE_DBM_COMPAT
key.dsize = strlen(key.dptr);
#else
key.dsize = strlen(key.dptr) + 1;
#endif
*value = NULL;
if (apr_dbm_fetch(f, key, &val) == APR_SUCCESS && val.dptr) {
*value = apr_pstrmemdup(pool, val.dptr, val.dsize);
}
apr_dbm_close(f);
return rv;
}
3.6.2
SQL Databases and apr_dbd
3.6.2 SQL数据库和apr_dbd
NOTE The apr_dbd module is not available in APR0.x and,
therefore, Apache 2.0. It requires APR 1.2 or higher, or the
current version of CVS.
注意:
apr_dbd模块在APR 0.x版本中不可用,因此Apache2.0需要APR1.2或者更高版本,或CVS的当前版本.
SQL is the standard for nontrivial database applications, and many such databases
are regularly used with Apache in web applications. The most popular option is
the lightweight open-source MySQL, but it is merely one choice among many
possibilities.
SQL是有实际价值数据库程序的标准,在web服务中,许多这样数据库正被Apache慢慢使用.最流行的是轻量级的开源MySQL,但是它仅仅是许多选择中的一种选择.
SQL databases are altogether bigger and more complex than DBMs, and are not in
general interchangeable, except where applications are explicitly designed to be
portable (or in a limited range of simple tasks). Nevertheless, a unified API for SQL
applications brings benefits analogous to the printer drivers.
SQL数据库比DBM更大,更复杂,通常,它们是不可互换的,除了应用程序被明确设计成可移植的(或者在有限的简单任务中),不过,SQL程序的统一API带来了和打印机驱动类似的好处.
The apr_dbd module is a unified API for using SQL databases in Apache and other
APR applications. The concept is similar to Perl
’
s DBI/DBD framework or libdbi
for C, but apr_dbd differs from these in that APR pools are used for resource
management. As a consequence, it is much easier to work with apr_dbd in APR
applications.
在Apache和其它APR应用程序中,apr_dbd模块用统一的API来使用SQL数据库.这个观点很像Perl的DBI/DBD框架或者C的libdbi,但是apr_dbd和这些不同的是,由于APR的pool被用来资源管理,因而,在APR应用程序中,能更容易的使用apr_dbd.
The apr_dbd module is also unusual within APR in terms of its approach. Whereas
the apr_dbd API is compiled into libaprutil, the drivers for individual databases
may be dynamically loaded at runtime. Thus, when you install a new database package,
you can install an APR driver for it without having to recompile the whole of
APR or APR-UTIL.
在APR中很少使用apr_dbd模块,尽管apr_dbd的API被编译到libaprutil库中,每一个独立的数据驱动在运行时期动态加载,因此,当你安装一个新的数据库的时候,你能安装APR数据库驱动,不用去重编译整个APR或者APR-UTIL.
At the time of this writing, apr_dbd supports the MySQL, PostgreSQL, SQLite,
and Oracle databases. Drivers for other databases will likely be contributed in due
course.
在这本书编写时候,apr_dbd支持MySQL,PostgreSQL,SQLite和Oracle数据库.其它数据库的驱动能在需要的时候被开发出来.
The MySQL Driver
MySQL数据驱动
Apache views MySQL as a special case. Because it is licensed under the GNU
General Public License (GPL), a driver for MySQL must also be distributed under
the GPL (or not at all). This requirement is incompatible with Apache licensing
policy, because it would impose additional restrictions on Apache users.
The author has dealt with this issue by making a MySQL driver available separately4
and licensing it under the GPL. Users requiring this driver should download it into
the apr_dbd directory or folder and build it there. If MySQL is installed in a standard
location, it should then be automatically detected and built by the standard
APR-UTIL configuration process.
Apache把MySQL作为一个特殊的情况,因为MySQL遵守GNU GPL,MySQL数据驱动的开发也必须遵守GPL(或者根本就不).这个和Apache的版权许可有冲突,因为对Apache用户,Apache的版权许可会有一些附加的限制.
Apache已经解决这个问题,通过独立使用MySQL数据驱动和让它遵守GPL.需要这个数据驱动的用户应该自行下载到apr_dbd目录,然后在这里编译.如果MySQL安装在标准目录,应该通过APR-UTIL配置过程自动被发现和编译.
Usage
使用
Apache modules should normally use apr_dbd through the provider module
mod_dbd.
Apache模块应该使用mod_dbd模块提供的apr_dbd.
3.7 Summary
3.7 总结
This chapter presented a brief overview of the APR and APR-UTIL (APU), focusing
on those modules most likely to be of interest to developers of Apache applications.
Many of the topics introduced here are discussed in more depth in later
chapters where they become relevant
—
indeed essential
—
to the techniques presented
there.
这个章节展示了APR和APR-UTIL(APU)的大概轮廓,专注这些模块很像Apache应用程序开发者感兴趣的.在这里介绍的很多主题,在以后章节会有更深入的讨论,这些章节会是技术相关展现(必须的).
Specifically, this chapter identified the principal roles of APR:
•
A platform-independent operating system layer
•
A solution to resource management issues
•
A utilities and class library
We took a detailed look at the following topics:
•
APR conventions and style
•
APR pools and resource management in Apache
•
The APR database classes
•
The principal APR types
We also engaged in a brief tour of other APR modules.
明确地,这个章节对APR主要角色进行归类:
• 一个和操作系统层无关的平台.
• 一个资源管理的解决方案.
• 实用集库.
我们已经详细讨论下面主题:
• APR 规定和设计.
• Apache中的APR pool和资源管理.
• APR数据库
• 主要的APR 类型
我们也简短的讨论其它APR模块..
4. http://apache.webthing.com/database/
An appreciation of the APR is fundamental to all C programming in Apache, and
the remainder of this book will use it extensively. For further reading on the APR,
you can refer to the excellent API documentation generated automatically from the
header files (available for browsing at apr.apache.org) and to INOUE Seiichiro
’
s
tutorial.5
所有Apache的C语言开发者感激APR,本书其它部分会更宽泛的使用APR.为了更进一步了解APR,你能够参考从头文件自动生成的非常棒的API文档(可以查看apr.apache.org网站),也可以参考INOUE Seiichiro的指南.
5. http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial.html