@@ -129,6 +129,69 @@ FB_SIZE_T TempSpace::FileBlock::write(offset_t offset, const void* buffer, FB_SI
129129 return file->write (offset, buffer, length);
130130}
131131
132+ //
133+ // FreeSegmentBySize class
134+ //
135+
136+ void TempSpace::FreeSegmentBySize::addSegment (Segment* const segment)
137+ {
138+ if (m_items.locate (segment->size ))
139+ {
140+ SegmentsStack* const cur = &m_items.current ();
141+ segment->next = nullptr ;
142+ segment->prev = cur->tail ;
143+ cur->tail ->next = segment;
144+ cur->tail = segment;
145+ }
146+ else
147+ {
148+ segment->prev = nullptr ;
149+ segment->next = nullptr ;
150+ m_items.add (SegmentsStack (segment->size , segment));
151+ }
152+ }
153+
154+ void TempSpace::FreeSegmentBySize::removeSegment (Segment* const segment)
155+ {
156+ if (segment->next == nullptr )
157+ {
158+ if (!m_items.locate (segment->size ))
159+ fb_assert (false );
160+
161+ SegmentsStack* cur = &m_items.current ();
162+ if (segment->prev )
163+ {
164+ segment->prev ->next = nullptr ;
165+ cur->tail = segment->prev ;
166+ segment->prev = nullptr ;
167+ }
168+ else
169+ m_items.fastRemove ();
170+ }
171+ else
172+ {
173+ if (segment->prev )
174+ segment->prev ->next = segment->next ;
175+
176+ segment->next ->prev = segment->prev ;
177+
178+ segment->prev = nullptr ;
179+ segment->next = nullptr ;
180+ }
181+ }
182+
183+ TempSpace::Segment* TempSpace::FreeSegmentBySize::getSegment (FB_SIZE_T size)
184+ {
185+ // Search through the available space in the not used segments list
186+ if (m_items.locate (locGreatEqual, size))
187+ {
188+ SegmentsStack* const cur = &m_items.current ();
189+ fb_assert (cur->tail );
190+ return cur->tail ;
191+ }
192+ return nullptr ;
193+ }
194+
132195//
133196// TempSpace::TempSpace
134197//
@@ -140,7 +203,7 @@ TempSpace::TempSpace(MemoryPool& p, const PathName& prefix, bool dynamic)
140203 logicalSize(0 ), physicalSize(0 ), localCacheUsage(0 ),
141204 head(NULL ), tail(NULL ), tempFiles(p),
142205 initialBuffer(p), initiallyDynamic(dynamic),
143- freeSegments(p)
206+ freeSegments(p), freeSegmentsBySize(p)
144207{
145208 if (!tempDirs)
146209 {
@@ -180,6 +243,9 @@ TempSpace::~TempSpace()
180243 dbb->decTempCacheUsage (localCacheUsage);
181244 }
182245
246+ for (bool found = freeSegments.getFirst (); found; found = freeSegments.getNext ())
247+ delete freeSegments.current ();
248+
183249 while (tempFiles.getCount ())
184250 delete tempFiles.pop ();
185251}
@@ -473,24 +539,15 @@ offset_t TempSpace::allocateSpace(FB_SIZE_T size)
473539{
474540 // Find the best available space. This is defined as the smallest free space
475541 // that is big enough. This preserves large blocks.
476- Segment* best = NULL ;
477-
478- // Search through the available space in the not used segments list
479- for (bool found = freeSegments.getFirst (); found; found = freeSegments.getNext ())
480- {
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- }
486- }
542+ Segment* best = freeSegmentsBySize.getSegment (size);
487543
488544 // If we didn't find any space, allocate it at the end of the file
489545 if (!best)
490546 {
491547 extend (size);
492548 return getSize () - size;
493549 }
550+ freeSegmentsBySize.removeSegment (best);
494551
495552 // Set up the return parameters
496553 const offset_t position = best->position ;
@@ -503,8 +560,11 @@ offset_t TempSpace::allocateSpace(FB_SIZE_T size)
503560 if (!freeSegments.locate (best->position ))
504561 fb_assert (false );
505562
563+ delete freeSegments.current ();
506564 freeSegments.fastRemove ();
507565 }
566+ else
567+ freeSegmentsBySize.addSegment (best);
508568
509569 return position;
510570}
@@ -526,37 +586,48 @@ void TempSpace::releaseSpace(offset_t position, FB_SIZE_T size)
526586 if (freeSegments.locate (locEqual, end))
527587 {
528588 // The next segment is found to be adjacent
529- Segment* const next_seg = &freeSegments.current ();
589+ Segment* const next_seg = freeSegments.current ();
590+ freeSegmentsBySize.removeSegment (next_seg);
591+
530592 next_seg->position -= size;
531593 next_seg->size += size;
532594
533595 if (freeSegments.getPrev ())
534596 {
535597 // Check the prior segment for being adjacent
536- Segment* const prior_seg = & freeSegments.current ();
598+ Segment* const prior_seg = freeSegments.current ();
537599 if (position == prior_seg->position + prior_seg->size )
538600 {
601+ freeSegmentsBySize.removeSegment (prior_seg);
602+
539603 next_seg->position -= prior_seg->size ;
540604 next_seg->size += prior_seg->size ;
605+
606+ delete prior_seg;
541607 freeSegments.fastRemove ();
542608 }
543609 }
544610
611+ freeSegmentsBySize.addSegment (next_seg);
545612 return ;
546613 }
547614
548615 if (freeSegments.locate (locLess, position))
549616 {
550617 // Check the prior segment for being adjacent
551- Segment* const prior_seg = & freeSegments.current ();
618+ Segment* const prior_seg = freeSegments.current ();
552619 if (position == prior_seg->position + prior_seg->size )
553620 {
621+ freeSegmentsBySize.removeSegment (prior_seg);
554622 prior_seg->size += size;
623+ freeSegmentsBySize.addSegment (prior_seg);
555624 return ;
556625 }
557626 }
558627
559- freeSegments.add (Segment (position, size));
628+ Segment* new_seg = FB_NEW_POOL (pool) Segment (position, size);
629+ if (freeSegments.add (new_seg))
630+ freeSegmentsBySize.addSegment (new_seg);
560631}
561632
562633//
@@ -610,14 +681,31 @@ UCHAR* TempSpace::findMemory(offset_t& begin, offset_t end, size_t size) const
610681
611682bool TempSpace::validate (offset_t & free) const
612683{
684+ FB_SIZE_T cnt = 0 ;
613685 free = 0 ;
614686 FreeSegmentTree::ConstAccessor accessor (&freeSegments);
615687 for (bool found = accessor.getFirst (); found; found = accessor.getNext ())
616688 {
617- const offset_t size = accessor.current (). size ;
689+ const offset_t size = accessor.current ()-> size ;
618690 fb_assert (size != 0 );
619691 free += size;
692+ cnt++;
693+ }
694+
695+ FreeSegmentsStackTree::ConstAccessor stackAccessor (&freeSegmentsBySize.m_items );
696+ for (bool found = stackAccessor.getFirst (); found; found = stackAccessor.getNext ())
697+ {
698+ const SegmentsStack* const stack = &stackAccessor.current ();
699+ const Segment* cur = stack->tail ;
700+ fb_assert (cur->next == NULL );
701+ while (cur)
702+ {
703+ cnt--;
704+ fb_assert (cur->size == stack->size );
705+ cur = cur->prev ;
706+ }
620707 }
708+ fb_assert (cnt == 0 );
621709
622710 offset_t disk = 0 ;
623711 for (FB_SIZE_T i = 0 ; i < tempFiles.getCount (); i++)
@@ -643,7 +731,7 @@ ULONG TempSpace::allocateBatch(ULONG count, FB_SIZE_T minSize, FB_SIZE_T maxSize
643731 offset_t freeMem = 0 ;
644732
645733 for (bool found = freeSegments.getFirst (); found; found = freeSegments.getNext ())
646- freeMem += freeSegments.current (). size ;
734+ freeMem += freeSegments.current ()-> size ;
647735
648736 freeMem = MIN (freeMem / count, maxSize);
649737 freeMem = MAX (freeMem, minSize);
@@ -653,7 +741,7 @@ ULONG TempSpace::allocateBatch(ULONG count, FB_SIZE_T minSize, FB_SIZE_T maxSize
653741 bool is_positioned = freeSegments.getFirst ();
654742 while (segments.getCount () < count && is_positioned)
655743 {
656- Segment* freeSpace = & freeSegments.current ();
744+ Segment* freeSpace = freeSegments.current ();
657745 offset_t freeSeek = freeSpace->position ;
658746 const offset_t freeEnd = freeSpace->position + freeSpace->size ;
659747
@@ -668,22 +756,25 @@ ULONG TempSpace::allocateBatch(ULONG count, FB_SIZE_T minSize, FB_SIZE_T maxSize
668756 fb_assert (p == mem);
669757 fb_assert (seek1 == freeSeek);
670758#endif
759+ freeSegmentsBySize.removeSegment (freeSpace);
760+
671761 if (freeSeek != freeSpace->position )
672762 {
673763 const offset_t skip_size = freeSeek - freeSpace->position ;
674- const Segment skip_space (freeSpace->position , skip_size);
764+ Segment* const skip_space = FB_NEW_POOL (pool) Segment (freeSpace->position , skip_size);
675765
676766 freeSpace->position += skip_size;
677767 freeSpace->size -= skip_size;
678768 fb_assert (freeSpace->size != 0 );
679769
680770 if (!freeSegments.add (skip_space))
681771 fb_assert (false );
772+ freeSegmentsBySize.addSegment (skip_space);
682773
683- if (!freeSegments.locate (skip_space. position + skip_size ))
774+ if (!freeSegments.locate (freeSpace-> position ))
684775 fb_assert (false );
685776
686- freeSpace = & freeSegments.current ();
777+ freeSpace = freeSegments.current ();
687778 }
688779
689780 SegmentInMemory seg;
@@ -697,8 +788,11 @@ ULONG TempSpace::allocateBatch(ULONG count, FB_SIZE_T minSize, FB_SIZE_T maxSize
697788
698789 if (!freeSpace->size )
699790 {
791+ delete freeSegments.current ();
700792 is_positioned = freeSegments.fastRemove ();
701793 }
794+ else
795+ freeSegmentsBySize.addSegment (freeSpace);
702796 }
703797 else
704798 {
0 commit comments