1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "components/dom_distiller/core/distilled_content_store.h" 6 7#include "base/message_loop/message_loop.h" 8 9namespace dom_distiller { 10 11InMemoryContentStore::InMemoryContentStore(const int max_num_entries) 12 : cache_(max_num_entries, CacheDeletor(this)) { 13} 14 15InMemoryContentStore::~InMemoryContentStore() { 16 // Clear the cache before destruction to ensure the CacheDeletor is not called 17 // after InMemoryContentStore has been destroyed. 18 cache_.Clear(); 19} 20 21void InMemoryContentStore::SaveContent( 22 const ArticleEntry& entry, 23 const DistilledArticleProto& proto, 24 InMemoryContentStore::SaveCallback callback) { 25 InjectContent(entry, proto); 26 if (!callback.is_null()) { 27 base::MessageLoop::current()->PostTask(FROM_HERE, 28 base::Bind(callback, true)); 29 } 30} 31 32void InMemoryContentStore::LoadContent( 33 const ArticleEntry& entry, 34 InMemoryContentStore::LoadCallback callback) { 35 if (callback.is_null()) 36 return; 37 38 ContentMap::const_iterator it = cache_.Get(entry.entry_id()); 39 bool success = it != cache_.end(); 40 if (!success) { 41 // Could not find article by entry ID, so try looking it up by URL. 42 for (int i = 0; i < entry.pages_size(); ++i) { 43 UrlMap::const_iterator url_it = url_to_id_.find(entry.pages(i).url()); 44 if (url_it != url_to_id_.end()) { 45 it = cache_.Get(url_it->second); 46 success = it != cache_.end(); 47 if (success) { 48 break; 49 } 50 } 51 } 52 } 53 scoped_ptr<DistilledArticleProto> distilled_article; 54 if (success) { 55 distilled_article.reset(new DistilledArticleProto(it->second)); 56 } else { 57 distilled_article.reset(new DistilledArticleProto()); 58 } 59 base::MessageLoop::current()->PostTask( 60 FROM_HERE, 61 base::Bind(callback, success, base::Passed(&distilled_article))); 62} 63 64void InMemoryContentStore::InjectContent(const ArticleEntry& entry, 65 const DistilledArticleProto& proto) { 66 cache_.Put(entry.entry_id(), proto); 67 AddUrlToIdMapping(entry, proto); 68} 69 70void InMemoryContentStore::AddUrlToIdMapping( 71 const ArticleEntry& entry, 72 const DistilledArticleProto& proto) { 73 for (int i = 0; i < proto.pages_size(); i++) { 74 const DistilledPageProto& page = proto.pages(i); 75 if (page.has_url()) { 76 url_to_id_[page.url()] = entry.entry_id(); 77 } 78 } 79} 80 81void InMemoryContentStore::EraseUrlToIdMapping( 82 const DistilledArticleProto& proto) { 83 for (int i = 0; i < proto.pages_size(); i++) { 84 const DistilledPageProto& page = proto.pages(i); 85 if (page.has_url()) { 86 url_to_id_.erase(page.url()); 87 } 88 } 89} 90 91InMemoryContentStore::CacheDeletor::CacheDeletor(InMemoryContentStore* store) 92 : store_(store) { 93} 94 95InMemoryContentStore::CacheDeletor::~CacheDeletor() { 96} 97 98void InMemoryContentStore::CacheDeletor::operator()( 99 const DistilledArticleProto& proto) { 100 // When InMemoryContentStore is deleted, the |store_| pointer becomes invalid, 101 // but since the ContentMap is cleared in the InMemoryContentStore destructor, 102 // this should never be called after the destructor. 103 store_->EraseUrlToIdMapping(proto); 104} 105 106} // namespace dom_distiller 107