/* * Copyright 2013-2014, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #ifndef HEAP_CACHE_H #define HEAP_CACHE_H #include #include #include #include #include using BPackageKit::BHPKG::BAbstractBufferedDataReader; using BPackageKit::BHPKG::BDataReader; class CachedDataReader : public BAbstractBufferedDataReader { public: CachedDataReader(); virtual ~CachedDataReader(); status_t Init(BAbstractBufferedDataReader* reader, off_t size); virtual status_t ReadDataToOutput(off_t offset, size_t size, BDataIO* output); private: class CacheLineLocker : public DoublyLinkedListLinkImpl { public: CacheLineLocker(CachedDataReader* reader, off_t cacheLineOffset) : fReader(reader), fOffset(cacheLineOffset) { fReader->_LockCacheLine(this); } ~CacheLineLocker() { fReader->_UnlockCacheLine(this); } off_t Offset() const { return fOffset; } CacheLineLocker*& HashNext() { return fHashNext; } DoublyLinkedList& Queue() { return fQueue; } void Wait(mutex& lock) { fWaitCondition.Init(this, "cached reader line locker"); ConditionVariableEntry waitEntry; fWaitCondition.Add(&waitEntry); mutex_unlock(&lock); waitEntry.Wait(); mutex_lock(&lock); } void WakeUp() { fWaitCondition.NotifyOne(); } private: CachedDataReader* fReader; off_t fOffset; CacheLineLocker* fHashNext; DoublyLinkedList fQueue; ConditionVariable fWaitCondition; }; friend class CacheLineLocker; struct LockerHashDefinition { typedef off_t KeyType; typedef CacheLineLocker ValueType; size_t HashKey(off_t key) const { return size_t(key / kCacheLineSize); } size_t Hash(const CacheLineLocker* value) const { return HashKey(value->Offset()); } bool Compare(off_t key, const CacheLineLocker* value) const { return value->Offset() == key; } CacheLineLocker*& GetLink(CacheLineLocker* value) const { return value->HashNext(); } }; typedef BOpenHashTable LockerTable; struct PagesDataOutput; private: status_t _ReadCacheLine(off_t lineOffset, size_t lineSize, off_t requestOffset, size_t requestLength, BDataIO* output); void _DiscardPages(vm_page** pages, size_t firstPage, size_t pageCount); void _CachePages(vm_page** pages, size_t firstPage, size_t pageCount); status_t _WritePages(vm_page** pages, size_t pagesRelativeOffset, size_t requestLength, BDataIO* output); status_t _ReadIntoPages(vm_page** pages, size_t firstPage, size_t pageCount); void _LockCacheLine(CacheLineLocker* lineLocker); void _UnlockCacheLine(CacheLineLocker* lineLocker); private: static const size_t kCacheLineSize = 64 * 1024; static const size_t kPagesPerCacheLine = kCacheLineSize / B_PAGE_SIZE; private: mutex fLock; BAbstractBufferedDataReader* fReader; VMCache* fCache; LockerTable fCacheLineLockers; }; #endif // HEAP_CACHE_H