147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/* 247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org * Copyright 2004 The WebRTC Project Authors. All rights reserved. 347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org * 447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org * Use of this source code is governed by a BSD-style license 547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org * that can be found in the LICENSE file in the root of the source 647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org * tree. An additional intellectual property rights grant can be found 747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org * in the file PATENTS. All contributing project authors may 847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org * be found in the AUTHORS file in the root of the source tree. 947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org */ 1047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 1147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <time.h> 1247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 1347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#if defined(WEBRTC_WIN) 1447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/win32.h" 1547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif 1647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 1747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/common.h" 1847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/diskcache.h" 1947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/fileutils.h" 2047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/pathutils.h" 2147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/stream.h" 2247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/stringencode.h" 2347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/stringutils.h" 2447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 2547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#ifdef _DEBUG 2647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#define TRANSPARENT_CACHE_NAMES 1 2747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#else // !_DEBUG 2847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#define TRANSPARENT_CACHE_NAMES 0 2947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif // !_DEBUG 3047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 3147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgnamespace rtc { 3247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 3347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgclass DiskCache; 3447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 3547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/////////////////////////////////////////////////////////////////////////////// 3647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// DiskCacheAdapter 3747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/////////////////////////////////////////////////////////////////////////////// 3847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 3947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgclass DiskCacheAdapter : public StreamAdapterInterface { 4047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgpublic: 4147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org DiskCacheAdapter(const DiskCache* cache, const std::string& id, size_t index, 4247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org StreamInterface* stream) 4347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org : StreamAdapterInterface(stream), cache_(cache), id_(id), index_(index) 4447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org { } 4547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org virtual ~DiskCacheAdapter() { 4647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Close(); 4747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org cache_->ReleaseResource(id_, index_); 4847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 4947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 5047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgprivate: 5147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org const DiskCache* cache_; 5247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org std::string id_; 5347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org size_t index_; 5447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}; 5547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 5647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/////////////////////////////////////////////////////////////////////////////// 5747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// DiskCache 5847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/////////////////////////////////////////////////////////////////////////////// 5947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 6047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgDiskCache::DiskCache() : max_cache_(0), total_size_(0), total_accessors_(0) { 6147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 6247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 6347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgDiskCache::~DiskCache() { 6447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org ASSERT(0 == total_accessors_); 6547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 6647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 6747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool DiskCache::Initialize(const std::string& folder, size_t size) { 6847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!folder_.empty() || !Filesystem::CreateFolder(folder)) 6947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 7047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 7147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org folder_ = folder; 7247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org max_cache_ = size; 7347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org ASSERT(0 == total_size_); 7447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 7547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!InitializeEntries()) 7647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 7747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 7847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return CheckLimit(); 7947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 8047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 8147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool DiskCache::Purge() { 8247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (folder_.empty()) 8347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 8447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 8547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (total_accessors_ > 0) { 8647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG_F(LS_WARNING) << "Cache files open"; 8747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 8847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 8947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 9047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!PurgeFiles()) 9147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 9247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 9347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org map_.clear(); 9447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return true; 9547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 9647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 9747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool DiskCache::LockResource(const std::string& id) { 9847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Entry* entry = GetOrCreateEntry(id, true); 9947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (LS_LOCKED == entry->lock_state) 10047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 10147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if ((LS_UNLOCKED == entry->lock_state) && (entry->accessors > 0)) 10247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 10347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if ((total_size_ > max_cache_) && !CheckLimit()) { 10447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG_F(LS_WARNING) << "Cache overfull"; 10547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 10647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 10747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org entry->lock_state = LS_LOCKED; 10847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return true; 10947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 11047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 11147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgStreamInterface* DiskCache::WriteResource(const std::string& id, size_t index) { 11247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Entry* entry = GetOrCreateEntry(id, false); 11347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (LS_LOCKED != entry->lock_state) 11447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 11547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 11647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org size_t previous_size = 0; 11747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org std::string filename(IdToFilename(id, index)); 11847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org FileStream::GetSize(filename, &previous_size); 11947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org ASSERT(previous_size <= entry->size); 12047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (previous_size > entry->size) { 12147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org previous_size = entry->size; 12247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 12347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 12447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org scoped_ptr<FileStream> file(new FileStream); 12547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!file->Open(filename, "wb", NULL)) { 12647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG_F(LS_ERROR) << "Couldn't create cache file"; 12747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 12847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 12947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 13047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org entry->streams = stdmax(entry->streams, index + 1); 13147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org entry->size -= previous_size; 13247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org total_size_ -= previous_size; 13347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 13447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org entry->accessors += 1; 13547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org total_accessors_ += 1; 13647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return new DiskCacheAdapter(this, id, index, file.release()); 13747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 13847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 13947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool DiskCache::UnlockResource(const std::string& id) { 14047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Entry* entry = GetOrCreateEntry(id, false); 14147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (LS_LOCKED != entry->lock_state) 14247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 14347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 14447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (entry->accessors > 0) { 14547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org entry->lock_state = LS_UNLOCKING; 14647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } else { 14747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org entry->lock_state = LS_UNLOCKED; 14847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org entry->last_modified = time(0); 14947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org CheckLimit(); 15047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 15147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return true; 15247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 15347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 15447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgStreamInterface* DiskCache::ReadResource(const std::string& id, 15547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org size_t index) const { 15647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org const Entry* entry = GetEntry(id); 15747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (LS_UNLOCKED != entry->lock_state) 15847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 15947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (index >= entry->streams) 16047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 16147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 16247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org scoped_ptr<FileStream> file(new FileStream); 16347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!file->Open(IdToFilename(id, index), "rb", NULL)) 16447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 16547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 16647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org entry->accessors += 1; 16747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org total_accessors_ += 1; 16847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return new DiskCacheAdapter(this, id, index, file.release()); 16947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 17047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 17147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool DiskCache::HasResource(const std::string& id) const { 17247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org const Entry* entry = GetEntry(id); 17347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return (NULL != entry) && (entry->streams > 0); 17447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 17547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 17647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool DiskCache::HasResourceStream(const std::string& id, size_t index) const { 17747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org const Entry* entry = GetEntry(id); 17847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if ((NULL == entry) || (index >= entry->streams)) 17947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 18047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 18147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org std::string filename = IdToFilename(id, index); 18247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 18347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return FileExists(filename); 18447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 18547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 18647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool DiskCache::DeleteResource(const std::string& id) { 18747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Entry* entry = GetOrCreateEntry(id, false); 18847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!entry) 18947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return true; 19047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 19147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if ((LS_UNLOCKED != entry->lock_state) || (entry->accessors > 0)) 19247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 19347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 19447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool success = true; 19547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org for (size_t index = 0; index < entry->streams; ++index) { 19647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org std::string filename = IdToFilename(id, index); 19747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 19847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!FileExists(filename)) 19947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org continue; 20047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 20147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!DeleteFile(filename)) { 20247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG_F(LS_ERROR) << "Couldn't remove cache file: " << filename; 20347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org success = false; 20447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 20547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 20647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 20747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org total_size_ -= entry->size; 20847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org map_.erase(id); 20947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return success; 21047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 21147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 21247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool DiskCache::CheckLimit() { 21347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#ifdef _DEBUG 21447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Temporary check to make sure everything is working correctly. 21547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org size_t cache_size = 0; 21647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org for (EntryMap::iterator it = map_.begin(); it != map_.end(); ++it) { 21747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org cache_size += it->second.size; 21847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 21947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org ASSERT(cache_size == total_size_); 22047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif // _DEBUG 22147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 22247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // TODO: Replace this with a non-brain-dead algorithm for clearing out the 22347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // oldest resources... something that isn't O(n^2) 22447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org while (total_size_ > max_cache_) { 22547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org EntryMap::iterator oldest = map_.end(); 22647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org for (EntryMap::iterator it = map_.begin(); it != map_.end(); ++it) { 22747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if ((LS_UNLOCKED != it->second.lock_state) || (it->second.accessors > 0)) 22847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org continue; 22947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org oldest = it; 23047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org break; 23147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 23247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (oldest == map_.end()) { 23347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG_F(LS_WARNING) << "All resources are locked!"; 23447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 23547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 23647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org for (EntryMap::iterator it = oldest++; it != map_.end(); ++it) { 23747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (it->second.last_modified < oldest->second.last_modified) { 23847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org oldest = it; 23947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 24047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 24147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!DeleteResource(oldest->first)) { 24247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG_F(LS_ERROR) << "Couldn't delete from cache!"; 24347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 24447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 24547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 24647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return true; 24747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 24847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 24947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstd::string DiskCache::IdToFilename(const std::string& id, size_t index) const { 25047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#ifdef TRANSPARENT_CACHE_NAMES 25147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // This escapes colons and other filesystem characters, so the user can't open 25247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // special devices (like "COM1:"), or access other directories. 25347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org size_t buffer_size = id.length()*3 + 1; 25447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org char* buffer = new char[buffer_size]; 25547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org encode(buffer, buffer_size, id.data(), id.length(), 25647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org unsafe_filename_characters(), '%'); 25747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // TODO: ASSERT(strlen(buffer) < FileSystem::MaxBasenameLength()); 25847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#else // !TRANSPARENT_CACHE_NAMES 25947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // We might want to just use a hash of the filename at some point, both for 26047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // obfuscation, and to avoid both filename length and escaping issues. 26147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org ASSERT(false); 26247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif // !TRANSPARENT_CACHE_NAMES 26347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 26447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org char extension[32]; 26547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org sprintfn(extension, ARRAY_SIZE(extension), ".%u", index); 26647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 26747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Pathname pathname; 26847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org pathname.SetFolder(folder_); 26947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org pathname.SetBasename(buffer); 27047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org pathname.SetExtension(extension); 27147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 27247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#ifdef TRANSPARENT_CACHE_NAMES 27347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org delete [] buffer; 27447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif // TRANSPARENT_CACHE_NAMES 27547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 27647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return pathname.pathname(); 27747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 27847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 27947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool DiskCache::FilenameToId(const std::string& filename, std::string* id, 28047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org size_t* index) const { 28147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Pathname pathname(filename); 28247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org unsigned tempdex; 28347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (1 != sscanf(pathname.extension().c_str(), ".%u", &tempdex)) 28447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 28547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 28647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *index = static_cast<size_t>(tempdex); 28747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 28847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org size_t buffer_size = pathname.basename().length() + 1; 28947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org char* buffer = new char[buffer_size]; 29047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org decode(buffer, buffer_size, pathname.basename().data(), 29147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org pathname.basename().length(), '%'); 29247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org id->assign(buffer); 29347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org delete [] buffer; 29447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return true; 29547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 29647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 29747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgDiskCache::Entry* DiskCache::GetOrCreateEntry(const std::string& id, 29847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool create) { 29947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org EntryMap::iterator it = map_.find(id); 30047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (it != map_.end()) 30147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return &it->second; 30247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!create) 30347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 30447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Entry e; 30547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org e.lock_state = LS_UNLOCKED; 30647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org e.accessors = 0; 30747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org e.size = 0; 30847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org e.streams = 0; 30947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org e.last_modified = time(0); 31047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org it = map_.insert(EntryMap::value_type(id, e)).first; 31147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return &it->second; 31247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 31347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 31447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid DiskCache::ReleaseResource(const std::string& id, size_t index) const { 31547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org const Entry* entry = GetEntry(id); 31647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!entry) { 31747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG_F(LS_WARNING) << "Missing cache entry"; 31847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org ASSERT(false); 31947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return; 32047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 32147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 32247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org entry->accessors -= 1; 32347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org total_accessors_ -= 1; 32447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 32547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (LS_UNLOCKED != entry->lock_state) { 32647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // This is safe, because locked resources only issue WriteResource, which 32747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // is non-const. Think about a better way to handle it. 32847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org DiskCache* this2 = const_cast<DiskCache*>(this); 32947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Entry* entry2 = this2->GetOrCreateEntry(id, false); 33047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 33147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org size_t new_size = 0; 33247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org std::string filename(IdToFilename(id, index)); 33347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org FileStream::GetSize(filename, &new_size); 33447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org entry2->size += new_size; 33547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org this2->total_size_ += new_size; 33647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 33747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if ((LS_UNLOCKING == entry->lock_state) && (0 == entry->accessors)) { 33847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org entry2->last_modified = time(0); 33947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org entry2->lock_state = LS_UNLOCKED; 34047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org this2->CheckLimit(); 34147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 34247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 34347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 34447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 34547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/////////////////////////////////////////////////////////////////////////////// 34647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 34747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} // namespace rtc 348