Tutorial - rings

Rings are new datatype on version 0.99. Ring is techincally circular double linked datatype with defined current (active) position. Rings use same path semantics than other scache functionality. Every path can contain a ring again containing zero or more items.

By definition rings don't have begin or end, but scache defines start of the ring to be pointer to current position of ring, while end of the ring being position just before current position.

Rings support following operations :

With functions above other datatype like queues and stacks (FIFOs and LIFOs) can be quite straighforwardly implemented.

Main uses for rings are work queues where clients push data to queue to be further processed and consumed by some dedicated server process. If you are going to implement work queue please ensure to have reliable consumer emptying queue to not risk exhausting the memory.

Examples

Enumerating through ring :

/* purge possible pre-existing */
scache_rnclear($sess, 'queue');  

/* populate ring */
scache_rnpush($sess, 'queue', 1); // as first element
scache_rnpush($sess, 'queue', 2); // as first element
scache_rnpush($sess, 'queue', 3); // as first element

for($i = 0, $count = scache_rnsize($sess, 'queue'); $i < $count; $i++)
    $val = scache_rnget($sess, 'queue');

Polling other positions than current position can be done with scache_iov. Please keep in mind, that rotation and querying with separate functions contain race condition in possibility of other separate clients accessing and rotating same ring between your client's accesses. Therefore combined rotation and querying must be done through scache_iov.

function scache_rngetlast($sess, $path) {
   list($dummy1, $val, $dummy2) =
      scache_iov($sess,
                 Array(Array(SCIOP_RNROTB, $path, 1),
	               Array(SCIOP_RNGET, $path),
	               Array(SCIOP_RNROTF, $path, 1)));
    return $val;
}

/* purge possible pre-existing */
scache_rnclear($sess, 'queue');

/* populate ring */
scache_rnpush($sess, 'queue', 1); // as first element
scache_rnpush($sess, 'queue', 2); // as first element
scache_rnpush($sess, 'queue', 3); // as first element

echo "Last-1: " . scache_rngetlast($sess, 'queue') . "\n"; // displays 3
echo "Last-2: " . scache_rngetlast($sess, 'queue') . "\n"; // displays 3
?>

Misc notes

Rings are enabled by default, but disabling them by server config should be considered on semi-hostile environment.

Rings are persistent data storage, so everything pushed to rings will be there until someone purges them. There is of cource memory limitter to prevent rings from hogging all system resources, but once ring hits on limit nothing can be pushed there until some data is purged to make space. This leaves door open for denial of service attack.

To make recovering harder there is no scache_shcoll like scache_rncoll() function to enumerate over rings to kill hostile one. This leaves very little options for graceful recovery.

If you are going to build workqueue like functionality assumption is that you keep good track where they are. Put your rings at least under some subdirectory to get rid of them without having to kill whole scached daemon.