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