Index: branches/5.2.x/core/install/install_data.sql =================================================================== diff -u -N -r16754 -r16770 --- branches/5.2.x/core/install/install_data.sql (.../install_data.sql) (revision 16754) +++ branches/5.2.x/core/install/install_data.sql (.../install_data.sql) (revision 16770) @@ -100,6 +100,7 @@ INSERT INTO SystemSettings VALUES(DEFAULT, 'Backup_Path', '/home/alex/web/in-portal.rc/system/backupdata', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_config_backup_path', 'text', '', '', 60.07, 0, 1, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'SystemTagCache', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_prompt_syscache_enable', 'checkbox', NULL, NULL, 60.08, 0, 0, NULL); INSERT INTO SystemSettings VALUES(DEFAULT, 'SocketBlockingMode', '0', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_prompt_socket_blocking_mode', 'checkbox', NULL, NULL, 60.09, 0, 0, NULL); +INSERT INTO SystemSettings VALUES(DEFAULT, 'SemaphoreLifetimeInSeconds', '300', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_config_SemaphoreLifetimeInSeconds', 'text', '', 'style=\"width: 50px;\"', 60.1, 0, 1, 'hint:la_config_SemaphoreLifetimeInSeconds'); INSERT INTO SystemSettings VALUES(DEFAULT, 'EnableEmailLog', '1', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsLogs', 'la_config_EnableEmailLog', 'radio', NULL, '1=la_Yes||0=la_No', 65.01, 0, 1, 'hint:la_config_EnableEmailLog'); INSERT INTO SystemSettings VALUES(DEFAULT, 'EmailLogRotationInterval', '2419200', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsLogs', 'la_config_EmailLogRotationInterval', 'select', NULL, '86400=la_opt_OneDay||604800=la_opt_OneWeek||1209600=la_opt_TwoWeeks||2419200=la_opt_OneMonth||7257600=la_opt_ThreeMonths||29030400=la_opt_OneYear||-1=la_opt_EmailLogKeepForever', 65.02, 0, 0, 'hint:la_config_EmailLogRotationInterval'); INSERT INTO SystemSettings VALUES(DEFAULT, 'SystemLogRotationInterval', '2419200', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsLogs', 'la_config_SystemLogRotationInterval', 'select', NULL, '86400=la_opt_OneDay||604800=la_opt_OneWeek||1209600=la_opt_TwoWeeks||2419200=la_opt_OneMonth||7257600=la_opt_ThreeMonths||29030400=la_opt_OneYear||-1=la_opt_SystemLogKeepForever', 65.03, 0, 1, 'hint:la_config_SystemLogRotationInterval'); Index: branches/5.2.x/core/install/install_schema.sql =================================================================== diff -u -N -r16754 -r16770 --- branches/5.2.x/core/install/install_schema.sql (.../install_schema.sql) (revision 16754) +++ branches/5.2.x/core/install/install_schema.sql (.../install_schema.sql) (revision 16770) @@ -1282,15 +1282,20 @@ ); CREATE TABLE Semaphores ( - SemaphoreId int(11) NOT NULL AUTO_INCREMENT, - SessionKey int(10) unsigned NOT NULL DEFAULT '0', + `SemaphoreId` int(11) NOT NULL AUTO_INCREMENT, + `SessionKey` int(10) unsigned NOT NULL DEFAULT '0', `Timestamp` int(10) unsigned NOT NULL DEFAULT '0', - MainPrefix varchar(255) NOT NULL DEFAULT '', - MainIDs text, - PRIMARY KEY (SemaphoreId), - KEY SessionKey (SessionKey), + `MainPrefix` varchar(255) NOT NULL DEFAULT '', + `MainIDs` text, + `UserId` int(11) DEFAULT NULL, + `IpAddress` varchar(15) NOT NULL DEFAULT '', + `Hostname` varchar(255) NOT NULL DEFAULT '', + `RequestURI` varchar(255) NOT NULL DEFAULT '', + `Backtrace` longtext, + PRIMARY KEY (`SemaphoreId`), + KEY `SessionKey` (`SessionKey`), KEY `Timestamp` (`Timestamp`), - KEY MainPrefix (MainPrefix) + KEY `MainPrefix` (`MainPrefix`) ); CREATE TABLE CachedUrls ( Index: branches/5.2.x/core/kernel/utility/temp_handler.php =================================================================== diff -u -N -r16733 -r16770 --- branches/5.2.x/core/kernel/utility/temp_handler.php (.../temp_handler.php) (revision 16733) +++ branches/5.2.x/core/kernel/utility/temp_handler.php (.../temp_handler.php) (revision 16770) @@ -1,6 +1,6 @@ 30) { - // another coping process failed to finished in 30 seconds + // Another coping process failed to finished in 30 seconds. $error_message = $this->Application->Phrase('la_error_TemporaryTableCopyingFailed'); $this->Application->SetVar('_temp_table_message', $error_message); + $log = $this->Application->log('Parallel item saving attempt detected'); + $log->addTrace(); + $log->setLogLevel(kLogger::LL_ERROR); + $log->write(); + 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'], - 'MainIDs' => implode(',', $master_ids), - ); + /* + * Mark, that we are coping from temp to live right now, + * so other similar attempt (from another script) will fail. + */ + $semaphore_id = $this->createSemaphore($conn, $master_ids); - $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'); @@ -1023,6 +1023,33 @@ return $ids; } + /** + * Creates a semaphore. + * + * @param IDBConnection $conn Database connection. + * @param array $master_ids Master record IDs. + * + * @return integer + */ + protected function createSemaphore(IDBConnection $conn, array $master_ids) + { + $fields_hash = array( + 'SessionKey' => $this->Application->GetSID(), + 'Timestamp' => adodb_mktime(), + 'MainPrefix' => $this->Tables['Prefix'], + 'MainIDs' => implode(',', $master_ids), + 'UserId' => $this->Application->RecallVar('user_id'), + 'IPAddress' => $this->Application->getClientIp(), + 'Hostname' => $_SERVER['HTTP_HOST'], + 'RequestURI' => $_SERVER['REQUEST_URI'], + 'Backtrace' => serialize(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)), + ); + + $conn->doInsert($fields_hash, TABLE_PREFIX . 'Semaphores'); + + return $conn->getInsertID(); + } + function CancelEdit($master=null) { if (!isset($master)) $master = $this->Tables; Index: branches/5.2.x/core/install/english.lang =================================================================== diff -u -N -r16754 -r16770 --- branches/5.2.x/core/install/english.lang (.../english.lang) (revision 16754) +++ branches/5.2.x/core/install/english.lang (.../english.lang) (revision 16770) @@ -204,6 +204,7 @@ UmVxdWlyZSBTU0wgZm9yIGxvZ2luICYgY2hlY2tvdXQ= RnJhbWVzIGluIGFkbWluaXN0cmF0aXZlIGNvbnNvbGUgYXJlIHJlc2l6YWJsZQ== TWluaW1hbCBTZWFyY2ggS2V5d29yZCBMZW5ndGg= + RGVsZXRlIFN0dWNrIFNlbWFwaG9yZXMgYWZ0ZXI= U2Vzc2lvbiBTZWN1cml0eSBDaGVjayBiYXNlZCBvbiBCcm93c2VyIFNpZ25hdHVyZQ== U2Vzc2lvbiBDb29raWUgRG9tYWlucyAoc2luZ2xlIGRvbWFpbiBwZXIgbGluZSk= U2Vzc2lvbiBTZWN1cml0eSBDaGVjayBiYXNlZCBvbiBJUA== @@ -1380,6 +1381,7 @@ Q29tbWVudHM= TW9kdWxlIFJvb3QgU2VjdGlvbg== U2F2ZQ== + c2Vjb25kcw== U2VsZWN0 U2Vzc2lvbiBFeHBpcmVk U2ltcGxl Index: branches/5.2.x/core/install/upgrades.sql =================================================================== diff -u -N -r16754 -r16770 --- branches/5.2.x/core/install/upgrades.sql (.../upgrades.sql) (revision 16754) +++ branches/5.2.x/core/install/upgrades.sql (.../upgrades.sql) (revision 16770) @@ -2964,3 +2964,11 @@ ADD COLUMN `LogCodeFragment` longtext NULL AFTER `LogSourceFileLine`, ADD COLUMN `LogCodeFragmentsRotated` tinyint(4) NOT NULL DEFAULT '0' AFTER `LogCodeFragment`; ALTER TABLE SystemLog ADD INDEX `TIMESTAMP_CODE_FRAGMENTS_ROTATED` (`LogTimestamp`,`LogCodeFragmentsRotated`) USING BTREE; + +ALTER TABLE Semaphores + ADD COLUMN `UserId` int(11) NULL, + ADD COLUMN `IpAddress` varchar(15) NOT NULL DEFAULT '', + ADD COLUMN `Hostname` varchar(255) NOT NULL DEFAULT '', + ADD COLUMN `RequestURI` varchar(255) NOT NULL DEFAULT '', + ADD COLUMN `Backtrace` longtext NULL; +INSERT INTO SystemSettings VALUES(DEFAULT, 'SemaphoreLifetimeInSeconds', '300', 'In-Portal', 'in-portal:configure_advanced', 'la_section_SettingsSystem', 'la_config_SemaphoreLifetimeInSeconds', 'text', '', 'style=\"width: 50px;\"', 60.1, 0, 1, 'hint:la_config_SemaphoreLifetimeInSeconds'); Index: branches/5.2.x/core/units/admin/admin_events_handler.php =================================================================== diff -u -N -r16664 -r16770 --- branches/5.2.x/core/units/admin/admin_events_handler.php (.../admin_events_handler.php) (revision 16664) +++ branches/5.2.x/core/units/admin/admin_events_handler.php (.../admin_events_handler.php) (revision 16770) @@ -1,6 +1,6 @@ Application->ConfigValue('SemaphoreLifetimeInSeconds'); + + $sql = 'SELECT * + FROM ' . TABLE_PREFIX . 'Semaphores + WHERE Timestamp < ' . strtotime('-' . $semaphore_lifetime . ' seconds'); + $stuck_semaphores = $this->Conn->Query($sql, 'SemaphoreId'); + + if ( !$stuck_semaphores ) { + return; + } + + /** @var LanguagesItem $language */ + $language = $this->Application->recallObject('lang.current', null, array('skip_autoload' => true)); + $date_format = $language->GetDBField('DateFormat') . ' ' . $language->GetDBField('TimeFormat'); + + foreach ( $stuck_semaphores as $semaphore_id => $semaphore_data ) { + $log = $this->Application->log('Stuck semaphore detected (unit: ' . $semaphore_data['MainPrefix'] . ')'); + $log->setLogLevel(kLogger::LL_ERROR); + $log->addTrace(unserialize($semaphore_data['Backtrace'])); + $log->setUserData(implode(PHP_EOL, array( + 'Main Prefix: ' . $semaphore_data['MainPrefix'], + 'Main IDs: ' . $semaphore_data['MainIDs'], + 'Created On: ' . date($date_format, $semaphore_data['Timestamp']), + 'Deleted On: ' . date($date_format), + ))); + + $log->setLogField('LogHostname', $semaphore_data['Hostname']); + $log->setLogField('LogRequestSource', 1); // Web. + $log->setLogField('LogInterface', kLogger::LI_ADMIN); + $log->setLogField('LogRequestURI', $semaphore_data['RequestURI']); + $log->setLogField('LogUserId', $semaphore_data['UserId']); + $log->setLogField('IpAddress', $semaphore_data['IpAddress']); + $log->setLogField('LogSessionKey', $semaphore_data['SessionKey']); + + $log->write(); + + $sql = 'DELETE FROM ' . TABLE_PREFIX . 'Semaphores + WHERE SemaphoreId = ' . $semaphore_id; + $this->Conn->Query($sql); + } + } + } Index: branches/5.2.x/core/admin_templates/config/custom_variables.tpl =================================================================== diff -u -N -r15608 -r16770 --- branches/5.2.x/core/admin_templates/config/custom_variables.tpl (.../custom_variables.tpl) (revision 15608) +++ branches/5.2.x/core/admin_templates/config/custom_variables.tpl (.../custom_variables.tpl) (revision 16770) @@ -143,4 +143,8 @@ - \ No newline at end of file + + + + + Index: branches/5.2.x/core/units/admin/admin_config.php =================================================================== diff -u -N -r16664 -r16770 --- branches/5.2.x/core/units/admin/admin_config.php (.../admin_config.php) (revision 16664) +++ branches/5.2.x/core/units/admin/admin_config.php (.../admin_config.php) (revision 16770) @@ -1,6 +1,6 @@ Array ('EventName' => 'OnOptimizePerformance', 'RunSchedule' => '0 0 * * *'), 'purge_expired_database_cache' => Array ('EventName' => 'OnPurgeExpiredDatabaseCacheScheduledTask', 'RunSchedule' => '0 0,12 * * *'), 'populate_url_unit_cache' => array('EventName' => 'OnPopulateUrlUnitCacheScheduledTask', 'RunSchedule' => '0 * * * *'), + 'delete_stuck_semaphores' => array('EventName' => 'OnDeleteStuckSemaphoresScheduledTask', 'RunSchedule' => '*/5 * * * *'), ), 'TitlePresets' => Array (