scache_coll

Description

bool scache_coll(resource session, string path, string target)
bool $SCacheConnection->coll(string path, string target)

scache_coll enumerates all direct subkeys on given path in private namespace and stores result into path target. Resulting listing is not returned and needs to be separately fetched with scache_get.

scache_coll produces PHP associative array where array keys are the subkeys found and values are the nodes nodetype, either SCNODE_VALUE or SCNODE_BRANCH.

In other words; this is like (dir|ls) /some/path > /targetpath/outputhere

Parameters

session
Session resource returned from scache_open, scache_reset or scache_connect
path
Path from where subkeys are to be collected. This path needs to be type SCNODE_BRANCH.
target
Target path where result is to be stored.

Return values

TRUE on success, FALSE on failure.

In case of failure, error codes resolvable by scache_lasterr is one of below :

Notes

When querying some path, keys are first enumerated in complete and after that stored to given location, so it is safe to store result under same path, either replacing or as subkey.

Listing very large subtrees (tens of thousands of keys) results large serialized php array to be stored. This might lead to hits on memory limits both on scached and also on querying client when later unserializing this returned large array.

Subkey listing can be disabled on scached's server config, thought disabling does not make much sense on private session namespace. Only imaginable reasons might be for ensuring good programming practices. If you are querying listings for some other reason than immediate index building, you are probably doing something very wrong. scache_add and scache_replace are for controlling whether to overwrite or not. All other ways lead to race conditions.

Notes II (six years later)

Generally scache_coll should not exist in it's current form. It has capability of heavy burdening (and even killing) the scache backend, it should not rely on php's serialize but provide some more portable format and it's implementation is something I really dislike.

Examples

Simple listing :

<?php
$sess = scache_reset('MySess');

scache_set($sess, 'my/path/somevalue', 'nothing');
scache_set($sess, 'my/path/anothervalue', 'nothing');
scache_set($sess, 'my/path/extras', 'nothing');
scache_set($sess, 'my/path/subdir/val1', 'nothing');
scache_set($sess, 'my/path/subdir/val2', 'nothing');

# collect keys under "my/path" and store them "my/listing"
scache_coll($sess, 'my/path', 'my/listing');

print_r(scache_get($sess, 'my/listing'));

/* outputs
Array
(
  [anothervalue] => 3
  [extras] => 3
  [somevalue] => 3
  [subdir] => 2
)
*/
?>

Example below is more complicated lockless example for storing and caching values when there might be multiple writers to same data simultaneously. This is also an example, how atomicity of scache_iov can be used to avoid race conditions with help of shared counters.

(This is actually example of scache_shcoll.)

<?php
$sess = scache_reset('MySess');
	
/* generate cached page for current datas in "nodes/data".
   store with current value of counter. scache_iov is atomic so
   no other process can get in middle */

function rebuild_index($serial, $listing) {
	
    global $sess;
	
    list($serial, $collok, $listing) =
        scache_iov($sess, 
	Array(Array(SCIOP_VGET, "nodes/serial"),
              Array(SCIOP_SHCOLL, "nodes/data", "nodes/listing"),
	      Array(SCIOP_SHGET, "nodes/listing")));
	
    $prepared = prepare_listing_to_cached_html($listing);

    /* store data with current serial */
    scache_set($sess, "nodes/prepared",
               Array('serial' => $serial,
                     'prepared' => $prepared));
    return $prepared;
}
	
/* for storing new data and incrementing counter to
   track invalidated cached index */

function store_node($node, $value) {

    list($stored, $serial) =
	scache_iov($GLOBALS['sess'], 
	           Array(Array(SCIOP_SHSET, "nodes/data/$node", $value),
	                 Array(SCIOP_VADD, "nodes/serial", 1)));
	
    /* skipped if ($stored && $listed) for simplicity) */
    rebuild_index();
}
	
/* return cached data, but verify serial number stored
   with it matches currend shared counter */

function getlisting() {
	
    list($serial, $prepared) =
        scache_iov($GLOBALS['sess'], 
	           Array(Array(SCIOP_VGET, "nodes/serial"),
		         Array(SCIOP_SHGET, "nodes/prepared")));
	
    if ($prepared && ($prepared['serial'] === $serial)) {
        return $prepared; /* cached matches current serial */
    } else {
        return rebuild_index();
    }
}