Index: branches/RC/core/install/install_schema.sql =================================================================== diff -u -N -r11870 -r11933 --- branches/RC/core/install/install_schema.sql (.../install_schema.sql) (revision 11870) +++ branches/RC/core/install/install_schema.sql (.../install_schema.sql) (revision 11933) @@ -1088,4 +1088,15 @@ Title VARCHAR(255) NOT NULL DEFAULT '', Description text, PRIMARY KEY (FormId) +); + +CREATE TABLE Semaphores ( + SemaphoreId int(11) NOT NULL auto_increment, + SessionKey int(10) unsigned NOT NULL, + Timestamp int(10) unsigned NOT NULL, + MainPrefix varchar(255) NOT NULL, + PRIMARY KEY (SemaphoreId), + KEY SessionKey (SessionKey), + KEY Timestamp (Timestamp), + KEY MainPrefix (MainPrefix) ); \ No newline at end of file Index: branches/RC/core/install/remove_schema.sql =================================================================== diff -u -N -r11623 -r11933 --- branches/RC/core/install/remove_schema.sql (.../remove_schema.sql) (revision 11623) +++ branches/RC/core/install/remove_schema.sql (.../remove_schema.sql) (revision 11933) @@ -67,4 +67,5 @@ DROP TABLE PageContent; DROP TABLE FormFields; DROP TABLE FormSubmissions; -DROP TABLE Forms; \ No newline at end of file +DROP TABLE Forms; +DROP TABLE Semaphores; Index: branches/RC/core/install/upgrades.sql =================================================================== diff -u -N -r11931 -r11933 --- branches/RC/core/install/upgrades.sql (.../upgrades.sql) (revision 11931) +++ branches/RC/core/install/upgrades.sql (.../upgrades.sql) (revision 11933) @@ -1319,6 +1319,17 @@ INSERT INTO ConfigurationAdmin VALUES ('DebugOnlyFormConfigurator', 'la_section_SettingsAdmin', 'la_config_DebugOnlyFormConfigurator', 'checkbox', '', '', 40.09, 0, 0); INSERT INTO ConfigurationValues VALUES (DEFAULT, 'DebugOnlyFormConfigurator', '0', 'In-Portal', 'in-portal:configure_advanced'); +CREATE TABLE Semaphores ( + SemaphoreId int(11) NOT NULL auto_increment, + SessionKey int(10) unsigned NOT NULL, + Timestamp int(10) unsigned NOT NULL, + MainPrefix varchar(255) NOT NULL, + PRIMARY KEY (SemaphoreId), + KEY SessionKey (SessionKey), + KEY Timestamp (Timestamp), + KEY MainPrefix (MainPrefix) +); + ALTER TABLE Language ADD IconDisabledURL VARCHAR(255) NULL DEFAULT NULL AFTER IconURL; UPDATE Phrase Index: branches/RC/core/kernel/db/db_event_handler.php =================================================================== diff -u -N -r11930 -r11933 --- branches/RC/core/kernel/db/db_event_handler.php (.../db_event_handler.php) (revision 11930) +++ branches/RC/core/kernel/db/db_event_handler.php (.../db_event_handler.php) (revision 11933) @@ -1,6 +1,6 @@ Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) { $live_ids = $temp->SaveEdit($event->getEventParam('master_ids') ? $event->getEventParam('master_ids') : Array()); + if ($live_ids === false) { + // coping from table failed, because we have another coping process to same table, that wasn't finished + $event->status = erFAIL; + return ; + } // Deleteing files scheduled for delete $var_name = $event->getPrefixSpecial().'_file_pending_actions'.$this->Application->GetVar('m_wid'); Index: branches/RC/core/kernel/utility/temp_handler.php =================================================================== diff -u -N -r11923 -r11933 --- branches/RC/core/kernel/utility/temp_handler.php (.../temp_handler.php) (revision 11923) +++ branches/RC/core/kernel/utility/temp_handler.php (.../temp_handler.php) (revision 11933) @@ -1,6 +1,6 @@ savedIDs[ $master['Prefix'] ]; } + /** + * Create separate connection for locking purposes + * + * @return kDBConnection + */ + function &_getSeparateConnection() + { + static $connection = null; + + if (!isset($connection)) { + $connection = new kDBConnection(SQL_TYPE, Array(&$this->Application, 'handleSQLError') ); + $connection->debugMode = $this->Application->isDebugMode(); + $connection->Connect(SQL_SERVER, SQL_USER, SQL_PASS, SQL_DB, true); + } + + return $connection; + } + function UpdateChangeLogForeignKeys($master, $live_id, $temp_id) { $main_prefix = $this->Application->GetTopmostPrefix($master['Prefix']); @@ -766,7 +784,60 @@ function SaveEdit($master_ids = Array()) { - return $this->DoCopyTempToOriginal($this->Tables, null, $master_ids); + // SessionKey field is required for deleting records from expired sessions + $conn =& $this->_getSeparateConnection(); + + $sleep_count = 0; + do { + // aquire lock + $conn->ChangeQuery('LOCK TABLES '.TABLE_PREFIX.'Semaphores WRITE'); + + $sql = 'SELECT SessionKey + FROM ' . TABLE_PREFIX . 'Semaphores + WHERE (MainPrefix = ' . $conn->qstr($this->Tables['Prefix']) . ')'; + $another_coping_active = $conn->GetOne($sql); + + if ($another_coping_active) { + // another user is coping data from temp table to live -> release lock and try again after 1 second + $conn->ChangeQuery('UNLOCK TABLES'); + $sleep_count++; + sleep(1); + } + } while ($another_coping_active && ($sleep_count <= 30)); + + if ($sleep_count > 30) { + // another coping process failed to finished in 30 seconds + $error_message = $this->Application->Phrase('la_error_TemporaryTableCopingFailed'); + $this->Application->SetVar('_temp_table_message', $error_message); + + return false; + } + + // mark, that we are coping from temp to live right now, so other similar attempt (from another script) will fail + $fields_hash = Array ( + 'SessionKey' => $this->Application->GetSID(), + 'Timestamp' => adodb_mktime(), + 'MainPrefix' => $this->Tables['Prefix'], + ); + + $conn->doInsert($fields_hash, TABLE_PREFIX.'Semaphores'); + $semaphore_id = $conn->getInsertID(); + + // unlock table now to prevent permanent lock in case, when coping will end with SQL error in the middle + $conn->ChangeQuery('UNLOCK TABLES'); + + $ids = $this->DoCopyTempToOriginal($this->Tables, null, $master_ids); + + // remove mark, that we are coping from temp to live + $conn->Query('LOCK TABLES '.TABLE_PREFIX.'Semaphores WRITE'); + + $sql = 'DELETE FROM ' . TABLE_PREFIX . 'Semaphores + WHERE SemaphoreId = ' . $semaphore_id; + $conn->ChangeQuery($sql); + + $conn->ChangeQuery('UNLOCK TABLES'); + + return $ids; } function CancelEdit($master=null) Index: branches/RC/core/admin_templates/incs/footer.tpl =================================================================== diff -u -N -r11661 -r11933 --- branches/RC/core/admin_templates/incs/footer.tpl (.../footer.tpl) (revision 11661) +++ branches/RC/core/admin_templates/incs/footer.tpl (.../footer.tpl) (revision 11933) @@ -38,6 +38,14 @@ InitEditors(); + + + addLoadEvent( + function() { + alert(''); + } + ); +