mirror of
https://github.com/nextcloud/server.git
synced 2026-04-01 23:25:47 -04:00
store filecache extension fields
Signed-off-by: Robin Appelman <robin@icewind.nl>
This commit is contained in:
parent
d3b6dbc0bc
commit
842da3f183
6 changed files with 196 additions and 28 deletions
|
|
@ -44,7 +44,7 @@ class Version17000Date20190514105811 extends SimpleMigrationStep {
|
|||
$schema = $schemaClosure();
|
||||
if(!$schema->hasTable('filecache_extended')) {
|
||||
$table = $schema->createTable('filecache_extended');
|
||||
$table->addColumn('fileid', Type::INTEGER, [
|
||||
$table->addColumn('fileid', Type::BIGINT, [
|
||||
'notnull' => true,
|
||||
'length' => 4,
|
||||
'unsigned' => true,
|
||||
|
|
|
|||
|
|
@ -187,6 +187,12 @@ class Cache implements ICache {
|
|||
$data['storage_mtime'] = $data['mtime'];
|
||||
}
|
||||
$data['permissions'] = (int)$data['permissions'];
|
||||
if (isset($data['creation_time'])) {
|
||||
$data['creation_time'] = (int) $data['creation_time'];
|
||||
}
|
||||
if (isset($data['upload_time'])) {
|
||||
$data['upload_time'] = (int) $data['upload_time'];
|
||||
}
|
||||
return new CacheEntry($data);
|
||||
}
|
||||
|
||||
|
|
@ -272,7 +278,7 @@ class Cache implements ICache {
|
|||
$data['parent'] = $this->getParentId($file);
|
||||
$data['name'] = basename($file);
|
||||
|
||||
$values = $this->normalizeData($data);
|
||||
[$values, $extensionValues] = $this->normalizeData($data);
|
||||
$values['storage'] = $this->getNumericStorageId();
|
||||
|
||||
try {
|
||||
|
|
@ -284,7 +290,17 @@ class Cache implements ICache {
|
|||
}
|
||||
|
||||
if ($builder->execute()) {
|
||||
$fileId = (int)$this->connection->lastInsertId('*PREFIX*filecache');
|
||||
$fileId = $builder->getLastInsertId();
|
||||
|
||||
$query = $this->getQueryBuilder();
|
||||
$query->insert('filecache_extended');
|
||||
|
||||
$query->setValue('fileid', $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT));
|
||||
foreach ($extensionValues as $column => $value) {
|
||||
$query->setValue($column, $query->createNamedParameter($value));
|
||||
}
|
||||
$query->execute();
|
||||
|
||||
$this->eventDispatcher->dispatch(CacheInsertEvent::class, new CacheInsertEvent($this->storage, $file, $fileId));
|
||||
return $fileId;
|
||||
}
|
||||
|
|
@ -319,24 +335,44 @@ class Cache implements ICache {
|
|||
$data['name'] = $this->normalize($data['name']);
|
||||
}
|
||||
|
||||
$values = $this->normalizeData($data);
|
||||
[$values, $extensionValues] = $this->normalizeData($data);
|
||||
|
||||
$query = $this->getQueryBuilder();
|
||||
if (count($values)) {
|
||||
$query = $this->getQueryBuilder();
|
||||
|
||||
$query->update('filecache')
|
||||
->whereFileId($id)
|
||||
->andWhere($query->expr()->orX(...array_map(function ($key, $value) use ($query) {
|
||||
return $query->expr()->orX(
|
||||
$query->expr()->neq($key, $query->createNamedParameter($value)),
|
||||
$query->expr()->isNull($key)
|
||||
);
|
||||
}, array_keys($values), array_values($values))));
|
||||
$query->update('filecache')
|
||||
->whereFileId($id)
|
||||
->andWhere($query->expr()->orX(...array_map(function ($key, $value) use ($query) {
|
||||
return $query->expr()->orX(
|
||||
$query->expr()->neq($key, $query->createNamedParameter($value)),
|
||||
$query->expr()->isNull($key)
|
||||
);
|
||||
}, array_keys($values), array_values($values))));
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
$query->set($key, $query->createNamedParameter($value));
|
||||
foreach ($values as $key => $value) {
|
||||
$query->set($key, $query->createNamedParameter($value));
|
||||
}
|
||||
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
$query->execute();
|
||||
if (count($extensionValues)) {
|
||||
$query = $this->getQueryBuilder();
|
||||
$query->update('filecache_extended')
|
||||
->whereFileId($id)
|
||||
->andWhere($query->expr()->orX(...array_map(function ($key, $value) use ($query) {
|
||||
return $query->expr()->orX(
|
||||
$query->expr()->neq($key, $query->createNamedParameter($value)),
|
||||
$query->expr()->isNull($key)
|
||||
);
|
||||
}, array_keys($extensionValues), array_values($extensionValues))));
|
||||
|
||||
foreach ($extensionValues as $key => $value) {
|
||||
$query->set($key, $query->createNamedParameter($value));
|
||||
}
|
||||
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
$path = $this->getPathById($id);
|
||||
// path can still be null if the file doesn't exist
|
||||
|
|
@ -355,6 +391,7 @@ class Cache implements ICache {
|
|||
$fields = [
|
||||
'path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'storage_mtime', 'encrypted',
|
||||
'etag', 'permissions', 'checksum', 'storage'];
|
||||
$extensionFields = ['metadata_etag', 'creation_time', 'upload_time'];
|
||||
|
||||
$doNotCopyStorageMTime = false;
|
||||
if (array_key_exists('mtime', $data) && $data['mtime'] === null) {
|
||||
|
|
@ -364,6 +401,7 @@ class Cache implements ICache {
|
|||
}
|
||||
|
||||
$params = [];
|
||||
$extensionParams = [];
|
||||
foreach ($data as $name => $value) {
|
||||
if (array_search($name, $fields) !== false) {
|
||||
if ($name === 'path') {
|
||||
|
|
@ -385,8 +423,11 @@ class Cache implements ICache {
|
|||
}
|
||||
$params[$name] = $value;
|
||||
}
|
||||
if (array_search($name, $extensionFields) !== false) {
|
||||
$extensionParams[$name] = $value;
|
||||
}
|
||||
}
|
||||
return $params;
|
||||
return [$params, $extensionParams];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -461,6 +502,12 @@ class Cache implements ICache {
|
|||
$query->delete('filecache')
|
||||
->whereFileId($entry->getId());
|
||||
$query->execute();
|
||||
|
||||
$query = $this->getQueryBuilder();
|
||||
$query->delete('filecache_extended')
|
||||
->whereFileId($entry->getId());
|
||||
$query->execute();
|
||||
|
||||
if ($entry->getMimeType() == FileInfo::MIMETYPE_FOLDER) {
|
||||
$this->removeChildren($entry);
|
||||
}
|
||||
|
|
@ -496,6 +543,11 @@ class Cache implements ICache {
|
|||
$query->delete('filecache')
|
||||
->whereParent($entry->getId());
|
||||
$query->execute();
|
||||
|
||||
$query = $this->getQueryBuilder();
|
||||
$query->delete('filecache_extended')
|
||||
->whereParent($entry->getId());
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -574,15 +626,16 @@ class Cache implements ICache {
|
|||
}
|
||||
}
|
||||
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query = $this->getQueryBuilder();
|
||||
$query->update('filecache')
|
||||
->set('storage', $query->createNamedParameter($targetStorageId))
|
||||
->set('path', $query->createNamedParameter($targetPath))
|
||||
->set('path_hash', $query->createNamedParameter(md5($targetPath)))
|
||||
->set('name', $query->createNamedParameter(basename($targetPath)))
|
||||
->set('parent', $query->createNamedParameter($newParentId, IQueryBuilder::PARAM_INT))
|
||||
->where($query->expr()->eq('fileid', $query->createNamedParameter($sourceId)));
|
||||
->whereFileId($sourceId);
|
||||
$query->execute();
|
||||
|
||||
$this->connection->commit();
|
||||
} else {
|
||||
$this->moveFromCacheFallback($sourceCache, $sourcePath, $targetPath);
|
||||
|
|
@ -595,7 +648,7 @@ class Cache implements ICache {
|
|||
public function clear() {
|
||||
$query = $this->getQueryBuilder();
|
||||
$query->delete('filecache')
|
||||
->whereStorageId();;
|
||||
->whereStorageId();
|
||||
$query->execute();
|
||||
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
|
|
@ -705,8 +758,7 @@ class Cache implements ICache {
|
|||
public function searchQuery(ISearchQuery $searchQuery) {
|
||||
$builder = $this->getQueryBuilder();
|
||||
|
||||
$query = $builder->select(['fileid', 'storage', 'path', 'parent', 'name', 'mimetype', 'mimepart', 'size', 'mtime', 'storage_mtime', 'encrypted', 'etag', 'permissions', 'checksum'])
|
||||
->from('filecache', 'file');
|
||||
$query = $builder->selectFileCache('file');
|
||||
|
||||
$query->whereStorageId();
|
||||
|
||||
|
|
|
|||
|
|
@ -109,6 +109,18 @@ class CacheEntry implements ICacheEntry, \ArrayAccess {
|
|||
return isset($this->data['encrypted']) && $this->data['encrypted'];
|
||||
}
|
||||
|
||||
public function getMetadataEtag(): ?string {
|
||||
return $this->data['metadata_etag'];
|
||||
}
|
||||
|
||||
public function getCreationTime(): ?int {
|
||||
return $this->data['creation_time'];
|
||||
}
|
||||
|
||||
public function getUploadTime(): ?int {
|
||||
return $this->data['upload_time'];
|
||||
}
|
||||
|
||||
public function getData() {
|
||||
return $this->data;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ use OCP\ILogger;
|
|||
*/
|
||||
class CacheQueryBuilder extends QueryBuilder {
|
||||
private $cache;
|
||||
private $alias = null;
|
||||
|
||||
public function __construct(IDBConnection $connection, SystemConfig $systemConfig, ILogger $logger, Cache $cache) {
|
||||
parent::__construct($connection, $systemConfig, $logger);
|
||||
|
|
@ -39,10 +40,14 @@ class CacheQueryBuilder extends QueryBuilder {
|
|||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
public function selectFileCache() {
|
||||
$this->select('fileid', 'storage', 'path', 'path_hash', 'parent', 'name', 'mimetype', 'mimepart', 'size', 'mtime',
|
||||
'storage_mtime', 'encrypted', 'etag', 'permissions', 'checksum')
|
||||
->from('filecache');
|
||||
public function selectFileCache(string $alias = null) {
|
||||
$name = $alias ? $alias : 'filecache';
|
||||
$this->select("$name.fileid", 'storage', 'path', 'path_hash', "$name.parent", 'name', 'mimetype', 'mimepart', 'size', 'mtime',
|
||||
'storage_mtime', 'encrypted', 'etag', 'permissions', 'checksum', 'metadata_etag', 'creation_time', 'upload_time')
|
||||
->from('filecache', $name)
|
||||
->leftJoin($name, 'filecache_extended', 'fe', $this->expr()->eq("$name.fileid", 'fe.fileid'));
|
||||
|
||||
$this->alias = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
@ -54,7 +59,14 @@ class CacheQueryBuilder extends QueryBuilder {
|
|||
}
|
||||
|
||||
public function whereFileId(int $fileId) {
|
||||
$this->andWhere($this->expr()->eq('fileid', $this->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
|
||||
$alias = $this->alias;
|
||||
if ($alias) {
|
||||
$alias .= '.';
|
||||
} else {
|
||||
$alias = '';
|
||||
}
|
||||
|
||||
$this->andWhere($this->expr()->eq("{$alias}fileid", $this->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
@ -66,7 +78,14 @@ class CacheQueryBuilder extends QueryBuilder {
|
|||
}
|
||||
|
||||
public function whereParent(int $parent) {
|
||||
$this->andWhere($this->expr()->eq('parent', $this->createNamedParameter($parent, IQueryBuilder::PARAM_INT)));
|
||||
$alias = $this->alias;
|
||||
if ($alias) {
|
||||
$alias .= '.';
|
||||
} else {
|
||||
$alias = '';
|
||||
}
|
||||
|
||||
$this->andWhere($this->expr()->eq("{$alias}parent", $this->createNamedParameter($parent, IQueryBuilder::PARAM_INT)));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,4 +132,28 @@ interface ICacheEntry {
|
|||
* @since 9.0.0
|
||||
*/
|
||||
public function isEncrypted();
|
||||
|
||||
/**
|
||||
* Get the metadata etag for the file
|
||||
*
|
||||
* @return string | null
|
||||
* @since 18.0.0
|
||||
*/
|
||||
public function getMetadataEtag(): ?string;
|
||||
|
||||
/**
|
||||
* Get the last modified date as unix timestamp
|
||||
*
|
||||
* @return int | null
|
||||
* @since 18.0.0
|
||||
*/
|
||||
public function getCreationTime(): ?int;
|
||||
|
||||
/**
|
||||
* Get the last modified date as unix timestamp
|
||||
*
|
||||
* @return int | null
|
||||
* @since 18.0.0
|
||||
*/
|
||||
public function getUploadTime(): ?int;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -707,6 +707,67 @@ class CacheTest extends \Test\TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
public function testExtended() {
|
||||
$folderData = ['size' => 100, 'mtime' => 50, 'mimetype' => 'httpd/unix-directory'];
|
||||
$this->cache->put("", $folderData);
|
||||
|
||||
$data = ['size' => 100, 'mtime' => 50, 'mimetype' => 'text/plain', 'creation_time' => 20];
|
||||
$id1 = $this->cache->put("foo1", $data);
|
||||
$data = ['size' => 100, 'mtime' => 50, 'mimetype' => 'text/plain', 'upload_time' => 30];
|
||||
$this->cache->put("foo2", $data);
|
||||
$data = ['size' => 100, 'mtime' => 50, 'mimetype' => 'text/plain', 'metadata_etag' => 'foo'];
|
||||
$this->cache->put("foo3", $data);
|
||||
$data = ['size' => 100, 'mtime' => 50, 'mimetype' => 'text/plain'];
|
||||
$this->cache->put("foo4", $data);
|
||||
|
||||
$entry = $this->cache->get($id1);
|
||||
$this->assertEquals(20, $entry->getCreationTime());
|
||||
$this->assertEquals(0, $entry->getUploadTime());
|
||||
$this->assertEquals(null, $entry->getMetadataEtag());
|
||||
|
||||
$entries = $this->cache->getFolderContents("");
|
||||
$this->assertCount(4, $entries);
|
||||
|
||||
$this->assertEquals("foo1", $entries[0]->getName());
|
||||
$this->assertEquals("foo2", $entries[1]->getName());
|
||||
$this->assertEquals("foo3", $entries[2]->getName());
|
||||
$this->assertEquals("foo4", $entries[3]->getName());
|
||||
|
||||
$this->assertEquals(20, $entries[0]->getCreationTime());
|
||||
$this->assertEquals(0, $entries[0]->getUploadTime());
|
||||
$this->assertEquals(null, $entries[0]->getMetadataEtag());
|
||||
|
||||
$this->assertEquals(0, $entries[1]->getCreationTime());
|
||||
$this->assertEquals(30, $entries[1]->getUploadTime());
|
||||
$this->assertEquals(null, $entries[1]->getMetadataEtag());
|
||||
|
||||
$this->assertEquals(0, $entries[2]->getCreationTime());
|
||||
$this->assertEquals(0, $entries[2]->getUploadTime());
|
||||
$this->assertEquals('foo', $entries[2]->getMetadataEtag());
|
||||
|
||||
$this->assertEquals(0, $entries[3]->getCreationTime());
|
||||
$this->assertEquals(0, $entries[3]->getUploadTime());
|
||||
$this->assertEquals(null, $entries[3]->getMetadataEtag());
|
||||
|
||||
$this->cache->update($id1, ['upload_time' => 25]);
|
||||
|
||||
$entry = $this->cache->get($id1);
|
||||
$this->assertEquals(20, $entry->getCreationTime());
|
||||
$this->assertEquals(25, $entry->getUploadTime());
|
||||
$this->assertEquals(null, $entry->getMetadataEtag());
|
||||
|
||||
$this->cache->put("sub", $folderData);
|
||||
|
||||
$this->cache->move("foo1", "sub/foo1");
|
||||
|
||||
$entries = $this->cache->getFolderContents("sub");
|
||||
$this->assertCount(1, $entries);
|
||||
|
||||
$this->assertEquals(20, $entries[0]->getCreationTime());
|
||||
$this->assertEquals(25, $entries[0]->getUploadTime());
|
||||
$this->assertEquals(null, $entries[0]->getMetadataEtag());
|
||||
}
|
||||
|
||||
protected function tearDown() {
|
||||
if ($this->cache) {
|
||||
$this->cache->clear();
|
||||
|
|
|
|||
Loading…
Reference in a new issue