1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// found in the LICENSE file. 4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#ifndef CONTENT_BROWSER_RENDERER_DATA_MEMOIZING_STORE_H_ 6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#define CONTENT_BROWSER_RENDERER_DATA_MEMOIZING_STORE_H_ 7f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include <map> 9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/bind.h" 11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/synchronization/lock.h" 12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/browser_thread.h" 135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "content/public/browser/render_process_host.h" 14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/render_process_host_observer.h" 15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace content { 17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// RendererDataMemoizingStore is a thread-safe container that retains reference 19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// counted objects that are associated with one or more render processes. 20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Objects are identified by an int and only a single reference to a given 21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// object is retained. RendererDataMemoizingStore watches for render process 22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// termination and releases objects that are no longer associated with any 23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// render process. 24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// 25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// TODO(jcampan): Rather than watching for render process termination, we should 26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// instead be listening to events such as resource cached/ 27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// removed from cache, and remove the items when we know they 28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// are not used anymore. 29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)template <typename T> 30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class RendererDataMemoizingStore : public RenderProcessHostObserver { 31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public: 32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) RendererDataMemoizingStore() : next_item_id_(1) { 33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ~RendererDataMemoizingStore() { 36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK_EQ(0U, id_to_item_.size()) << "Failed to outlive render processes"; 37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Store adds |item| to this collection, associates it with the given render 40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // process id and returns an opaque identifier for it. If |item| is already 41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // known, the same identifier will be returned. 42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int Store(T* item, int process_id) { 43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(item); 44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::AutoLock auto_lock(lock_); 45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int item_id; 47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Do we already know this item? 49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) typename ReverseItemMap::iterator item_iter = item_to_id_.find(item); 50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (item_iter == item_to_id_.end()) { 51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) item_id = next_item_id_++; 52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // We use 0 as an invalid item_id value. In the unlikely event that 53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // next_item_id_ wraps around, we reset it to 1. 54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (next_item_id_ == 0) 55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) next_item_id_ = 1; 56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) id_to_item_[item_id] = item; 57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) item_to_id_[item] = item_id; 58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else { 59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) item_id = item_iter->second; 60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Let's update process_id_to_item_id_. 63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::pair<IDMap::iterator, IDMap::iterator> process_ids = 64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) process_id_to_item_id_.equal_range(process_id); 65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool already_watching_process = (process_ids.first != process_ids.second); 66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (std::find_if(process_ids.first, process_ids.second, 67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MatchSecond<int>(item_id)) == process_ids.second) { 68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) process_id_to_item_id_.insert(std::make_pair(process_id, item_id)); 69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // And item_id_to_process_id_. 72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::pair<IDMap::iterator, IDMap::iterator> item_ids = 73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) item_id_to_process_id_.equal_range(item_id); 74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (std::find_if(item_ids.first, item_ids.second, 75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MatchSecond<int>(process_id)) == item_ids.second) { 76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) item_id_to_process_id_.insert(std::make_pair(item_id, process_id)); 77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // If we're not doing so already, keep an eye for the process host deletion. 80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!already_watching_process) { 81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) StartObservingProcess(process_id); 83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else { 84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) BrowserThread::PostTask( 85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) BrowserThread::UI, 86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) FROM_HERE, 87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Bind(&RendererDataMemoizingStore::StartObservingProcess, 88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Unretained(this), 89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) process_id)); 90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(item_id); 94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return item_id; 95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Retrieve fetches a previously Stored() item, identified by |item_id|. 98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // If |item_id| is recognized, |item| will be updated and Retrieve() will 99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // return true, it will otherwise return false. 100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool Retrieve(int item_id, scoped_refptr<T>* item) { 101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::AutoLock auto_lock(lock_); 102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) typename ItemMap::iterator iter = id_to_item_.find(item_id); 104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (iter == id_to_item_.end()) 105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return false; 106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (item) 107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *item = iter->second; 108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return true; 109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private: 112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) typedef std::multimap<int, int> IDMap; 113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) typedef std::map<int, scoped_refptr<T> > ItemMap; 114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) typedef std::map<T*, int, typename T::LessThan> ReverseItemMap; 115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) template <typename M> 117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) struct MatchSecond { 118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) explicit MatchSecond(const M& t) : value(t) {} 119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) template <typename Pair> 121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool operator()(const Pair& p) const { 122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return (value == p.second); 123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) M value; 126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) }; 127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) void StartObservingProcess(int process_id) { 129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) RenderProcessHost* host = RenderProcessHost::FromID(process_id); 131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!host) { 132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // We lost the race to observe the host before it was destroyed. Since 133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // this function was called because we're managing objects tied to that 134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // (now destroyed) RenderProcessHost, let's clean up. 135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) RemoveRenderProcessItems(process_id); 136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) host->AddObserver(this); 140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Remove the item specified by |item_id| from id_to_item_ and item_to_id_. 143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // NOTE: the caller (RemoveRenderProcessItems) must hold lock_. 144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) void RemoveInternal(int item_id) { 145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) typename ItemMap::iterator item_iter = id_to_item_.find(item_id); 146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(item_iter != id_to_item_.end()); 147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) typename ReverseItemMap::iterator id_iter = 149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) item_to_id_.find(item_iter->second.get()); 150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(id_iter != item_to_id_.end()); 151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) item_to_id_.erase(id_iter); 152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) id_to_item_.erase(item_iter); 154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) void RenderProcessHostDestroyed(RenderProcessHost* host) { 157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) RemoveRenderProcessItems(host->GetID()); 159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Removes all the items associated with the specified process from the store. 162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) void RemoveRenderProcessItems(int process_id) { 163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::AutoLock auto_lock(lock_); 164f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // We iterate through all the item ids for that process. 166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::pair<IDMap::iterator, IDMap::iterator> process_ids = 167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) process_id_to_item_id_.equal_range(process_id); 168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (IDMap::iterator ids_iter = process_ids.first; 169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ids_iter != process_ids.second; ++ids_iter) { 170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int item_id = ids_iter->second; 171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Find all the processes referring to this item id in 172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // item_id_to_process_id_, then locate the process being removed within 173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // that range. 174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::pair<IDMap::iterator, IDMap::iterator> item_ids = 175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) item_id_to_process_id_.equal_range(item_id); 176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) IDMap::iterator proc_iter = std::find_if( 177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) item_ids.first, item_ids.second, MatchSecond<int>(process_id)); 178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(proc_iter != item_ids.second); 179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Before removing, determine if no other processes refer to the current 181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // item id. If |proc_iter| (the current process) is the lower bound of 182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // processes containing the current item id and if |next_proc_iter| is the 183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // upper bound (the first process that does not), then only one process, 184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // the one being removed, refers to the item id. 185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) IDMap::iterator next_proc_iter = proc_iter; 186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ++next_proc_iter; 187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool last_process_for_item_id = 188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) (proc_iter == item_ids.first && next_proc_iter == item_ids.second); 189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) item_id_to_process_id_.erase(proc_iter); 190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 191f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (last_process_for_item_id) { 192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // The current item id is not referenced by any other processes, so 193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // remove it from id_to_item_ and item_to_id_. 194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) RemoveInternal(item_id); 195f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 196f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 197f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (process_ids.first != process_ids.second) 198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) process_id_to_item_id_.erase(process_ids.first, process_ids.second); 199f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 200f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 201f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) IDMap process_id_to_item_id_; 202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) IDMap item_id_to_process_id_; 203f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ItemMap id_to_item_; 204f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ReverseItemMap item_to_id_; 205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int next_item_id_; 207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 208f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // This lock protects: process_id_to_item_id_, item_id_to_process_id_, 209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // id_to_item_, and item_to_id_. 210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Lock lock_; 211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}; 212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} // namespace content 214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif // CONTENT_BROWSER_RENDERER_DATA_MEMOIZING_STORE_H_ 216