Guest User

Untitled

a guest
Feb 19th, 2018
68
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.06 KB | None | 0 0
  1. merb-cache was rewritten with a few goals in mind:
  2. <ol>
  3. <li>make it modulular</li>
  4. <li>define a public <span class="caps">API</span></li>
  5. <li>do the heavy lifting on key generation</li>
  6. <li>100% thread-safe</li>
  7. <li>work with multiple caching layers through the same <span class="caps">API</span></li>
  8. <li>keep it hackable</li>
  9. </ol>
  10.  
  11.  
  12. <h3>Stores</h3>
  13.  
  14.  
  15. <p>First and foremost, cache stores have been seperated into two families: fundamental stores and strategy stores. A fundamental store is any store that interacts directly with the persistence layer. The <b>FileStore</b>, for example, is a fundamental store that reads & writes cache entries to the file system. <b>MemcachedStore</b> is also a fundamental store. They have almost identical functionality to the existing caching technique, only they implement a common <span class="caps">API</span> defined by <b>AbstractStore</b>.</p>
  16.  
  17.  
  18. <p>The strategy store is the new kid on the block. A strategy store wraps one or more fundamental stores, acting as a middle man between caching requests. For example, if you need to save memory on your Memcache server, you could wrap your <b>MemcachedStore</b> with a <b>GzipStore</b>. This would automatically compress the cached data when put into the cache, and decompressed on the way out. You can even wrap strategy caches with other strategy caches. In the last example, if you key was comprised of sensitive information, like a <span class="caps">SSN</span>, you might want to encrypt the key before storage. Wrapping your <b>GzipStore</b> in a <b>SHA1Store</b> would take care of that for you.</p>
  19.  
  20.  
  21. <h3>Public <span class="caps">API</span></h3>
  22.  
  23.  
  24. <p>The <b>AbstractStore</b> class defines 9 methods as the <span class="caps">API</span>:</p>
  25.  
  26.  
  27. <ol>
  28. <li><b>writable?(key, parameters = {}, conditions = {})</b></li>
  29. <li><b>exists?(key, parameters = {})</b></li>
  30. <li><b>read(key, parameters = {})</b></li>
  31. <li><b>write(key, data = nil, parameters = {}, conditions = {})</b></li>
  32. <li><b>write_all(key, data = nil, parameters = {}, conditions = {})</b></li>
  33. <li><b>fetch(key, parameters = {}, conditions = {}, &blk)</b></li>
  34. <li><b>delete(key, parameters = {})</b></li>
  35. <li><b>delete_all</b></li>
  36. <li><b>delete_all!</b></li>
  37. </ol>
  38.  
  39.  
  40. <p><b>AbstractStrategyStore</b> implements all of these with the exception of <b>delete_all</b>. If a strategy store can guarantee that calling <b>delete_all</b> on it&#8217;s wrapped store(s) will only delete entries populated by the strategy store, it may define the safe version of <b>delete_all</b>. However, this is usually not the case, hence <b>delete_all</b> is not part of the public <span class="caps">API</span> for <b>AbstractStrategyStore</b>.</p>
  41.  
  42.  
  43. <p>A more detailed documentation on each method can be found here: <span class="caps">LINK</span></p>
  44.  
  45.  
  46. <h3>Less Talk, More Code</h3>
  47.  
  48.  
  49. <p>So here&#8217;s how you can setup and use merb-cache in your merb app:</p>
  50.  
  51.  
  52. <h4>config/environments/development.rb</h4>
  53.  
  54.  
  55. <pre>
  56. <code>
  57. # create a fundamental memcache store named :memcache for localhost
  58. Merb::Cache.setup(:memcache, Merb::Cache::MemcachedStore, {
  59. :namespace => "my_app",
  60. :servers => ["127.0.0.1:11211"]
  61. }
  62.  
  63. # a default FileStore
  64. Merb::Cache.setup(Merb::Cache::FileStore)
  65.  
  66. # another FileStore
  67. Merb::Cache.setup(:tmp_cache, Merb::Cache::FileStore, :dir => "/tmp")
  68. </code>
  69. </pre>
  70.  
  71. <p>Now lets use these in a model:</p>
  72.  
  73.  
  74. <h4>app/models/tag.rb</h4>
  75.  
  76.  
  77. <pre>
  78. <code>
  79. class Tag
  80. #...
  81.  
  82. def find(parameters = {})
  83. # poor man's identity map
  84.  
  85. if Merb::Cache[:memcached].exists?("tags", parameters)
  86. Merb::Cache[:memcached].read("tags", parameters)
  87. else
  88. returning(super(parameters)) do |results|
  89. Merb::Cache[:memcached].write("tags", results, parameters)
  90. end
  91. end
  92. end
  93.  
  94. def popularity_rating
  95. # lets keep the popularity rating cached for 30 seconds
  96. # merb-cache will create a key from the model's id & the interval parameter
  97.  
  98. Merb::Cache[:memcache].fetch(self.id, :interval => Time.now.to_i / 30) do
  99. self.run_long_popularity_rating_query
  100. end
  101. end
  102. end
  103. </code>
  104. </pre>
  105.  
  106. <p>Or, if you want to use memcache&#8217;s built in expire option:</p>
  107.  
  108.  
  109. <pre>
  110. <code>
  111. # expire a cache entry for "bar" (identified by the key "foo" and
  112. # parameters {:baz => :bay}) in two hours
  113. Merb::Cache[:memcache].write("foo", "bar", {:baz => :bay}, :expire_in => 2.hours)
  114.  
  115. # this will fail, because FileStore cannot expire cache entries
  116. Merb::Cache[:default].write("foo", "bar", {:baz => :bay}, :expire_in => 2.hours)
  117.  
  118. # writing to the FileStore will fail, but the MemcachedStore will succeed
  119. Merb::Cache[:default, :memcache].write("foo", "bar", {:baz => :bay}, :expire_in => 2.hours)
  120.  
  121. # this will fail
  122. Merb::Cache[:default, :memcached].write_all("foo", "bar", {:baz => :bay}, :expire_in => 2.hours)
  123. </code>
  124. </pre>
  125.  
  126. <h3>Strategy Stores</h3>
  127.  
  128.  
  129. <p>Setting up strategy stores is very similar to fundamental stores:</p>
  130.  
  131.  
  132. <h4>config/environments/development.rb</h4>
  133.  
  134.  
  135. <pre>
  136. <code>
  137. # wraps the :memcache store we setup earlier
  138. Merb::Cache.setup(:zipped, Merb::Cache::GzipStore[:memcache])
  139.  
  140. # wrap a strategy store
  141. Merb::Cache.setup(:sha_and_zip, Merb::Cache::SHA1Store[:zipped])
  142.  
  143. # you can even use unnamed fundamental stores
  144. Merb::Cache.setup(:zipped_images, Merb::Cache::GzipStore[Merb::Cache::FileStore],
  145. :dir => Merb.root / "public" / "images")
  146.  
  147. # or a combination or strategy & fundamental stores
  148. module Merb::Cache #makes things a bit shorter
  149.  
  150. setup(:secured, SHA1Store[GzipStore[FileStore], FileStore],
  151. :dir => Merb.root / "private")
  152. end
  153. </code>
  154. </pre>
  155.  
  156. <p>You can use these strategy stores exactly like fundamental stores in your app code.</p>
  157.  
  158.  
  159. <h3>Action & Page Caching</h3>
  160.  
  161.  
  162. <p>Action & page caching have been implemented in strategy stores. So instead of manually specifying which type of caching you want for each action, you simply ask merb-cache to cache your action, and merb-cache will use the fastest available cache.</p>
  163.  
  164.  
  165. <p>First, let&#8217;s setup our page & action stores:</p>
  166.  
  167.  
  168. <h4>config/environments/development.rb</h4>
  169.  
  170.  
  171. <pre>
  172. <code>
  173. # the order that stores are setup is important
  174. # faster stores should be setup first
  175.  
  176. # page cache to the public dir
  177. Merb::Cache.setup(:page_store, Merb::Cache::PageCache[FileStore],
  178. :dir => Merb.root / "public")
  179.  
  180. # action cache to memcache
  181. Merb::Cache.setup(:action_store, Merb::Cache::ActionCache[:sha_and_zip])
  182. </code>
  183. </pre>
  184.  
  185. <p>And now in our controller:</p>
  186.  
  187.  
  188. <h4>app/controllers/tags.rb</h4>
  189.  
  190.  
  191. <pre>
  192. <code>
  193. class Tags < Merb::Controller
  194.  
  195. # index & show will be page cached to the public dir. The index
  196. # action has no parameters, and the show parameter's are part of
  197. # the query string, making them both page-cache'able
  198. cache :index, :show
  199.  
  200. def index
  201. render
  202. end
  203.  
  204. # merb-cache works automatically with merb-action-args
  205. def show(id)
  206. dispay Tag.first(:id => id)
  207. end
  208.  
  209. # action caches if there are POST parameters
  210. cache :graph, :params => [:tags, :start_date, :end_date, :interval]
  211.  
  212. def graph
  213. @interval = params[:interval]
  214. display Tag.all(:id.in => params[:tags], :start_date => params[:start_date],
  215. :end_date => params[:end_date])
  216. end
  217.  
  218. # works with :if/:unless conditions, but action caches
  219. cache :home, :if => :logged_in?
  220.  
  221. def home
  222. display Tag.all(:user => current_user)
  223. end
  224.  
  225. # or you can manually specify a store
  226. cache :short, :store => :action_store
  227.  
  228. def short(id)
  229. display Tag.first(id)
  230. end
  231. end
  232. </code>
  233. </pre>
  234.  
  235. <h3>Keeping A Hot Cache & Eager Caching</h3>
  236.  
  237.  
  238. <p>Keeping your cache current is a problem for a lot of web apps. The new merb-cache gives you a few tools to keep your cache from getting stale. The eager_cache method allows you to create triggers for updating cache content when it becomes stale. It uses the run_later method, which means the cached content is replaced after the response is served.</p>
  239.  
  240.  
  241. <h4>app/controllers/articles.rb</h4>
  242.  
  243.  
  244. <pre>
  245. <code>
  246. class Articles < Merb::Controller
  247.  
  248. # start by page caching the index
  249. cache :index
  250.  
  251. # simple action, nothing fancy
  252. def index(page = 1)
  253. display Acticle.paginate(:page => page)
  254. end
  255.  
  256. # lets automatically cache the next page, if the user requests
  257. # anything other than the first page
  258. eager_cache(:index, :unless => :main_page?) do |controller|
  259. controller.params[:page] = (controller.params[:page].to_i) + 1
  260. end
  261.  
  262. def main_page?
  263. params[:page].nil? || params[:page].to_i == 1
  264. end
  265.  
  266. # or, we can specify eager caching in the action itself
  267. def index(page = 1)
  268. unless page == 1
  269. eager_cache :index do |controller|
  270. controller.params[:page] = page + 1
  271. end
  272. end
  273.  
  274. display Acticle.paginate(:page => page)
  275. end
  276. end
  277. </code>
  278. </pre>
Add Comment
Please, Sign In to add comment