ProfilerWrapperCache.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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 setTTL(string $key, int $ttl) {
  152. $this->wrappedCache->setTTL($key, $ttl);
  153. }
  154. public function getTTL(string $key): int|false {
  155. return $this->wrappedCache->getTTL($key);
  156. }
  157. public function compareSetTTL(string $key, mixed $value, int $ttl): bool {
  158. return $this->wrappedCache->compareSetTTL($key, $value, $ttl);
  159. }
  160. public function offsetExists($offset): bool {
  161. return $this->hasKey($offset);
  162. }
  163. public function offsetSet($offset, $value): void {
  164. $this->set($offset, $value);
  165. }
  166. /**
  167. * @return mixed
  168. */
  169. #[\ReturnTypeWillChange]
  170. public function offsetGet($offset) {
  171. return $this->get($offset);
  172. }
  173. public function offsetUnset($offset): void {
  174. $this->remove($offset);
  175. }
  176. public function collect(Request $request, Response $response, ?\Throwable $exception = null): void {
  177. // Nothing to do here $data is already ready
  178. }
  179. public function getName(): string {
  180. return 'cache/' . $this->type . '/' . $this->prefix;
  181. }
  182. public static function isAvailable(): bool {
  183. return true;
  184. }
  185. }