@@ -204,14 +204,22 @@ public function draft_if_empty($language)
204204 throw new \InvalidArgumentException ('ACP_BOARDRULES_INVALID_LANGUAGE ' );
205205 }
206206
207- if ($ this ->get_rule_count ($ language ) > 0 )
207+ $ acquired_lock = $ this ->acquire_write_lock ();
208+ try
208209 {
209- return false ;
210- }
210+ if ($ this ->get_rule_count ($ language ) > 0 )
211+ {
212+ return false ;
213+ }
211214
212- $ this ->save_published_state ($ language , false );
215+ $ this ->save_published_state ($ language , false );
213216
214- return true ;
217+ return true ;
218+ }
219+ finally
220+ {
221+ $ this ->release_write_lock ($ acquired_lock );
222+ }
215223 }
216224
217225 /**
@@ -252,12 +260,20 @@ public function set_published($language, $published)
252260 throw new \InvalidArgumentException ('ACP_BOARDRULES_INVALID_LANGUAGE ' );
253261 }
254262
255- if ($ this ->get_rule_count ($ language ) === 0 )
263+ $ acquired_lock = $ this ->acquire_write_lock ();
264+ try
256265 {
257- throw new \InvalidArgumentException ('ACP_BOARDRULES_STATUS_CHANGE_EMPTY ' );
258- }
266+ if ($ this ->get_rule_count ($ language ) === 0 )
267+ {
268+ throw new \InvalidArgumentException ('ACP_BOARDRULES_STATUS_CHANGE_EMPTY ' );
269+ }
259270
260- $ this ->save_published_state ($ language , (bool ) $ published );
271+ $ this ->save_published_state ($ language , (bool ) $ published );
272+ }
273+ finally
274+ {
275+ $ this ->release_write_lock ($ acquired_lock );
276+ }
261277 }
262278
263279 /**
@@ -396,30 +412,73 @@ protected function save_published_state($language, $published)
396412 */
397413 protected function save_ruleset_value ($ language , $ column , $ value )
398414 {
399- $ sql = 'SELECT language_iso
400- FROM ' . $ this ->rulesets_table . "
401- WHERE language_iso = ' " . $ this ->db ->sql_escape ($ language ) . "' " ;
402- $ result = $ this ->db ->sql_query_limit ($ sql , 1 );
403- $ exists = (bool ) $ this ->db ->sql_fetchfield ('language_iso ' );
404- $ this ->db ->sql_freeresult ($ result );
405-
406- if ($ exists )
415+ $ acquired_lock = $ this ->acquire_write_lock ();
416+ try
407417 {
408- $ sql = 'UPDATE ' . $ this -> rulesets_table . '
409- SET ' . $ this ->db -> sql_build_array ( ' UPDATE ' , array ( $ column => $ value )) . "
418+ $ sql = 'SELECT language_iso
419+ FROM ' . $ this ->rulesets_table . "
410420 WHERE language_iso = ' " . $ this ->db ->sql_escape ($ language ) . "' " ;
421+ $ result = $ this ->db ->sql_query_limit ($ sql , 1 );
422+ $ exists = (bool ) $ this ->db ->sql_fetchfield ('language_iso ' );
423+ $ this ->db ->sql_freeresult ($ result );
424+
425+ if ($ exists )
426+ {
427+ $ sql = 'UPDATE ' . $ this ->rulesets_table . '
428+ SET ' . $ this ->db ->sql_build_array ('UPDATE ' , array ($ column => $ value )) . "
429+ WHERE language_iso = ' " . $ this ->db ->sql_escape ($ language ) . "' " ;
430+ }
431+ else
432+ {
433+ $ sql_data = array (
434+ 'language_iso ' => $ language ,
435+ 'rules_published ' => 1 ,
436+ 'rules_intro_text ' => '' ,
437+ );
438+ $ sql_data [$ column ] = $ value ;
439+ $ sql = 'INSERT INTO ' . $ this ->rulesets_table . ' ' . $ this ->db ->sql_build_array ('INSERT ' , $ sql_data );
440+ }
441+
442+ $ this ->db ->sql_query ($ sql );
443+ }
444+ finally
445+ {
446+ $ this ->release_write_lock ($ acquired_lock );
447+ }
448+ }
449+
450+ /**
451+ * Acquire the shared write lock unless this request already owns it.
452+ *
453+ * @return bool True when this method acquired the lock
454+ * @throws \RuntimeException If another request owns the lock
455+ */
456+ protected function acquire_write_lock ()
457+ {
458+ if ($ this ->lock ->owns_lock ())
459+ {
460+ return false ;
411461 }
412- else
462+
463+ if (!$ this ->lock ->acquire ())
413464 {
414- $ sql_data = array (
415- 'language_iso ' => $ language ,
416- 'rules_published ' => 1 ,
417- 'rules_intro_text ' => '' ,
418- );
419- $ sql_data [$ column ] = $ value ;
420- $ sql = 'INSERT INTO ' . $ this ->rulesets_table . ' ' . $ this ->db ->sql_build_array ('INSERT ' , $ sql_data );
465+ throw new \RuntimeException ('RULES_NESTEDSET_LOCK_FAILED_ACQUIRE ' );
421466 }
422467
423- $ this ->db ->sql_query ($ sql );
468+ return true ;
469+ }
470+
471+ /**
472+ * Release the shared write lock only when acquired by the current method.
473+ *
474+ * @param bool $acquired_lock
475+ * @return void
476+ */
477+ protected function release_write_lock ($ acquired_lock )
478+ {
479+ if ($ acquired_lock )
480+ {
481+ $ this ->lock ->release ();
482+ }
424483 }
425484}
0 commit comments