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 9 namespace dom_distiller { 10 11 InMemoryContentStore::InMemoryContentStore(const int max_num_entries) 12 : cache_(max_num_entries, CacheDeletor(this)) { 13 } 14 15 InMemoryContentStore::~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 21 void 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 32 void 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 64 void InMemoryContentStore::InjectContent(const ArticleEntry& entry, 65 const DistilledArticleProto& proto) { 66 cache_.Put(entry.entry_id(), proto); 67 AddUrlToIdMapping(entry, proto); 68 } 69 70 void 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 81 void 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 91 InMemoryContentStore::CacheDeletor::CacheDeletor(InMemoryContentStore* store) 92 : store_(store) { 93 } 94 95 InMemoryContentStore::CacheDeletor::~CacheDeletor() { 96 } 97 98 void 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