| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013 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 "chrome/browser/policy/resource_cache.h" | |
| 6 | |
| 7 #include <string.h> | |
| 8 | |
| 9 #include "base/file_util.h" | |
| 10 #include "base/files/file_path.h" | |
| 11 #include "base/logging.h" | |
| 12 #include "base/string_util.h" | |
| 13 #include "base/strings/string_number_conversions.h" | |
| 14 #include "base/threading/thread_restrictions.h" | |
| 15 #include "third_party/leveldatabase/src/include/leveldb/db.h" | |
| 16 #include "third_party/leveldatabase/src/include/leveldb/iterator.h" | |
| 17 #include "third_party/leveldatabase/src/include/leveldb/options.h" | |
| 18 #include "third_party/leveldatabase/src/include/leveldb/slice.h" | |
| 19 #include "third_party/leveldatabase/src/include/leveldb/status.h" | |
| 20 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" | |
| 21 | |
| 22 namespace policy { | |
| 23 | |
| 24 ResourceCache::ResourceCache(const base::FilePath& cache_path) { | |
| 25 // Allow the cache to be created in a different thread than the thread that's | |
| 26 // going to use it. | |
| 27 DetachFromThread(); | |
| 28 | |
| 29 file_util::CreateDirectory(cache_path.DirName()); | |
| 30 leveldb::Options options; | |
| 31 options.create_if_missing = true; | |
| 32 leveldb::DB* db = NULL; | |
| 33 leveldb::Status status = | |
| 34 leveldb::DB::Open(options, cache_path.AsUTF8Unsafe(), &db); | |
| 35 if (!status.ok()) { | |
| 36 LOG(WARNING) << "Failed to open leveldb at " << cache_path.AsUTF8Unsafe() | |
| 37 << ": " << status.ToString(); | |
| 38 // Maybe the database is busted; drop everything and try to create it again. | |
| 39 file_util::Delete(cache_path, true); | |
| 40 status = leveldb::DB::Open(options, cache_path.AsUTF8Unsafe(), &db); | |
| 41 | |
| 42 if (!status.ok()) | |
| 43 LOG(WARNING) << "Failed to open a new leveldb after wiping: " | |
| 44 << status.ToString(); | |
| 45 } | |
| 46 db_.reset(db); | |
| 47 } | |
| 48 | |
| 49 ResourceCache::~ResourceCache() { | |
| 50 DCHECK(CalledOnValidThread()); | |
| 51 } | |
| 52 | |
| 53 bool ResourceCache::Store(const std::string& key, | |
| 54 const std::string& subkey, | |
| 55 const std::string& data) { | |
| 56 DCHECK(CalledOnValidThread()); | |
| 57 base::ThreadRestrictions::AssertIOAllowed(); | |
| 58 | |
| 59 if (!IsOpen()) | |
| 60 return false; | |
| 61 | |
| 62 std::string path(CreatePath(key, subkey)); | |
| 63 return db_->Put(leveldb::WriteOptions(), path, data).ok(); | |
| 64 } | |
| 65 | |
| 66 bool ResourceCache::Load(const std::string& key, | |
| 67 const std::string& subkey, | |
| 68 std::string* data) { | |
| 69 DCHECK(CalledOnValidThread()); | |
| 70 base::ThreadRestrictions::AssertIOAllowed(); | |
| 71 if (!IsOpen()) | |
| 72 return false; | |
| 73 | |
| 74 leveldb::ReadOptions options; | |
| 75 options.fill_cache = false; | |
| 76 std::string path(CreatePath(key, subkey)); | |
| 77 return db_->Get(options, path, data).ok(); | |
| 78 } | |
| 79 | |
| 80 void ResourceCache::LoadAllSubkeys( | |
| 81 const std::string& key, | |
| 82 std::map<std::string, std::string>* contents) { | |
| 83 DCHECK(CalledOnValidThread()); | |
| 84 base::ThreadRestrictions::AssertIOAllowed(); | |
| 85 if (!IsOpen()) | |
| 86 return; | |
| 87 | |
| 88 contents->clear(); | |
| 89 | |
| 90 const std::string prefix(CreatePathPrefix(key)); | |
| 91 leveldb::ReadOptions options; | |
| 92 options.fill_cache = false; | |
| 93 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options)); | |
| 94 for (it->Seek(prefix); it->Valid(); it->Next()) { | |
| 95 if (!it->key().starts_with(prefix)) | |
| 96 break; | |
| 97 const std::string subkey(GetSubkey(it->key().ToString())); | |
| 98 leveldb::Slice slice = it->value(); | |
| 99 (*contents)[subkey].assign(slice.data(), slice.size()); | |
| 100 } | |
| 101 } | |
| 102 | |
| 103 void ResourceCache::Delete(const std::string& key, const std::string& subkey) { | |
| 104 DCHECK(CalledOnValidThread()); | |
| 105 base::ThreadRestrictions::AssertIOAllowed(); | |
| 106 if (!IsOpen()) | |
| 107 return; | |
| 108 | |
| 109 const std::string path(CreatePath(key, subkey)); | |
| 110 leveldb::Status status = db_->Delete(leveldb::WriteOptions(), path); | |
| 111 if (!status.ok()) { | |
| 112 LOG(WARNING) << "Failed to Delete \"" << path << "\" from leveldb: " | |
| 113 << status.ToString(); | |
| 114 } | |
| 115 } | |
| 116 | |
| 117 void ResourceCache::PurgeOtherSubkeys( | |
| 118 const std::string& key, | |
| 119 const std::set<std::string>& subkeys_to_keep) { | |
| 120 DCHECK(CalledOnValidThread()); | |
| 121 base::ThreadRestrictions::AssertIOAllowed(); | |
| 122 if (!IsOpen()) | |
| 123 return; | |
| 124 | |
| 125 leveldb::WriteBatch batch; | |
| 126 const std::string prefix(CreatePathPrefix(key)); | |
| 127 leveldb::ReadOptions options; | |
| 128 options.fill_cache = false; | |
| 129 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options)); | |
| 130 for (it->Seek(prefix); it->Valid(); it->Next()) { | |
| 131 if (!it->key().starts_with(prefix)) | |
| 132 break; | |
| 133 const std::string subkey(GetSubkey(it->key().ToString())); | |
| 134 if (subkeys_to_keep.find(subkey) == subkeys_to_keep.end()) | |
| 135 batch.Delete(it->key()); | |
| 136 } | |
| 137 | |
| 138 leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); | |
| 139 if (!status.ok()) { | |
| 140 LOG(WARNING) << "Purge of leveldb subkeys of " << key << " failed: " | |
| 141 << status.ToString(); | |
| 142 } | |
| 143 } | |
| 144 | |
| 145 std::string ResourceCache::GetStringWithPrefix(const std::string& s) { | |
| 146 char buffer[sizeof(size_t)]; | |
| 147 size_t size = s.size(); | |
| 148 memcpy(buffer, &size, sizeof(size_t)); | |
| 149 return std::string(buffer, sizeof(size_t)) + s; | |
| 150 } | |
| 151 | |
| 152 std::string ResourceCache::CreatePathPrefix(const std::string& key) { | |
| 153 return GetStringWithPrefix(key); | |
| 154 } | |
| 155 | |
| 156 std::string ResourceCache::CreatePath(const std::string& key, | |
| 157 const std::string& subkey) { | |
| 158 return GetStringWithPrefix(key) + GetStringWithPrefix(subkey); | |
| 159 } | |
| 160 | |
| 161 std::string ResourceCache::GetSubkey(const std::string& path) { | |
| 162 // |path| was produced by CreatePath(). Skip the first key, then skip the | |
| 163 // size of the subkey. | |
| 164 if (path.size() < sizeof(size_t)) { | |
| 165 NOTREACHED(); | |
| 166 return EmptyString(); | |
| 167 } | |
| 168 | |
| 169 // Skip the first string. |offset| is the start of the second string, | |
| 170 // immediately preceded by its size. | |
| 171 const size_t* size = reinterpret_cast<const size_t*>(path.data()); | |
| 172 size_t offset = sizeof(size_t) + *size + sizeof(size_t); | |
| 173 if (path.size() < offset) { | |
| 174 NOTREACHED(); | |
| 175 return EmptyString(); | |
| 176 } | |
| 177 | |
| 178 // Skip the size of the second string. | |
| 179 size = reinterpret_cast<const size_t*>(path.data() + offset - sizeof(size_t)); | |
| 180 if (*size != path.size() - offset) { | |
| 181 NOTREACHED(); | |
| 182 return EmptyString(); | |
| 183 } | |
| 184 | |
| 185 return path.substr(offset, *size); | |
| 186 } | |
| 187 | |
| 188 } // namespace policy | |
| OLD | NEW |