Code Monkey home page Code Monkey logo

stash's Introduction

Stash - A PHP Caching Library

License Latest Stable Version Total Downloads

Stash makes it easy to speed up your code by caching the results of expensive functions or code. Certain actions, like database queries or calls to external APIs, take a lot of time to run but tend to have the same results over short periods of time. This makes it much more efficient to store the results and call them back up later.

Installing

Installing Stash can be done through a variety of methods, although Composer is recommended.

Composer

Until Stash reaches a stable API with version 1.0 it is recommended that you review changes before Minor updates, although bug fixes will always be backwards compatible.

"require": {
  "tedivm/stash": "0.17.*"
}

or by using the composer require command:

composer require tedivm/stash

Github

Releases of Stash are available on Github.

Documentation

Although this README contains some useful data there is a lot more information at the main site, stashphp.com.

Core Concepts

Main Classes

Stash has three main components: a Pool class that represents a specific grouping of cached objects, an Item class that provides access to individual objects, and a series of Driver classes that allow Stash to interact with caching systems.

Each Driver is initialized and then passed into a Pool, at which point the developer can simply forget about it. Developers also have the option of using multiple Drivers together by joining them with the Composite Driver.

The Pool class allows developers to perform a number of tasks. There are a few maintenance related tasks, such as running a "Purge" to allow backend systems to perform maintenance tasks or set new logging or driver classes. The Pool also can be used to create Item objects, singly or in groups.

Each Item represents a single object inside the cache. It has a unique Key, meaning that any two Items created from the same Pool will contain the same Value. An Item can set, get and remove a value from a caching system.

Keys

A Key is a string that represents an Item in a caching system. At its simplest, a key is an alphanumeric string and has a one to one relationship with a value in the cache.

Stash provides a feature known as "stacks" that allows developers to group related Items together so they can be erased as a group. This is done by giving Items a nested structure, similar to folders on a computer. Just like with folders, this is represented by adding slashes to the name representing the file or cached object.

For example, a Key like "/models/users/34/profile" can allow developers to clear the data for specific users using that user's id, or clear the data for all users or even all models. It can also allow that developer to break up data into specific pieces to only load what is needed.

Session Storage

The provided Session class takes a Pool in its constructor and can then be registered as a Session Handler using the built-in PHP methods, the Session::registerHandler static function, or by using any framework that uses the SessionHandlerInterface interface.

Drivers

Stash currently supports the following backends:

  • FileSystem
  • Sqlite
  • APC
  • Memcached
  • Redis
  • Ephemeral (runtime only)

Stash also supports a specialized "Composite" Driver which can contain any number of the above drivers. This allows developers to created multi-tiered drivers that use a variety of back ends.

Symfony Integration

The Stash Bundle makes using Stash inside of Symfony projects significantly easier. This bundle exposes Stash as a Service for developers to use, and allows Symfony to use Stash as a session handler.

License

Stash is licensed under the BSD License. See the LICENSE file for details.

Reporting Security and Vulnerability Issues

This project utilizes the Tidelift Security Reporting System for security and vulnerability reporting.

Support

Issues can be opened directly in Github for issues that aren't related to security.

Professionally supported Stash is now available with Tidelift.

stash's People

Contributors

alexbowers avatar andheiberg avatar andrerom avatar biont avatar brutto avatar bshaffer avatar cmcdragonkai avatar davereid avatar finesse avatar hannesvdvreken avatar icio avatar iclukas avatar jhallbachner avatar jonmchan avatar kbond avatar korvinszanto avatar localheinz avatar lolautruche avatar lstrojny avatar m1n0 avatar mbaynton avatar mrclay avatar pborreli avatar phy25 avatar pwhelan avatar rodnaph avatar staabm avatar tedivm avatar thesebas avatar vicb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stash's Issues

Support for "multi" functions

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.

Disable stampede lock on cache object destruction

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.

Isolate Default Cache Implementations

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.

Undefined variable: data

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

Locking of cache item per key

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?

Unable to create file on windows

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.

TTL "jitter"

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);
}

Rework In-Memory Storage

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.

New stable? (0.10.3)

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.

Filesystem driver: allow different serialization methods

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

DocBlocks and License

Had some thoughts to improve readability for source files:

  1. use {@inheritdoc} for overridden/implemented methods (reduce duplication)

  2. 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
    
  3. 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?

Handler error states / canEnable

Right now, there are two distinct, not entirely compatible reasons one might want to use the canEnable methods:

  • For a specific, instantiated cache handler object, to find out whether the object can be used given its current configuration
  • For a type of handler, to get information about whether the necessary system resources (PHP extensions, etc.) are present for that handler type to be used

Right now, the handlers do not deal with either issue consistently:

  • FileSystem: Always returns true for canEnable; will return false on storeData and getData (usually with a system-level warning on the former) if file system permissions don't allow writing at the provided location.
  • SQLite: Returns true from canEnable if the currently specified subhandler is available; generates a fatal PDO error on storeData if the target filesystem is not writeable.
  • APC: Returns true from canEnable if the extension is loaded; generates a fatal undefined-function error if store or get is called when it isn't.
  • Memcached: Returns the subhandler's value (i.e. a class_exists on either 'Memcache' or 'Memcached') from canEnable, but it throws a MemcacheException from the constructor if neither extension is available to load.
  • MultiHandler: Always returns true from canEnable, but throws a MultiHandlerException from the constructor if no handlers are provided at instantiation.

My off-the-cuff proposal for a rework:

  • Remove all exceptions from the constructors; let all handlers be instantiated without any errors.
  • Give each handler an isAvailable() method; this would perform the system-level check regarding whether it is possible to use that handler at all, i.e., return false if the extension isn't loaded.
  • Expand the canEnable methods to check fully that the current instance of the cache object can in fact be used; e.g. check file permissions for FileSystem and SQLite, check that the servers are available for Memcache, etc.
  • Have store/get/purge call canEnable first thing and throw a handler-specific exception if the result is false. (Alternately, return false if that's a preferable error-handling behavior here.)
  • All subhandler-based handlers (currently SQLite and Memcache) should apply a priority of subhandlers and automatically step through it to find the best option when no specific version is specified (Memcache does this but SQLite does not.)

Add inc/dec functions to handlers

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.

move Ephemeral handler to tests

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.

Migrate Documentation From Google Code

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.

Cannot purge or flush files that are on windows filesystem.

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 

How to use Pool::setItemClass?

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.

problems with keys calculations for in-memory storage and filesystem driver

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

Remove Static Method Requirement for Handler List

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.

Store function

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?

Add support for PSR-3, logging.

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).

memcache drivers: phantom reads possible in presence of memory pressure

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

PSR-0 Support

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.

Xcache driver missing makekey method

which seems to indicate it is currently broken.

Btw, the different methods makeKey, makeKeyString, getKeyIndex (in different drivers) should probably be renamed for consistency

Session Handler

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.

More complex handlers

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:

  • Store in Memcache only (currently achievable by disabling memory storage in Stash\Cache and using Memcache handler)
  • Size bases balancing: Store small entries in APC, large ones in Memcache (currently not possible)
  • Overflow based balancing: store everything in APC but overflow to Memcache (currently no possble)
  • Any combination of those use cases

Architecture overview:

  • We split handlers into three layers: invocation strategies (the "what is invoked"), handlers (interacts with the caching store) and drivers (abstracts client differences for Memcache vs. Memcached, Predis vs. PHP Redis)
  • A 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 it
  • A Handler may use a Driver to do it’s work

Here’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);
}

And here is some UML:
UML

memcache drivers: a long-running process will not "sense" cache-clears from other processes

Imagine the following scenario:

  1. process A caches item X/Y/Z => item gets saved in memcache, "curent revision" for X/, X/Y and X/Y/Z saved in both memcache and process memory. Process keeps running
  2. process B invalidates X/Y. This means bumping the revision nr of X/Y in memcache
  3. process A reads cache for item X/Y/Z => it takes from memory the revision number, and considers the stale item still valid

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

Remove PHP 5.2 Support

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.

Semver tags

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

Unit Tests Fail for Sqlite Handler When Some Modules are Missing

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.)

Strict cache expiration

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?

Stash\Item::$queryRecord leaks memory on long running processes

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 :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.