@@ -38,7 +38,7 @@ class Store implements StoreInterface
38
38
public function __construct ($ root )
39
39
{
40
40
$ this ->root = $ root ;
41
- if (!is_dir ($ this ->root ) && !@mkdir ($ this ->root , 0777 , true ) && !is_dir ($ this ->root )) {
41
+ if (!file_exists ($ this ->root ) && !@mkdir ($ this ->root , 0777 , true ) && !is_dir ($ this ->root )) {
42
42
throw new \RuntimeException (sprintf ('Unable to create the store directory (%s). ' , $ this ->root ));
43
43
}
44
44
$ this ->keyCache = new \SplObjectStorage ();
@@ -52,44 +52,40 @@ public function cleanup()
52
52
{
53
53
// unlock everything
54
54
foreach ($ this ->locks as $ lock ) {
55
- if (file_exists ($ lock )) {
56
- @unlink ($ lock );
57
- }
55
+ flock ($ lock , LOCK_UN );
56
+ fclose ($ lock );
58
57
}
59
58
60
- $ error = error_get_last ();
61
- if (1 === $ error ['type ' ] && false === headers_sent ()) {
62
- // send a 503
63
- header ('HTTP/1.0 503 Service Unavailable ' );
64
- header ('Retry-After: 10 ' );
65
- echo '503 Service Unavailable ' ;
66
- }
59
+ $ this ->locks = array ();
67
60
}
68
61
69
62
/**
70
- * Locks the cache for a given Request.
63
+ * Tries to lock the cache for a given Request, without blocking .
71
64
*
72
65
* @param Request $request A Request instance
73
66
*
74
67
* @return bool|string true if the lock is acquired, the path to the current lock otherwise
75
68
*/
76
69
public function lock (Request $ request )
77
70
{
78
- $ path = $ this ->getPath ($ this ->getCacheKey ($ request ).'.lck ' );
79
- if (!is_dir (dirname ($ path )) && false === @mkdir (dirname ($ path ), 0777 , true ) && !is_dir (dirname ($ path ))) {
80
- return false ;
81
- }
71
+ $ key = $ this ->getCacheKey ($ request );
82
72
83
- $ lock = @fopen ($ path , 'x ' );
84
- if (false !== $ lock ) {
85
- fclose ($ lock );
73
+ if (!isset ($ this ->locks [$ key ])) {
74
+ $ path = $ this ->getPath ($ key );
75
+ if (!file_exists (dirname ($ path )) && false === @mkdir (dirname ($ path ), 0777 , true ) && !is_dir (dirname ($ path ))) {
76
+ return $ path ;
77
+ }
78
+ $ h = fopen ($ path , 'cb ' );
79
+ if (!flock ($ h , LOCK_EX | LOCK_NB )) {
80
+ fclose ($ h );
86
81
87
- $ this ->locks [] = $ path ;
82
+ return $ path ;
83
+ }
88
84
89
- return true ;
85
+ $ this -> locks [ $ key ] = $ h ;
90
86
}
91
87
92
- return ! file_exists ( $ path ) ?: $ path ;
88
+ return true ;
93
89
}
94
90
95
91
/**
@@ -101,17 +97,37 @@ public function lock(Request $request)
101
97
*/
102
98
public function unlock (Request $ request )
103
99
{
104
- $ file = $ this ->getPath ($ this ->getCacheKey ($ request ).'.lck ' );
100
+ $ key = $ this ->getCacheKey ($ request );
101
+
102
+ if (isset ($ this ->locks [$ key ])) {
103
+ flock ($ this ->locks [$ key ], LOCK_UN );
104
+ fclose ($ this ->locks [$ key ]);
105
+ unset($ this ->locks [$ key ]);
106
+
107
+ return true ;
108
+ }
105
109
106
- return is_file ( $ file ) ? @ unlink ( $ file ) : false ;
110
+ return false ;
107
111
}
108
112
109
113
public function isLocked (Request $ request )
110
114
{
111
- $ path = $ this ->getPath ($ this ->getCacheKey ($ request ).'.lck ' );
112
- clearstatcache (true , $ path );
115
+ $ key = $ this ->getCacheKey ($ request );
116
+
117
+ if (isset ($ this ->locks [$ key ])) {
118
+ return true ; // shortcut if lock held by this process
119
+ }
120
+
121
+ if (!file_exists ($ path = $ this ->getPath ($ key ))) {
122
+ return false ;
123
+ }
113
124
114
- return is_file ($ path );
125
+ $ h = fopen ($ path , 'rb ' );
126
+ flock ($ h , LOCK_EX | LOCK_NB , $ wouldBlock );
127
+ flock ($ h , LOCK_UN ); // release the lock we just acquired
128
+ fclose ($ h );
129
+
130
+ return (bool ) $ wouldBlock ;
115
131
}
116
132
117
133
/**
@@ -144,7 +160,7 @@ public function lookup(Request $request)
144
160
}
145
161
146
162
list ($ req , $ headers ) = $ match ;
147
- if (is_file ($ body = $ this ->getPath ($ headers ['x-content-digest ' ][0 ]))) {
163
+ if (file_exists ($ body = $ this ->getPath ($ headers ['x-content-digest ' ][0 ]))) {
148
164
return $ this ->restoreResponse ($ headers , $ body );
149
165
}
150
166
@@ -291,7 +307,7 @@ private function requestsMatch($vary, $env1, $env2)
291
307
*/
292
308
private function getMetadata ($ key )
293
309
{
294
- if (false === $ entries = $ this ->load ($ key )) {
310
+ if (! $ entries = $ this ->load ($ key )) {
295
311
return array ();
296
312
}
297
313
@@ -307,7 +323,15 @@ private function getMetadata($key)
307
323
*/
308
324
public function purge ($ url )
309
325
{
310
- if (is_file ($ path = $ this ->getPath ($ this ->getCacheKey (Request::create ($ url ))))) {
326
+ $ key = $ this ->getCacheKey (Request::create ($ url ));
327
+
328
+ if (isset ($ this ->locks [$ key ])) {
329
+ flock ($ this ->locks [$ key ], LOCK_UN );
330
+ fclose ($ this ->locks [$ key ]);
331
+ unset($ this ->locks [$ key ]);
332
+ }
333
+
334
+ if (file_exists ($ path = $ this ->getPath ($ key ))) {
311
335
unlink ($ path );
312
336
313
337
return true ;
@@ -327,7 +351,7 @@ private function load($key)
327
351
{
328
352
$ path = $ this ->getPath ($ key );
329
353
330
- return is_file ($ path ) ? file_get_contents ($ path ) : false ;
354
+ return file_exists ($ path ) ? file_get_contents ($ path ) : false ;
331
355
}
332
356
333
357
/**
@@ -341,23 +365,36 @@ private function load($key)
341
365
private function save ($ key , $ data )
342
366
{
343
367
$ path = $ this ->getPath ($ key );
344
- if (!is_dir (dirname ($ path )) && false === @mkdir (dirname ($ path ), 0777 , true ) && !is_dir (dirname ($ path ))) {
345
- return false ;
346
- }
347
368
348
- $ tmpFile = tempnam (dirname ($ path ), basename ($ path ));
349
- if (false === $ fp = @fopen ($ tmpFile , 'wb ' )) {
350
- return false ;
351
- }
352
- @fwrite ($ fp , $ data );
353
- @fclose ($ fp );
369
+ if (isset ($ this ->locks [$ key ])) {
370
+ $ fp = $ this ->locks [$ key ];
371
+ @ftruncate ($ fp , 0 );
372
+ @fseek ($ fp , 0 );
373
+ $ len = @fwrite ($ fp , $ data );
374
+ if (strlen ($ data ) !== $ len ) {
375
+ @ftruncate ($ fp , 0 );
354
376
355
- if ($ data != file_get_contents ($ tmpFile )) {
356
- return false ;
357
- }
377
+ return false ;
378
+ }
379
+ } else {
380
+ if (!file_exists (dirname ($ path )) && false === @mkdir (dirname ($ path ), 0777 , true ) && !is_dir (dirname ($ path ))) {
381
+ return false ;
382
+ }
358
383
359
- if (false === @rename ($ tmpFile , $ path )) {
360
- return false ;
384
+ $ tmpFile = tempnam (dirname ($ path ), basename ($ path ));
385
+ if (false === $ fp = @fopen ($ tmpFile , 'wb ' )) {
386
+ return false ;
387
+ }
388
+ @fwrite ($ fp , $ data );
389
+ @fclose ($ fp );
390
+
391
+ if ($ data != file_get_contents ($ tmpFile )) {
392
+ return false ;
393
+ }
394
+
395
+ if (false === @rename ($ tmpFile , $ path )) {
396
+ return false ;
397
+ }
361
398
}
362
399
363
400
@chmod ($ path , 0666 & ~umask ());
0 commit comments