1// Copyright (c) 2012 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 "storage/common/blob/shareable_file_reference.h"
6
7#include <map>
8
9#include "base/lazy_instance.h"
10#include "base/message_loop/message_loop_proxy.h"
11#include "base/task_runner.h"
12#include "base/threading/non_thread_safe.h"
13
14namespace storage {
15
16namespace {
17
18// A shareable file map with enforcement of thread checker.
19class ShareableFileMap : public base::NonThreadSafe {
20 public:
21  typedef std::map<base::FilePath, ShareableFileReference*> FileMap;
22  typedef FileMap::iterator iterator;
23  typedef FileMap::key_type key_type;
24  typedef FileMap::value_type value_type;
25
26  ShareableFileMap() {}
27
28  ~ShareableFileMap() {
29    DetachFromThread();
30  }
31
32  iterator Find(key_type key) {
33    DCHECK(CalledOnValidThread());
34    return file_map_.find(key);
35  }
36
37  iterator End() {
38    DCHECK(CalledOnValidThread());
39    return file_map_.end();
40  }
41
42  std::pair<iterator, bool> Insert(value_type value) {
43    DCHECK(CalledOnValidThread());
44    return file_map_.insert(value);
45  }
46
47  void Erase(key_type key) {
48    DCHECK(CalledOnValidThread());
49    file_map_.erase(key);
50  }
51
52 private:
53  FileMap file_map_;
54  DISALLOW_COPY_AND_ASSIGN(ShareableFileMap);
55};
56
57base::LazyInstance<ShareableFileMap> g_file_map = LAZY_INSTANCE_INITIALIZER;
58
59}  // namespace
60
61// static
62scoped_refptr<ShareableFileReference> ShareableFileReference::Get(
63    const base::FilePath& path) {
64  ShareableFileMap::iterator found = g_file_map.Get().Find(path);
65  ShareableFileReference* reference =
66      (found == g_file_map.Get().End()) ? NULL : found->second;
67  return scoped_refptr<ShareableFileReference>(reference);
68}
69
70// static
71scoped_refptr<ShareableFileReference> ShareableFileReference::GetOrCreate(
72    const base::FilePath& path,
73    FinalReleasePolicy policy,
74    base::TaskRunner* file_task_runner) {
75  return GetOrCreate(
76      ScopedFile(path, static_cast<ScopedFile::ScopeOutPolicy>(policy),
77                 file_task_runner));
78}
79
80// static
81scoped_refptr<ShareableFileReference> ShareableFileReference::GetOrCreate(
82    ScopedFile scoped_file) {
83  if (scoped_file.path().empty())
84    return scoped_refptr<ShareableFileReference>();
85
86  typedef std::pair<ShareableFileMap::iterator, bool> InsertResult;
87  // Required for VS2010:
88  // http://connect.microsoft.com/VisualStudio/feedback/
89  // details/520043/error-converting-from-null-to-a-pointer-type-in-std-pair
90  storage::ShareableFileReference* null_reference = NULL;
91  InsertResult result = g_file_map.Get().Insert(
92      ShareableFileMap::value_type(scoped_file.path(), null_reference));
93  if (result.second == false) {
94    scoped_file.Release();
95    return scoped_refptr<ShareableFileReference>(result.first->second);
96  }
97
98  // Wasn't in the map, create a new reference and store the pointer.
99  scoped_refptr<ShareableFileReference> reference(
100      new ShareableFileReference(scoped_file.Pass()));
101  result.first->second = reference.get();
102  return reference;
103}
104
105void ShareableFileReference::AddFinalReleaseCallback(
106    const FinalReleaseCallback& callback) {
107  DCHECK(g_file_map.Get().CalledOnValidThread());
108  scoped_file_.AddScopeOutCallback(callback, NULL);
109}
110
111ShareableFileReference::ShareableFileReference(ScopedFile scoped_file)
112    : scoped_file_(scoped_file.Pass()) {
113  DCHECK(g_file_map.Get().Find(path())->second == NULL);
114}
115
116ShareableFileReference::~ShareableFileReference() {
117  DCHECK(g_file_map.Get().Find(path())->second == this);
118  g_file_map.Get().Erase(path());
119}
120
121}  // namespace storage
122