tedious / stash Goto Github PK
View Code? Open in Web Editor NEWThe place to keep your cache.
Home Page: http://www.stashphp.com
License: BSD 3-Clause "New" or "Revised" License
The place to keep your cache.
Home Page: http://www.stashphp.com
License: BSD 3-Clause "New" or "Revised" License
The filesystem driver saves in-memory the on-disk path corresponding to an item, using an array.
The ephemeral driver stores items in memory using an array.
The problem both have is that the keys into the in-memory array are calculated using an optimistic algorithm: implode keys using a one-char separator, '/' in one case, '#' in the other.
This makes it easy to have collisions, using keys such as:
array( "##", "#" ) vs array( "#", "##" )
and
array( "/", "/" ) vs array( "//", "/" )
A short-term fix would be to make the separator char an attribute passed via constructor, so that users can decide which character they want to use, and document this.
A better fix would be using md5(serialize($keys)) or md5(var_epxort($keys)), whatever is faster
How does stash handle garbage collection for old cache items that are never again requested?
This might be an infrequent case, maybe even impossible given the LRU eviction policy, but it should be at least investigated more, possibly documented:
cache clears are implemented for the memcache drivers by bumping a 'revision number' associated with cache keys and kept in memcache itself. The cached items are never removed from memcache.
Under memory pressure, memcache might at some point drop the revision-number item corresponding to a cached item. If the corresponding "revision 0" item is still present in the cache, what will happen is that subsequent requests will read as valid the item which was already cleared and maybe superseded by a new version
canEnable
should not be static as it might depends on the config depending on the underlying backend (i.e. host, port, ...).
Along with the PSR-0 update, Stash should move fully to PHP 5.3 support, utilizing namespaces and eliminating the hack method we use to maintain 5.2 compatibility.
Hello on your documentation, you mention the "store" function for cache invalidation.
However I can't find the "store" function in your source code. Also am I able to set an expiration like "set"? Wouldn't it be easier if set did this conditionally anyway?
Right now Cache::isMiss does not check to see if get had already been called, and just assumes it has been. This needs to be both corrected and tested for.
I am trying to cache an item with strict expiration. By this I mean that if I read and update an item the cache doesnt get a new expiration. Currently if I set an item that already exists I need to set a new expiration. However I want the item to continue with the same expiration. This is useful for caching OAuth access tokens.
This could be done in several ways. One could to allow the end developer to access the remaining expiration and exact expiration date so they can reset with a new remaining expiration time. But you can also add new methods to the item to facilitate this.
One thing though is that inserting an item with 0 as expiration. How would that work?
Optional support on the handlers for "multii" functions (running multiple actions, such as retrieving or deleting records en mass) should be built in, with low level abstraction for those actions around handlers that don't. From the developers perspective there should be no difference, this just provides performance improvements from the handlers that support it natively.
Adding support for internal logging would let us offset some of the basic reporting, as well as making it easier for admins to discover problems with the caching system without having to disrupt the user workflow (log errors rather than throwing exceptions).
Imagine the following scenario:
I am not sure 100% about the best way to solve this.
One way would be to add a "global counter" as memcache item, which gets bumped on every invocation of clear(). Then, it would have to always be checked in makeKeyString() before using the in-memory version of revision numbers.
A small pref loss (1 more memcache get per read/write) for more stability
Had some thoughts to improve readability for source files:
use {@inheritdoc} for overridden/implemented methods (reduce duplication)
I think we should the following (from the top of each file)
@copyright 2009-2011 Robert Hafner <[email protected]>
@license http://www.opensource.org/licenses/bsd-license.php BSD License
@link http://code.google.com/p/stash/
@since File available since Release 0.9.1
@version Release: 0.9.5
replace to full license at the top of each file with:
/*
* This file is part of the Stash package.
*
* (c) Robert Hafner <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Is the docs for this project generated anywhere?
Currently the documentation of Stash exists only on the Google Code site. It should be migrated and reformatted into Markdown for inclusion directly in the library on Github.
which seems to indicate it is currently broken.
Btw, the different methods makeKey, makeKeyString, getKeyIndex (in different drivers) should probably be renamed for consistency
When you do a cache warmup, people often use a single TTL for a lot of keys. When the keys are related, this can cause the callback to be stampeded with requests. The solution is to make those TTLs have a slight variation. Usually that is done with a percentage of the original TTL.
I propose adding a method which will add jitter to the TTL. Something like
/**
* @param int $ttl
* @param float $jitter
* @return int
*/
function jitter($ttl, $jitter)
{
if ($jitter >= 1 || $jitter =< 0)
{
throw new Exception('$jitter must be between 1 and 0');
}
$variation = $ttl * $jitter;
$min = ceil($ttl - $variation);
$max = ceil($ttl + $variation);
return rand($min, $max);
}
As provided implementations for per-project use, the StashBox and StashManager classes should be isolated in the class structure away from the core Library classes.
Currently, the unit tests for the Stash module (correctly) skip tests for any handlers which are not available on the testing machine. However, it does not uniquely identify which of the Sqlite subhandlers are available, meaning that a test will fail (due to trying, and failing, to use a non-existent handler) rather than skip when some of the submodules aren't available. (I discovered this because Ubuntu 11.10 no longer ships sqlite2 support in their php5-sqlite package.) Instead, each subhandler should implement a "isAvailable"-type method and the main handler should deal with a situation where an unavailable subhandler is enabled in an explicit fashion.
(This issue may also affect the Memcache(d) handler and the same solution should be generalized to it.)
Stash currently uses its own unique system of class naming. It should be rewritten to follow the PSR-0 standard for easier loading without a custom autoloader.
This static parameter does not seem to be used anywhere, and is causing memory use to increase over time.
If it is needed somehow I would suggest it does not append, but instead keeps a number for hits and misses with are increased, makes sure only dimension causing increased memory use is variations in keys, not hits and misses on the keys themselves.
If not used, please remove :)
So I have discovered an error in the Utilities::deleteRecursive function.
It doesn't work for Windows filesystems.
This is because of this line:
if (substr($file, 0, 1) !== '/' && substr($file, 1, 2) !== ':\\') {
throw new RuntimeException('deleteRecursive function requires an absolute path.');
}
The first substr asks if its not equal to '/', then throw an exception about absolute paths.
Well Window's paths start with C:/ or D:/... etc. They don't start with the Unix '/'.
Therefore the purging and the flushing doesn't work. We need some different kind of checking function, or throw away that function anyway. I think there's another function allows us to see if a path is an absolute path. Actually this is a regex solution: http://stackoverflow.com/a/7392769/582917 (first comment)
Furthermore, when I am purging my cache. It seems that it takes into account files that were not created by Stash in the first place. This results in a couple errors too. It's not a huge problem, but if Stash could differentiate it's files from some other kind of file/folders, that would be great too.
You should use this instead:
checking for a leading slash is not enough if you expect your PHP scripts to be portable to other platforms - absolute paths on Windows may start with a backslash or "C:\" ... I came up with the following (Preg) regular expression: /^(?:\/|\\|\w\:\\).*$/ - this will match "/file", "\file", "c:\file", but not "file" or "path/file" etc. – mindplay.dk
Is it possible to namespace keys, similar to how Doctrine Cache does it?
http://docs.doctrine-project.org/en/2.0.x/reference/caching.html#namespaces
It really makes sense, as there might be different size constraints on memory and disk caches.
Also maybe the ability to add an item directly to only disk cache and not to memory... (avoid the always-copy strategy in getData()
This could be a 1st step to feat. req. #23
More of an question, but would it be possible to make a new release within the next few days? Potentially with #66 if that looks ok?
I know it's short time since 0.10.2, but we are trying to minimize the amount of obstacles our users will meet with the cache system, and BlackHole fix and the FileSystem fix are the remaining blockers for us on the cache side.
It would be great to have a driver to use Redis as backend.
While working on Ephemeral Handler I more and more loved the idea to make handlers more capable to achieve more complex caching strategies and on the other hand to separate concers in Stash\Cache
more cleanly. These are the use cases I have in mind:
Stash\Cache
and using Memcache
handler)Architecture overview:
Memcache
vs. Memcached
, Predis
vs. PHP Redis
)CompositeHandler
uses an InvocationStrategy
to call instances of HandlerInterface
. InvocationStrategy
works on a HandlerCollection
and decides what instance of HandlerInterface
needs to be called and calls itHandler
may use a Driver
to do it’s workHere’s some pseudo code:
<?php
namespace Stash\Handler\InvokationStrategy;
interface InvocationStrategyInterface
{
public function invoke(HandlerCollection $handler, $method, array $params = array());
}
namespace Stash\Handler;
class HandlerCollection extends ArrayCollection
{
public function add($name, HandlerInterface $handler);
public function get($name);
}
namespace Stash\Handler;
class CompositeHandler implements HandlerInterface
{
public function __construct(InvocationStrategyInterface $invocationStrategy, HandlerCollection $handler);
}
The code for retrieving a list of available handlers (currently generated by a static method in the StashHandlers class) should be refactored so it does not require a static call, possibly by moving it into the Stash object.
Many caching libraries handle this natively, and those that don't can have it emulated. Since it's a common usage it should be supported.
They are 2 different things
Hi,
If I understand correctly, the Item object will have the cache time as a static time which means that once I want to have a variable cache time / item I won't be able to do it.
https://github.com/tedivm/Stash/blob/master/src/Stash/Item.php#L39
Is this by design or a mistake?
as the 2 extensions live independently
Stash v0.10.1 on windows fails with the following error.
Message: touch() [function.touch]: Unable to create file C:\wamp\www\clickfortime.com\httpdocs/application//cache/1952a01898073d1e/561b9b4f2e42cbd7/a8b72798beb911ae/98c8c8907d45950a/b2eb734903575495/3b57a32e2841bda5/dc960c46c38bd16e/953d97cdeefdbc68/e9772a20f09b5d13/28a579892c11a4c8/cfcd208495d565ef/66e7dff9f98764da.php because Invalid argument
My best guess is because it is not using the correct path directory separator.
Apologies if this is a dumb question, but what is the session handler for? I may be setting my own custom session handler, it worries me that they may conflict.
This is due to a bad fix for issue #84 (see my comment on that issue)
It is my understanding that the Ephemeral
handler is for testing purposes only - is that correct? If so, it should be moved to the tests directory.
Atm the tagged versions are not semver.org compilant. Having them compilant would ease handling with composer and stash since it would allw to use the ~
for dependecy declaration.
You just need to drop the v
in front of the tagnames
Currently Stash can't easily support multiple distinct cache spaces due to the potential for a collision in the memory handler. In order to improve this, the static in-memory handler should be replaced with an optional use of the Array handler stacked upfront in the Multihandler.
Currently the only way to unlock a cache item is to store a new object, but there may be some cases where that isn't possible. If the request ends without storing a new object then the caching system won't make another attempt until the stampede expiration time goes by. To avoid this situation the cache item should clear the stampede flag as part of it's destructor.
hi,
i get a notice error in:
Error File: ...stash/Driver/FileSystem.php
Error Line:135
Error No: ERROR_8
Undefined variable: data
return !isset($data) && !@is_null($data) ? false : array('data' => $data, 'expiration' => $expiration);
i change the line to:
return !isset($data) || !@is_null($data) ? false : array('data' => $data, 'expiration' => $expiration);
so, i dont know the effects.
at the moment it works for me and i get no warnings ^^
could you help me and say if this is ok?
thanks in advance and
thanks for stash, its a nice piece of code
best regards
Right now, there are two distinct, not entirely compatible reasons one might want to use the canEnable methods:
Right now, the handlers do not deal with either issue consistently:
My off-the-cuff proposal for a rework:
While writing php files is a very convenient technique, it can have quite a negative impact upon usage of opcode caches like APC, when the data saved in the cache is big.
To avoid this, and since there is no huge benefit in not-parsing the cached item when their cache-files are included (they contain quite simple code), sysadmins might be tempted to configure Opcache/APC to exclude the Stash cache dir from caching.
It would be nice if the FS driver had a pluggable serialization backend, which could create either php files, php-serialized files, igbinary-serialized files etc
See http://www.php.net/manual/en/memcached.callbacks.read-through.php
If isMiss() is true, then do a callback and call set() with what that callback returns.
In any get methods
if isMiss() $doSet = call_user_func_array($callback, array($key, &$value, &$ttl)); if ($doSet) set($key, $value, $ttl);
According to the doc ( http://stash.tedivm.com/Drivers.html ) it is a max-age limitation, while according to the code it acts as a min-age limitation
See https://jira.ez.no/browse/EZP-21993 for a description of the problem
I have a situation where there may be race conditions in the cache. That is when multiple requests are sent to the server, each one may manipulate the cache at the same time. Is there way to lock the cache item per process and make them evaluate one at a time after the previous lock opens?
Maybe this isn't ready for release yet since it's missing from the docs, but are there any examples of using setItemClass? Everything I've tried fails with Item class Stash\ItemExpires must inherit from \Stash\Interfaces\ItemInterface
.
Based on code, it's really undefined.
Don't know how to reproduce this issue though.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.