xref: /haiku/src/add-ons/kernel/file_systems/packagefs/package/CachedDataReader.h (revision e81a954787e50e56a7f06f72705b7859b6ab06d1)
1 /*
2  * Copyright 2013-2014, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 #ifndef HEAP_CACHE_H
6 #define HEAP_CACHE_H
7 
8 
9 #include <package/hpkg/DataReader.h>
10 
11 #include <condition_variable.h>
12 #include <util/DoublyLinkedList.h>
13 #include <util/OpenHashTable.h>
14 #include <vm/vm_types.h>
15 
16 
17 using BPackageKit::BHPKG::BAbstractBufferedDataReader;
18 using BPackageKit::BHPKG::BDataReader;
19 
20 
21 class CachedDataReader : public BAbstractBufferedDataReader {
22 public:
23 								CachedDataReader();
24 	virtual						~CachedDataReader();
25 
26 			status_t			Init(BAbstractBufferedDataReader* reader,
27 									off_t size);
28 
29 	virtual	status_t			ReadDataToOutput(off_t offset, size_t size,
30 									BDataIO* output);
31 
32 private:
33 			class CacheLineLocker
34 				: public DoublyLinkedListLinkImpl<CacheLineLocker> {
35 			public:
36 				CacheLineLocker(CachedDataReader* reader, off_t cacheLineOffset)
37 					:
38 					fReader(reader),
39 					fOffset(cacheLineOffset)
40 				{
41 					fReader->_LockCacheLine(this);
42 				}
43 
44 				~CacheLineLocker()
45 				{
46 					fReader->_UnlockCacheLine(this);
47 				}
48 
49 				off_t Offset() const
50 				{
51 					return fOffset;
52 				}
53 
54 				CacheLineLocker*& HashNext()
55 				{
56 					return fHashNext;
57 				}
58 
59 				DoublyLinkedList<CacheLineLocker>& Queue()
60 				{
61 					return fQueue;
62 				}
63 
64 				void Wait(mutex& lock)
65 				{
66 					fWaitCondition.Init(this, "cached reader line locker");
67 					ConditionVariableEntry waitEntry;
68 					fWaitCondition.Add(&waitEntry);
69 					mutex_unlock(&lock);
70 					waitEntry.Wait();
71 					mutex_lock(&lock);
72 				}
73 
74 				void WakeUp()
75 				{
76 					fWaitCondition.NotifyOne();
77 				}
78 
79 			private:
80 				CachedDataReader*					fReader;
81 				off_t								fOffset;
82 				CacheLineLocker*					fHashNext;
83 				DoublyLinkedList<CacheLineLocker>	fQueue;
84 				ConditionVariable					fWaitCondition;
85 			};
86 
87 			friend class CacheLineLocker;
88 
89 			struct LockerHashDefinition {
90 				typedef off_t			KeyType;
91 				typedef	CacheLineLocker	ValueType;
92 
93 				size_t HashKey(off_t key) const
94 				{
95 					return size_t(key / kCacheLineSize);
96 				}
97 
98 				size_t Hash(const CacheLineLocker* value) const
99 				{
100 					return HashKey(value->Offset());
101 				}
102 
103 				bool Compare(off_t key, const CacheLineLocker* value) const
104 				{
105 					return value->Offset() == key;
106 				}
107 
108 				CacheLineLocker*& GetLink(CacheLineLocker* value) const
109 				{
110 					return value->HashNext();
111 				}
112 			};
113 
114 			typedef BOpenHashTable<LockerHashDefinition> LockerTable;
115 
116 			struct PagesDataOutput;
117 
118 private:
119 			status_t			_ReadCacheLine(off_t lineOffset,
120 									size_t lineSize, off_t requestOffset,
121 							 		size_t requestLength, BDataIO* output);
122 
123 			void				_DiscardPages(vm_page** pages, size_t firstPage,
124 									size_t pageCount);
125 			void				_CachePages(vm_page** pages, size_t firstPage,
126 									size_t pageCount);
127 			status_t			_WritePages(vm_page** pages,
128 									size_t pagesRelativeOffset,
129 									size_t requestLength, BDataIO* output);
130 			status_t			_ReadIntoPages(vm_page** pages,
131 									size_t firstPage, size_t pageCount);
132 
133 			void				_LockCacheLine(CacheLineLocker* lineLocker);
134 			void				_UnlockCacheLine(CacheLineLocker* lineLocker);
135 
136 private:
137 			static const size_t kCacheLineSize = 64 * 1024;
138 			static const size_t kPagesPerCacheLine
139 				= kCacheLineSize / B_PAGE_SIZE;
140 
141 private:
142 			mutex				fLock;
143 			BAbstractBufferedDataReader* fReader;
144 			VMCache*			fCache;
145 			LockerTable			fCacheLineLockers;
146 };
147 
148 
149 #endif	// HEAP_CACHE_H
150