Add select() method to query objects from cache; Use locks to avoid multiple threads synching the same folder simultaneously

This commit is contained in:
Thomas Bruederli 2012-05-09 19:01:51 +02:00
parent ed467e73f9
commit 86c1d510f1
4 changed files with 106 additions and 5 deletions

View file

@ -6,7 +6,7 @@
* @licence GNU AGPL
**/
CREATE TABLE `kolab_cache` (
CREATE TABLE IF NOT EXISTS `kolab_cache` (
`resource` VARCHAR(255) CHARACTER SET ascii NOT NULL,
`type` VARCHAR(32) CHARACTER SET ascii NOT NULL,
`msguid` BIGINT UNSIGNED NOT NULL,

View file

@ -81,6 +81,9 @@ class kolab_storage_cache
if ($this->synched)
return;
// lock synchronization for this folder or wait if locked
$this->_sync_lock();
// synchronize IMAP mailbox cache
$this->imap->folder_sync($this->folder->name);
@ -92,8 +95,9 @@ class kolab_storage_cache
if ($this->ready) {
// read cache index
$sql_result = $this->db->query(
"SELECT msguid, uid FROM kolab_cache WHERE resource=?",
$this->resource_uri
"SELECT msguid, uid FROM kolab_cache WHERE resource=? AND type<>?",
$this->resource_uri,
'lock'
);
$old_index = array();
@ -120,6 +124,9 @@ class kolab_storage_cache
}
}
// remove lock
$this->_sync_unlock();
$this->synched = time();
}
@ -349,6 +356,7 @@ class kolab_storage_cache
$this->db->quote($param[2])
);
}
return $sql_where;
}
@ -400,6 +408,11 @@ class kolab_storage_cache
// 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['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'])
@ -453,6 +466,61 @@ class kolab_storage_cache
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
*

View file

@ -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
*

View file

@ -63,9 +63,7 @@ class libkolab extends rcube_plugin
*/
function storage_init($p)
{
$rcmail = rcmail::get_instance();
$p['fetch_headers'] = trim($p['fetch_headers'] .' X-KOLAB-TYPE');
return $p;
}