ProfilerWrapperCache.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. <?php
  2. declare(strict_types = 1);
  3. /**
  4. * @copyright 2022 Carl Schwan <carl@carlschwan.eu>
  5. *
  6. * @author Carl Schwan <carl@carlschwan.eu>
  7. *
  8. * @license GNU AGPL version 3 or any later version
  9. *
  10. * This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License as
  12. * published by the Free Software Foundation, either version 3 of the
  13. * License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Affero General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Affero General Public License
  21. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. *
  23. */
  24. namespace OC\Memcache;
  25. use OC\AppFramework\Http\Request;
  26. use OCP\AppFramework\Http\Response;
  27. use OCP\DataCollector\AbstractDataCollector;
  28. use OCP\IMemcacheTTL;
  29. /**
  30. * Cache wrapper that logs profiling information
  31. */
  32. class ProfilerWrapperCache extends AbstractDataCollector implements IMemcacheTTL, \ArrayAccess {
  33. /** @var Redis $wrappedCache*/
  34. protected $wrappedCache;
  35. /** @var string $prefix */
  36. protected $prefix;
  37. /** @var string $type */
  38. private $type;
  39. public function __construct(Redis $wrappedCache, string $type) {
  40. $this->prefix = $wrappedCache->getPrefix();
  41. $this->wrappedCache = $wrappedCache;
  42. $this->type = $type;
  43. $this->data['queries'] = [];
  44. $this->data['cacheHit'] = 0;
  45. $this->data['cacheMiss'] = 0;
  46. }
  47. public function getPrefix(): string {
  48. return $this->prefix;
  49. }
  50. /** @inheritDoc */
  51. public function get($key) {
  52. $start = microtime(true);
  53. $ret = $this->wrappedCache->get($key);
  54. if ($ret === null) {
  55. $this->data['cacheMiss']++;
  56. } else {
  57. $this->data['cacheHit']++;
  58. }
  59. $this->data['queries'][] = [
  60. 'start' => $start,
  61. 'end' => microtime(true),
  62. 'op' => $this->getPrefix() . '::get::' . $key,
  63. 'hit' => $ret !== null,
  64. ];
  65. return $ret;
  66. }
  67. /** @inheritDoc */
  68. public function set($key, $value, $ttl = 0) {
  69. $start = microtime(true);
  70. $ret = $this->wrappedCache->set($key, $value, $ttl);
  71. $this->data['queries'][] = [
  72. 'start' => $start,
  73. 'end' => microtime(true),
  74. 'op' => $this->getPrefix() . '::set::' . $key,
  75. ];
  76. return $ret;
  77. }
  78. /** @inheritDoc */
  79. public function hasKey($key) {
  80. $start = microtime(true);
  81. $ret = $this->wrappedCache->hasKey($key);
  82. $this->data['queries'][] = [
  83. 'start' => $start,
  84. 'end' => microtime(true),
  85. 'op' => $this->getPrefix() . '::hasKey::' . $key,
  86. ];
  87. return $ret;
  88. }
  89. /** @inheritDoc */
  90. public function remove($key) {
  91. $start = microtime(true);
  92. $ret = $this->wrappedCache->remove($key);
  93. $this->data['queries'][] = [
  94. 'start' => $start,
  95. 'end' => microtime(true),
  96. 'op' => $this->getPrefix() . '::remove::' . $key,
  97. ];
  98. return $ret;
  99. }
  100. /** @inheritDoc */
  101. public function clear($prefix = '') {
  102. $start = microtime(true);
  103. $ret = $this->wrappedCache->clear($prefix);
  104. $this->data['queries'][] = [
  105. 'start' => $start,
  106. 'end' => microtime(true),
  107. 'op' => $this->getPrefix() . '::clear::' . $prefix,
  108. ];
  109. return $ret;
  110. }
  111. /** @inheritDoc */
  112. public function add($key, $value, $ttl = 0) {
  113. $start = microtime(true);
  114. $ret = $this->wrappedCache->add($key, $value, $ttl);
  115. $this->data['queries'][] = [
  116. 'start' => $start,
  117. 'end' => microtime(true),
  118. 'op' => $this->getPrefix() . '::add::' . $key,
  119. ];
  120. return $ret;
  121. }
  122. /** @inheritDoc */
  123. public function inc($key, $step = 1) {
  124. $start = microtime(true);
  125. $ret = $this->wrappedCache->inc($key, $step);
  126. $this->data['queries'][] = [
  127. 'start' => $start,
  128. 'end' => microtime(true),
  129. 'op' => $this->getPrefix() . '::inc::' . $key,
  130. ];
  131. return $ret;
  132. }
  133. /** @inheritDoc */
  134. public function dec($key, $step = 1) {
  135. $start = microtime(true);
  136. $ret = $this->wrappedCache->dec($key, $step);
  137. $this->data['queries'][] = [
  138. 'start' => $start,
  139. 'end' => microtime(true),
  140. 'op' => $this->getPrefix() . '::dev::' . $key,
  141. ];
  142. return $ret;
  143. }
  144. /** @inheritDoc */
  145. public function cas($key, $old, $new) {
  146. $start = microtime(true);
  147. $ret = $this->wrappedCache->cas($key, $old, $new);
  148. $this->data['queries'][] = [
  149. 'start' => $start,
  150. 'end' => microtime(true),
  151. 'op' => $this->getPrefix() . '::cas::' . $key,
  152. ];
  153. return $ret;
  154. }
  155. /** @inheritDoc */
  156. public function cad($key, $old) {
  157. $start = microtime(true);
  158. $ret = $this->wrappedCache->cad($key, $old);
  159. $this->data['queries'][] = [
  160. 'start' => $start,
  161. 'end' => microtime(true),
  162. 'op' => $this->getPrefix() . '::cad::' . $key,
  163. ];
  164. return $ret;
  165. }
  166. /** @inheritDoc */
  167. public function setTTL(string $key, int $ttl) {
  168. $this->wrappedCache->setTTL($key, $ttl);
  169. }
  170. public function getTTL(string $key): int|false {
  171. return $this->wrappedCache->getTTL($key);
  172. }
  173. public function compareSetTTL(string $key, mixed $value, int $ttl): bool {
  174. return $this->wrappedCache->compareSetTTL($key, $value, $ttl);
  175. }
  176. public function offsetExists($offset): bool {
  177. return $this->hasKey($offset);
  178. }
  179. public function offsetSet($offset, $value): void {
  180. $this->set($offset, $value);
  181. }
  182. /**
  183. * @return mixed
  184. */
  185. #[\ReturnTypeWillChange]
  186. public function offsetGet($offset) {
  187. return $this->get($offset);
  188. }
  189. public function offsetUnset($offset): void {
  190. $this->remove($offset);
  191. }
  192. public function collect(Request $request, Response $response, \Throwable $exception = null): void {
  193. // Nothing to do here $data is already ready
  194. }
  195. public function getName(): string {
  196. return 'cache/' . $this->type . '/' . $this->prefix;
  197. }
  198. public static function isAvailable(): bool {
  199. return true;
  200. }
  201. }