Add select() method to query objects from cache; Use locks to avoid multiple threads synching the same folder simultaneously
This commit is contained in:
parent
ed467e73f9
commit
86c1d510f1
4 changed files with 106 additions and 5 deletions
|
@ -6,7 +6,7 @@
|
||||||
* @licence GNU AGPL
|
* @licence GNU AGPL
|
||||||
**/
|
**/
|
||||||
|
|
||||||
CREATE TABLE `kolab_cache` (
|
CREATE TABLE IF NOT EXISTS `kolab_cache` (
|
||||||
`resource` VARCHAR(255) CHARACTER SET ascii NOT NULL,
|
`resource` VARCHAR(255) CHARACTER SET ascii NOT NULL,
|
||||||
`type` VARCHAR(32) CHARACTER SET ascii NOT NULL,
|
`type` VARCHAR(32) CHARACTER SET ascii NOT NULL,
|
||||||
`msguid` BIGINT UNSIGNED NOT NULL,
|
`msguid` BIGINT UNSIGNED NOT NULL,
|
||||||
|
|
|
@ -81,6 +81,9 @@ class kolab_storage_cache
|
||||||
if ($this->synched)
|
if ($this->synched)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// lock synchronization for this folder or wait if locked
|
||||||
|
$this->_sync_lock();
|
||||||
|
|
||||||
// synchronize IMAP mailbox cache
|
// synchronize IMAP mailbox cache
|
||||||
$this->imap->folder_sync($this->folder->name);
|
$this->imap->folder_sync($this->folder->name);
|
||||||
|
|
||||||
|
@ -92,8 +95,9 @@ class kolab_storage_cache
|
||||||
if ($this->ready) {
|
if ($this->ready) {
|
||||||
// read cache index
|
// read cache index
|
||||||
$sql_result = $this->db->query(
|
$sql_result = $this->db->query(
|
||||||
"SELECT msguid, uid FROM kolab_cache WHERE resource=?",
|
"SELECT msguid, uid FROM kolab_cache WHERE resource=? AND type<>?",
|
||||||
$this->resource_uri
|
$this->resource_uri,
|
||||||
|
'lock'
|
||||||
);
|
);
|
||||||
|
|
||||||
$old_index = array();
|
$old_index = array();
|
||||||
|
@ -120,6 +124,9 @@ class kolab_storage_cache
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove lock
|
||||||
|
$this->_sync_unlock();
|
||||||
|
|
||||||
$this->synched = time();
|
$this->synched = time();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,6 +356,7 @@ class kolab_storage_cache
|
||||||
$this->db->quote($param[2])
|
$this->db->quote($param[2])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $sql_where;
|
return $sql_where;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,6 +408,11 @@ class kolab_storage_cache
|
||||||
// database runs in server's timezone so using date() is what we want
|
// database runs in server's timezone so using date() is what we want
|
||||||
$sql_data['dtstart'] = date('Y-m-d H:i:s', is_object($object['start']) ? $object['start']->format('U') : $object['start']);
|
$sql_data['dtstart'] = date('Y-m-d H:i:s', is_object($object['start']) ? $object['start']->format('U') : $object['start']);
|
||||||
$sql_data['dtend'] = date('Y-m-d H:i:s', is_object($object['end']) ? $object['end']->format('U') : $object['end']);
|
$sql_data['dtend'] = date('Y-m-d H:i:s', is_object($object['end']) ? $object['end']->format('U') : $object['end']);
|
||||||
|
|
||||||
|
// extend date range for recurring events
|
||||||
|
if ($object['recurrence']) {
|
||||||
|
$sql_data['dtend'] = date('Y-m-d H:i:s', $object['recurrence']['UNTIL'] ?: strtotime('now + 2 years'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($object['_formatobj'])
|
if ($object['_formatobj'])
|
||||||
|
@ -453,6 +466,61 @@ class kolab_storage_cache
|
||||||
return $object;
|
return $object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check lock record for this folder and wait if locked or set lock
|
||||||
|
*/
|
||||||
|
private function _sync_lock()
|
||||||
|
{
|
||||||
|
if (!$this->ready)
|
||||||
|
return;
|
||||||
|
|
||||||
|
$sql_arr = $this->db->fetch_assoc($this->db->query(
|
||||||
|
"SELECT msguid AS locked FROM kolab_cache ".
|
||||||
|
"WHERE resource=? AND type=?",
|
||||||
|
$this->resource_uri,
|
||||||
|
'lock'
|
||||||
|
));
|
||||||
|
|
||||||
|
// create lock record if not exists
|
||||||
|
if (!$sql_arr) {
|
||||||
|
$this->db->query(
|
||||||
|
"INSERT INTO kolab_cache (resource, type, msguid, uid, data, xml)".
|
||||||
|
" VALUES (?, ?, ?, '', '', '')",
|
||||||
|
$this->resource_uri,
|
||||||
|
'lock',
|
||||||
|
time()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// wait if locked (expire locks after 10 minutes)
|
||||||
|
else if (intval($sql_arr['locked']) > 0 && (time() - $sql_arr['locked']) < 600) {
|
||||||
|
usleep(500000);
|
||||||
|
return $this->_sync_lock();
|
||||||
|
}
|
||||||
|
// set lock
|
||||||
|
else {
|
||||||
|
$this->db->query(
|
||||||
|
"UPDATE kolab_cache SET msguid=? ".
|
||||||
|
"WHERE resource=? AND type=?",
|
||||||
|
time(),
|
||||||
|
$this->resource_uri,
|
||||||
|
'lock'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove lock for this folder
|
||||||
|
*/
|
||||||
|
private function _sync_unlock()
|
||||||
|
{
|
||||||
|
$this->db->query(
|
||||||
|
"UPDATE kolab_cache SET msguid=0 ".
|
||||||
|
"WHERE resource=? AND type=?",
|
||||||
|
$this->resource_uri,
|
||||||
|
'lock'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve an object UID into an IMAP message UID
|
* Resolve an object UID into an IMAP message UID
|
||||||
*
|
*
|
||||||
|
|
|
@ -317,6 +317,41 @@ class kolab_storage_folder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select *some* Kolab objects matching the given query
|
||||||
|
*
|
||||||
|
* @param array Pseudo-SQL query as list of filter parameter triplets
|
||||||
|
* triplet: array('<colname>', '<comparator>', '<value>')
|
||||||
|
* @return array List of Kolab data objects (each represented as hash array)
|
||||||
|
*/
|
||||||
|
public function select($query = array())
|
||||||
|
{
|
||||||
|
// check query argument
|
||||||
|
if (empty($query))
|
||||||
|
return $this->get_objects();
|
||||||
|
|
||||||
|
$type = null;
|
||||||
|
foreach ($query as $i => $param) {
|
||||||
|
if ($param[0] == 'type') {
|
||||||
|
$type = $param[2];
|
||||||
|
}
|
||||||
|
else if (($param[0] == 'dtstart' || $param[0] == 'dtend') && is_numeric($param[2])) {
|
||||||
|
$query[$i][2] = date('Y-m-d H:i:s', $param[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add type selector if not in $query
|
||||||
|
if (!$type)
|
||||||
|
$query[] = array('type','=',$this->type);
|
||||||
|
|
||||||
|
// synchronize caches
|
||||||
|
$this->cache->synchronize();
|
||||||
|
|
||||||
|
// fetch objects from cache
|
||||||
|
return $this->cache->select($query);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getter for a single Kolab object, identified by its UID
|
* Getter for a single Kolab object, identified by its UID
|
||||||
*
|
*
|
||||||
|
|
|
@ -63,9 +63,7 @@ class libkolab extends rcube_plugin
|
||||||
*/
|
*/
|
||||||
function storage_init($p)
|
function storage_init($p)
|
||||||
{
|
{
|
||||||
$rcmail = rcmail::get_instance();
|
|
||||||
$p['fetch_headers'] = trim($p['fetch_headers'] .' X-KOLAB-TYPE');
|
$p['fetch_headers'] = trim($p['fetch_headers'] .' X-KOLAB-TYPE');
|
||||||
|
|
||||||
return $p;
|
return $p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue