ProfilerWrapperCache.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. <?php
  2. declare(strict_types = 1);
  3. /**
  4. * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OC\Memcache;
  8. use OC\AppFramework\Http\Request;
  9. use OCP\AppFramework\Http\Response;
  10. use OCP\DataCollector\AbstractDataCollector;
  11. use OCP\IMemcacheTTL;
  12. /**
  13. * Cache wrapper that logs profiling information
  14. * @template-implements \ArrayAccess<string,mixed>
  15. */
  16. class ProfilerWrapperCache extends AbstractDataCollector implements IMemcacheTTL, \ArrayAccess {
  17. /** @var Redis $wrappedCache */
  18. protected $wrappedCache;
  19. /** @var string $prefix */
  20. protected $prefix;
  21. /** @var string $type */
  22. private $type;
  23. public function __construct(Redis $wrappedCache, string $type) {
  24. $this->prefix = $wrappedCache->getPrefix();
  25. $this->wrappedCache = $wrappedCache;
  26. $this->type = $type;
  27. $this->data['queries'] = [];
  28. $this->data['cacheHit'] = 0;
  29. $this->data['cacheMiss'] = 0;
  30. }
  31. public function getPrefix(): string {
  32. return $this->prefix;
  33. }
  34. /** @inheritDoc */
  35. public function get($key) {
  36. $start = microtime(true);
  37. $ret = $this->wrappedCache->get($key);
  38. if ($ret === null) {
  39. $this->data['cacheMiss']++;
  40. } else {
  41. $this->data['cacheHit']++;
  42. }
  43. $this->data['queries'][] = [
  44. 'start' => $start,
  45. 'end' => microtime(true),
  46. 'op' => $this->getPrefix() . '::get::' . $key,
  47. 'hit' => $ret !== null,
  48. ];
  49. return $ret;
  50. }
  51. /** @inheritDoc */
  52. public function set($key, $value, $ttl = 0) {
  53. $start = microtime(true);
  54. $ret = $this->wrappedCache->set($key, $value, $ttl);
  55. $this->data['queries'][] = [
  56. 'start' => $start,
  57. 'end' => microtime(true),
  58. 'op' => $this->getPrefix() . '::set::' . $key,
  59. ];
  60. return $ret;
  61. }
  62. /** @inheritDoc */
  63. public function hasKey($key) {
  64. $start = microtime(true);
  65. $ret = $this->wrappedCache->hasKey($key);
  66. $this->data['queries'][] = [
  67. 'start' => $start,
  68. 'end' => microtime(true),
  69. 'op' => $this->getPrefix() . '::hasKey::' . $key,
  70. ];
  71. return $ret;
  72. }
  73. /** @inheritDoc */
  74. public function remove($key) {
  75. $start = microtime(true);
  76. $ret = $this->wrappedCache->remove($key);
  77. $this->data['queries'][] = [
  78. 'start' => $start,
  79. 'end' => microtime(true),
  80. 'op' => $this->getPrefix() . '::remove::' . $key,
  81. ];
  82. return $ret;
  83. }
  84. /** @inheritDoc */
  85. public function clear($prefix = '') {
  86. $start = microtime(true);
  87. $ret = $this->wrappedCache->clear($prefix);
  88. $this->data['queries'][] = [
  89. 'start' => $start,
  90. 'end' => microtime(true),
  91. 'op' => $this->getPrefix() . '::clear::' . $prefix,
  92. ];
  93. return $ret;
  94. }
  95. /** @inheritDoc */
  96. public function add($key, $value, $ttl = 0) {
  97. $start = microtime(true);
  98. $ret = $this->wrappedCache->add($key, $value, $ttl);
  99. $this->data['queries'][] = [
  100. 'start' => $start,
  101. 'end' => microtime(true),
  102. 'op' => $this->getPrefix() . '::add::' . $key,
  103. ];
  104. return $ret;
  105. }
  106. /** @inheritDoc */
  107. public function inc($key, $step = 1) {
  108. $start = microtime(true);
  109. $ret = $this->wrappedCache->inc($key, $step);
  110. $this->data['queries'][] = [
  111. 'start' => $start,
  112. 'end' => microtime(true),
  113. 'op' => $this->getPrefix() . '::inc::' . $key,
  114. ];
  115. return $ret;
  116. }
  117. /** @inheritDoc */
  118. public function dec($key, $step = 1) {
  119. $start = microtime(true);
  120. $ret = $this->wrappedCache->dec($key, $step);
  121. $this->data['queries'][] = [
  122. 'start' => $start,
  123. 'end' => microtime(true),
  124. 'op' => $this->getPrefix() . '::dev::' . $key,
  125. ];
  126. return $ret;
  127. }
  128. /** @inheritDoc */
  129. public function cas($key, $old, $new) {
  130. $start = microtime(true);
  131. $ret = $this->wrappedCache->cas($key, $old, $new);
  132. $this->data['queries'][] = [
  133. 'start' => $start,
  134. 'end' => microtime(true),
  135. 'op' => $this->getPrefix() . '::cas::' . $key,
  136. ];
  137. return $ret;
  138. }
  139. /** @inheritDoc */
  140. public function cad($key, $old) {
  141. $start = microtime(true);
  142. $ret = $this->wrappedCache->cad($key, $old);
  143. $this->data['queries'][] = [
  144. 'start' => $start,
  145. 'end' => microtime(true),
  146. 'op' => $this->getPrefix() . '::cad::' . $key,
  147. ];
  148. return $ret;
  149. }
  150. /** @inheritDoc */
  151. public function ncad(string $key, mixed $old): bool {
  152. $start = microtime(true);
  153. $ret = $this->wrappedCache->ncad($key, $old);
  154. $this->data['queries'][] = [
  155. 'start' => $start,
  156. 'end' => microtime(true),
  157. 'op' => $this->getPrefix() . '::ncad::' . $key,
  158. ];
  159. return $ret;
  160. }
  161. /** @inheritDoc */
  162. public function setTTL(string $key, int $ttl) {
  163. $this->wrappedCache->setTTL($key, $ttl);
  164. }
  165. public function getTTL(string $key): int|false {
  166. return $this->wrappedCache->getTTL($key);
  167. }
  168. public function compareSetTTL(string $key, mixed $value, int $ttl): bool {
  169. return $this->wrappedCache->compareSetTTL($key, $value, $ttl);
  170. }
  171. public function offsetExists($offset): bool {
  172. return $this->hasKey($offset);
  173. }
  174. public function offsetSet($offset, $value): void {
  175. $this->set($offset, $value);
  176. }
  177. /**
  178. * @return mixed
  179. */
  180. #[\ReturnTypeWillChange]
  181. public function offsetGet($offset) {
  182. return $this->get($offset);
  183. }
  184. public function offsetUnset($offset): void {
  185. $this->remove($offset);
  186. }
  187. public function collect(Request $request, Response $response, ?\Throwable $exception = null): void {
  188. // Nothing to do here $data is already ready
  189. }
  190. public function getName(): string {
  191. return 'cache/' . $this->type . '/' . $this->prefix;
  192. }
  193. public static function isAvailable(): bool {
  194. return true;
  195. }
  196. }