Smarty Forum Index Smarty
The discussions here are for Smarty, a template engine for the PHP programming language.

Interaction between $use_sub_dirs and a PHP mkdir issue

 
Post new topic   Reply to topic    Smarty Forum Index -> Bugs
View previous topic :: View next topic  
Author Message
lxs
Smarty Rookie


Joined: 12 Nov 2010
Posts: 5

PostPosted: Mon Dec 19, 2016 11:39 pm    Post subject: Interaction between $use_sub_dirs and a PHP mkdir issue Reply with quote

Hi,

I am running into an issue with what appears to be an interaction between $use_sub_dirs and PHP's mkdir implementation. I am using Smarty 3.1.30 although if I'm right about what is happening the problem is in the latest sources as well.


The symptom of the problem is that very very infrequently a request will die with an "unable to write file" exception inside Smarty_Internal_Runtime_WriteFile::writeFile(). This happens most often when the cache is empty and multiple processes start simultaneously creating the directory structure. However there are some very rarely used compile ids which can trigger the exception long after the last time the cache was empty so the failures can seem quite random.

After some debugging I determined that when the exception is thrown, Smarty_Internal_Runtime_WriteFile::writeFile():
- Calls file_exists($_dirpath), which notices the cache directory does not exist.
- Calls mkdir($_dirpath, $_dir_perms, true) which returns false and logs a "File exists" warning (normally suppressed).
- Calls file_put_contents($_tmp_file, $_contents) which returns false and logs a "No such file or directory" warning (normally suppressed).
- Throws a SmartyException.

Logging between the calls to mkdir and file_put_contents I noticed that a call to file_exists($_dirpath) still returns false after the mkdir, despite the "File exists" warning. Suspiciously if I actually call error_log() between mkdir and file_put_contents (rather than tacking the result of the file_exists onto the exception message) the problem goes away. In fact anything which slows down the operations seems to make the problem less frequent so I started working under the assumption that this was some sort of race condition.


After some searching around with Google, I found a PHP mkdir ticket marked as "Not a bug" which matches what I am seeing: https://bugs.php.net/bug.php?id=35326

The gist of the report is that PHP's mkdir implementation of the recursive parameter is not thread or multi-process safe. The implementation first checks to see what directories need to be created and then tries to create the ones that don't exist. If any of the individual directory creation operations fail (including a failure of "file exists"), mkdir immediately returns false.

Now imagine two processes trying to create Smarty cache directories A/B/C and A/B/D where only A exists. If process 1 and 2 both simultaneously check for B, they'll notice that B needs to be created. Then if both processes try to create B and process 1 gets there first, process 2's mkdir will abort with a "file exists" warning even though D was not created.


I'm contemplating turning off $use_sub_dirs to avoid this problem since we don't have a massive number of templates but I was wondering if anyone had any suggestions for working around this PHP behavior.
Back to top
View user's profile Send private message
AnrDaemon
Administrator


Joined: 03 Dec 2012
Posts: 1518

PostPosted: Tue Dec 20, 2016 12:53 am    Post subject: Reply with quote

Either use non-file cache storage (memcached?) or patch Smarty for safe implementation of a desired behavior.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Smarty Forum Index -> Bugs All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group
Protected by Anti-Spam ACP