Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RFile.cxx
Go to the documentation of this file.
1 /// \file v7/src/RFile.cxx
2 /// \ingroup Base ROOT7
3 /// \author Axel Naumann <axel@cern.ch>
4 /// \date 2015-07-31
5 /// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6 /// is welcome!
7 
8 /*************************************************************************
9  * Copyright (C) 1995-2016, Rene Brun and Fons Rademakers. *
10  * All rights reserved. *
11  * *
12  * For the licensing terms see $ROOTSYS/LICENSE. *
13  * For the list of contributors see $ROOTSYS/README/CREDITS. *
14  *************************************************************************/
15 
16 #include "ROOT/RFile.hxx"
17 #include "TFile.h"
18 
19 #include <memory>
20 #include <mutex>
21 #include <string>
22 
23 ROOT::Experimental::RDirectory &ROOT::Experimental::RDirectory::Heap()
24 {
25  static RDirectory heapDir;
26  return heapDir;
27 }
28 
29 namespace ROOT {
30 namespace Experimental {
31 namespace Internal {
32 // This will have to move to some "semi-internal" header.
33 /** \class RFileStorageInterface
34  Base class for RFile storage backends.
35  */
36 class RFileStorageInterface {
37 public:
38  virtual void Flush() = 0;
39  virtual void Close() = 0;
40  virtual ~RFileStorageInterface() = default;
41  virtual void WriteMemoryWithType(std::string_view name, const void *address, TClass *cl) = 0;
42 };
43 
44 // make_shared<RFile> doesn't work, as RFile() is private. Take detour
45 // through a friend instead.
46 class RFileSharedPtrCtor: public ROOT::Experimental::RFile {
47 public:
48  RFileSharedPtrCtor(std::unique_ptr<RFileStorageInterface> &&storage): RFile(std::move(storage)) {}
49 };
50 } // namespace Internal
51 } // namespace Experimental
52 } // namespace ROOT
53 
54 namespace {
55 /// We cannot afford users not closing their files. Yes, we return a unique_ptr -
56 /// but that might be stored in an object that itself leaks. That would leave
57 /// the RFile unclosed and data corrupted / not written. Instead, keep a
58 /// collection of all opened writable RFiles and close them at destruction time,
59 /// explicitly.
60 static void AddFilesToClose(std::weak_ptr<ROOT::Experimental::RFile> pFile)
61 {
62  struct CloseFiles_t {
63  std::vector<std::weak_ptr<ROOT::Experimental::RFile>> fFiles;
64  std::mutex fMutex;
65  ~CloseFiles_t()
66  {
67  for (auto &wFile: fFiles) {
68  if (auto sFile = wFile.lock()) {
69  sFile->Flush(); // or Close()? but what if there's still a Write()?
70  }
71  }
72  }
73  };
74  static CloseFiles_t closer;
75 
76  std::lock_guard<std::mutex> lock(closer.fMutex);
77  closer.fFiles.emplace_back(pFile);
78 }
79 
80 /** \class TV6Storage
81  RFile for a ROOT v6 storage backend.
82  */
83 class TV6Storage: public ROOT::Experimental::Internal::RFileStorageInterface {
84  ::TFile *fOldFile;
85 
86 public:
87  TV6Storage(const std::string &name, const std::string &mode): fOldFile(::TFile::Open(name.c_str(), mode.c_str())) {}
88 
89  void Flush() final { fOldFile->Flush(); }
90 
91  void Close() final { fOldFile->Close(); }
92 
93  ~TV6Storage() { delete fOldFile; }
94 
95  void WriteMemoryWithType(std::string_view name, const void *address, TClass *cl) final
96  {
97  fOldFile->WriteObjectAny(address, cl, std::string(name).c_str());
98  }
99 };
100 } // namespace
101 
102 ROOT::Experimental::RFilePtr::RFilePtr(std::shared_ptr<ROOT::Experimental::RFile> &&file): fFile(std::move(file))
103 {
104  AddFilesToClose(fFile);
105 }
106 
107 namespace {
108 static std::string GetV6RFileOpts(const char *mode, const ROOT::Experimental::RFile::Options_t &opts)
109 {
110  std::string ret(mode);
111  if (opts.fCachedRead)
112  ret += " CACHEREAD ";
113  if (opts.fAsynchronousOpen && opts.fAsyncTimeout > 0)
114  ret += " TIMEOUT=" + std::to_string(opts.fAsyncTimeout) + " ";
115  return ret;
116 }
117 
118 static std::mutex &GetCacheDirMutex()
119 {
120  static std::mutex sMutex;
121  return sMutex;
122 }
123 
124 static std::unique_ptr<ROOT::Experimental::Internal::RFileStorageInterface>
125 OpenV6RFile(std::string_view name, const char *mode, const ROOT::Experimental::RFile::Options_t &opts)
126 {
127  // Set and re-set the cache dir.
128  // FIXME: do not modify a static here, pass this to the underlying Open.
129  struct SetCacheDirRAII_t {
130  std::string fOldCacheDir;
131  std::lock_guard<std::mutex> fLock;
132 
133  SetCacheDirRAII_t(bool need): fLock(GetCacheDirMutex())
134  {
135  if (need)
136  fOldCacheDir = ::TFile::GetCacheFileDir();
137  }
138 
139  ~SetCacheDirRAII_t()
140  {
141  if (!fOldCacheDir.empty())
142  ::TFile::SetCacheFileDir(fOldCacheDir.c_str());
143  }
144  } setCacheDirRAII(opts.fCachedRead);
145 
146  auto v6storage = std::make_unique<TV6Storage>(std::string(name), GetV6RFileOpts(mode, opts));
147 
148  using namespace ROOT::Experimental::Internal;
149  return std::unique_ptr<RFileStorageInterface>{std::move(v6storage)};
150 }
151 } // namespace
152 
153 ROOT::Experimental::RFilePtr ROOT::Experimental::RFile::Open(std::string_view name,
154  const Options_t &opts /*= Options_t()*/)
155 {
156  // will become delegation to RFileSystemFile, TWebFile etc.
157  using namespace Internal;
158  auto file = std::make_shared<RFileSharedPtrCtor>(OpenV6RFile(name, "READ", opts));
159  return ROOT::Experimental::RFilePtr(std::move(file));
160 }
161 
162 ROOT::Experimental::RFilePtr ROOT::Experimental::RFile::Create(std::string_view name,
163  const Options_t &opts /*= Options_t()*/)
164 {
165  // will become delegation to RFileSystemFile, TWebFile etc.
166  using namespace Internal;
167  auto file = std::make_shared<RFileSharedPtrCtor>(OpenV6RFile(name, "CREATE", opts));
168  return ROOT::Experimental::RFilePtr(std::move(file));
169 }
170 
171 ROOT::Experimental::RFilePtr ROOT::Experimental::RFile::Recreate(std::string_view name,
172  const Options_t &opts /*= Options_t()*/)
173 {
174  // will become delegation to RFileSystemFile, TWebFile etc.
175  using namespace Internal;
176  auto file = std::make_shared<RFileSharedPtrCtor>(OpenV6RFile(name, "RECREATE", opts));
177  return ROOT::Experimental::RFilePtr(std::move(file));
178 }
179 
180 ROOT::Experimental::RFilePtr ROOT::Experimental::RFile::OpenForUpdate(std::string_view name,
181  const Options_t &opts /*= Options_t()*/)
182 {
183  // will become delegation to RFileSystemFile, TWebFile etc.
184  using namespace Internal;
185  auto file = std::make_shared<RFileSharedPtrCtor>(OpenV6RFile(name, "UPDATE", opts));
186  return ROOT::Experimental::RFilePtr(std::move(file));
187 }
188 
189 std::string ROOT::Experimental::RFile::SetCacheDir(std::string_view path)
190 {
191  std::lock_guard<std::mutex> lock(GetCacheDirMutex());
192 
193  std::string ret = ::TFile::GetCacheFileDir();
194  ::TFile::SetCacheFileDir(std::string(path).c_str());
195  return ret;
196 }
197 
198 std::string ROOT::Experimental::RFile::GetCacheDir()
199 {
200  std::lock_guard<std::mutex> lock(GetCacheDirMutex());
201  return ::TFile::GetCacheFileDir();
202 }
203 
204 // Implement outlined, to hide implementation of RFileStorageInterface from
205 // header.
206 ROOT::Experimental::RFile::RFile(std::unique_ptr<ROOT::Experimental::Internal::RFileStorageInterface> &&storage)
207  : fStorage(std::move(storage))
208 {}
209 
210 // Implement outlined, to hide implementation of RFileStorageInterface from
211 // header.
212 ROOT::Experimental::RFile::~RFile() = default;
213 
214 void ROOT::Experimental::RFile::Flush()
215 {
216  fStorage->Flush();
217 }
218 void ROOT::Experimental::RFile::Close()
219 {
220  fStorage->Close();
221 }
222 void ROOT::Experimental::RFile::WriteMemoryWithType(std::string_view name, const void *address, TClass *cl)
223 {
224  fStorage->WriteMemoryWithType(name, address, cl);
225 }