rework filecache to work directly on storage backends wip

This commit is contained in:
Robin Appelman 2012-09-16 16:52:32 +02:00
parent c94fe38d39
commit 954596c251
3 changed files with 328 additions and 0 deletions

189
lib/files/cache/cache.php vendored Normal file
View File

@ -0,0 +1,189 @@
<?php
/**
* Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Files\Cache;
class Cache {
/**
* @var array partial data for the cache
*/
private static $partial = array();
/**
* get the stored metadata of a file or folder
*
* @param \OC\Files\File or int $file
* @return array
*/
static public function get($file) {
if ($file instanceof \OC\Files\File) {
$where = 'WHERE `storage` = ? AND `path_hash` = ?';
$params = array($file->getStorageId(), $file->getInternalPath());
} else { //file id
$where = 'WHERE `fileid` = ?';
$params = array($file);
}
$query = \OC_DB::prepare(
'SELECT `id`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`
FROM `*PREFIX*filecache` ' . $where);
$result=$query->execute($params);
return $result->fetchRow();
}
/**
* store meta data for a file or folder
*
* @param \OC\Files\File $file
* @param array $data
*
* @return int file id
*/
static public function put(\OC\Files\File $file, array $data) {
if ($id = self::getId($file) > -1) {
self::update($id, $data);
return $id;
} else {
$key = $file->getStorageId() . '::' . $file->getInternalPath();
if (isset(self::$partial[$key])) { //add any saved partial data
$data = array_merge($data, self::$partial[$key]);
unset(self::$partial[$key]);
}
$requiredFields = array('size', 'mtime', 'mimetype');
foreach ($requiredFields as $field) {
if (!isset($data[$field])) { //data not complete save as partial and return
self::$partial[$key] = $data;
return -1;
}
}
$data['path'] = $file->getInternalPath();
$data['parent'] = self::getParentId($file);
$data['name'] = basename($file->getInternalPath());
list($queryParts, $params) = self::buildParts($data);
$queryParts[] = '`storage`';
$params[] = $file->getStorageId();
$valuesPlaceholder = array_fill(0, count($queryParts), '?');
$query = \OC_DB::prepare('INSERT INTO `*PREFIX*filecache`(' . implode(', ', $queryParts) . ' VALUES(' . implode(', ', $valuesPlaceholder) . ')');
$query->execute($params);
return \OC_DB::insertid('*PREFIX*filecache');
}
}
/**
* update the metadata in the cache
*
* @param int $id
* @param array $data
*/
static public function update($id, array $data) {
list($queryParts, $params) = self::buildParts($data);
$params[] = $id;
$query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET ' . implode(' = ?, ', $queryParts) . '=? WHERE fileid = ?');
$query->execute($params);
}
/**
* extract query parts and params array from data array
*
* @param array $data
* @return array
*/
private static function buildParts(array $data) {
$fields = array('path', 'parent', 'name', 'mimetype', 'size', 'mtime');
$params = array();
$queryParts = array();
foreach ($data as $name => $value) {
if (array_search($name, $fields) !== false) {
$params[] = $value;
$queryParts[] = '`' . $name . '`';
if ($name === 'path') {
$params[] = md5($value);
$queryParts[] = '`path_hash`';
} elseif ($name === 'mimetype') {
$params[] = substr($value, 0, strpos($value, '/'));
$queryParts[] = '`mimepart`';
}
}
}
return array($queryParts, $params);
}
/**
* get the file id for a file
*
* @param \OC\Files\File $file
* @return int
*/
static public function getId(\OC\Files\File $file) {
$storageId = $file->getStorageId();
$pathHash = md5($file->getInternalPath());
$query = \OC_DB::prepare('SELECT id FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?');
$result = $query->execute(array($storageId, $pathHash));
if ($row = $result->fetchRow()) {
return $row['id'];
} else {
return -1;
}
}
/**
* get the id of the parent folder of a file
*
* @param \OC\Files\File $file
* return int
*/
static public function getParentId(\OC\Files\File $file) {
$path = $file->getInternalPath();
if ($path === '/' or $path === '') {
return -1;
} else {
return self::getId(new \OC\Files\File($file->getStorage(), dirname($path)));
}
}
/**
* check if a file is available in the cache
*
* @param \OC\Files\File $file
* @return bool
*/
static public function inCache(\OC\Files\File $file) {
return self::getId($file) != -1;
}
/**
* remove a file or folder from the cache
*
* @param \OC\Files\File $file
*/
public function remove(\OC\Files\File $file) {
$storageId = $file->getStorageId();
$pathHash = md5($file->getInternalPath());
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?');
$query->execute(array($storageId, $pathHash));
}
/**
* remove all entries for files that are stored on $storage form the cache
*
* @param \OC\Files\Storage\Storage $storage
*/
public function removeStorage(\OC\Files\Storage\Storage $storage) {
$storageId = $storage->getId();
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*filecache` WHERE storage=?');
$query->execute(array($storageId));
}
}

78
lib/files/cache/scanner.php vendored Normal file
View File

@ -0,0 +1,78 @@
<?php
/**
* Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Files\Cache;
class Scanner {
const SCAN_RECURSIVE = true;
const SCAN_SHALLOW = false;
/**
* get all the metadata of a file or folder
* *
* @param \OC\Files\File $file
* @return array with metadata of the file
*/
public static function getData(\OC\Files\File $file) {
$data = array();
$storage = $file->getStorage();
$path = $file->getInternalPath();
if (!$storage->isReadable($path)) return null; //cant read, nothing we can do
clearstatcache();
$data['mimetype'] = $storage->getMimeType($path);
$data['mtime'] = $storage->filemtime($path);
if ($data['mimetype'] == 'httpd/unix-directory') {
$data['size'] = -1; //unknown
$data['permissions'] = $storage->getPermissions($path . '/');
} else {
$data['size'] = $storage->filesize($path);
$data['permissions'] = $storage->getPermissions($path);
}
return $data;
}
/**
* scan a single file and store it in the cache
*
* @param \OC\Files\File $file
* @return array with metadata of the scanned file
*/
public static function scanFile(\OC\Files\File $file) {
$data = self::getData($file);
Cache::put($file, $data);
return $data;
}
/**
* scan all the files in a folder and store them in the cache
*
* @param \OC\Files\File $folder
* @param SCAN_RECURSIVE/SCAN_SHALLOW $recursive
* @return int the size of the scanned folder or -1 if the size is unknown at this stage
*/
public static function scan(\OC\Files\File $folder, $recursive) {
$size = 0;
$storage = $folder->getStorage();
$path = $folder->getInternalPath();
if ($dh = $storage->opendir($path)) {
while ($file = readdir($dh)) {
if ($file !== '.' and $file !== '..') {
$child = new \OC\Files\File($storage, $path . '/' . $file);
$data = self::scanFile($child);
if ($recursive === self::SCAN_RECURSIVE and $data['mimetype'] === 'httpd/unix-directory') {
$data['size'] = self::scan($child, self::SCAN_RECURSIVE);
}
if ($data['size'] >= 0 and $size >= 0) {
$size += $data['size'];
}
}
}
}
return $size;
}
}

61
lib/files/file.php Normal file
View File

@ -0,0 +1,61 @@
<?php
/**
* Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\Files;
/**
* representation of the location a file or folder is stored
*/
class File{
/**
* @var Storage\Storage $storage
*/
private $storage;
/**
* @var string internalPath
*/
private $internalPath;
public function __construct(Storage\Storage $storage, $internalPath){
$this->storage = $storage;
$this->internalPath = $internalPath;
}
public static function resolve($fullPath){
$storage = null;
$internalPath = '';
list($storage, $internalPath) = \OC_Filesystem::resolvePath($fullPath);
return new File($storage, $internalPath);
}
/**
* get the internal path of the file inside the filestorage
* @return string
*/
public function getInternalPath(){
return $this->internalPath;
}
/**
* get the storage the file is stored in
* @return \OC\Files\Storage\Storage
*/
public function getStorage(){
return $this->storage;
}
/**
* get the id of the storage the file is stored in
* @return string
*/
public function getStorageId(){
return $this->storage->getId();
}
}