PageRenderTime 62ms CodeModel.GetById 34ms RepoModel.GetById 1ms app.codeStats 0ms

/core/cache_memory/class.cache.driver.apc.php

http://buddypress-media.googlecode.com/
PHP | 596 lines | 288 code | 163 blank | 145 comment | 32 complexity | 548c55c204b2948395587cbb131cf23a MD5 | raw file
Possible License(s): AGPL-1.0, Apache-2.0, GPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * BP-MEDIA MEMORY CACHE - APC DRIVER
  4. * Stores keys to PHP's built-in APC caching system @link http://php.net/manual/en/book.apc.php
  5. * providing *server level* persistent caching that *survives a reboot*.
  6. *
  7. * @version 0.1.9
  8. * @since 0.1.9
  9. * @package BP-Media
  10. * @subpackage Cache APC
  11. * @license GPL v2.0
  12. * @link http://code.google.com/p/buddypress-media/
  13. *
  14. * ========================================================================================================
  15. */
  16. class BPM_mCache_driver_apc extends BPM_mCache_driver_base {
  17. // VERY IMPORTANT: The following must be set in your php.ini file:
  18. // ======================================================================
  19. // [PECL]
  20. // extension=php_apc.dll (on XAMPP installations remove the ";" in front of it)
  21. // [APC]
  22. // apc.slam_defense = 0 (workaround for "cache slam error" defect in PHP's APC lib)
  23. // apc.write_lock = 1
  24. var $enable = true; // True to enable the driver. False to disable it.
  25. var $is_active; // If true, the driver is enabled, there's a working APC installation on
  26. // the server, we can connect to it, and we're allowed to use it.
  27. // ================================================================================================================
  28. public function __construct(){
  29. if( function_exists("apc_store") && ($this->enable == true) ){
  30. $this->is_active = true;
  31. }
  32. else {
  33. $this->is_active = false;
  34. }
  35. }
  36. /**
  37. * Checks if the cache engine driver is active
  38. *
  39. * @version 0.1.9
  40. * @since 0.1.9
  41. *
  42. * @return bool | True if active. False if disabled.
  43. */
  44. public function isActive(){
  45. return $this->is_active;
  46. }
  47. /**
  48. * Returns the current performance stats of the cache
  49. *
  50. * @version 0.1.9
  51. * @since 0.1.9
  52. *
  53. * @return array | Exception on failure. Data array on success.
  54. */
  55. public function getStats(){
  56. if( !$this->isActive() ){
  57. throw new BPM_exception(array(
  58. 'numeric'=>1,
  59. 'text'=>"Cache driver is not active",
  60. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  61. 'child'=>null
  62. ));
  63. }
  64. else {
  65. return apc_cache_info();
  66. }
  67. }
  68. /**
  69. * Removes all entries in the cache.
  70. *
  71. * @version 0.1.9
  72. * @since 0.1.9
  73. *
  74. * @return bool | Exception on failure. True on success.
  75. */
  76. public function flushAll(){
  77. if( !$this->isActive() ){
  78. throw new BPM_exception(array(
  79. 'numeric'=>1,
  80. 'text'=>"Cache driver is not active",
  81. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  82. 'child'=>null
  83. ));
  84. }
  85. else {
  86. apc_clear_cache(); // Clear the "system" (opcode) cache
  87. apc_clear_cache('opcode'); // Clear the "system" (opcode) cache for PHP < 5.3
  88. apc_clear_cache('user'); // Clear the "user" (data) cache
  89. }
  90. return true;
  91. }
  92. /**
  93. * Removes all entries within the specified namespace from the cache.
  94. *
  95. * @version 0.1.9
  96. * @since 0.1.9
  97. *
  98. * @param string $ns | Namespace of the cache variable
  99. * @return bool | Exception on failure. True on success.
  100. */
  101. public function flushNamespace($ns){
  102. if( !$this->isActive() ){
  103. throw new BPM_exception(array(
  104. 'numeric'=>1,
  105. 'text'=>"Cache driver is not active",
  106. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  107. 'child'=>null
  108. ));
  109. }
  110. else {
  111. $offset = self::getOffset($ns);
  112. if($offset < 255){
  113. $offset++;
  114. }
  115. else {
  116. $offset = 1;
  117. }
  118. $result = apc_store("bpm.ns_offset.".$ns, $offset);
  119. }
  120. return $result;
  121. }
  122. /**
  123. * Gets the offset for a cache namespace.
  124. *
  125. * @version 0.1.9
  126. * @since 0.1.9
  127. *
  128. * @param string $ns | Namespace of the cache variable
  129. * @return bool | False on failure. True on success.
  130. */
  131. public function getOffset($ns){
  132. if( !$this->isActive() ){
  133. throw new BPM_exception(array(
  134. 'numeric'=>1,
  135. 'text'=>"Cache driver is not active",
  136. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  137. 'child'=>null
  138. ));
  139. }
  140. else {
  141. $offset = apc_fetch("bpm.ns_offset.".$ns);
  142. // If there is no offset key for the namespace present in
  143. // the cache, create one
  144. if(!$offset){
  145. $offset = 1;
  146. $store_ok = apc_store("bpm.ns_offset.".$ns, $offset);
  147. if(!$store_ok){
  148. throw new BPM_exception(array(
  149. 'numeric'=>2,
  150. 'text'=>"Error writing to cache",
  151. 'data'=>array('namespace'=>$ns, 'offset'=>$offset),
  152. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  153. 'child'=>null
  154. ));
  155. }
  156. }
  157. }
  158. return $offset;
  159. }
  160. /**
  161. * Stores a value into the cache
  162. *
  163. * @version 0.1.9
  164. * @since 0.1.9
  165. *
  166. * @param string $ns | Namespace of the cache variable
  167. * @param string $var | Name of the cache variable
  168. * @param mixed $val | Value to assign
  169. *
  170. * @return bool | Exception on failure. True on success.
  171. */
  172. public function set($ns, $var, $val){
  173. if( !$this->isActive() ){
  174. throw new BPM_exception(array(
  175. 'numeric'=>1,
  176. 'text'=>"Cache driver is not active",
  177. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  178. 'child'=>null
  179. ));
  180. }
  181. else {
  182. try {
  183. $offset = self::getOffset($ns);
  184. }
  185. catch (BPM_exception $child) {
  186. throw new BPM_exception(array(
  187. 'numeric'=>2,
  188. 'text'=>"Error in self::getOffset()",
  189. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  190. 'child'=>$child
  191. ));
  192. }
  193. $key = "bpm." . $ns . "." . $offset . "." . $var;
  194. $store_ok = apc_store($key, $val);
  195. if(!$store_ok){
  196. throw new BPM_exception(array(
  197. 'numeric'=>3,
  198. 'text'=>"Error writing to cache",
  199. 'data'=>array('namespace'=>$ns, 'offset'=>$offset),
  200. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  201. 'child'=>null
  202. ));
  203. }
  204. }
  205. return true;
  206. }
  207. /**
  208. * Stores multiple values into the cache
  209. *
  210. * @version 0.1.9
  211. * @since 0.1.9
  212. *
  213. * @param string $ns | Namespace of the cache variable
  214. * @param array $data | Data to set in the form "key"=>"val"
  215. * @return bool | Exception on failure. True on success.
  216. */
  217. public function setMulti($ns, $data){
  218. if( !$this->isActive() ){
  219. throw new BPM_exception(array(
  220. 'numeric'=>1,
  221. 'text'=>"Cache driver is not active",
  222. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  223. 'child'=>null
  224. ));
  225. }
  226. else {
  227. try {
  228. $offset = self::getOffset($ns);
  229. }
  230. catch (BPM_exception $child) {
  231. throw new BPM_exception(array(
  232. 'numeric'=>2,
  233. 'text'=>"Error in self::getOffset()",
  234. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  235. 'child'=>$child
  236. ));
  237. }
  238. $processed = array();
  239. // Add namespace prefix to each keyname
  240. foreach($data as $key => $val){
  241. $processed["bpm." . $ns . "." . $offset . "." . $key] = $val;
  242. }
  243. unset($key, $val);
  244. // NOTE: apc_store() has a different error reporting format when
  245. // passed an array @see http://php.net/manual/en/function.apc-store.php
  246. $cache_result = apc_store($processed);
  247. if( count($cache_result) != 0 ){
  248. throw new BPM_exception(array(
  249. 'numeric'=>3,
  250. 'text'=>"Error writing to cache",
  251. 'data'=>array('namespace'=>$ns, 'data'=>$data, 'error'=>$cache_result),
  252. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  253. 'child'=>null
  254. ));
  255. }
  256. }
  257. return true;
  258. }
  259. /**
  260. * Retrieves a value from the cache
  261. *
  262. * @version 0.1.9
  263. * @since 0.1.9
  264. *
  265. * @param string $ns | Namespace of the cache variable
  266. * @param string $var | Name of the cache variable
  267. * @param bool &$valid | True if key exists in cache. False if not.
  268. *
  269. * @return mixed | Exception on failure. Stored data item on success.
  270. */
  271. public function get($ns, $var, &$valid=null){
  272. if( !$this->isActive() ){
  273. throw new BPM_exception(array(
  274. 'numeric'=>1,
  275. 'text'=>"Cache driver is not active",
  276. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  277. 'child'=>null
  278. ));
  279. }
  280. else {
  281. try {
  282. $offset = self::getOffset($ns);
  283. }
  284. catch (BPM_exception $child) {
  285. throw new BPM_exception(array(
  286. 'numeric'=>2,
  287. 'text'=>"Error in self::getOffset()",
  288. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  289. 'child'=>$child
  290. ));
  291. }
  292. $key = "bpm." . $ns . "." . $offset . "." . $var;
  293. $result = apc_fetch($key, $valid);
  294. }
  295. return $result;
  296. }
  297. /**
  298. * Retrieves multiple values from the cache
  299. *
  300. * @version 0.1.9
  301. * @since 0.1.9
  302. *
  303. * @param string $ns | Namespace of the cache variable
  304. * @param array $names | Array of cache variable names
  305. * @return mixed | Exception on failure. Stored data item on success.
  306. */
  307. public function getMulti($ns, $names){
  308. if( !$this->isActive() ){
  309. throw new BPM_exception(array(
  310. 'numeric'=>1,
  311. 'text'=>"Cache driver is not active",
  312. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  313. 'child'=>null
  314. ));
  315. }
  316. else {
  317. try {
  318. $offset = self::getOffset($ns);
  319. }
  320. catch (BPM_exception $child) {
  321. throw new BPM_exception(array(
  322. 'numeric'=>2,
  323. 'text'=>"Error in self::getOffset()",
  324. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  325. 'child'=>$child
  326. ));
  327. }
  328. // Add namespace prefix to each keyname
  329. foreach($names as $key){
  330. $processed[] = "bpm." . $ns . "." . $offset . "." . $key;
  331. }
  332. unset($key);
  333. $cache_result = apc_fetch($processed);
  334. // APC will return an array of the form "keyname"=>"value". If a key doesn't exist in the
  335. // cache, the requested key will not be present in the results array.
  336. $result = array();
  337. foreach($names as $key){
  338. // BEFORE: "namespace.offset.keyname"=>"value"
  339. // AFTER: "keyname"=>"value"
  340. $prefixed_name = "bpm." . $ns . "." . $offset . "." . $key;
  341. if( array_key_exists($prefixed_name, $cache_result) ){ // This prevents the loop from creating keys
  342. // in the $result array if they don't exist in
  343. $result[$key] = $cache_result[$prefixed_name]; // the $cache_result array
  344. }
  345. }
  346. unset($key);
  347. }
  348. return $result;
  349. }
  350. /**
  351. * Deletes an item from the cache
  352. *
  353. * @version 0.1.9
  354. * @since 0.1.9
  355. *
  356. * @param string $ns | Namespace of the cache variable
  357. * @param string $var | Name of key
  358. *
  359. * @return bool | Exception on failure. True on key exists. False on key doesn't exist.
  360. */
  361. public function del($ns, $var){
  362. if( !$this->isActive() ){
  363. throw new BPM_exception(array(
  364. 'numeric'=>1,
  365. 'text'=>"Cache driver is not active",
  366. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  367. 'child'=>null
  368. ));
  369. }
  370. else {
  371. try {
  372. $offset = self::getOffset($ns);
  373. }
  374. catch (BPM_exception $child) {
  375. throw new BPM_exception(array(
  376. 'numeric'=>2,
  377. 'text'=>"Error in self::getOffset()",
  378. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  379. 'child'=>$child
  380. ));
  381. }
  382. $key = "bpm." . $ns . "." . $offset . "." . $var;
  383. $delete_ok = apc_delete($key);
  384. }
  385. return $delete_ok;
  386. }
  387. /**
  388. * Deletes multiple items from the cache
  389. *
  390. * @version 0.1.9
  391. * @since 0.1.9
  392. *
  393. * @param string $ns | Namespace of the cache variable
  394. * @param array $data | Key names as array of strings.
  395. * @return int | Exception on failure. Int number of keys deleted on success.
  396. */
  397. public function delMulti($ns, $data){
  398. if( !$this->isActive() ){
  399. throw new BPM_exception(array(
  400. 'numeric'=>1,
  401. 'text'=>"Cache driver is not active",
  402. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  403. 'child'=>null
  404. ));
  405. }
  406. else {
  407. try {
  408. $offset = self::getOffset($ns);
  409. }
  410. catch (BPM_exception $child) {
  411. throw new BPM_exception(array(
  412. 'numeric'=>2,
  413. 'text'=>"Error in self::getOffset()",
  414. 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,
  415. 'child'=>$child
  416. ));
  417. }
  418. $processed = array();
  419. // Add namespace prefix to each keyname
  420. foreach($data as $val){
  421. $processed[] = "bpm." . $ns . "." . $offset . "." . $val ;
  422. }
  423. unset($val);
  424. // An undocumented feature of apc_delete() is that it can accept multiple
  425. // keys at once, as an array of strings. The return value is an array
  426. // containing the names of any keys that didn't exist in the cache.
  427. $cache_result = apc_delete($processed);
  428. $keys_deleted = count($data) - count($cache_result);
  429. }
  430. return $keys_deleted;
  431. }
  432. } // End of class BPM_mCache_driver_apc
  433. ?>