Remove duplicates on cache synchronization.
https://issues.kolab.org/show_bug.cgi?id=4067 and (Bifrost#TT20881) It happens that IMAP folder may contain many objects with the same UID. The precise reason for this is unknown, but it can be e.g. a faulty client or an error between "create a new object instance" and "remove the old one". It causes various issues when editing such objects. With the change we assume that the most recent object (with max. IMAP UID) is the one that should be used and all the older instances will be removed automatically.
This commit is contained in:
parent
febb0d4bfa
commit
45ce87f545
1 changed files with 39 additions and 6 deletions
|
@ -219,22 +219,45 @@ class kolab_storage_cache
|
|||
// determine objects to fetch or to invalidate
|
||||
if (!$imap_index->is_error()) {
|
||||
$imap_index = $imap_index->get();
|
||||
$old_index = array();
|
||||
$del_index = array();
|
||||
|
||||
// read cache index
|
||||
$sql_result = $this->db->query(
|
||||
"SELECT `msguid`, `uid` FROM `{$this->cache_table}` WHERE `folder_id` = ?",
|
||||
$this->folder_id
|
||||
"SELECT `msguid`, `uid` FROM `{$this->cache_table}` WHERE `folder_id` = ?"
|
||||
. " ORDER BY `msguid` DESC", $this->folder_id
|
||||
);
|
||||
|
||||
$old_index = array();
|
||||
while ($sql_arr = $this->db->fetch_assoc($sql_result)) {
|
||||
$old_index[] = $sql_arr['msguid'];
|
||||
// Mark all duplicates for removal (note sorting order above)
|
||||
// Duplicates here should not happen, but they do sometimes
|
||||
if (isset($old_index[$sql_arr['uid']])) {
|
||||
$del_index[] = $sql_arr['msguid'];
|
||||
}
|
||||
else {
|
||||
$old_index[$sql_arr['uid']] = $sql_arr['msguid'];
|
||||
}
|
||||
}
|
||||
|
||||
// fetch new objects from imap
|
||||
$i = 0;
|
||||
foreach (array_diff($imap_index, $old_index) as $msguid) {
|
||||
if ($object = $this->folder->read_object($msguid, '*')) {
|
||||
// Deduplication: remove older objects with the same UID
|
||||
// Here we do not resolve conflicts, we just make sure
|
||||
// the most recent version of the object will be used
|
||||
if ($old_msguid = $old_index[$object['uid']]) {
|
||||
if ($old_msguid < $msguid) {
|
||||
$del_index[] = $old_msguid;
|
||||
}
|
||||
else {
|
||||
$del_index[] = $msguid;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$old_index[$object['uid']] = $msguid;
|
||||
|
||||
$this->_extended_insert($msguid, $object);
|
||||
|
||||
// check time limit and abort sync if running too long
|
||||
|
@ -246,8 +269,18 @@ class kolab_storage_cache
|
|||
}
|
||||
$this->_extended_insert(0, null);
|
||||
|
||||
// delete invalid entries from local DB
|
||||
$del_index = array_diff($old_index, $imap_index);
|
||||
$del_index = array_unique($del_index);
|
||||
|
||||
// delete duplicate entries from IMAP
|
||||
$rem_index = array_intersect($del_index, $imap_index);
|
||||
if (!empty($rem_index)) {
|
||||
$this->imap_mode(true);
|
||||
$this->imap->delete_message($rem_index, $this->folder->name);
|
||||
$this->imap_mode(false);
|
||||
}
|
||||
|
||||
// delete old/invalid entries from the cache
|
||||
$del_index += array_diff($old_index, $imap_index);
|
||||
if (!empty($del_index)) {
|
||||
$quoted_ids = join(',', array_map(array($this->db, 'quote'), $del_index));
|
||||
$this->db->query(
|
||||
|
|
Loading…
Add table
Reference in a new issue