cachingnoticestream.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. <?php
  2. /**
  3. * StatusNet - the distributed open-source microblogging tool
  4. * Copyright (C) 2011, StatusNet, Inc.
  5. *
  6. * A stream of notices
  7. *
  8. * PHP version 5
  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 published by
  12. * the Free Software Foundation, either version 3 of the License, or
  13. * (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. * @category Stream
  24. * @package StatusNet
  25. * @author Evan Prodromou <evan@status.net>
  26. * @copyright 2011 StatusNet, Inc.
  27. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
  28. * @link http://status.net/
  29. */
  30. if (!defined('STATUSNET')) {
  31. // This check helps protect against security problems;
  32. // your code file can't be executed directly from the web.
  33. exit(1);
  34. }
  35. /**
  36. * Class for notice streams
  37. *
  38. * @category Stream
  39. * @package StatusNet
  40. * @author Evan Prodromou <evan@status.net>
  41. * @copyright 2011 StatusNet, Inc.
  42. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
  43. * @link http://status.net/
  44. */
  45. class CachingNoticeStream extends NoticeStream
  46. {
  47. const CACHE_WINDOW = 200;
  48. public $stream = null;
  49. public $cachekey = null;
  50. public $useLast = true;
  51. function __construct($stream, $cachekey, $useLast = true)
  52. {
  53. $this->stream = $stream;
  54. $this->cachekey = $cachekey;
  55. $this->useLast = $useLast;
  56. }
  57. function getNoticeIds($offset, $limit, $sinceId, $maxId)
  58. {
  59. $cache = Cache::instance();
  60. // We cache self::CACHE_WINDOW elements at the tip of the stream.
  61. // If the cache won't be hit, just generate directly.
  62. if (empty($cache) ||
  63. $sinceId != 0 || $maxId != 0 ||
  64. is_null($limit) ||
  65. ($offset + $limit) > self::CACHE_WINDOW) {
  66. return $this->stream->getNoticeIds($offset, $limit, $sinceId, $maxId);
  67. }
  68. // Check the cache to see if we have the stream.
  69. $idkey = Cache::key($this->cachekey);
  70. $idstr = $cache->get($idkey);
  71. if ($idstr !== false) {
  72. // Cache hit! Woohoo!
  73. $window = explode(',', $idstr);
  74. $ids = array_slice($window, $offset, $limit);
  75. return $ids;
  76. }
  77. if ($this->useLast) {
  78. // Check the cache to see if we have a "last-known-good" version.
  79. // The actual cache gets blown away when new notices are added, but
  80. // the "last" value holds a lot of info. We might need to only generate
  81. // a few at the "tip", which can bound our queries and save lots
  82. // of time.
  83. $laststr = $cache->get($idkey.';last');
  84. if ($laststr !== false) {
  85. $window = explode(',', $laststr);
  86. $last_id = $window[0];
  87. $new_ids = $this->stream->getNoticeIds(0, self::CACHE_WINDOW, $last_id, 0);
  88. $new_window = array_merge($new_ids, $window);
  89. $new_windowstr = implode(',', $new_window);
  90. $result = $cache->set($idkey, $new_windowstr);
  91. $result = $cache->set($idkey . ';last', $new_windowstr);
  92. $ids = array_slice($new_window, $offset, $limit);
  93. return $ids;
  94. }
  95. }
  96. // No cache hits :( Generate directly and stick the results
  97. // into the cache. Note we generate the full cache window.
  98. $window = $this->stream->getNoticeIds(0, self::CACHE_WINDOW, 0, 0);
  99. $windowstr = implode(',', $window);
  100. $result = $cache->set($idkey, $windowstr);
  101. if ($this->useLast) {
  102. $result = $cache->set($idkey . ';last', $windowstr);
  103. }
  104. // Return just the slice that was requested
  105. $ids = array_slice($window, $offset, $limit);
  106. return $ids;
  107. }
  108. }