1#ifndef OSMSCOUT_NUMERICINDEX_H
2#define OSMSCOUT_NUMERICINDEX_H
56 std::vector<Entry> entries;
58 inline bool IndexIsValid(
size_t index)
const
60 return index<entries.size();
64 using PageRef = std::shared_ptr<Page>;
66 using PageSimpleCache = std::unordered_map<N, PageRef>;
71 struct NumericIndexCacheValueSizer :
public PageCache::ValueSizer
73 size_t GetSize(
const PageRef& value)
const
75 return sizeof(value)+
sizeof(Page)+
sizeof(Entry)*value->entries.size();
83 mutable FileScanner scanner;
88 std::vector<uint32_t> pageCounts;
92 size_t simpleCacheMaxLevel;
93 mutable std::vector<PageSimpleCache> simplePageCache;
94 mutable std::vector<PageCache> pageCaches;
96 mutable std::mutex accessMutex;
99 size_t GetPageIndex(
const Page& page, N
id)
const;
100 void ReadPage(
FileOffset offset, PageRef& page)
const;
101 void InitializeCache();
108 bool Open(
const std::string& path,
116 template<
typename IteratorIn>
120 std::vector<FileOffset>& offsets)
const;
128 : filepart(filename),
146 inline size_t NumericIndex<N>::GetPageIndex(
const Page& page, N
id)
const
148 size_t size=page.entries.size();
156 while (left<=right) {
157 size_t mid=(left+right)/2;
159 if (page.entries[mid].startId<=
id &&
160 (mid+1>=size || page.entries[mid+1].startId>
id)) {
164 if (page.entries[mid].startId<
id) {
181 inline void NumericIndex<N>::ReadPage(
FileOffset offset, PageRef& page)
const
184 page=std::make_shared<Page>();
187 page->entries.clear();
190 page->entries.reserve(pageSize/4);
192 scanner.SetPos(offset);
203 while (currentPos<pageSize &&
204 buffer[currentPos]!=0) {
205 unsigned int idBytes;
206 unsigned int fileOffsetBytes;
219 currentPos+=fileOffsetBytes;
221 entry.startId=prevId+curId;
222 entry.fileOffset=prefFileOffset+curFileOffset;
226 prevId=entry.startId;
227 prefFileOffset=entry.fileOffset;
229 page->entries.push_back(entry);
234 void NumericIndex<N>::InitializeCache()
236 size_t currentCacheSize=cacheSize;
237 size_t requiredCacheSize=0;
239 for (
const auto count : pageCounts) {
240 requiredCacheSize+=count;
243 if (requiredCacheSize>cacheSize) {
244 log.Warn() <<
"Warning: Index " << filepart <<
" has cache size " << cacheSize<<
", but requires cache size " << requiredCacheSize <<
" to load index completely into cache!";
247 simpleCacheMaxLevel=0;
248 for (
size_t level=1; level<pageCounts.size(); level++) {
249 size_t resultingCacheSize;
251 simplePageCache.push_back(PageSimpleCache());
253 if (pageCounts[level]>currentCacheSize) {
254 resultingCacheSize=currentCacheSize;
257 pageCaches.push_back(PageCache(resultingCacheSize));
260 resultingCacheSize=pageCounts[level];
261 currentCacheSize-=pageCounts[level];
263 simpleCacheMaxLevel=level;
265 pageCaches.push_back(PageCache(0));
277 scanner.Open(filename,
278 FileScanner::FastRandom,
281 pageSize=scanner.ReadUInt32Number();
282 scanner.ReadUInt32Number();
284 levels=scanner.ReadUInt32();
285 pageCounts.resize(levels);
287 FileOffset lastLevelPageStart=scanner.ReadFileOffset();
288 FileOffset indexPageCountsOffset=scanner.ReadFileOffset();
290 scanner.SetPos(indexPageCountsOffset);
291 for (
size_t level=0; level<levels; level++) {
292 pageCounts[level]=scanner.ReadUInt32Number();
296 buffer=
new char[pageSize];
300 ReadPage(lastLevelPageStart,root);
306 scanner.CloseFailsafe();
310 return !scanner.HasError();
317 if (scanner.IsOpen()) {
323 scanner.CloseFailsafe();
333 return scanner.IsOpen();
347 std::lock_guard<std::mutex> lock(accessMutex);
351 size_t r=GetPageIndex(*root,
id);
354 if (!root->IndexIsValid(r)) {
359 const Entry& rootEntry=root->entries[r];
363 offset=rootEntry.fileOffset;
365 N startId=rootEntry.startId;
366 for (
size_t level=0; level+2<=levels; level++) {
368 if (level<=simpleCacheMaxLevel) {
369 auto cacheRef=simplePageCache[level].find(startId);
371 if (cacheRef==simplePageCache[level].end()) {
374 ReadPage(offset,pageRef);
376 simplePageCache[level].emplace(startId,pageRef);
379 pageRef=cacheRef->second;
385 if (!pageCaches[level].GetEntry(startId,cacheRef)) {
386 typename PageCache::CacheEntry cacheEntry(startId);
388 cacheRef=pageCaches[level].SetEntry(cacheEntry);
390 ReadPage(offset,cacheRef->value);
393 pageRef=cacheRef->value;
398 size_t i=GetPageIndex(page,
id);
400 if (!page.IndexIsValid(i)) {
405 const Entry& entry=page.entries[i];
409 startId=entry.startId;
410 offset=entry.fileOffset;
431 template<
typename IteratorIn>
435 std::vector<FileOffset>& offsets)
const
438 offsets.reserve(size);
440 for (IteratorIn idIter=begin; idIter!=end; ++idIter) {
445 offsets.push_back(offset);
459 memory+=root->entries.size()*
sizeof(Entry);
462 for (
size_t i=0; i<pageCaches.size(); i++) {
463 pages+=pageCaches[i].GetSize();
464 memory+=
sizeof(pageCaches[i])+pageCaches[i].GetMemory(NumericIndexCacheValueSizer());
467 log.Info() <<
"Index " << filepart <<
": " << pages <<
" pages, memory " << memory;
typename OrderList::iterator CacheRef
Definition Cache.h:98
Definition Exception.h:73
std::string GetDescription() const override
bool IsOpen() const
Definition NumericIndex.h:331
bool Close()
Definition NumericIndex.h:314
bool GetOffsets(IteratorIn begin, IteratorIn end, size_t size, std::vector< FileOffset > &offsets) const
Definition NumericIndex.h:432
virtual ~NumericIndex()
Definition NumericIndex.h:135
bool GetOffset(const N &id, FileOffset &offset) const
Definition NumericIndex.h:342
void DumpStatistics() const
Definition NumericIndex.h:453
bool Open(const std::string &path, bool memoryMapped)
Definition NumericIndex.h:271
NumericIndex(const std::string &filename, size_t cacheSize)
Definition NumericIndex.h:126
OSMSCOUT_API std::string AppendFileToDir(const std::string &dir, const std::string &file)
OSMSCOUT_API Log log
Definition LoggerImpl.h:95
unsigned int DecodeNumber(const char *buffer, N &number)
Definition Number.h:294
uint64_t FileOffset
Definition OSMScoutTypes.h:46