5
5
class FileLock
6
6
{
7
7
private $ config ;
8
- private $ fs ;
9
8
10
9
private $ checkIntervalMs ;
11
10
private $ timeLimit ;
@@ -16,7 +15,6 @@ class FileLock
16
15
public function __construct (Config $ config )
17
16
{
18
17
$ this ->config = $ config ;
19
- $ this ->fs = new \Symfony \Component \Filesystem \Filesystem ();
20
18
$ this ->checkIntervalMs = 500 ;
21
19
$ this ->timeLimit = 30 ;
22
20
$ this ->disabled = (bool ) $ this ->config ->getWithDefault ('api.disable_locks ' , false );
@@ -48,10 +46,7 @@ public function acquireOrWait($lockName, callable $onWait = null, callable $chec
48
46
if (!\file_exists ($ filename )) {
49
47
break ;
50
48
}
51
- $ content = \file_get_contents ($ filename );
52
- if ($ content === false || $ content === '' ) {
53
- break ;
54
- }
49
+ $ content = $ this ->readWithLock ($ filename );
55
50
$ lockedAt = \intval ($ content );
56
51
if ($ lockedAt === 0 || \time () >= $ lockedAt + $ this ->timeLimit ) {
57
52
break ;
@@ -69,7 +64,7 @@ public function acquireOrWait($lockName, callable $onWait = null, callable $chec
69
64
}
70
65
}
71
66
}
72
- $ this ->fs -> dumpFile ($ filename , (string ) \time ());
67
+ $ this ->writeWithLock ($ filename , (string ) \time ());
73
68
$ this ->locks [$ lockName ] = $ lockName ;
74
69
return null ;
75
70
}
@@ -82,13 +77,13 @@ public function acquireOrWait($lockName, callable $onWait = null, callable $chec
82
77
public function release ($ lockName )
83
78
{
84
79
if (!$ this ->disabled && isset ($ this ->locks [$ lockName ])) {
85
- $ this ->fs -> dumpFile ($ this ->filename ($ lockName ), '' );
80
+ $ this ->writeWithLock ($ this ->filename ($ lockName ), '' );
86
81
unset($ this ->locks [$ lockName ]);
87
82
}
88
83
}
89
84
90
85
/**
91
- * Destructor. Release locks that still exist on exit.
86
+ * Destructor. Releases locks that still exist on exit.
92
87
*/
93
88
public function __destruct ()
94
89
{
@@ -98,6 +93,8 @@ public function __destruct()
98
93
}
99
94
100
95
/**
96
+ * Finds the filename for a lock.
97
+ *
101
98
* @param string $lockName
102
99
* @return string
103
100
*/
@@ -109,4 +106,74 @@ private function filename($lockName)
109
106
. preg_replace ('/[^\w_-]+/ ' , '- ' , $ lockName )
110
107
. '.lock ' ;
111
108
}
109
+
110
+ /**
111
+ * Reads a file using a shared lock.
112
+ *
113
+ * @param string $filename
114
+ * @return string
115
+ */
116
+ private function readWithLock ($ filename )
117
+ {
118
+ $ handle = \fopen ($ filename , 'r ' );
119
+ if (!$ handle ) {
120
+ throw new \RuntimeException ('Failed to open file for reading: ' . $ filename );
121
+ }
122
+ try {
123
+ if (!\flock ($ handle , LOCK_SH )) {
124
+ \trigger_error ('Failed to lock file: ' . $ filename , E_USER_WARNING );
125
+ }
126
+ $ content = \fgets ($ handle );
127
+ if ($ content === false && !\feof ($ handle )) {
128
+ throw new \RuntimeException ('Failed to read file: ' . $ filename );
129
+ }
130
+ } finally {
131
+ if (!\flock ($ handle , LOCK_UN )) {
132
+ \trigger_error ('Failed to unlock file: ' . $ filename , E_USER_WARNING );
133
+ }
134
+ if (!\fclose ($ handle )) {
135
+ \trigger_error ('Failed to close file: ' . $ filename , E_USER_WARNING );
136
+ }
137
+ }
138
+ return $ content ;
139
+ }
140
+
141
+ /**
142
+ * Writes to a file using an exclusive lock.
143
+ *
144
+ * @param string $filename
145
+ * @param string $content
146
+ * @return void
147
+ */
148
+ private function writeWithLock ($ filename , $ content )
149
+ {
150
+ $ dir = \dirname ($ filename );
151
+ if (!\is_dir ($ dir )) {
152
+ if (!\mkdir ($ dir , 0777 , true )) {
153
+ throw new \RuntimeException ('Failed to create directory: ' . $ dir );
154
+ }
155
+ }
156
+ $ handle = \fopen ($ filename , 'w ' );
157
+ if (!$ handle ) {
158
+ throw new \RuntimeException ('Failed to open file for writing: ' . $ filename );
159
+ }
160
+ try {
161
+ if (!\flock ($ handle , LOCK_EX )) {
162
+ \trigger_error ('Failed to lock file: ' . $ filename , E_USER_WARNING );
163
+ }
164
+ if (\fputs ($ handle , $ content ) === false ) {
165
+ throw new \RuntimeException ('Failed to write to file: ' . $ filename );
166
+ }
167
+ if (!\fflush ($ handle )) {
168
+ \trigger_error ('Failed to flush file: ' . $ filename , E_USER_WARNING );
169
+ }
170
+ } finally {
171
+ if (!\flock ($ handle , LOCK_UN )) {
172
+ \trigger_error ('Failed to unlock file: ' . $ filename , E_USER_WARNING );
173
+ }
174
+ if (!\fclose ($ handle )) {
175
+ \trigger_error ('Failed to close file: ' . $ filename , E_USER_WARNING );
176
+ }
177
+ }
178
+ }
112
179
}
0 commit comments