scache_coll
Description
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
Return values
TRUE on success, FALSE on failure.
In case of failure, error codes resolvable by scache_lasterr is one of below :
- SCERR_NOT_EXIST Path given does not exist or is not type SCNODE_BRANCH (ie. subtree)
- SCERR_NO_ACCESS Listing is disabled by server config.
- SCERR_NO_SESSION Connected session does not exist or has been expired. Connection is not valid any more.
- SCERR_LIMITS_REACHED Partition has exceeded its memory or node limits and new session cannot be created until memory is freed.
- SCERR_NOT_CONNECTED Connection to backend is broken and cannot be reconnected.
- SCERR_PROTOCOL Internal protocol error has occurred when communicating to backend. This indicates something is severely broken.
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(); } }