Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RPagePool.cxx
Go to the documentation of this file.
1/// \file RPagePool.cxx
2/// \author Jakob Blomer <jblomer@cern.ch>
3/// \date 2018-10-04
4
5/*************************************************************************
6 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13#include <ROOT/RPagePool.hxx>
14#include <ROOT/RPageStorage.hxx>
15#include <ROOT/RColumn.hxx>
16
17#include <TError.h>
18
19#include <algorithm>
20#include <cstdlib>
21#include <utility>
22
23ROOT::Internal::RPagePool::RPagePool(RPageSource &pageSource) : fPageSource(pageSource), fMetrics("RPagePool")
24{
26 fCounters = std::make_unique<RCounters>(
27 RCounters{*fMetrics.MakeCounter<RNTupleAtomicCounter *>("nPage", "", "number of currently cached pages")});
28}
29
31ROOT::Internal::RPagePool::AddPage(RPage page, const RKey &key, std::int64_t initialRefCounter)
32{
33 assert(fLookupByBuffer.count(page.GetBuffer()) == 0);
34
35 const auto entryIndex = fEntries.size();
36
37 auto itrPageSet = fLookupByKey.find(key);
38 if (itrPageSet != fLookupByKey.end()) {
39 auto [itrEntryIdx, isNew] = itrPageSet->second.emplace(RPagePosition(page), entryIndex);
40 if (!isNew) {
41 assert(itrEntryIdx->second < fEntries.size());
42 // We require that pages cover pairwise distinct element ranges of the column
43 assert(fEntries[itrEntryIdx->second].fPage.GetGlobalRangeLast() == page.GetGlobalRangeLast());
44 fEntries[itrEntryIdx->second].fRefCounter += initialRefCounter;
45 return fEntries[itrEntryIdx->second];
46 }
47 } else {
48 fLookupByKey.emplace(key, std::map<RPagePosition, std::size_t>{{RPagePosition(page), entryIndex}});
49 }
50
51 fLookupByBuffer[page.GetBuffer()] = entryIndex;
52
53 fCounters->fNPage.Inc();
54 return fEntries.emplace_back(REntry{std::move(page), key, initialRefCounter});
55}
56
58{
59 std::lock_guard<std::mutex> lockGuard(fLock);
60 return RPageRef(AddPage(std::move(page), key, 1).fPage, this);
61}
62
64{
65 auto p = std::make_pair(std::move(page), key);
66 PreloadPageV(std::span<std::pair<RPage, RKey>>(&p, 1));
67}
68
69void ROOT::Internal::RPagePool::PreloadPageV(std::span<std::pair<RPage, RKey>> pages)
70{
71 std::lock_guard<std::mutex> lockGuard(fLock);
72 for (auto &p : pages) {
73 const auto &entry = AddPage(std::move(p.first), p.second, 0);
74 if (entry.fRefCounter == 0)
75 AddToUnusedPages(entry.fPage);
76 }
77}
78
79void ROOT::Internal::RPagePool::ErasePage(std::size_t entryIdx, decltype(fLookupByBuffer)::iterator lookupByBufferItr)
80{
81 fLookupByBuffer.erase(lookupByBufferItr);
82
83 auto itrPageSet = fLookupByKey.find(fEntries[entryIdx].fKey);
84 assert(itrPageSet != fLookupByKey.end());
85 itrPageSet->second.erase(RPagePosition(fEntries[entryIdx].fPage));
86 if (itrPageSet->second.empty())
87 fLookupByKey.erase(itrPageSet);
88
89 const auto N = fEntries.size();
90 assert(entryIdx < N);
91 if (entryIdx != (N - 1)) {
92 fLookupByBuffer[fEntries[N - 1].fPage.GetBuffer()] = entryIdx;
93 itrPageSet = fLookupByKey.find(fEntries[N - 1].fKey);
94 assert(itrPageSet != fLookupByKey.end());
95 auto itrEntryIdx = itrPageSet->second.find(RPagePosition(fEntries[N - 1].fPage));
96 assert(itrEntryIdx != itrPageSet->second.end());
97 itrEntryIdx->second = entryIdx;
98 fEntries[entryIdx] = std::move(fEntries[N - 1]);
99 }
100
101 fCounters->fNPage.Dec();
102 fEntries.resize(N - 1);
103}
104
106{
107 if (page.IsNull()) return;
108 std::lock_guard<std::mutex> lockGuard(fLock);
109
110 auto itrLookup = fLookupByBuffer.find(page.GetBuffer());
111 assert(itrLookup != fLookupByBuffer.end());
112 const auto idx = itrLookup->second;
113
114 assert(fEntries[idx].fRefCounter >= 1);
115 if (--fEntries[idx].fRefCounter == 0) {
116 if (fPageSource.GetPinnedClusters().count(page.GetClusterInfo().GetId()) > 0) {
117 AddToUnusedPages(page);
118 } else {
119 ErasePage(idx, itrLookup);
120 }
121 }
122}
123
125{
126 fUnusedPages[page.GetClusterInfo().GetId()].emplace(page.GetBuffer());
127}
128
130{
131 auto itr = fUnusedPages.find(page.GetClusterInfo().GetId());
132 assert(itr != fUnusedPages.end());
133 itr->second.erase(page.GetBuffer());
134 if (itr->second.empty())
135 fUnusedPages.erase(itr);
136}
137
139{
140 std::lock_guard<std::mutex> lockGuard(fLock);
141 auto itrPageSet = fLookupByKey.find(key);
142 if (itrPageSet == fLookupByKey.end())
143 return RPageRef();
144 assert(!itrPageSet->second.empty());
145
146 auto itrEntryIdx = itrPageSet->second.upper_bound(RPagePosition(globalIndex));
147 if (itrEntryIdx == itrPageSet->second.begin())
148 return RPageRef();
149
150 --itrEntryIdx;
151 if (fEntries[itrEntryIdx->second].fPage.Contains(globalIndex)) {
152 if (fEntries[itrEntryIdx->second].fRefCounter == 0)
153 RemoveFromUnusedPages(fEntries[itrEntryIdx->second].fPage);
154 fEntries[itrEntryIdx->second].fRefCounter++;
155 return RPageRef(fEntries[itrEntryIdx->second].fPage, this);
156 }
157 return RPageRef();
158}
159
161{
162 std::lock_guard<std::mutex> lockGuard(fLock);
163 auto itrPageSet = fLookupByKey.find(key);
164 if (itrPageSet == fLookupByKey.end())
165 return RPageRef();
166 assert(!itrPageSet->second.empty());
167
168 auto itrEntryIdx = itrPageSet->second.upper_bound(RPagePosition(localIndex));
169 if (itrEntryIdx == itrPageSet->second.begin())
170 return RPageRef();
171
172 --itrEntryIdx;
173 if (fEntries[itrEntryIdx->second].fPage.Contains(localIndex)) {
174 if (fEntries[itrEntryIdx->second].fRefCounter == 0)
175 RemoveFromUnusedPages(fEntries[itrEntryIdx->second].fPage);
176 fEntries[itrEntryIdx->second].fRefCounter++;
177 return RPageRef(fEntries[itrEntryIdx->second].fPage, this);
178 }
179 return RPageRef();
180}
181
183{
184 std::lock_guard<std::mutex> lockGuard(fLock);
185 auto itr = fUnusedPages.find(clusterId);
186 if (itr == fUnusedPages.end())
187 return;
188
189 for (auto pageBuffer : itr->second) {
190 const auto itrLookupByBuffer = fLookupByBuffer.find(pageBuffer);
191 assert(itrLookupByBuffer != fLookupByBuffer.end());
192 const auto entryIdx = itrLookupByBuffer->second;
193 assert(fEntries[entryIdx].fRefCounter == 0);
194 ErasePage(entryIdx, itrLookupByBuffer);
195 }
196
197 fUnusedPages.erase(itr);
198}
#define N
winID h TVirtualViewer3D TVirtualGLPainter p
A thread-safe integral performance counter.
CounterPtrT MakeCounter(const std::string &name, Args &&... args)
std::unique_ptr< RCounters > fCounters
void ErasePage(std::size_t entryIdx, decltype(fLookupByBuffer)::iterator lookupByBufferItr)
Called both by ReleasePage() and by Evict() to remove an unused page from the pool.
Definition RPagePool.cxx:79
ROOT::Experimental::Detail::RNTupleMetrics fMetrics
The page pool counters are observed by the page source.
void Evict(ROOT::DescriptorId_t clusterId)
Removes unused pages (pages with reference counter 0) from the page pool.
REntry & AddPage(RPage page, const RKey &key, std::int64_t initialRefCounter)
Add a new page to the fLookupByBuffer and fLookupByKey data structures.
Definition RPagePool.cxx:31
RPageRef GetPage(RKey key, ROOT::NTupleSize_t globalIndex)
Tries to find the page corresponding to column and index in the cache.
RPagePool(RPageSource &pageSource)
Definition RPagePool.cxx:23
void AddToUnusedPages(const RPage &page)
Called by PreloadPage() if the page at hand is new and thus added with ref counter 0.
void PreloadPage(RPage page, RKey key)
Like RegisterPage() but the reference counter is initialized to 0.
Definition RPagePool.cxx:63
RPageRef RegisterPage(RPage page, RKey key)
Adds a new page to the pool.
Definition RPagePool.cxx:57
void RemoveFromUnusedPages(const RPage &page)
Called by GetPage(), when the reference counter increases from zero to one.
void ReleasePage(const RPage &page)
Give back a page to the pool and decrease the reference counter.
void PreloadPageV(std::span< std::pair< RPage, RKey > > pages)
Definition RPagePool.cxx:69
Reference to a page stored in the page pool.
Abstract interface to read data from an ntuple.
ROOT::DescriptorId_t GetId() const
Definition RPage.hxx:62
A page is a slice of a column that is mapped into memory.
Definition RPage.hxx:43
bool IsNull() const
Definition RPage.hxx:173
ROOT::NTupleSize_t GetGlobalRangeLast() const
Definition RPage.hxx:123
void * GetBuffer() const
Definition RPage.hxx:142
const RClusterInfo & GetClusterInfo() const
Definition RPage.hxx:126
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
std::uint64_t DescriptorId_t
Distriniguishes elements of the same type within a descriptor, e.g. different fields.
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
Performance counters that get registered in fMetrics.
Every page in the page pool is annotated with a search key and a reference counter.
Definition RPagePool.hxx:78
Used in fLookupByKey to store both the absolute and the cluster-local page index of the referenced pa...
Definition RPagePool.hxx:87