rfc:url-opcode-cache

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
rfc:url-opcode-cache [2017/06/02 14:26] francoisrfc:url-opcode-cache [2017/09/22 13:28] (current) – external edit 127.0.0.1
Line 1: Line 1:
 ====== PHP RFC: Add support for stream-wrapped URLs in opcode cache ====== ====== PHP RFC: Add support for stream-wrapped URLs in opcode cache ======
-  * Version: 1.1 +  * Version: 1.2 
-  * Date: 2017-06-025-25+  * Date: 2017-06-05
   * Author: François Laupretre, francois@tekwire.net   * Author: François Laupretre, francois@tekwire.net
-  * Status: Under discussion+  * Status: Suspended
   * First Published at: http://wiki.php.net/rfc/url-opcode-cache   * First Published at: http://wiki.php.net/rfc/url-opcode-cache
  
Line 11: Line 11:
  
 It is an extension of the 'is_cacheable' concept developed [[https://wiki.php.net/rfc/streams-is-cacheable|in a previous RFC]]. It is an extension of the 'is_cacheable' concept developed [[https://wiki.php.net/rfc/streams-is-cacheable|in a previous RFC]].
- 
-===== Proposal ===== 
  
 When stream wrappers were introduced in PHP, their relationship with opcode When stream wrappers were introduced in PHP, their relationship with opcode
 caches was not a problem, as they were mostly used to access remote data. The caches was not a problem, as they were mostly used to access remote data. The
 need for a better interaction arose with package systems, like phar and phk, as need for a better interaction arose with package systems, like phar and phk, as
-these stream wrappers manage a virtual PHP source tree through stream URLs. If +these sytems use stream wrappers to expose virtual trees of PHP code. If the scripts distributed by such systems cannot be opcode-cached, they loose a great part of their value.
-the scripts provided by such a system cannot be opcode-cached, the system looses a great part of its value.+
  
-Historically, the issue was addressed using different workarounds : either every +Historically, the issue was addressed using different workarounds : 
-URL is considered as opcode-cacheable (APC), whatever wrapper it is coming from, or +  - every URL may be considered as opcode-cacheable, whatever wrapper it is coming from. This approach is wrong because most URLs are intrinsically dynamic and NOT cacheable. 
-a list of 'cacheable' protocols is declared explicitely in the code. opcache is using the second solution : 'file' and 'phar' are explicitely +  - In order to avoid this, opcache implements another workaround : 'file' and 'phar' are hardcoded in the opcache code as the only 'cacheable' stream wrappers. Obviously, such tight coupling cannot be considered as a satisfactory solution.
-declared as the only 'cacheable' stream wrappers. It also implies that every 'phar:%%//%%' and 'file:%%//%%' paths are cacheable.+
  
-I consider that we need a more generic system, which must allow any PHP code handled via a stream wrapper ('core' or 'userspace') to be opcode-cached.+So, I consider that we need a more generic system, which must allow any PHP code handled via a stream wrapper ('core' or 'userspace') to be opcode-cached. 
 + 
 +===== Proposal =====
  
 My previous RFC proposed the implementation of an 'is_cacheable' operation, returning a boolean value. This implied that the cache key to use would always be the URL itself. Some users expressed concerns that the stream wrapper should also have the power to determine the cache key. So, this is what I am now proposing : My previous RFC proposed the implementation of an 'is_cacheable' operation, returning a boolean value. This implied that the cache key to use would always be the URL itself. Some users expressed concerns that the stream wrapper should also have the power to determine the cache key. So, this is what I am now proposing :
  
-  * An operation named 'stream_cache_key' is added at the end of the php_stream_wrapper_ops structure. This is an optional pointer to a function able to determine if a given URL is cacheable or not and, if this is the case, to return the (string) key to use to cache this data. +  * An operation named 'stream_cache_key' is added at the end of the php_stream_wrapper_ops structure. This is an optional pointer to a function able to determine whether a given URL is cacheable or not and, if this is the case, to return the (string) key to use when caching this data. 
  
   * A new C function named php_stream_cache_key(zend_string *path, int options, php_stream_context *context) is defined. It determines the right wrapper from the path it receives and forwards the request to the corresponding stream_cache_key() function, if it exists. If the stream_cache_key() element is not defined, NULL is returned.   * A new C function named php_stream_cache_key(zend_string *path, int options, php_stream_context *context) is defined. It determines the right wrapper from the path it receives and forwards the request to the corresponding stream_cache_key() function, if it exists. If the stream_cache_key() element is not defined, NULL is returned.
  
-  * Userspace stream wrappers can define a method named cache_key(path [,options]). This method determines if the input path is cacheable and the key to use. If the path is not cacheable, the function should return null. Any other value is converted to string and considered as the key to use. If the method is not defined, every path for this wrapper are non-cacheable. For security reasons, the returned key must start with the same '<scheme>:%%//%%' prefix as the input path. If it not the case, an error is raised and the key is ignored.+  * Userspace stream wrappers can define a method named cache_key(path [,options]). This method determines if the input path is cacheable and the key to use. If the path is not cacheable, the function should return null. Any other value is converted to string and considered as the key to use. If the method is not defined, every path associated to this wrapper are non-cacheable. In order to avoid key value conflicts, the returned key must start with the same '<scheme>:%%//%%' prefix as the input path. If it not the case, an error is raised and the key is ignored.
  
   * For completeness, a new PHP function named file_cache_key(path [, options [, context]]) is defined. It allows to call the 'cache_key' operation from a PHP script.   * For completeness, a new PHP function named file_cache_key(path [, options [, context]]) is defined. It allows to call the 'cache_key' operation from a PHP script.
Line 51: Line 49:
   /* }}} */   /* }}} */
  
-In order to ensure key unicity, the returned string must start with '<wrapper-scheme>:%%//%%' prefix. For performance reasons, this is checked in debug mode only on C-level wrappers.+In order to ensure key unicity, the returned string must start with the same '<scheme>:%%//%%' prefix as the input URL. For performance reasons, this is checked in debug mode only on C-level wrappers.
  
-The stream wrapper has the responsibility to ensure that the data associated with a given key will always be the same.+The stream wrapper has the responsibility to ensure that the data associated with a given key will always be the same. If this is not the case (e.g. if a 'non-cacheable' URL is declared as 'cacheable'), PHP won't fail but, from a user's point of view, the behavior will be unpredictable.
  
 ===== Backward Incompatible Changes ===== ===== Backward Incompatible Changes =====
Line 70: Line 68:
 ==== To Existing Extensions ==== ==== To Existing Extensions ====
  
-Phar needs to implement a cache_key() function, always returning the input path.+Phar implements new cache_key() operation, always returning the input path.
  
 The same for the plain files wrapper. The same for the plain files wrapper.
  
-Both changes are included in the PR below.+No other core extension needs to be modified. 
 + 
 +When 3rd-party extensions decide to have the benefit of the new feature, they will just implement an additional 'cache_key' operation. This is not mandatory and only stream wrappers distributing PHP source code have a reason to do that. In order to remain compatible with previous PHP versions, the declaration for this operation must be enclosed in an appropriate '#if PHP_API_VERSION >= 20160731' block. 
 + 
 +Userspace stream wrappers may just define a new 'cache_key()' method. On previous PHP versions, this method will never be called, but won't harm.
  
 ==== To Opcache ==== ==== To Opcache ====
Line 84: Line 86:
   * If the returned value is non null, use this value as key to search or register the data.    * If the returned value is non null, use this value as key to search or register the data. 
  
-These changes are NOT included in the PR below because opcache code is a performance-critical part of the core. As the change is not trivial and requires some re-organizations in the way functions call themselves, I would prefer someone more familiar with this code to implement these changes.+These changes are NOT included yet in the PR below.
  
 ==== New Constants ==== ==== New Constants ====
Line 91: Line 93:
  
 ===== Open Issues ===== ===== Open Issues =====
- 
-  * Security check on the key returned by userspace wrappers is not implemented yet. I'll add it ASAP. 
  
 ===== Unaffected PHP Functionality ===== ===== Unaffected PHP Functionality =====
rfc/url-opcode-cache.1496413569.txt.gz · Last modified: 2017/09/22 13:28 (external edit)