Merge pull request #7897 from owncloud/ext-swiftcaching
Added object cache for Swift ext storage
This commit is contained in:
commit
e8c3794308
|
@ -73,6 +73,14 @@ class Swift extends \OC\Files\Storage\Common {
|
|||
*/
|
||||
private static $tmpFiles = array();
|
||||
|
||||
/**
|
||||
* Key value cache mapping path to data object. Maps path to
|
||||
* \OpenCloud\OpenStack\ObjectStorage\Resource\DataObject for existing
|
||||
* paths and path to false for not existing paths.
|
||||
* @var \OCP\ICache
|
||||
*/
|
||||
private $objectCache;
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*/
|
||||
|
@ -96,18 +104,31 @@ class Swift extends \OC\Files\Storage\Common {
|
|||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
private function getContainerName($path) {
|
||||
$path = trim(trim($this->root, '/') . "/" . $path, '/.');
|
||||
return str_replace('/', '\\', $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches an object from the API.
|
||||
* If the object is cached already or a
|
||||
* failed "doesn't exist" response was cached,
|
||||
* that one will be returned.
|
||||
*
|
||||
* @param string $path
|
||||
* @return \OpenCloud\OpenStack\ObjectStorage\Resource\DataObject|bool object
|
||||
* or false if the object did not exist
|
||||
*/
|
||||
private function doesObjectExist($path) {
|
||||
private function fetchObject($path) {
|
||||
if ($this->objectCache->hasKey($path)) {
|
||||
// might be "false" if object did not exist from last check
|
||||
return $this->objectCache->get($path);
|
||||
}
|
||||
try {
|
||||
$this->getContainer()->getPartialObject($path);
|
||||
return true;
|
||||
$object = $this->getContainer()->getPartialObject($path);
|
||||
$this->objectCache->set($path, $object);
|
||||
return $object;
|
||||
} catch (ClientErrorResponseException $e) {
|
||||
// this exception happens when the object does not exist, which
|
||||
// is expected in most cases
|
||||
$this->objectCache->set($path, false);
|
||||
return false;
|
||||
} catch (ClientErrorResponseException $e) {
|
||||
// Expected response is "404 Not Found", so only log if it isn't
|
||||
if ($e->getResponse()->getStatusCode() !== 404) {
|
||||
|
@ -117,6 +138,17 @@ class Swift extends \OC\Files\Storage\Common {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given path exists.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return bool true if the object exist, false otherwise
|
||||
*/
|
||||
private function doesObjectExist($path) {
|
||||
return $this->fetchObject($path) !== false;
|
||||
}
|
||||
|
||||
public function __construct($params) {
|
||||
if ((empty($params['key']) and empty($params['password']))
|
||||
or empty($params['user']) or empty($params['bucket'])
|
||||
|
@ -144,6 +176,8 @@ class Swift extends \OC\Files\Storage\Common {
|
|||
}
|
||||
|
||||
$this->params = $params;
|
||||
// FIXME: private class...
|
||||
$this->objectCache = new \OC\Cache\CappedMemoryCache();
|
||||
}
|
||||
|
||||
public function mkdir($path) {
|
||||
|
@ -162,6 +196,9 @@ class Swift extends \OC\Files\Storage\Common {
|
|||
$metadataHeaders = DataObject::stockHeaders(array());
|
||||
$allHeaders = $customHeaders + $metadataHeaders;
|
||||
$this->getContainer()->uploadObject($path, '', $allHeaders);
|
||||
// invalidate so that the next access gets the real object
|
||||
// with all properties
|
||||
$this->objectCache->remove($path);
|
||||
} catch (Exceptions\CreateUpdateError $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
return false;
|
||||
|
@ -202,6 +239,7 @@ class Swift extends \OC\Files\Storage\Common {
|
|||
|
||||
try {
|
||||
$this->getContainer()->dataObject()->setName($path . '/')->delete();
|
||||
$this->objectCache->remove($path . '/');
|
||||
} catch (Exceptions\DeleteError $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
return false;
|
||||
|
@ -256,7 +294,10 @@ class Swift extends \OC\Files\Storage\Common {
|
|||
|
||||
try {
|
||||
/** @var DataObject $object */
|
||||
$object = $this->getContainer()->getPartialObject($path);
|
||||
$object = $this->fetchObject($path);
|
||||
if (!$object) {
|
||||
return false;
|
||||
}
|
||||
} catch (ClientErrorResponseException $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
return false;
|
||||
|
@ -310,8 +351,12 @@ class Swift extends \OC\Files\Storage\Common {
|
|||
|
||||
try {
|
||||
$this->getContainer()->dataObject()->setName($path)->delete();
|
||||
$this->objectCache->remove($path);
|
||||
$this->objectCache->remove($path . '/');
|
||||
} catch (ClientErrorResponseException $e) {
|
||||
if ($e->getResponse()->getStatusCode() !== 404) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -391,8 +436,11 @@ class Swift extends \OC\Files\Storage\Common {
|
|||
$path .= '/';
|
||||
}
|
||||
|
||||
$object = $this->getContainer()->getPartialObject($path);
|
||||
$object->saveMetadata($metadata);
|
||||
$object = $this->fetchObject($path);
|
||||
if ($object->saveMetadata($metadata)) {
|
||||
// invalidate target object to force repopulation on fetch
|
||||
$this->objectCache->remove($path);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
|
||||
|
@ -400,6 +448,8 @@ class Swift extends \OC\Files\Storage\Common {
|
|||
$metadataHeaders = DataObject::stockHeaders($metadata);
|
||||
$allHeaders = $customHeaders + $metadataHeaders;
|
||||
$this->getContainer()->uploadObject($path, '', $allHeaders);
|
||||
// invalidate target object to force repopulation on fetch
|
||||
$this->objectCache->remove($path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -415,8 +465,11 @@ class Swift extends \OC\Files\Storage\Common {
|
|||
$this->unlink($path2);
|
||||
|
||||
try {
|
||||
$source = $this->getContainer()->getPartialObject($path1);
|
||||
$source = $this->fetchObject($path1);
|
||||
$source->copy($this->bucket . '/' . $path2);
|
||||
// invalidate target object to force repopulation on fetch
|
||||
$this->objectCache->remove($path2);
|
||||
$this->objectCache->remove($path2 . '/');
|
||||
} catch (ClientErrorResponseException $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
return false;
|
||||
|
@ -428,8 +481,11 @@ class Swift extends \OC\Files\Storage\Common {
|
|||
$this->unlink($path2);
|
||||
|
||||
try {
|
||||
$source = $this->getContainer()->getPartialObject($path1 . '/');
|
||||
$source = $this->fetchObject($path1 . '/');
|
||||
$source->copy($this->bucket . '/' . $path2 . '/');
|
||||
// invalidate target object to force repopulation on fetch
|
||||
$this->objectCache->remove($path2);
|
||||
$this->objectCache->remove($path2 . '/');
|
||||
} catch (ClientErrorResponseException $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
return false;
|
||||
|
@ -461,10 +517,6 @@ class Swift extends \OC\Files\Storage\Common {
|
|||
$fileType = $this->filetype($path1);
|
||||
|
||||
if ($fileType === 'dir' || $fileType === 'file') {
|
||||
|
||||
// make way
|
||||
$this->unlink($path2);
|
||||
|
||||
// copy
|
||||
if ($this->copy($path1, $path2) === false) {
|
||||
return false;
|
||||
|
@ -564,6 +616,8 @@ class Swift extends \OC\Files\Storage\Common {
|
|||
}
|
||||
$fileData = fopen($tmpFile, 'r');
|
||||
$this->getContainer()->uploadObject(self::$tmpFiles[$tmpFile], $fileData);
|
||||
// invalidate target object to force repopulation on fetch
|
||||
$this->objectCache->remove(self::$tmpFiles[$tmpFile]);
|
||||
unlink($tmpFile);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue