146122852SIngo Weinhold/*
232832cbeSIngo Weinhold * Copyright 2013-2014, Ingo Weinhold, ingo_weinhold@gmx.de.
346122852SIngo Weinhold * Distributed under the terms of the MIT License.
446122852SIngo Weinhold */
546122852SIngo Weinhold#ifndef HEAP_CACHE_H
646122852SIngo Weinhold#define HEAP_CACHE_H
746122852SIngo Weinhold
846122852SIngo Weinhold
946122852SIngo Weinhold#include <package/hpkg/DataReader.h>
1046122852SIngo Weinhold
1146122852SIngo Weinhold#include <condition_variable.h>
1246122852SIngo Weinhold#include <util/DoublyLinkedList.h>
1346122852SIngo Weinhold#include <util/OpenHashTable.h>
1446122852SIngo Weinhold#include <vm/vm_types.h>
1546122852SIngo Weinhold
1646122852SIngo Weinhold
1746122852SIngo Weinholdusing BPackageKit::BHPKG::BAbstractBufferedDataReader;
1846122852SIngo Weinholdusing BPackageKit::BHPKG::BDataReader;
1946122852SIngo Weinhold
2046122852SIngo Weinhold
2146122852SIngo Weinholdclass CachedDataReader : public BAbstractBufferedDataReader {
2246122852SIngo Weinholdpublic:
2346122852SIngo Weinhold								CachedDataReader();
2446122852SIngo Weinhold	virtual						~CachedDataReader();
2546122852SIngo Weinhold
2646122852SIngo Weinhold			status_t			Init(BAbstractBufferedDataReader* reader,
2746122852SIngo Weinhold									off_t size);
2846122852SIngo Weinhold
2946122852SIngo Weinhold	virtual	status_t			ReadDataToOutput(off_t offset, size_t size,
3032832cbeSIngo Weinhold									BDataIO* output);
3146122852SIngo Weinhold
3246122852SIngo Weinholdprivate:
3346122852SIngo Weinhold			class CacheLineLocker
3446122852SIngo Weinhold				: public DoublyLinkedListLinkImpl<CacheLineLocker> {
3546122852SIngo Weinhold			public:
3646122852SIngo Weinhold				CacheLineLocker(CachedDataReader* reader, off_t cacheLineOffset)
3746122852SIngo Weinhold					:
3846122852SIngo Weinhold					fReader(reader),
3946122852SIngo Weinhold					fOffset(cacheLineOffset)
4046122852SIngo Weinhold				{
4146122852SIngo Weinhold					fReader->_LockCacheLine(this);
4246122852SIngo Weinhold				}
4346122852SIngo Weinhold
4446122852SIngo Weinhold				~CacheLineLocker()
4546122852SIngo Weinhold				{
4646122852SIngo Weinhold					fReader->_UnlockCacheLine(this);
4746122852SIngo Weinhold				}
4846122852SIngo Weinhold
4946122852SIngo Weinhold				off_t Offset() const
5046122852SIngo Weinhold				{
5146122852SIngo Weinhold					return fOffset;
5246122852SIngo Weinhold				}
5346122852SIngo Weinhold
5446122852SIngo Weinhold				CacheLineLocker*& HashNext()
5546122852SIngo Weinhold				{
5646122852SIngo Weinhold					return fHashNext;
5746122852SIngo Weinhold				}
5846122852SIngo Weinhold
5946122852SIngo Weinhold				DoublyLinkedList<CacheLineLocker>& Queue()
6046122852SIngo Weinhold				{
6146122852SIngo Weinhold					return fQueue;
6246122852SIngo Weinhold				}
6346122852SIngo Weinhold
6446122852SIngo Weinhold				void Wait(mutex& lock)
6546122852SIngo Weinhold				{
6646122852SIngo Weinhold					fWaitCondition.Init(this, "cached reader line locker");
6746122852SIngo Weinhold					ConditionVariableEntry waitEntry;
6846122852SIngo Weinhold					fWaitCondition.Add(&waitEntry);
6946122852SIngo Weinhold					mutex_unlock(&lock);
7046122852SIngo Weinhold					waitEntry.Wait();
7146122852SIngo Weinhold					mutex_lock(&lock);
7246122852SIngo Weinhold				}
7346122852SIngo Weinhold
7446122852SIngo Weinhold				void WakeUp()
7546122852SIngo Weinhold				{
7646122852SIngo Weinhold					fWaitCondition.NotifyOne();
7746122852SIngo Weinhold				}
7846122852SIngo Weinhold
7946122852SIngo Weinhold			private:
8046122852SIngo Weinhold				CachedDataReader*					fReader;
8146122852SIngo Weinhold				off_t								fOffset;
8246122852SIngo Weinhold				CacheLineLocker*					fHashNext;
8346122852SIngo Weinhold				DoublyLinkedList<CacheLineLocker>	fQueue;
8446122852SIngo Weinhold				ConditionVariable					fWaitCondition;
8546122852SIngo Weinhold			};
8646122852SIngo Weinhold
8746122852SIngo Weinhold			friend class CacheLineLocker;
8846122852SIngo Weinhold
8946122852SIngo Weinhold			struct LockerHashDefinition {
9046122852SIngo Weinhold				typedef off_t			KeyType;
9146122852SIngo Weinhold				typedef	CacheLineLocker	ValueType;
9246122852SIngo Weinhold
9346122852SIngo Weinhold				size_t HashKey(off_t key) const
9446122852SIngo Weinhold				{
9546122852SIngo Weinhold					return size_t(key / kCacheLineSize);
9646122852SIngo Weinhold				}
9746122852SIngo Weinhold
9846122852SIngo Weinhold				size_t Hash(const CacheLineLocker* value) const
9946122852SIngo Weinhold				{
10046122852SIngo Weinhold					return HashKey(value->Offset());
10146122852SIngo Weinhold				}
10246122852SIngo Weinhold
10346122852SIngo Weinhold				bool Compare(off_t key, const CacheLineLocker* value) const
10446122852SIngo Weinhold				{
10546122852SIngo Weinhold					return value->Offset() == key;
10646122852SIngo Weinhold				}
10746122852SIngo Weinhold
10846122852SIngo Weinhold				CacheLineLocker*& GetLink(CacheLineLocker* value) const
10946122852SIngo Weinhold				{
11046122852SIngo Weinhold					return value->HashNext();
11146122852SIngo Weinhold				}
11246122852SIngo Weinhold			};
11346122852SIngo Weinhold
11446122852SIngo Weinhold			typedef BOpenHashTable<LockerHashDefinition> LockerTable;
11546122852SIngo Weinhold
11646122852SIngo Weinhold			struct PagesDataOutput;
11746122852SIngo Weinhold
11846122852SIngo Weinholdprivate:
11946122852SIngo Weinhold			status_t			_ReadCacheLine(off_t lineOffset,
12046122852SIngo Weinhold									size_t lineSize, off_t requestOffset,
12132832cbeSIngo Weinhold							 		size_t requestLength, BDataIO* output);
12246122852SIngo Weinhold
12346122852SIngo Weinhold			void				_DiscardPages(vm_page** pages, size_t firstPage,
12446122852SIngo Weinhold									size_t pageCount);
12546122852SIngo Weinhold			void				_CachePages(vm_page** pages, size_t firstPage,
12646122852SIngo Weinhold									size_t pageCount);
12746122852SIngo Weinhold			status_t			_WritePages(vm_page** pages,
12846122852SIngo Weinhold									size_t pagesRelativeOffset,
12932832cbeSIngo Weinhold									size_t requestLength, BDataIO* output);
13046122852SIngo Weinhold			status_t			_ReadIntoPages(vm_page** pages,
13146122852SIngo Weinhold									size_t firstPage, size_t pageCount);
13246122852SIngo Weinhold
13346122852SIngo Weinhold			void				_LockCacheLine(CacheLineLocker* lineLocker);
13446122852SIngo Weinhold			void				_UnlockCacheLine(CacheLineLocker* lineLocker);
13546122852SIngo Weinhold
13646122852SIngo Weinholdprivate:
13746122852SIngo Weinhold			static const size_t kCacheLineSize = 64 * 1024;
13846122852SIngo Weinhold			static const size_t kPagesPerCacheLine
13946122852SIngo Weinhold				= kCacheLineSize / B_PAGE_SIZE;
14046122852SIngo Weinhold
14146122852SIngo Weinholdprivate:
14246122852SIngo Weinhold			mutex				fLock;
14346122852SIngo Weinhold			BAbstractBufferedDataReader* fReader;
14446122852SIngo Weinhold			VMCache*			fCache;
14546122852SIngo Weinhold			LockerTable			fCacheLineLockers;
14646122852SIngo Weinhold};
14746122852SIngo Weinhold
14846122852SIngo Weinhold
14946122852SIngo Weinhold#endif	// HEAP_CACHE_H
150