1
0
mirror of synced 2024-12-13 06:46:03 +03:00

Removed object cache and all references to it, ticket #89 fixed

This commit is contained in:
zYne 2006-09-20 21:07:13 +00:00
parent edbe5cd3ac
commit ebad53b79d
12 changed files with 35 additions and 651 deletions

View File

@ -168,24 +168,6 @@ final class Doctrine {
*/
const LIMIT_RECORDS = 2;
/**
* CACHE CONSTANTS
*/
/**
* sqlite cache constant
*/
const CACHE_SQLITE = 0;
/**
* constant for disabling the caching
*/
const CACHE_NONE = 1;
/**
* FETCHMODE CONSTANTS
*/
@ -520,4 +502,4 @@ final class Doctrine {
return preg_replace('~(_?)(_)([\w])~e', '"$1".strtoupper("$3")', ucfirst($tablename));
}
}
?>
?>

View File

@ -1,71 +0,0 @@
<?php
interface iDoctrine_Cache {
public function store(Doctrine_Record $record);
public function clean();
public function delete($id);
public function fetch($id);
public function exists($id);
}
class Doctrine_Cache implements iDoctrine_Cache {
/**
* implemented by child classes
* @param Doctrine_Record $record
* @return boolean
*/
public function store(Doctrine_Record $record) {
return false;
}
/**
* implemented by child classes
* @return boolean
*/
public function clean() {
return false;
}
/**
* implemented by child classes
* @return boolean
*/
public function delete($id) {
return false;
}
/**
* implemented by child classes
* @throws InvalidKeyException
* @return Doctrine_Record found Data Access Object
*/
public function fetch($id) {
throw new InvalidKeyException();
}
/**
* implemented by child classes
* @param array $keys
* @return boolean
*/
public function fetchMultiple($keys) {
return false;
}
/**
* implemented by child classes
* @param integer $id
* @return boolean
*/
public function exists($id) {
return false;
}
/**
* implemented by child classes
*/
public function deleteMultiple($keys) {
return 0;
}
/**
* implemented by child classes
* @return integer
*/
public function deleteAll() {
return 0;
}
}

View File

@ -1,260 +0,0 @@
<?php
/**
* Doctrine_CacheFile
* @author Konsta Vesterinen
* @package Doctrine ORM
* @url www.phpdoctrine.com
* @license LGPL
* @version 1.0 alpha
*/
class Doctrine_Cache_File implements Countable {
const STATS_FILE = "stats.cache";
/**
* @var string $path path for the cache files
*/
private $path;
/**
* @var array $fetched an array of fetched primary keys
*/
private $fetched = array();
/**
* @var Doctrine_Table $objTable
*/
private $objTable;
/**
* constructor
* @param Doctrine_Table $objTable
*/
public function __construct(Doctrine_Table $objTable) {
$this->objTable = $objTable;
$name = $this->getTable()->getTableName();
$manager = Doctrine_Manager::getInstance();
$dir = $manager->getAttribute(Doctrine::ATTR_CACHE_DIR);
if( ! is_dir($dir))
mkdir($dir, 0777);
if( ! is_dir($dir.DIRECTORY_SEPARATOR.$name))
mkdir($dir.DIRECTORY_SEPARATOR.$name, 0777);
$this->path = $dir.DIRECTORY_SEPARATOR.$name.DIRECTORY_SEPARATOR;
/**
* create stats file
*/
if( ! file_exists($this->path.self::STATS_FILE))
touch($this->path.self::STATS_FILE);
}
/**
* @return Doctrine_Table
*/
public function getTable() {
return $this->objTable;
}
/**
* @return integer number of cache files
*/
public function count() {
$c = -1;
foreach(glob($this->path."*.cache") as $file) {
$c++;
}
return $c;
}
/**
* getStats
* @return array an array of fetch statistics, keys as primary keys
* and values as fetch times
*/
public function getStats() {
$f = file_get_contents($this->path.self::STATS_FILE);
// every cache file starts with a ":"
$f = substr(trim($f),1);
$e = explode(":",$f);
return array_count_values($e);
}
/**
* store store a Doctrine_Record into file cache
* @param Doctrine_Record $record data access object to be stored
* @return boolean whether or not storing was successful
*/
public function store(Doctrine_Record $record) {
if($record->getState() != Doctrine_Record::STATE_CLEAN)
return false;
$file = $this->path.$record->getID().".cache";
if(file_exists($file))
return false;
$clone = clone $record;
$id = $clone->getID();
$fp = fopen($file,"w+");
fwrite($fp,serialize($clone));
fclose($fp);
$this->fetched[] = $id;
return true;
}
/**
* clean
* @return void
*/
public function clean() {
$stats = $this->getStats();
arsort($stats);
$size = $this->objTable->getAttribute(Doctrine::ATTR_CACHE_SIZE);
$count = count($stats);
$i = 1;
$preserve = array();
foreach($stats as $id => $count) {
if($i > $size)
break;
$preserve[$id] = true;
$i++;
}
foreach(glob($this->path."*.cache") as $file) {
$e = explode(".",basename($file));
$c = count($e);
$id = $e[($c - 2)];
if( ! isset($preserve[$id]))
@unlink($this->path.$id.".cache");
}
$fp = fopen($this->path.self::STATS_FILE,"w+");
fwrite($fp,"");
fclose($fp);
}
/**
* @param integer $id primary key of the DAO
* @return string filename and path
*/
public function getFileName($id) {
return $this->path.$id.".cache";
}
/**
* @return array an array of fetched primary keys
*/
public function getFetched() {
return $this->fetched;
}
/**
* fetch fetch a Doctrine_Record from the file cache
* @param integer $id
*/
public function fetch($id) {
$name = $this->getTable()->getComponentName();
$file = $this->path.$id.".cache";
if( ! file_exists($file))
throw new InvalidKeyException();
$data = file_get_contents($file);
$record = unserialize($data);
if( ! ($record instanceof Doctrine_Record)) {
// broken file, delete silently
$this->delete($id);
throw new InvalidKeyException();
}
$this->fetched[] = $id;
return $record;
}
/**
* exists check the existence of a cache file
* @param integer $id primary key of the cached DAO
* @return boolean whether or not a cache file exists
*/
public function exists($id) {
$name = $this->getTable()->getComponentName();
$file = $this->path.$id.".cache";
return file_exists($file);
}
/**
* deleteAll
* @return void
*/
public function deleteAll() {
foreach(glob($this->path."*.cache") as $file) {
@unlink($file);
}
$fp = fopen($this->path.self::STATS_FILE,"w+");
fwrite($fp,"");
fclose($fp);
}
/**
* delete delete a cache file
* @param integer $id primary key of the cached DAO
*/
public function delete($id) {
$file = $this->path.$id.".cache";
if( ! file_exists($file))
return false;
@unlink($file);
return true;
}
/**
* deleteMultiple delete multiple cache files
* @param array $ids an array containing cache file ids
* @return integer the number of files deleted
*/
public function deleteMultiple(array $ids) {
$deleted = 0;
foreach($ids as $id) {
if($this->delete($id)) $deleted++;
}
return $deleted;
}
/**
* destructor
* the purpose of this destructor is to save all the fetched
* primary keys into the cache stats
*/
public function __destruct() {
if( ! empty($this->fetched)) {
$fp = fopen($this->path.self::STATS_FILE,"a");
fwrite($fp,":".implode(":",$this->fetched));
fclose($fp);
}
/**
*
* cache auto-cleaning algorithm
* $ttl is the number of page loads between each cache cleaning
* the default is 100 page loads
*
* this means that the average number of page loads between
* each cache clean is 100 page loads (= 100 constructed Doctrine_Managers)
*
*/
$ttl = $this->objTable->getAttribute(Doctrine::ATTR_CACHE_TTL);
$l1 = (mt_rand(1,$ttl) / $ttl);
$l2 = (1 - 1/$ttl);
if($l1 > $l2)
$this->clean();
}
}

View File

@ -1,5 +0,0 @@
<?php
class Doctrine_Cache_Manager {
}

View File

@ -1,5 +0,0 @@
<?php
class Doctrine_Cache_Memcache extends Doctrine_Cache {
}

View File

@ -1,265 +0,0 @@
<?php
class Doctrine_Cache_Sqlite {
/**
* STATS_FILE constant
* the name of the statistics file
*/
const STATS_FILE = "stats.cache";
/**
* SELECT constant
* used as a base for SQL SELECT queries
*/
const SELECT = "SELECT object FROM %s WHERE id %s";
/**
* INSERT constant
* used as a base for SQL INSERT queries
*/
const INSERT = "REPLACE INTO %s (id, object) VALUES (?, ?)";
/**
* DELETE constant
* used as a base for SQL DELETE queries
*/
const DELETE = "DELETE FROM %s WHERE id %s";
/**
* @var Doctrine_Table $table the table object this cache container belongs to
*/
private $table;
/**
* @var PDO $dbh database handler
*/
private $dbh;
/**
* @var array $fetched an array of fetched primary keys
*/
private $fetched = array();
public function __construct(Doctrine_Table $table) {
$this->table = $table;
$dir = $this->table->getSession()->getAttribute(Doctrine::ATTR_CACHE_DIR);
if( ! is_dir($dir))
mkdir($dir, 0777);
$this->path = $dir.DIRECTORY_SEPARATOR;
$this->dbh = $this->table->getSession()->getCacheHandler();
try {
$this->dbh->query("CREATE TABLE ".$this->table->getTableName()." (id INTEGER UNIQUE, object TEXT)");
} catch(PDOException $e) {
}
/**
* create stats file
*/
if( ! file_exists($this->path.self::STATS_FILE))
touch($this->path.self::STATS_FILE);
}
/*
* stores a Doctrine_Record into cache
* @param Doctrine_Record $record record to be stored
* @return boolean whether or not storing was successful
*/
public function store(Doctrine_Record $record) {
if($record->getState() != Doctrine_Record::STATE_CLEAN)
return false;
$clone = clone $record;
$id = $clone->getID();
$stmt = $this->dbh->query(sprintf(self::INSERT,$this->table->getTableName()));
$stmt->execute(array($id, serialize($clone)));
return true;
}
/**
* fetches a Doctrine_Record from the cache
* @param mixed $id
* @return mixed false on failure, Doctrine_Record on success
*/
public function fetch($id) {
$stmt = $this->dbh->query(sprintf(self::SELECT,$this->table->getTableName(),"= ?"));
$stmt->execute(array($id));
$data = $stmt->fetch(PDO::FETCH_NUM);
if($data === false)
throw new InvalidKeyException();
$this->fetched[] = $id;
$record = unserialize($data[0]);
if(is_string($record)) {
$this->delete($id);
throw new InvalidKeyException();
}
return $record;
}
/**
* fetches multiple records from the cache
* @param array $keys
* @return mixed false on failure, an array of Doctrine_Record objects on success
*/
public function fetchMultiple(array $keys) {
$count = (count($keys)-1);
$keys = array_values($keys);
$sql = sprintf(self::SELECT,$this->table->getTableName(),"IN (".str_repeat("?, ",$count)."?)");
$stmt = $this->dbh->query($sql);
$stmt->execute($keys);
while($data = $stmt->fetch(PDO::FETCH_NUM)) {
$array[] = unserialize($data[0]);
}
$this->fetched = array_merge($this->fetched, $keys);
if( ! isset($array))
return false;
return $array;
}
/**
* deletes all records from cache
* @return void
*/
public function deleteAll() {
$stmt = $this->dbh->query("DELETE FROM ".$this->table->getTableName());
return $stmt->rowCount();
}
/**
* @param mixed $id
* @return void
*/
public function delete($id) {
$stmt = $this->dbh->query(sprintf(self::DELETE,$this->table->getTableName(),"= ?"));
$stmt->execute(array($id));
if($stmt->rowCount() > 0)
return true;
return false;
}
/**
* count
* @return integer
*/
public function count() {
$stmt = $this->dbh->query("SELECT COUNT(*) FROM ".$this->table->getTableName());
$data = $stmt->fetch(PDO::FETCH_NUM);
// table has two columns so we have to divide the count by two
return ($data[0] / 2);
}
/**
* @param array $keys
* @return integer
*/
public function deleteMultiple(array $keys) {
if(empty($keys))
return 0;
$keys = array_values($keys);
$count = (count($keys)-1);
$sql = sprintf(self::DELETE,$this->table->getTableName(),"IN (".str_repeat("?, ",$count)."?)");
$stmt = $this->dbh->query($sql);
$stmt->execute($keys);
return $stmt->rowCount();
}
/**
* getStats
* @return array an array of fetch statistics, keys as primary keys
* and values as fetch times
*/
public function getStats() {
$f = file_get_contents($this->path.self::STATS_FILE);
// every cache file starts with a ":"
$f = substr(trim($f),1);
$e = explode(":",$f);
return array_count_values($e);
}
/**
* clean
* @return void
*/
public function clean() {
$stats = $this->getStats();
asort($stats);
$size = $this->table->getAttribute(Doctrine::ATTR_CACHE_SIZE);
$count = count($stats);
if($count <= $size)
return 0;
$e = $count - $size;
$keys = array();
foreach($stats as $id => $count) {
if( ! $e--)
break;
$keys[] = $id;
}
return $this->deleteMultiple($keys);
}
/**
* saves statistics
* @return boolean
*/
public function saveStats() {
if( ! empty($this->fetched)) {
$fp = fopen($this->path.self::STATS_FILE,"a");
fwrite($fp,":".implode(":",$this->fetched));
fclose($fp);
$this->fetched = array();
return true;
}
return false;
}
/**
* autoClean
* $ttl is the number of page loads between each cache cleaning
* the default is 100 page loads
*
* this means that the average number of page loads between
* each cache clean is 100 page loads (= 100 constructed Doctrine_Managers)
* @return boolean
*/
public function autoClean() {
$ttl = $this->table->getAttribute(Doctrine::ATTR_CACHE_TTL);
$l1 = (mt_rand(1,$ttl) / $ttl);
$l2 = (1 - 1/$ttl);
if($l1 > $l2) {
$this->clean();
return true;
}
return false;
}
/**
* @param mixed $id
*/
public function addDelete($id) {
$this->delete[] = $id;
}
/**
* destructor
* the purpose of this destructor is to save all the fetched
* primary keys into the cache stats and to clean cache if necessary
*
*/
public function __destruct() {
$this->saveStats();
$this->autoClean();
}
}

View File

@ -300,8 +300,6 @@ class Doctrine_Connection_Transaction implements Countable, IteratorAggregate {
$params = substr(str_repeat("?, ",count($ids)),0,-2);
$query = "DELETE FROM ".$record->getTable()->getTableName()." WHERE ".$table->getIdentifier()." IN(".$params.")";
$this->conn->execute($query,$ids);
$record->getTable()->getCache()->deleteMultiple($ids);
}
}
$this->delete = array();

View File

@ -79,7 +79,6 @@ class Doctrine_Manager extends Doctrine_Configurable implements Countable, Itera
$init = true;
$attributes = array(
Doctrine::ATTR_FETCHMODE => Doctrine::FETCH_IMMEDIATE,
Doctrine::ATTR_CACHE => Doctrine::CACHE_NONE,
Doctrine::ATTR_BATCH_SIZE => 5,
Doctrine::ATTR_COLL_LIMIT => 5,
Doctrine::ATTR_LISTENER => new Doctrine_EventListener_Empty(),

View File

@ -249,24 +249,8 @@ class Doctrine_Table extends Doctrine_Configurable implements Countable {
// check if an instance of this table is already initialized
if( ! $this->connection->addTable($this))
throw new Doctrine_Table_Exception();
$this->initComponents();
}
/**
* initializes components this table uses
*
* @return void
*/
final public function initComponents() {
$this->repository = new Doctrine_Repository($this);
switch($this->getAttribute(Doctrine::ATTR_CACHE)):
case Doctrine::CACHE_SQLITE:
$this->cache = new Doctrine_Cache_Sqlite($this);
break;
case Doctrine::CACHE_NONE:
$this->cache = new Doctrine_Cache($this);
break;
endswitch;
}
/**
* @return Doctrine_Repository

View File

@ -94,13 +94,27 @@ $menu = array("Getting started" =>
"Starting new project",
"Setting table definition" => array(
"Introduction",
"Field(Column) naming",
"Field(Column) naming",
"Data types and lengths",
"Constraints and validators",
"Default values",
"Enum emulation",
),
"Data types" => array(
"Boolean",
"Integer",
"Float",
"String",
"Array",
"Object",
"Blob",
"Clob",
"Timestamp",
"Date",
"Enum",
"Gzip",
),
"Record identifiers" => array(
"Introduction",
"Autoincremented",
@ -108,6 +122,20 @@ $menu = array("Getting started" =>
"Composite",
"Sequential")
),
"Schema reference" =>
array(
"Data types" => array(
"PHP based types" =>
array(
"Boolean",
"Integer",
"Float",
"String",
"Array",
"Object",
),
),
),
"Basic Components" =>
array(
"Manager"
@ -387,12 +415,12 @@ $menu = array("Getting started" =>
if( ! file_exists("docs/$title - $k - $v2.php")) {
$missing[0]++;
$str .= " [ <font color='red'>doc</font> ] ";
touch("docs/$title - $k - $v2.php");
//touch("docs/$title - $k - $v2.php");
}
if( ! file_exists("codes/$title - $k - $v2.php")) {
$missing[1]++;
$str .= " [ <font color='red'>code</font> ] ";
touch("codes/$title - $k - $v2.php");
//touch("codes/$title - $k - $v2.php");
}

View File

@ -4,7 +4,7 @@ require_once("UnitTestCase.php");
class Doctrine_Cache_Query_SqliteTestCase extends Doctrine_UnitTestCase {
public function setUp() {
parent::setUp();
$this->manager->setAttribute(Doctrine::ATTR_CACHE,Doctrine::CACHE_NONE);
$dir = $this->connection->getAttribute(Doctrine::ATTR_CACHE_DIR);
if(file_exists($dir.DIRECTORY_SEPARATOR."stats.cache"))

View File

@ -36,7 +36,6 @@ class Doctrine_UnitTestCase extends UnitTestCase {
$name = get_class($this);
$this->manager = Doctrine_Manager::getInstance();
$this->manager->setAttribute(Doctrine::ATTR_CACHE, Doctrine::CACHE_NONE);
$this->manager->setAttribute(Doctrine::ATTR_FETCHMODE, Doctrine::FETCH_IMMEDIATE);
@ -95,7 +94,7 @@ class Doctrine_UnitTestCase extends UnitTestCase {
foreach($this->tables as $name) {
$name = ucwords($name);
$table = $this->connection->getTable($name);
$table->getCache()->deleteAll();
$table->clear();
}