Logo ROOT  
Reference Guide
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
Loading...
Searching...
No Matches
RPagePool.cxx
Go to the documentation of this file.
1/// \file RPagePool.cxx
2/// \ingroup NTuple
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2018-10-04
5
6/*************************************************************************
7 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
8 * All rights reserved. *
9 * *
10 * For the licensing terms see $ROOTSYS/LICENSE. *
11 * For the list of contributors see $ROOTSYS/README/CREDITS. *
12 *************************************************************************/
13
14#include <ROOT/RPagePool.hxx>
15#include <ROOT/RColumn.hxx>
16
17#include <TError.h>
18
19#include <algorithm>
20#include <cstdlib>
21#include <utility>
22
25{
26 assert(fLookupByBuffer.count(page.GetBuffer()) == 0);
27
28 const auto entryIndex = fEntries.size();
29
30 auto itrPageSet = fLookupByKey.find(key);
31 if (itrPageSet != fLookupByKey.end()) {
32 auto [itrEntryIdx, isNew] = itrPageSet->second.emplace(RPagePosition(page), entryIndex);
33 if (!isNew) {
34 assert(itrEntryIdx->second < fEntries.size());
35 // We require that pages cover pairwise distinct element ranges of the column
36 assert(fEntries[itrEntryIdx->second].fPage.GetGlobalRangeLast() == page.GetGlobalRangeLast());
37 fEntries[itrEntryIdx->second].fRefCounter += initialRefCounter;
38 return fEntries[itrEntryIdx->second];
39 }
40 } else {
41 fLookupByKey.emplace(key, std::map<RPagePosition, std::size_t>{{RPagePosition(page), entryIndex}});
42 }
43
44 fLookupByBuffer[page.GetBuffer()] = entryIndex;
45
46 return fEntries.emplace_back(REntry{std::move(page), key, initialRefCounter});
47}
48
50{
51 std::lock_guard<std::mutex> lockGuard(fLock);
52 return RPageRef(AddPage(std::move(page), key, 1).fPage, this);
53}
54
56{
57 std::lock_guard<std::mutex> lockGuard(fLock);
58 const auto &entry = AddPage(std::move(page), key, 0);
59 if (entry.fRefCounter == 0)
60 fUnusedPages[entry.fPage.GetClusterInfo().GetId()].emplace(entry.fPage.GetBuffer());
61}
62
63void ROOT::Internal::RPagePool::ErasePage(std::size_t entryIdx, decltype(fLookupByBuffer)::iterator lookupByBufferItr)
64{
65 fLookupByBuffer.erase(lookupByBufferItr);
66
67 auto itrPageSet = fLookupByKey.find(fEntries[entryIdx].fKey);
68 assert(itrPageSet != fLookupByKey.end());
69 itrPageSet->second.erase(RPagePosition(fEntries[entryIdx].fPage));
70 if (itrPageSet->second.empty())
71 fLookupByKey.erase(itrPageSet);
72
73 const auto N = fEntries.size();
74 assert(entryIdx < N);
75 if (entryIdx != (N - 1)) {
76 fLookupByBuffer[fEntries[N - 1].fPage.GetBuffer()] = entryIdx;
77 itrPageSet = fLookupByKey.find(fEntries[N - 1].fKey);
78 assert(itrPageSet != fLookupByKey.end());
79 auto itrEntryIdx = itrPageSet->second.find(RPagePosition(fEntries[N - 1].fPage));
80 assert(itrEntryIdx != itrPageSet->second.end());
81 itrEntryIdx->second = entryIdx;
82 fEntries[entryIdx] = std::move(fEntries[N - 1]);
83 }
84
85 fEntries.resize(N - 1);
86}
87
89{
90 if (page.IsNull()) return;
91 std::lock_guard<std::mutex> lockGuard(fLock);
92
93 auto itrLookup = fLookupByBuffer.find(page.GetBuffer());
94 assert(itrLookup != fLookupByBuffer.end());
95 const auto idx = itrLookup->second;
96
97 assert(fEntries[idx].fRefCounter >= 1);
98 if (--fEntries[idx].fRefCounter == 0) {
99 ErasePage(idx, itrLookup);
100 }
101}
102
104{
105 auto itr = fUnusedPages.find(page.GetClusterInfo().GetId());
106 assert(itr != fUnusedPages.end());
107 itr->second.erase(page.GetBuffer());
108 if (itr->second.empty())
109 fUnusedPages.erase(itr);
110}
111
113{
114 std::lock_guard<std::mutex> lockGuard(fLock);
115 auto itrPageSet = fLookupByKey.find(key);
116 if (itrPageSet == fLookupByKey.end())
117 return RPageRef();
118 assert(!itrPageSet->second.empty());
119
120 auto itrEntryIdx = itrPageSet->second.upper_bound(RPagePosition(globalIndex));
121 if (itrEntryIdx == itrPageSet->second.begin())
122 return RPageRef();
123
124 --itrEntryIdx;
125 if (fEntries[itrEntryIdx->second].fPage.Contains(globalIndex)) {
126 if (fEntries[itrEntryIdx->second].fRefCounter == 0)
127 RemoveFromUnusedPages(fEntries[itrEntryIdx->second].fPage);
128 fEntries[itrEntryIdx->second].fRefCounter++;
129 return RPageRef(fEntries[itrEntryIdx->second].fPage, this);
130 }
131 return RPageRef();
132}
133
135{
136 std::lock_guard<std::mutex> lockGuard(fLock);
137 auto itrPageSet = fLookupByKey.find(key);
138 if (itrPageSet == fLookupByKey.end())
139 return RPageRef();
140 assert(!itrPageSet->second.empty());
141
142 auto itrEntryIdx = itrPageSet->second.upper_bound(RPagePosition(localIndex));
143 if (itrEntryIdx == itrPageSet->second.begin())
144 return RPageRef();
145
146 --itrEntryIdx;
147 if (fEntries[itrEntryIdx->second].fPage.Contains(localIndex)) {
148 if (fEntries[itrEntryIdx->second].fRefCounter == 0)
149 RemoveFromUnusedPages(fEntries[itrEntryIdx->second].fPage);
150 fEntries[itrEntryIdx->second].fRefCounter++;
151 return RPageRef(fEntries[itrEntryIdx->second].fPage, this);
152 }
153 return RPageRef();
154}
155
157{
158 std::lock_guard<std::mutex> lockGuard(fLock);
159 auto itr = fUnusedPages.find(clusterId);
160 if (itr == fUnusedPages.end())
161 return;
162
163 for (auto pageBuffer : itr->second) {
164 const auto itrLookupByBuffer = fLookupByBuffer.find(pageBuffer);
165 assert(itrLookupByBuffer != fLookupByBuffer.end());
166 const auto entryIdx = itrLookupByBuffer->second;
167 assert(fEntries[entryIdx].fRefCounter == 0);
168 ErasePage(entryIdx, itrLookupByBuffer);
169 }
170
171 fUnusedPages.erase(itr);
172}
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define N
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:63
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:24
RPageRef GetPage(RKey key, ROOT::NTupleSize_t globalIndex)
Tries to find the page corresponding to column and index in the cache.
std::unordered_map< RKey, std::map< RPagePosition, std::size_t >, RKeyHasher > fLookupByKey
Used in GetPage() to find the right page in fEntries.
void PreloadPage(RPage page, RKey key)
Like RegisterPage() but the reference counter is initialized to 0.
Definition RPagePool.cxx:55
RPageRef RegisterPage(RPage page, RKey key)
Adds a new page to the pool.
Definition RPagePool.cxx:49
void RemoveFromUnusedPages(const RPage &page)
Called by GetPage(), when the reference counter increases from zero to one.
std::unordered_map< void *, std::size_t > fLookupByBuffer
Used in ReleasePage() to find the page index in fPages.
std::vector< REntry > fEntries
All cached pages in the page pool.
void ReleasePage(const RPage &page)
Give back a page to the pool and decrease the reference counter.
Definition RPagePool.cxx:88
Reference to a page stored in the page pool.
A page is a slice of a column that is mapped into memory.
Definition RPage.hxx:44
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
const_iterator begin() const
const_iterator end() const
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.
Every page in the page pool is annotated with a search key and a reference counter.
Definition RPagePool.hxx:74
Used in fLookupByKey to store both the absolute and the cluster-local page index of the referenced pa...
Definition RPagePool.hxx:83