mirror of
https://gitlab.com/davical-project/davical.git
synced 2026-08-29 18:26:05 +00:00
Add caching of collection reads
Also a special header is added for telling DAViCal to flush the cache during regression testing etc. Signed-off-by: Andrew McMillan <andrew@morphoss.com>
This commit is contained in:
parent
fe095d009d
commit
4178ab4254
@ -14,6 +14,7 @@
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once("AwlCache.php");
|
||||
require_once("XMLDocument.php");
|
||||
require_once("CalDAVPrincipal.php");
|
||||
include("DAVTicket.php");
|
||||
@ -343,6 +344,11 @@ EOSQL;
|
||||
$qry->Exec('caldav',__LINE__,__FILE__);
|
||||
dbg_error_log( 'caldav', 'Created new collection as "%s".', trim($params[':boxname']) );
|
||||
|
||||
// Uncache anything to do with the collection
|
||||
$cache = getCacheInstance();
|
||||
$cache->delete( 'collection-'.$params[':dav_name'], null );
|
||||
$cache->delete( 'principal-'.$params[':parent_container'], null );
|
||||
|
||||
$qry = new AwlQuery( "SELECT * FROM collection WHERE dav_name = :dav_name", array( ':dav_name' => $matches[1] ) );
|
||||
if ( $qry->Exec('caldav',__LINE__,__FILE__) && $qry->rows() == 1 && ($row = $qry->Fetch()) ) {
|
||||
$this->collection_id = $row->collection_id;
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once('AwlCache.php');
|
||||
require_once('AwlQuery.php');
|
||||
require_once('DAVTicket.php');
|
||||
|
||||
@ -295,23 +296,8 @@ class DAVResource
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the collection associated with this resource.
|
||||
*/
|
||||
function FetchCollection() {
|
||||
global $c, $session, $request;
|
||||
/**
|
||||
* RFC4918, 8.3: Identifiers for collections SHOULD end in '/'
|
||||
* - also discussed at more length in 5.2
|
||||
*
|
||||
* So we look for a collection which matches one of the following URLs:
|
||||
* - The exact request.
|
||||
* - If the exact request, doesn't end in '/', then the request URL with a '/' appended
|
||||
* - The request URL truncated to the last '/'
|
||||
* The collection URL for this request is therefore the longest row in the result, so we
|
||||
* can "... ORDER BY LENGTH(dav_name) DESC LIMIT 1"
|
||||
*/
|
||||
dbg_error_log( 'DAVResource', ':FetchCollection: Looking for collection for "%s".', $this->dav_name );
|
||||
private function ReadCollectionFromDatabase() {
|
||||
global $c, $session;
|
||||
|
||||
$this->collection = (object) array(
|
||||
'collection_id' => -1,
|
||||
@ -385,7 +371,9 @@ EOSQL;
|
||||
|| preg_match( '#^((/principals/[^/]+/)[^/]+)/?$#', $this->dav_name, $matches) ) {
|
||||
$this->_is_principal = true;
|
||||
$this->FetchPrincipal();
|
||||
}
|
||||
$this->collection->is_principal = true;
|
||||
$this->collection->type = 'principal';
|
||||
}
|
||||
else if ( $this->dav_name == '/' ) {
|
||||
$this->collection->dav_name = '/';
|
||||
$this->collection->type = 'root';
|
||||
@ -418,16 +406,10 @@ EOSQL;
|
||||
if ( $qry->Exec('DAVResource',__LINE__,__FILE__) && $qry->rows() == 1 && ($row = $qry->Fetch()) ) {
|
||||
$this->collection = $row;
|
||||
$this->collection->exists = true;
|
||||
$this->_is_binding = true;
|
||||
$this->collection->parent_set = $row->parent_container;
|
||||
$this->collection->parent_container = $row->bind_parent_container;
|
||||
$this->bound_from = str_replace( $row->bound_to, $row->dav_name, $this->dav_name);
|
||||
$this->collection->bound_from = $row->dav_name;
|
||||
$this->collection->dav_name = $row->bound_to;
|
||||
if ( isset($row->access_ticket_id) ) {
|
||||
if ( !isset($this->tickets) ) $this->tickets = array();
|
||||
$this->tickets[] = new DAVTicket($row->access_ticket_id);
|
||||
}
|
||||
if ( $row->is_calendar == 't' )
|
||||
$this->collection->type = 'calendar';
|
||||
else if ( $row->is_addressbook == 't' )
|
||||
@ -436,6 +418,13 @@ EOSQL;
|
||||
$this->collection->type = 'schedule-'. $matches[3]. 'box';
|
||||
else
|
||||
$this->collection->type = 'collection';
|
||||
|
||||
$this->_is_binding = true;
|
||||
$this->bound_from = str_replace( $row->bound_to, $row->dav_name, $this->dav_name);
|
||||
if ( isset($row->access_ticket_id) ) {
|
||||
if ( !isset($this->tickets) ) $this->tickets = array();
|
||||
$this->tickets[] = new DAVTicket($row->access_ticket_id);
|
||||
}
|
||||
}
|
||||
else {
|
||||
dbg_error_log( 'DAVResource', 'No collection for path "%s".', $this->dav_name );
|
||||
@ -443,9 +432,63 @@ EOSQL;
|
||||
$this->collection->dav_name = preg_replace('{/[^/]*$}', '/', $this->dav_name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the collection associated with this resource.
|
||||
*/
|
||||
function FetchCollection() {
|
||||
global $session;
|
||||
|
||||
/**
|
||||
* RFC4918, 8.3: Identifiers for collections SHOULD end in '/'
|
||||
* - also discussed at more length in 5.2
|
||||
*
|
||||
* So we look for a collection which matches one of the following URLs:
|
||||
* - The exact request.
|
||||
* - If the exact request, doesn't end in '/', then the request URL with a '/' appended
|
||||
* - The request URL truncated to the last '/'
|
||||
* The collection URL for this request is therefore the longest row in the result, so we
|
||||
* can "... ORDER BY LENGTH(dav_name) DESC LIMIT 1"
|
||||
*/
|
||||
dbg_error_log( 'DAVResource', ':FetchCollection: Looking for collection for "%s".', $this->dav_name );
|
||||
|
||||
@dbg_error_log( 'DAVResource', ':FetchCollection: Found collection named "%s" of type "%s".', $this->collection->dav_name, $this->collection->type );
|
||||
// Try and pull the answer out of a hat
|
||||
$cache = getCacheInstance();
|
||||
$cache_ns = 'collection-'.preg_replace( '{/[^/]*$}', '/', $this->dav_name);
|
||||
$cache_key = 'dav_resource'.$session->user_no;
|
||||
$this->collection = $cache->get( $cache_ns, $cache_key );
|
||||
if ( $this->collection === false ) {
|
||||
$this->ReadCollectionFromDatabase();
|
||||
if ( $this->collection->type != 'principal' ) {
|
||||
$cache_ns = 'collection-'.$this->collection->dav_name;
|
||||
@dbg_error_log( 'Cache', ':FetchCollection: Setting cache ns "%s" key "%s". Type: %s', $cache_ns, $cache_key, $this->collection->type );
|
||||
$cache->set( $cache_ns, $cache_key, $this->collection );
|
||||
}
|
||||
@dbg_error_log( 'DAVResource', ':FetchCollection: Found collection named "%s" of type "%s".', $this->collection->dav_name, $this->collection->type );
|
||||
}
|
||||
else {
|
||||
@dbg_error_log( 'Cache', ':FetchCollection: Got cache ns "%s" key "%s". Type: %s', $cache_ns, $cache_key, $this->collection->type );
|
||||
if ( preg_match( '#^(/[^/]+)/?$#', $this->dav_name, $matches)
|
||||
|| preg_match( '#^((/principals/[^/]+/)[^/]+)/?$#', $this->dav_name, $matches) ) {
|
||||
$this->_is_principal = true;
|
||||
$this->FetchPrincipal();
|
||||
$this->collection->is_principal = true;
|
||||
$this->collection->type = 'principal';
|
||||
}
|
||||
@dbg_error_log( 'DAVResource', ':FetchCollection: Read cached collection named "%s" of type "%s".', $this->collection->dav_name, $this->collection->type );
|
||||
}
|
||||
|
||||
if ( isset($this->collection->bound_from) ) {
|
||||
$this->_is_binding = true;
|
||||
$this->bound_from = str_replace( $this->collection->bound_to, $this->collection->bound_from, $this->dav_name);
|
||||
if ( isset($this->collection->access_ticket_id) ) {
|
||||
if ( !isset($this->tickets) ) $this->tickets = array();
|
||||
$this->tickets[] = new DAVTicket($this->collection->access_ticket_id);
|
||||
}
|
||||
}
|
||||
|
||||
$this->_is_collection = ( $this->_is_principal || $this->collection->dav_name == $this->dav_name || $this->collection->dav_name == $this->dav_name.'/' );
|
||||
if ( $this->_is_collection ) {
|
||||
$this->dav_name = $this->collection->dav_name;
|
||||
|
||||
@ -78,6 +78,12 @@ $params = array(
|
||||
$qry = new AwlQuery( $sql, $params );
|
||||
if ( $qry->Exec('BIND',__LINE__,__FILE__) ) {
|
||||
header('Location: '. ConstructURL($destination_path) );
|
||||
|
||||
// Uncache anything to do with the target
|
||||
$cache = getCacheInstance();
|
||||
$cache_ns = 'collection-'.$destination_path;
|
||||
$cache->delete( $cache_ns, null );
|
||||
|
||||
$request->DoResponse(201);
|
||||
}
|
||||
else {
|
||||
|
||||
@ -59,6 +59,9 @@ if ( $dav_resource->IsBinding() ) {
|
||||
}
|
||||
else if ( $dav_resource->IsCollection() ) {
|
||||
if ( delete_collection( $dav_resource->resource_id() ) && $qry->Commit() ) {
|
||||
// Uncache anything to do with the collection
|
||||
$cache = getCacheInstance();
|
||||
$cache->delete( 'collection-'.$dav_resource->dav_name(), null );
|
||||
$request->DoResponse( 204 );
|
||||
}
|
||||
}
|
||||
@ -78,6 +81,8 @@ else {
|
||||
if ( function_exists('log_caldav_action') ) {
|
||||
log_caldav_action( 'DELETE', $dav_resource->GetProperty('uid'), $dav_resource->GetProperty('user_no'), $dav_resource->GetProperty('collection_id'), $request->path );
|
||||
}
|
||||
$cache = getCacheInstance();
|
||||
$cache->delete( 'collection-'.$dav_resource->parent_path(), null );
|
||||
$request->DoResponse( 204 );
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,8 +108,13 @@ $dst_collection = $dest->GetProperty('collection_id');
|
||||
$src_user_no = $src->GetProperty('user_no');
|
||||
$dst_user_no = $dest->GetProperty('user_no');
|
||||
|
||||
$cache = getCacheInstance();
|
||||
$cachekeys = array();
|
||||
|
||||
if ( $src->IsCollection() ) {
|
||||
$cachekeys[] = ($src->ContainerType() == 'principal' ? 'principal' : 'collection').'-'.$src->parent_path();
|
||||
$cachekeys[] = ($src->IsPrincipal() == 'principal' ? 'principal' : 'collection').'-'.$src->dav_name();
|
||||
$cachekeys[] = ($src->IsPrincipal() ? 'principal' : 'collection').'-'.$dest->dav_name();
|
||||
if ( $dest->Exists() ) {
|
||||
$qry = new AwlQuery( 'DELETE FROM collection WHERE dav_name = :dst_name', array( ':dst_name' => $dst_name ) );
|
||||
if ( !$qry->Exec('move') ) rollback(500);
|
||||
@ -121,6 +126,11 @@ if ( $src->IsCollection() ) {
|
||||
$sql .= ', user_no = :dst_user_no ';
|
||||
$params[':dst_user_no'] = $dst_user_no;
|
||||
}
|
||||
if ( $src->parent_path() != $dest->parent_path() ) {
|
||||
$sql .= ', parent_container=:parent ';
|
||||
$params[':parent'] = $dest->parent_path();
|
||||
$cachekeys[] = ($dest->ContainerType() == 'principal' ? 'principal' : 'collection').'-'.$dest->parent_path();
|
||||
}
|
||||
$sql .= 'WHERE collection_id = :src_collection';
|
||||
$params[':src_collection'] = $src_collection;
|
||||
$qry = new AwlQuery( $sql, $params );
|
||||
@ -131,6 +141,8 @@ else {
|
||||
$qry = new AwlQuery( 'DELETE FROM caldav_data WHERE dav_name = :dst_name', array( ':dst_name' => $dst_name) );
|
||||
if ( !$qry->Exec('move') ) rollback(500);
|
||||
}
|
||||
$cachekeys[] = ($src->ContainerType() == 'principal' ? 'principal' : 'collection').'-'.$src->parent_path();
|
||||
|
||||
$sql = 'UPDATE caldav_data SET dav_name = :dst_name';
|
||||
$params = array( ':dst_name' => $dst_name );
|
||||
if ( $src_user_no != $dst_user_no ) {
|
||||
@ -140,6 +152,7 @@ else {
|
||||
if ( $src_collection != $dst_collection ) {
|
||||
$sql .= ', collection_id = :dst_collection';
|
||||
$params[':dst_collection'] = $dst_collection;
|
||||
$cachekeys[] = ($dest->ContainerType() == 'principal' ? 'principal' : 'collection').'-'.$dest->parent_path();
|
||||
}
|
||||
$sql .=' WHERE dav_name = :src_name';
|
||||
$params[':src_name'] = $src_name;
|
||||
@ -170,4 +183,7 @@ else {
|
||||
$qry = new AwlQuery('COMMIT');
|
||||
if ( !$qry->Exec('move') ) rollback(500);
|
||||
|
||||
// We need to delete from the cache *after* we commit the transaction :-)
|
||||
foreach( $cachekeys AS $cache_ns ) $cache->delete( $cache_ns, null );
|
||||
|
||||
$request->DoResponse( 200 );
|
||||
|
||||
@ -10,7 +10,6 @@
|
||||
*/
|
||||
dbg_error_log("PROPPATCH", "method handler");
|
||||
|
||||
require_once('AWLCache.php');
|
||||
require_once('iCalendar.php');
|
||||
require_once('DAVResource.php');
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
* return true if it's a whole calendar
|
||||
*/
|
||||
|
||||
require_once('AWLCache.php');
|
||||
require_once('AwlCache.php');
|
||||
require_once('iCalendar.php');
|
||||
require_once('WritableCollection.php');
|
||||
|
||||
@ -121,7 +121,7 @@ VALUES( :user_no, :parent_container, :dav_name, :dav_etag, :dav_displayname, TRU
|
||||
);
|
||||
$qry->QDo( $sql, $params );
|
||||
}
|
||||
else if ( isset($public) ) {
|
||||
else if ( isset($public) && $collection->is_public == ($public?'t':'f') ) {
|
||||
$collection = $qry->Fetch();
|
||||
$sql = 'UPDATE collection SET publicly_readable = :is_public::boolean WHERE collection_id = :collection_id';
|
||||
$params = array( ':is_public' => ($public?'t':'f'), ':collection_id' => $collection->collection_id );
|
||||
@ -129,6 +129,7 @@ VALUES( :user_no, :parent_container, :dav_name, :dav_etag, :dav_displayname, TRU
|
||||
rollback_on_error( $caldav_context, $user_no, $path );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -631,7 +632,7 @@ EOSQL;
|
||||
|
||||
// Uncache anything to do with the collection
|
||||
$cache = getCacheInstance();
|
||||
$cache_ns = 'collection-'.preg_replace( '{/.*$}', '/', $path);
|
||||
$cache_ns = 'collection-'.preg_replace( '{/[^/]*$}', '/', $path);
|
||||
$cache->delete( $cache_ns, null );
|
||||
}
|
||||
|
||||
@ -995,7 +996,7 @@ EOSQL;
|
||||
|
||||
// Uncache anything to do with the collection
|
||||
$cache = getCacheInstance();
|
||||
$cache_ns = 'collection-'.preg_replace( '{/.*$}', '/', $path);
|
||||
$cache_ns = 'collection-'.preg_replace( '{/[^/]*$}', '/', $path);
|
||||
$cache->delete( $cache_ns, null );
|
||||
|
||||
dbg_error_log( 'PUT', 'User: %d, ETag: %s, Path: %s', $author, $etag, $path);
|
||||
|
||||
@ -12,6 +12,7 @@ SELECT ticket_id FROM access_ticket
|
||||
WHERE target_collection_id = 11 AND target_resource_id is null;
|
||||
ENDSQL
|
||||
|
||||
HEADER=X-DAViCal-Flush-Cache: true
|
||||
HEADER=User-Agent: Ticket Spec Tests
|
||||
HEADER=Content-Type: text/xml; charset="UTF-8"
|
||||
HEADER=Ticket: ##ticket##
|
||||
|
||||
@ -5,6 +5,8 @@ TYPE=MKCOL
|
||||
URL=http://mycaldav/caldav.php/user1/addressbook/
|
||||
HEADER=User-Agent: DAViCalTester/public
|
||||
HEADER=Content-Type: text/xml
|
||||
HEADER=X-DAViCal-Flush-Cache: true
|
||||
|
||||
HEAD
|
||||
|
||||
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
#
|
||||
TYPE=POST
|
||||
URL=http://mycaldav/caldav.php/user1/.out/
|
||||
|
||||
HEADER=X-DAViCal-Flush-Cache: true
|
||||
HEADER=User-Agent: DAVKit/4.0.3 (732); CalendarStore/4.0.4 (997); iCal/4.0.4 (1395); Mac OS X/10.6.5 (10H574)
|
||||
HEADER=Recipient: mailto:user2@example.net
|
||||
HEADER=Content-Type: text/calendar
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user