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