Page MenuHomePhorge

D5223.1774819179.diff
No OneTemporary

Authored By
Unknown
Size
6 KB
Referenced Files
None
Subscribers
None

D5223.1774819179.diff

diff --git a/docs/SQL/mysql.initial.sql b/docs/SQL/mysql.initial.sql
--- a/docs/SQL/mysql.initial.sql
+++ b/docs/SQL/mysql.initial.sql
@@ -48,6 +48,7 @@
`lastfiltertype` int(11) DEFAULT NULL,
`supportedfields` longblob DEFAULT NULL,
`resync` tinyint(1) DEFAULT NULL,
+ `is_deleted` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `device_id--class--folderid` (`device_id`(40),`class`(40),`folderid`(40)),
KEY `folderstates::device_id--devices::id` (`device_id`),
diff --git a/docs/SQL/mysql/2025043000.sql b/docs/SQL/mysql/2025043000.sql
new file mode 100644
--- /dev/null
+++ b/docs/SQL/mysql/2025043000.sql
@@ -0,0 +1 @@
+ALTER TABLE `syncroton_folder` ADD `is_deleted` tinyint(1) NOT NULL DEFAULT '0';
diff --git a/lib/kolab_sync_backend_folder.php b/lib/kolab_sync_backend_folder.php
--- a/lib/kolab_sync_backend_folder.php
+++ b/lib/kolab_sync_backend_folder.php
@@ -45,6 +45,21 @@
$this->db->query('DELETE FROM `' . $this->table_name . '` WHERE ' . implode(' AND ', $where));
}
+ /**
+ * mark folder as deleted. The state gets removed finally,
+ * when the synckey gets validated during next sync.
+ *
+ * @param Syncroton_Model_IFolder|string $id
+ */
+ public function delete($id)
+ {
+ $id = $id instanceof Syncroton_Model_IFolder ? $id->id : $id;
+
+ $result = $this->db->query("UPDATE `{$this->table_name}` SET `is_deleted` = 1 WHERE `id` = ?", [$id]);
+
+ return $result;
+ }
+
/**
* Get array of ids which got send to the client for a given class
*
diff --git a/lib/kolab_sync_backend_state.php b/lib/kolab_sync_backend_state.php
--- a/lib/kolab_sync_backend_state.php
+++ b/lib/kolab_sync_backend_state.php
@@ -145,6 +145,28 @@
$this->db->query("DELETE FROM `{$this->table_name}` WHERE " . implode(' AND ', $where));
}
+ /**
+ * Run a query and retry on deadlock
+ */
+ private function runAndRetry($query)
+ {
+ $retryCounter = 0;
+ while (true) {
+ $result = $this->db->query($query);
+ if ($this->db->is_error($result)) {
+ $retryCounter++;
+ // Retry on deadlock
+ if ($this->db->error_info()[0] != '40001' || $retryCounter > 60) {
+ throw new Exception("Failed to run query ($retryCounter retries): " . $query);
+ }
+ } else {
+ break;
+ }
+ // Give the other transactions some time before we try again
+ sleep(1);
+ }
+ }
+
/**
* Validates specified sync state by checking for existance of newer keys
*
@@ -184,32 +206,24 @@
$state = $states[$sync_key];
$next = max(array_keys($states));
- $where = [];
- $where['device_id'] = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($device_id);
- $where['folder_id'] = $this->db->quote_identifier('folder_id') . ' = ' . $this->db->quote($folder_id);
- $where['is_deleted'] = $this->db->quote_identifier('is_deleted') . ' = 1';
-
// found more recent synckey => the last sync response was not received by the client
if ($next > $sync_key) {
// We store the clientIdMap with the "next" sync state, so we need to copy it back.
$state->clientIdMap = $states[$next]->clientIdMap;
$state->counterNext = $next;
} else {
- // finally delete all entries marked for removal in syncroton_content table
- $retryCounter = 0;
- while (true) {
- $result = $this->db->query("DELETE FROM `syncroton_content` WHERE " . implode(' AND ', $where));
- if ($this->db->is_error($result)) {
- $retryCounter++;
- // Retry on deadlock
- if ($this->db->error_info()[0] != '40001' || $retryCounter > 60) {
- throw new Exception('Failed to delete entries in sync_key check');
- }
- } else {
- break;
- }
- //Give the other transactions some time before we try again
- sleep(1);
+ // Cleanup deleted entries
+ if ($folderid == 'FolderSync') {
+ $where = [];
+ $where['device_id'] = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($device_id);
+ $where['is_deleted'] = $this->db->quote_identifier('is_deleted') . ' = 1';
+ $this->runAndRetry("DELETE FROM `syncroton_folder` WHERE " . implode(' AND ', $where));
+ } else {
+ $where = [];
+ $where['device_id'] = $this->db->quote_identifier('device_id') . ' = ' . $this->db->quote($device_id);
+ $where['folder_id'] = $this->db->quote_identifier('folder_id') . ' = ' . $this->db->quote($folder_id);
+ $where['is_deleted'] = $this->db->quote_identifier('is_deleted') . ' = 1';
+ $this->runAndRetry("DELETE FROM `syncroton_content` WHERE " . implode(' AND ', $where));
}
}
diff --git a/tests/Sync/FoldersTest.php b/tests/Sync/FoldersTest.php
--- a/tests/Sync/FoldersTest.php
+++ b/tests/Sync/FoldersTest.php
@@ -126,6 +126,7 @@
*/
public function testSyncKeyResend()
{
+ $this->createTestFolder("NewFolderToRemove", "mail");
$request = <<<EOF
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
@@ -141,6 +142,8 @@
//Now change something
$this->createTestFolder("NewFolder", "mail");
+ $this->deleteTestFolder('NewFolderToRemove', 'mail');
+
$request = <<<EOF
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
@@ -155,7 +158,7 @@
$xpath = $this->xpath($dom);
$this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue);
$this->assertSame('2', $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue);
- $this->assertSame(strval(1), $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue);
+ $this->assertSame(strval(2), $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue);
//Resend the same synckey
$request = <<<EOF
@@ -172,7 +175,7 @@
$xpath = $this->xpath($dom);
$this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue);
$this->assertSame('2', $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue);
- $this->assertSame(strval(1), $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue);
+ $this->assertSame(strval(2), $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue);
//And now make sure we can still move on
$request = <<<EOF

File Metadata

Mime Type
text/plain
Expires
Sun, Mar 29, 9:19 PM (3 d, 20 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18776460
Default Alt Text
D5223.1774819179.diff (6 KB)

Event Timeline