1/*
2 * The contents of this file are subject to the Initial
3 * Developer's Public License Version 1.0 (the "License");
4 * you may not use this file except in compliance with the
5 * License. You may obtain a copy of the License at
6 * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
7 *
8 * Software distributed under the License is distributed AS IS,
9 * WITHOUT WARRANTY OF ANY KIND, either express or implied.
10 * See the License for the specific language governing rights
11 * and limitations under the License.
12 *
13 * The Original Code was created by Dmitry Yemanov
14 * for the Firebird Open Source RDBMS project.
15 *
16 * Copyright (c) 2006 Dmitry Yemanov <dimitr@users.sf.net>
17 * and all contributors signed below.
18 *
19 * All Rights Reserved.
20 * Contributor(s): ______________________________________.
21 */
22
23#ifndef JRD_TEMP_SPACE_H
24#define JRD_TEMP_SPACE_H
25
26#include "firebird.h"
27#include "../common/classes/fb_string.h"
28#include "../common/classes/array.h"
29#include "../common/classes/TempFile.h"
30#include "../common/config/dir_list.h"
31#include "../common/classes/init.h"
32#include "../common/classes/tree.h"
33
34class TempSpace : public Firebird::File
35{
36public:
37 TempSpace(MemoryPool& pool, const Firebird::PathName& prefix, bool dynamic = true);
38 virtual ~TempSpace();
39
40 size_t read(offset_t offset, void* buffer, size_t length);
41 size_t write(offset_t offset, const void* buffer, size_t length);
42
43 void unlink() {}
44
45 offset_t getSize() const
46 {
47 return logicalSize;
48 }
49
50 void extend(size_t size);
51
52 offset_t allocateSpace(size_t size);
53 void releaseSpace(offset_t offset, size_t size);
54
55 UCHAR* inMemory(offset_t offset, size_t size) const;
56
57 struct SegmentInMemory
58 {
59 UCHAR* memory;
60 offset_t position;
61 size_t size;
62 };
63
64 typedef Firebird::Array<SegmentInMemory> Segments;
65
66 size_t allocateBatch(size_t count, size_t minSize, size_t maxSize, Segments& segments);
67
68 bool validate(offset_t& freeSize) const;
69private:
70
71 // Generic space block
72 class Block
73 {
74 public:
75 Block(Block* tail, size_t length)
76 : next(NULL), size(length)
77 {
78 if (tail)
79 {
80 tail->next = this;
81 }
82 prev = tail;
83 }
84
85 virtual ~Block() {}
86
87 virtual size_t read(offset_t offset, void* buffer, size_t length) = 0;
88 virtual size_t write(offset_t offset, const void* buffer, size_t length) = 0;
89
90 virtual UCHAR* inMemory(offset_t offset, size_t size) const = 0;
91 virtual bool sameFile(const Firebird::TempFile* file) const = 0;
92
93 Block *prev;
94 Block *next;
95 offset_t size;
96 };
97
98 class MemoryBlock : public Block
99 {
100 public:
101 MemoryBlock(UCHAR* memory, Block* tail, size_t length)
102 : Block(tail, length), ptr(memory)
103 {}
104
105 ~MemoryBlock()
106 {
107 delete[] ptr;
108 }
109
110 size_t read(offset_t offset, void* buffer, size_t length);
111 size_t write(offset_t offset, const void* buffer, size_t length);
112
113 UCHAR* inMemory(offset_t offset, size_t _size) const
114 {
115 if ((offset < this->size) && (offset + _size <= this->size))
116 return ptr + offset;
117
118 return NULL;
119 }
120
121 bool sameFile(const Firebird::TempFile*) const
122 {
123 return false;
124 }
125
126 protected:
127 UCHAR* ptr;
128 };
129
130 class InitialBlock : public MemoryBlock
131 {
132 public:
133 InitialBlock(UCHAR* memory, size_t length)
134 : MemoryBlock(memory, NULL, length)
135 {}
136
137 ~InitialBlock()
138 {
139 ptr = NULL;
140 }
141 };
142
143 class FileBlock : public Block
144 {
145 public:
146 FileBlock(Firebird::TempFile* f, Block* tail, size_t length)
147 : Block(tail, length), file(f)
148 {
149 fb_assert(file);
150
151 // FileBlock is created after file was extended by length (look at
152 // TempSpace::extend) so this FileBlock is already inside the file
153 seek = file->getSize() - length;
154 }
155
156 ~FileBlock() {}
157
158 size_t read(offset_t offset, void* buffer, size_t length);
159 size_t write(offset_t offset, const void* buffer, size_t length);
160
161 UCHAR* inMemory(offset_t /*offset*/, size_t /*a_size*/) const
162 {
163 return NULL;
164 }
165
166 bool sameFile(const Firebird::TempFile* aFile) const
167 {
168 return (aFile == this->file);
169 }
170
171 private:
172 Firebird::TempFile* file;
173 offset_t seek;
174 };
175
176 Block* findBlock(offset_t& offset) const;
177 Firebird::TempFile* setupFile(size_t size);
178
179 UCHAR* findMemory(offset_t& begin, offset_t end, size_t size) const;
180
181 // free/used segments management
182 class Segment
183 {
184 public:
185 Segment() : position(0), size(0)
186 {}
187
188 Segment(offset_t aPosition, offset_t aSize) :
189 position(aPosition), size(aSize)
190 {}
191
192 offset_t position;
193 offset_t size;
194
195 static const offset_t& generate(const void* /*sender*/, const Segment& segment)
196 {
197 return segment.position;
198 }
199 };
200
201 MemoryPool& pool;
202 Firebird::PathName filePrefix;
203 offset_t logicalSize;
204 offset_t physicalSize;
205 offset_t localCacheUsage;
206 Block* head;
207 Block* tail;
208 Firebird::Array<Firebird::TempFile*> tempFiles;
209 Firebird::Array<UCHAR> initialBuffer;
210 bool initiallyDynamic;
211
212 typedef Firebird::BePlusTree<Segment, offset_t, MemoryPool, Segment> FreeSegmentTree;
213 FreeSegmentTree freeSegments;
214
215 static Firebird::GlobalPtr<Firebird::Mutex> initMutex;
216 static Firebird::TempDirectoryList* tempDirs;
217 static size_t minBlockSize;
218 static offset_t globalCacheUsage;
219};
220
221#endif // JRD_TEMP_SPACE_H
222