8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-30 09:23:09 +01:00
firebird-mirror/src/qli/all.cpp

512 lines
12 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Command Oriented Query Language
* MODULE: all.cpp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Internal block allocator
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
/***************************************************
THIS MODULE HAS SEVERAL KISSING COUSINS; IF YOU
SHOULD CHANGE ONE OF THE MODULES IN THE FOLLOWING
LIST, PLEASE BE SURE TO CHECK THE OTHERS FOR
SIMILAR CHANGES:
2004-03-07 08:58:55 +01:00
/dsql/all.cpp
/jrd/all.cpp
/pipe/allp.cpp
/qli/all.cpp
/remote/allr.cpp
/gpre/msc.cpp
2001-05-23 15:26:42 +02:00
- THANK YOU
***************************************************/
#include "firebird.h"
2001-05-23 15:26:42 +02:00
#include <string.h>
2003-09-15 18:32:22 +02:00
#include "../qli/dtr.h"
#include "../qli/parse.h"
#include "../qli/compile.h"
#include "../qli/exe.h"
#include "../qli/report.h"
#include "../qli/format.h"
2001-05-23 15:26:42 +02:00
#include "../qli/all_proto.h"
#include "../qli/err_proto.h"
#include "../qli/mov_proto.h"
#include "../jrd/gds_proto.h"
2003-09-19 12:26:46 +02:00
#define BLKDEF(type, root, tail) { sizeof(root), tail },
2001-05-23 15:26:42 +02:00
2008-01-15 21:15:58 +01:00
static const struct
{
2001-05-23 15:26:42 +02:00
SSHORT typ_root_length;
SSHORT typ_tail_length;
} block_sizes[] = {
{0, 0},
2001-05-23 15:26:42 +02:00
#include "../qli/blk.h"
2003-09-19 12:26:46 +02:00
};
2001-05-23 15:26:42 +02:00
#undef BLKDEF
static void extend_pool(PLB, USHORT);
2004-02-02 12:02:12 +01:00
static qli_vec* global_pools;
2001-05-23 15:26:42 +02:00
2004-05-16 03:42:11 +02:00
const int MIN_ALLOCATION = 1024;
2001-05-23 15:26:42 +02:00
BLK ALLQ_alloc( PLB pool, UCHAR type, int count)
{
/**************************************
*
* A L L Q _ a l l o c
*
**************************************
*
* Functional description
* Allocate a block from a given pool and initialize the block.
* This is the primary block allocation routine.
*
**************************************/
if (type <= (SCHAR) type_MIN || type >= (SCHAR) type_MAX)
2004-05-16 03:42:11 +02:00
ERRQ_bugcheck(1); // Msg1 bad block type
2001-05-23 15:26:42 +02:00
// Compute block length
2001-05-23 15:26:42 +02:00
2004-03-14 06:51:54 +01:00
size_t size = block_sizes[type].typ_root_length;
2001-05-23 15:26:42 +02:00
SLONG tail = block_sizes[type].typ_tail_length;
if (tail)
2001-05-23 15:26:42 +02:00
size += count * tail;
size = FB_ALIGN(size, ALIGNMENT);
if (size <= 4 || size > 65535)
2004-05-16 03:42:11 +02:00
ERRQ_bugcheck(2); // Msg2 bad block size
2001-05-23 15:26:42 +02:00
/* Find best fit. Best fit is defined to be the free block of SHORTest
tail. If there isn't a fit, extend the pool and try, try again. */
FRB free;
FRB* best;
2004-03-14 06:51:54 +01:00
size_t best_tail;
2008-01-15 21:15:58 +01:00
while (true)
{
2001-05-23 15:26:42 +02:00
best = NULL;
best_tail = 32767;
for (FRB* ptr = &pool->plb_free; (free = *ptr); ptr = &free->frb_next)
2008-01-15 21:15:58 +01:00
{
if (free->frb_next && (SCHAR *) free >= (SCHAR *) free->frb_next)
2004-05-16 03:42:11 +02:00
ERRQ_bugcheck(434); // memory pool free list is incorrect
2001-05-23 15:26:42 +02:00
else if ((tail = free->frb_header.blk_length - size) >= 0
2004-03-14 06:51:54 +01:00
&& tail < static_cast<SLONG>(best_tail))
{
2001-05-23 15:26:42 +02:00
best = ptr;
best_tail = tail;
if (tail == 0)
break;
}
2008-01-15 21:15:58 +01:00
}
2001-05-23 15:26:42 +02:00
if (best)
break;
extend_pool(pool, size);
}
/* We've got our free block. If there's enough left of the free block
after taking out our block, chop out out block. If not, allocate
the entire free block as our block (a little extra won't hurt). */
free = *best;
FRB block;
2003-09-19 12:26:46 +02:00
if (best_tail > sizeof(frb)) {
USHORT l = free->frb_header.blk_length - size;
2001-05-23 15:26:42 +02:00
block = (FRB) ((SCHAR *) free + l);
free->frb_header.blk_length -= size;
}
else {
*best = free->frb_next;
size += best_tail;
block = free;
}
block->frb_header.blk_type = type;
block->frb_header.blk_pool_id = pool->plb_pool_id;
block->frb_header.blk_length = size;
2003-09-19 12:26:46 +02:00
if (size -= sizeof(blk))
memset((SCHAR *) block + sizeof(blk), 0, size);
2001-05-23 15:26:42 +02:00
return (BLK) block;
}
BLK ALLQ_extend(BLK* pointer, int size)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* A L L Q _ e x t e n d
*
**************************************
*
* Functional description
* Extend a repeating block, copying the constant part.
*
**************************************/
BLK block = *pointer;
BLK new_blk = (BLK) ALLQ_alloc((PLB) global_pools->vec_object[block->blk_pool_id],
2001-05-23 15:26:42 +02:00
block->blk_type, size);
const int length = MIN(block->blk_length, new_blk->blk_length) - sizeof(blk);
memcpy((SCHAR*) new_blk + sizeof(blk), (SCHAR*) block + sizeof(blk), length);
2001-07-12 07:46:06 +02:00
ALLQ_release((FRB) block);
2001-05-23 15:26:42 +02:00
2001-07-12 07:46:06 +02:00
if (new_blk->blk_type == (SCHAR) type_vec)
2004-02-02 12:02:12 +01:00
((qli_vec*) new_blk)->vec_count = size;
2001-07-12 07:46:06 +02:00
else if (new_blk->blk_type == (SCHAR) type_vcl)
2004-02-02 12:02:12 +01:00
((qli_vcl*) new_blk)->vcl_count = size;
2001-05-23 15:26:42 +02:00
2001-07-12 07:46:06 +02:00
*pointer = new_blk;
2001-05-23 15:26:42 +02:00
2001-07-12 07:46:06 +02:00
return new_blk;
2001-05-23 15:26:42 +02:00
}
void ALLQ_fini()
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* A L L Q _ f i n i
*
**************************************
*
* Functional description
* Get rid of everything.
*
**************************************/
PLB* vector = (PLB*) global_pools->vec_object + global_pools->vec_count;
PLB* until = (PLB*) global_pools->vec_object;
while (--vector >= until)
{
PLB pool = *vector;
if (pool)
{
HNK hunks, hunk;
2001-05-23 15:26:42 +02:00
for (hunks = pool->plb_hunks; hunk = hunks;) {
hunks = hunk->hnk_next;
ALLQ_free(hunk->hnk_address);
}
}
}
2001-05-23 15:26:42 +02:00
}
void ALLQ_free(void* memory)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* A L L Q _ f r e e
*
**************************************
*
* Functional description
* Give space back to system.
*
**************************************/
gds__free(memory);
}
void ALLQ_init()
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* A L L Q _ i n i t
*
**************************************
*
* Functional description
* Initialize the pool system.
*
**************************************/
qli_vec temp_vector[2];
memcpy(temp_vector, 0, sizeof(temp_vector));
2001-05-23 15:26:42 +02:00
global_pools = temp_vector;
global_pools->vec_count = 1;
global_pools->vec_object[0] = NULL;
2001-05-23 15:26:42 +02:00
PLB pool = ALLQ_pool();
QLI_default_pool = QLI_permanent_pool = pool;
2004-02-02 12:02:12 +01:00
global_pools = (qli_vec*) ALLQ_alloc(pool, type_vec, 10);
global_pools->vec_count = 10;
global_pools->vec_object[0] = (BLK) pool;
2001-05-23 15:26:42 +02:00
}
SCHAR *ALLQ_malloc(SLONG size)
{
/**************************************
*
* A L L Q _ m a l l o c
*
**************************************
*
* Functional description
* Get memory from system.
*
**************************************/
SCHAR *memory = (SCHAR*) gds__alloc(size);
2001-05-23 15:26:42 +02:00
if (memory) {
2001-05-23 15:26:42 +02:00
#ifdef DEBUG_GDS_ALLOC
gds_alloc_flag_unfreed((void *) memory); // Don't care about QLI leaks
2001-05-23 15:26:42 +02:00
#endif
return memory;
}
IBERROR(5); // Msg5 "memory gonzo"
2002-06-29 10:49:39 +02:00
return 0;
2001-05-23 15:26:42 +02:00
}
PLB ALLQ_pool()
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* A L L Q _ p o o l
*
**************************************
*
* Functional description
* Allocate a new pool. This is done by creating a tempory
* pool block on the stack, then allocating a real pool block.
* In SHORT, by mirrors.
*
**************************************/
USHORT pool_id;
2001-05-23 15:26:42 +02:00
// Start by assigning a pool id
2001-05-23 15:26:42 +02:00
for (pool_id = 0; pool_id < global_pools->vec_count; pool_id++)
2008-01-15 21:15:58 +01:00
{
if (!(global_pools->vec_object[pool_id]))
2001-05-23 15:26:42 +02:00
break;
2008-01-15 21:15:58 +01:00
}
2001-05-23 15:26:42 +02:00
if (pool_id >= global_pools->vec_count)
ALLQ_extend((BLK*) &global_pools, pool_id + 10);
2001-05-23 15:26:42 +02:00
plb temp_pool;
global_pools->vec_object[pool_id] = (BLK) &temp_pool;
2001-05-23 15:26:42 +02:00
temp_pool.plb_free = NULL;
temp_pool.plb_hunks = NULL;
temp_pool.plb_pool_id = pool_id;
if (pool_id == 0)
QLI_permanent_pool = &temp_pool;
PLB pool = (PLB) ALLQ_alloc(&temp_pool, type_plb, 0);
2001-05-23 15:26:42 +02:00
pool->plb_pool_id = pool_id;
pool->plb_free = temp_pool.plb_free;
pool->plb_hunks = temp_pool.plb_hunks;
global_pools->vec_object[pool_id] = (BLK) pool;
2001-05-23 15:26:42 +02:00
if (pool_id == 0)
QLI_permanent_pool = pool;
return pool;
}
2004-02-02 12:02:12 +01:00
void ALLQ_push( BLK object, qli_lls** stack)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* A L L Q _ p u s h
*
**************************************
*
* Functional description
2004-02-02 12:02:12 +01:00
* Push an object on a qli_lls stack.
2001-05-23 15:26:42 +02:00
*
**************************************/
PLB pool = QLI_default_pool;
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
qli_lls* node = pool->plb_lls;
if (node)
2001-05-23 15:26:42 +02:00
pool->plb_lls = node->lls_next;
else
2004-02-02 12:02:12 +01:00
node = (qli_lls*) ALLQ_alloc(pool, type_lls, 0);
2001-05-23 15:26:42 +02:00
node->lls_object = object;
node->lls_next = *stack;
*stack = node;
}
2004-02-02 12:02:12 +01:00
BLK ALLQ_pop(qli_lls** stack)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* A L L Q _ p o p
*
**************************************
*
* Functional description
* Pop an object off a linked list stack. Save the node for
* further use.
*
**************************************/
2004-02-02 12:02:12 +01:00
qli_lls* node = *stack;
PLB pool = (PLB) global_pools->vec_object[node->lls_header.blk_pool_id];
2001-05-23 15:26:42 +02:00
*stack = node->lls_next;
node->lls_next = pool->plb_lls;
pool->plb_lls = node;
return node->lls_object;
}
void ALLQ_release( FRB block)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* A L L Q _ r e l e a s e
*
**************************************
*
* Functional description
* Release a block to its pool. If it is contiguous to
* another free block, combine them. Otherwise link it
* into the free block linked list (kept in ascending order
* of addresses).
*
**************************************/
block->frb_header.blk_type = (SCHAR) type_frb;
2004-03-14 06:51:54 +01:00
UCHAR pool_id = block->frb_header.blk_pool_id;
2001-05-23 15:26:42 +02:00
PLB pool;
if (pool_id >= global_pools->vec_count ||
!(pool = (PLB) global_pools->vec_object[pool_id]))
{
2004-05-16 03:42:11 +02:00
ERRQ_bugcheck(4);
// Msg4 bad pool id
}
2001-05-23 15:26:42 +02:00
FRB prior = NULL;
FRB free;
FRB* ptr;
2001-05-23 15:26:42 +02:00
for (ptr = &pool->plb_free; free = *ptr;
2003-09-13 13:48:09 +02:00
prior = free, ptr = &free->frb_next)
{
if ((SCHAR *) block <= (SCHAR *) free)
break;
}
2001-05-23 15:26:42 +02:00
2003-02-28 14:38:30 +01:00
if ((SCHAR *) block == (SCHAR *) free)
2004-05-16 03:42:11 +02:00
ERRQ_bugcheck(435); // block released twice
2001-05-23 15:26:42 +02:00
// Merge block into list first, then try to combine blocks
2001-05-23 15:26:42 +02:00
block->frb_next = free;
*ptr = block;
// Try to merge the free block with the next one down.
2001-05-23 15:26:42 +02:00
if (free) {
if ((SCHAR *) block + block->frb_header.blk_length == (SCHAR *) free)
{
2001-05-23 15:26:42 +02:00
block->frb_header.blk_length += free->frb_header.blk_length;
block->frb_next = free->frb_next;
}
else if ((SCHAR *) block + block->frb_header.blk_length > (SCHAR *) free)
2004-05-16 03:42:11 +02:00
ERRQ_bugcheck(436); // released block overlaps following free block
2001-05-23 15:26:42 +02:00
}
// Try and merge the block with the prior free block
2001-05-23 15:26:42 +02:00
if (prior) {
if ((SCHAR *) prior + prior->frb_header.blk_length == (SCHAR *) block)
{
2001-05-23 15:26:42 +02:00
prior->frb_header.blk_length += block->frb_header.blk_length;
prior->frb_next = block->frb_next;
}
else if ((SCHAR *) prior + prior->frb_header.blk_length > (SCHAR *) block)
2004-05-16 03:42:11 +02:00
ERRQ_bugcheck(437); // released block overlaps prior free block
2001-05-23 15:26:42 +02:00
}
}
void ALLQ_rlpool( PLB pool)
{
/**************************************
*
* A L L Q _ r l p o o l
*
**************************************
*
* Functional description
* Release a storage pool. This involves nothing more than returning
* hunks to the free hunk list.
*
**************************************/
global_pools->vec_object[pool->plb_pool_id] = NULL;
2001-05-23 15:26:42 +02:00
HNK hunk, hunks;
2001-05-23 15:26:42 +02:00
for (hunks = pool->plb_hunks; hunk = hunks;) {
hunks = hunk->hnk_next;
gds__free(hunk->hnk_address);
}
}
static void extend_pool( PLB pool, USHORT count)
{
/**************************************
*
* e x t e n d _ p o o l
*
**************************************
*
* Functional description
* Extend a pool by at least enough to accomodate a block
* of given size.
*
**************************************/
const SLONG size =
(count + sizeof(hnk) + MIN_ALLOCATION - 1) & ~(MIN_ALLOCATION - 1);
2001-05-23 15:26:42 +02:00
if ((USHORT) size < count)
IBERROR(481); // msg 481 unsuccessful attempt to extend pool beyond 64KB
2001-05-23 15:26:42 +02:00
BLK block = (BLK) ALLQ_malloc(size);
2001-05-23 15:26:42 +02:00
block->blk_length = size;
block->blk_type = (SCHAR) type_frb;
block->blk_pool_id = pool->plb_pool_id;
2001-07-12 07:46:06 +02:00
ALLQ_release((FRB) block);
2001-05-23 15:26:42 +02:00
HNK hunk = (HNK) ALLQ_alloc(pool, type_hnk, 0);
2001-05-23 15:26:42 +02:00
hunk->hnk_address = (SCHAR *) block;
hunk->hnk_length = size;
hunk->hnk_next = pool->plb_hunks;
pool->plb_hunks = hunk;
}