Blame design-guide.txt

Packit 3adb1e
APACHE COMMONS: serf                                    -*-indented-text-*-
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
TOPICS
Packit 3adb1e
Packit 3adb1e
  1. Introduction
Packit 3adb1e
  2. Thread Safety
Packit 3adb1e
  3. Pool Usage
Packit 3adb1e
  4. Bucket Read Functions
Packit 3adb1e
  5. Versioning
Packit 3adb1e
  6. Bucket lifetimes
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
-----------------------------------------------------------------------------
Packit 3adb1e
Packit 3adb1e
1. INTRODUCTION
Packit 3adb1e
Packit 3adb1e
This document details various design choices for the serf library. It
Packit 3adb1e
is intended to be a guide for serf developers. Of course, these design
Packit 3adb1e
principles, choices made, etc are a good source of information for
Packit 3adb1e
users of the serf library, too.
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
-----------------------------------------------------------------------------
Packit 3adb1e
Packit 3adb1e
2. THREAD SAFETY
Packit 3adb1e
Packit 3adb1e
The serf library should contain no mutable globals, making it is safe
Packit 3adb1e
to use in a multi-threaded environment.
Packit 3adb1e
Packit 3adb1e
Each "object" within the system does not need to be used from multiple
Packit 3adb1e
threads at a time. Thus, they require no internal mutexes, and can
Packit 3adb1e
disable mutexes within APR objects where applicable (e.g. pools that
Packit 3adb1e
are created).
Packit 3adb1e
Packit 3adb1e
The objects should not have any thread affinity (i.e. don't use
Packit 3adb1e
thread-local storage). This enables an application to use external
Packit 3adb1e
mutexes to guard entry to the serf objects, which then allows the
Packit 3adb1e
objects to be used from multiple threads.
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
-----------------------------------------------------------------------------
Packit 3adb1e
Packit 3adb1e
3. POOL USAGE
Packit 3adb1e
Packit 3adb1e
For general information on the proper use of pools, please see:
Packit 3adb1e
Packit 3adb1e
  http://cvs.apache.org/viewcvs/*checkout*/apr/docs/pool-design.html
Packit 3adb1e
Packit 3adb1e
Within serf itself, the buckets introduce a significant issue related
Packit 3adb1e
to pools. Since it is very possible to end up creating *many* buckets
Packit 3adb1e
within a transaction, and that creation could be proportional to an
Packit 3adb1e
incoming or outgoing data stream, a lot of care must be take to avoid
Packit 3adb1e
tying bucket allocations to pools. If a bucket allocated any internal
Packit 3adb1e
memory against a pool, and if that bucket is created an unbounded
Packit 3adb1e
number of times, then the pool memory could be exhausted.
Packit 3adb1e
Packit 3adb1e
Thus, buckets are allocated using a custom allocator which allows the
Packit 3adb1e
memory to be freed when that bucket is no longer needed. This
Packit 3adb1e
contrasts with pools where the "free" operation occurs over a large
Packit 3adb1e
set of objects, which is problematic if some are still in use.
Packit 3adb1e
Packit 3adb1e
### need more explanation of strategy/solution ...
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
-----------------------------------------------------------------------------
Packit 3adb1e
Packit 3adb1e
4. BUCKET READ FUNCTIONS
Packit 3adb1e
Packit 3adb1e
The bucket reading and peek functions must not block. Each read
Packit 3adb1e
function should return (up to) the specified amount of data. If
Packit 3adb1e
SERF_READ_ALL_AVAIL is passed, then the function should provide
Packit 3adb1e
whatever is immediately available, without blocking.
Packit 3adb1e
Packit 3adb1e
The peek function does not take a requested length because it is
Packit 3adb1e
non-destructive. It is not possible to "read past" any barrier with a
Packit 3adb1e
peek function. Thus, peek should operate like SERF_READ_ALL_AVAIL.
Packit 3adb1e
Packit 3adb1e
The return values from the read functions should follow this general
Packit 3adb1e
pattern:
Packit 3adb1e
Packit 3adb1e
    APR_SUCCESS    Some data was returned, and the caller can
Packit 3adb1e
                   immediately call the read function again to read
Packit 3adb1e
                   more data.
Packit 3adb1e
Packit 3adb1e
                   NOTE: when bucket behavior tracking is enabled,
Packit 3adb1e
                   then you must read more data from this bucket
Packit 3adb1e
                   before returning to the serf context loop. If a
Packit 3adb1e
                   bucket is not completely drained first, then it is
Packit 3adb1e
                   possible to deadlock (the server might not read
Packit 3adb1e
                   anything until you read everything it has already
Packit 3adb1e
                   given to you).
Packit 3adb1e
Packit 3adb1e
    APR_EAGAIN     Some data was returned, but no more is available
Packit 3adb1e
                   for now. The caller must "wait for a bit" or wait
Packit 3adb1e
                   for some event before attempting to read again
Packit 3adb1e
                   (basically, this simply means re-run the serf
Packit 3adb1e
                   context loop). Though it shouldn't be done, reading
Packit 3adb1e
                   again will, in all likelihood, return zero length
Packit 3adb1e
                   data and APR_EAGAIN again.
Packit 3adb1e
Packit 3adb1e
                   NOTE: when bucket behavior tracking is enabled,
Packit 3adb1e
                   then it is illegal to immediately read a bucket
Packit 3adb1e
                   again after it has returned APR_EAGAIN. You must
Packit 3adb1e
                   run the serf context loop again to (potentially)
Packit 3adb1e
                   fetch more data for the bucket.
Packit 3adb1e
Packit 3adb1e
    APR_EOF        Some data was returned, and this bucket has no more
Packit 3adb1e
                   data available and should not be read again. If you
Packit 3adb1e
                   happen to read it again, then it will return zero
Packit 3adb1e
                   length data and APR_EOF.
Packit 3adb1e
Packit 3adb1e
                   NOTE: when bucket behavior tracking is enabled,
Packit 3adb1e
                   then it is illegal to read this bucket ever again.
Packit 3adb1e
Packit 3adb1e
    other          An error has occurred. No data was returned. The
Packit 3adb1e
                   returned length is undefined.
Packit 3adb1e
Packit 3adb1e
In the above paragraphs, when it says "some data was returned", note
Packit 3adb1e
that this could be data of length zero.
Packit 3adb1e
Packit 3adb1e
If a length of zero is returned, then the caller should not attempt to
Packit 3adb1e
dereference the data pointer. It may be invalid. Note that there is no
Packit 3adb1e
reason to dereference that pointer, since it doesn't point to any
Packit 3adb1e
valid data.
Packit 3adb1e
Packit 3adb1e
Any data returned by the bucket should live as long as the bucket, or
Packit 3adb1e
until the next read or peek occurs.
Packit 3adb1e
Packit 3adb1e
The read_bucket function falls into a very different pattern. See its
Packit 3adb1e
doc string for more information.
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
-----------------------------------------------------------------------------
Packit 3adb1e
Packit 3adb1e
5. VERSIONING
Packit 3adb1e
Packit 3adb1e
The serf project uses the APR versioning guidelines described here:
Packit 3adb1e
Packit 3adb1e
  http://apr.apache.org/versioning.html
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
-----------------------------------------------------------------------------
Packit 3adb1e
Packit 3adb1e
6. BUCKET LIFETIMES
Packit 3adb1e
Packit 3adb1e
### flesh out. basically: if you hold a bucket pointer, then you own
Packit 3adb1e
### it. passing a bucket into another transfers ownership. use barrier
Packit 3adb1e
### buckets to limit destruction of a tree of buckets.
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
-----------------------------------------------------------------------------