Skip to content

Commit 59ab8d5

Browse files
committed
Add pointers tree to TempSpace class
Necessary for faster search of a free segment of the required size. When using temporary blobs, there are situations when a large number of free segments of a small size accumulate during one transaction.
1 parent 9791f8d commit 59ab8d5

File tree

2 files changed

+128
-24
lines changed

2 files changed

+128
-24
lines changed

src/jrd/TempSpace.cpp

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ TempSpace::TempSpace(MemoryPool& p, const PathName& prefix, bool dynamic)
140140
logicalSize(0), physicalSize(0), localCacheUsage(0),
141141
head(NULL), tail(NULL), tempFiles(p),
142142
initialBuffer(p), initiallyDynamic(dynamic),
143-
freeSegments(p)
143+
freeSegments(p), freeSegmentLastPointers(p)
144144
{
145145
if (!tempDirs)
146146
{
@@ -180,6 +180,9 @@ TempSpace::~TempSpace()
180180
dbb->decTempCacheUsage(localCacheUsage);
181181
}
182182

183+
for (bool found = freeSegments.getFirst(); found; found = freeSegments.getNext())
184+
delete freeSegments.current();
185+
183186
while (tempFiles.getCount())
184187
delete tempFiles.pop();
185188
}
@@ -476,13 +479,17 @@ offset_t TempSpace::allocateSpace(FB_SIZE_T size)
476479
Segment* best = NULL;
477480

478481
// Search through the available space in the not used segments list
479-
for (bool found = freeSegments.getFirst(); found; found = freeSegments.getNext())
482+
if (freeSegmentLastPointers.locate(locGreatEqual, size))
480483
{
481-
Segment* const space = &freeSegments.current();
482-
// If this is smaller than our previous best, use it
483-
if (space->size >= size && (!best || (space->size < best->size))) {
484-
best = space;
485-
}
484+
SegmentLastPointer* const cur = &freeSegmentLastPointers.current();
485+
const offset_t position = cur->pop();
486+
if (cur->isEmpty())
487+
freeSegmentLastPointers.fastRemove();
488+
489+
if (!freeSegments.locate(position))
490+
fb_assert(false);
491+
492+
best = freeSegments.current();
486493
}
487494

488495
// If we didn't find any space, allocate it at the end of the file
@@ -503,8 +510,11 @@ offset_t TempSpace::allocateSpace(FB_SIZE_T size)
503510
if (!freeSegments.locate(best->position))
504511
fb_assert(false);
505512

513+
delete freeSegments.current();
506514
freeSegments.fastRemove();
507515
}
516+
else
517+
lastPointerAdd(best);
508518

509519
return position;
510520
}
@@ -526,37 +536,48 @@ void TempSpace::releaseSpace(offset_t position, FB_SIZE_T size)
526536
if (freeSegments.locate(locEqual, end))
527537
{
528538
// The next segment is found to be adjacent
529-
Segment* const next_seg = &freeSegments.current();
539+
Segment* const next_seg = freeSegments.current();
540+
lastPointerRemove(next_seg);
541+
530542
next_seg->position -= size;
531543
next_seg->size += size;
532544

533545
if (freeSegments.getPrev())
534546
{
535547
// Check the prior segment for being adjacent
536-
Segment* const prior_seg = &freeSegments.current();
548+
Segment* const prior_seg = freeSegments.current();
537549
if (position == prior_seg->position + prior_seg->size)
538550
{
551+
lastPointerRemove(prior_seg);
552+
539553
next_seg->position -= prior_seg->size;
540554
next_seg->size += prior_seg->size;
555+
556+
delete prior_seg;
541557
freeSegments.fastRemove();
542558
}
543559
}
544560

561+
lastPointerAdd(next_seg);
545562
return;
546563
}
547564

548565
if (freeSegments.locate(locLess, position))
549566
{
550567
// Check the prior segment for being adjacent
551-
Segment* const prior_seg = &freeSegments.current();
568+
Segment* const prior_seg = freeSegments.current();
552569
if (position == prior_seg->position + prior_seg->size)
553570
{
571+
lastPointerRemove(prior_seg);
554572
prior_seg->size += size;
573+
lastPointerAdd(prior_seg);
555574
return;
556575
}
557576
}
558577

559-
freeSegments.add(Segment(position, size));
578+
Segment* new_seg = FB_NEW_POOL(pool) Segment(position, size);
579+
freeSegments.add(new_seg);
580+
lastPointerAdd(new_seg);
560581
}
561582

562583
//
@@ -614,7 +635,7 @@ bool TempSpace::validate(offset_t& free) const
614635
FreeSegmentTree::ConstAccessor accessor(&freeSegments);
615636
for (bool found = accessor.getFirst(); found; found = accessor.getNext())
616637
{
617-
const offset_t size = accessor.current().size;
638+
const offset_t size = accessor.current()->size;
618639
fb_assert(size != 0);
619640
free += size;
620641
}
@@ -643,7 +664,7 @@ ULONG TempSpace::allocateBatch(ULONG count, FB_SIZE_T minSize, FB_SIZE_T maxSize
643664
offset_t freeMem = 0;
644665

645666
for (bool found = freeSegments.getFirst(); found; found = freeSegments.getNext())
646-
freeMem += freeSegments.current().size;
667+
freeMem += freeSegments.current()->size;
647668

648669
freeMem = MIN(freeMem / count, maxSize);
649670
freeMem = MAX(freeMem, minSize);
@@ -653,7 +674,7 @@ ULONG TempSpace::allocateBatch(ULONG count, FB_SIZE_T minSize, FB_SIZE_T maxSize
653674
bool is_positioned = freeSegments.getFirst();
654675
while (segments.getCount() < count && is_positioned)
655676
{
656-
Segment* freeSpace = &freeSegments.current();
677+
Segment* freeSpace = freeSegments.current();
657678
offset_t freeSeek = freeSpace->position;
658679
const offset_t freeEnd = freeSpace->position + freeSpace->size;
659680

@@ -668,22 +689,25 @@ ULONG TempSpace::allocateBatch(ULONG count, FB_SIZE_T minSize, FB_SIZE_T maxSize
668689
fb_assert(p == mem);
669690
fb_assert(seek1 == freeSeek);
670691
#endif
692+
lastPointerRemove(freeSpace);
693+
671694
if (freeSeek != freeSpace->position)
672695
{
673696
const offset_t skip_size = freeSeek - freeSpace->position;
674-
const Segment skip_space(freeSpace->position, skip_size);
697+
Segment* const skip_space = FB_NEW_POOL(pool) Segment(freeSpace->position, skip_size);
675698

676699
freeSpace->position += skip_size;
677700
freeSpace->size -= skip_size;
678701
fb_assert(freeSpace->size != 0);
679702

680703
if (!freeSegments.add(skip_space))
681704
fb_assert(false);
705+
lastPointerAdd(skip_space);
682706

683-
if (!freeSegments.locate(skip_space.position + skip_size))
707+
if (!freeSegments.locate(freeSpace->position))
684708
fb_assert(false);
685709

686-
freeSpace = &freeSegments.current();
710+
freeSpace = freeSegments.current();
687711
}
688712

689713
SegmentInMemory seg;
@@ -697,8 +721,11 @@ ULONG TempSpace::allocateBatch(ULONG count, FB_SIZE_T minSize, FB_SIZE_T maxSize
697721

698722
if (!freeSpace->size)
699723
{
724+
delete freeSegments.current();
700725
is_positioned = freeSegments.fastRemove();
701726
}
727+
else
728+
lastPointerAdd(freeSpace);
702729
}
703730
else
704731
{

src/jrd/TempSpace.h

Lines changed: 84 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -182,19 +182,50 @@ class TempSpace : public Firebird::File
182182
class Segment
183183
{
184184
public:
185-
Segment() : position(0), size(0)
186-
{}
187-
188185
Segment(offset_t aPosition, offset_t aSize) :
189-
position(aPosition), size(aSize)
186+
position(aPosition), size(aSize), prev(NULL), next(NULL)
190187
{}
191188

192189
offset_t position;
193190
offset_t size;
191+
Segment* prev;
192+
Segment* next;
193+
194+
static const offset_t& generate(const void* /*sender*/, const Segment* segment)
195+
{
196+
return segment->position;
197+
}
198+
};
199+
200+
class SegmentLastPointer
201+
{
202+
public:
203+
SegmentLastPointer() : size(0), last(NULL)
204+
{}
205+
206+
SegmentLastPointer(offset_t aSize, Segment* aSegment) :
207+
size(aSize), last(aSegment)
208+
{}
209+
210+
offset_t pop()
211+
{
212+
fb_assert(last);
213+
offset_t last_position = last->position;
214+
last = last->prev;
215+
return last_position;
216+
}
217+
218+
bool isEmpty()
219+
{
220+
return !last;
221+
}
222+
223+
offset_t size;
224+
Segment* last;
194225

195-
static const offset_t& generate(const void* /*sender*/, const Segment& segment)
226+
static const offset_t& generate(const void* /*sender*/, const SegmentLastPointer& segment)
196227
{
197-
return segment.position;
228+
return segment.size;
198229
}
199230
};
200231

@@ -209,9 +240,55 @@ class TempSpace : public Firebird::File
209240
Firebird::Array<UCHAR> initialBuffer;
210241
bool initiallyDynamic;
211242

212-
typedef Firebird::BePlusTree<Segment, offset_t, MemoryPool, Segment> FreeSegmentTree;
243+
typedef Firebird::BePlusTree<Segment*, offset_t, MemoryPool, Segment> FreeSegmentTree;
213244
FreeSegmentTree freeSegments;
214245

246+
typedef Firebird::BePlusTree<SegmentLastPointer, offset_t, MemoryPool, SegmentLastPointer> FreeSegmentLastPointerTree;
247+
FreeSegmentLastPointerTree freeSegmentLastPointers;
248+
249+
inline void lastPointerAdd(Segment* const segment)
250+
{
251+
if (freeSegmentLastPointers.locate(segment->size))
252+
{
253+
SegmentLastPointer* const pointer = &freeSegmentLastPointers.current();
254+
segment->next = NULL;
255+
segment->prev = pointer->last;
256+
pointer->last->next = segment;
257+
pointer->last = segment;
258+
}
259+
else
260+
{
261+
segment->prev = NULL;
262+
segment->next = NULL;
263+
freeSegmentLastPointers.add(SegmentLastPointer(segment->size, segment));
264+
}
265+
}
266+
267+
inline void lastPointerRemove(Segment* const segment)
268+
{
269+
if (segment->next == NULL)
270+
{
271+
if (!freeSegmentLastPointers.locate(segment->size))
272+
fb_assert(false);
273+
274+
SegmentLastPointer* pointer = &freeSegmentLastPointers.current();
275+
if (segment->prev)
276+
{
277+
segment->prev->next = NULL;
278+
pointer->last = segment->prev;
279+
}
280+
else
281+
freeSegmentLastPointers.fastRemove();
282+
}
283+
else
284+
{
285+
if (segment->prev)
286+
segment->prev->next = segment->next;
287+
288+
segment->next->prev = segment->prev;
289+
}
290+
}
291+
215292
static Firebird::GlobalPtr<Firebird::Mutex> initMutex;
216293
static Firebird::TempDirectoryList* tempDirs;
217294
static FB_SIZE_T minBlockSize;

0 commit comments

Comments
 (0)