mirror of
https://github.com/postgres/postgres.git
synced 2025-11-12 05:01:15 +03:00
Add FILLFACTOR to CREATE INDEX.
ITAGAKI Takahiro
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.107 2006/06/27 02:51:39 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.108 2006/07/02 02:23:18 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1738,3 +1738,54 @@ heap_addheader(int natts, /* max domain index */
|
||||
|
||||
return tuple;
|
||||
}
|
||||
|
||||
/*
|
||||
* build_class_tuple
|
||||
*
|
||||
* XXX Natts_pg_class_fixed is a hack - see pg_class.h
|
||||
*/
|
||||
HeapTuple
|
||||
build_class_tuple(Form_pg_class pgclass, ArrayType *options)
|
||||
{
|
||||
HeapTuple tuple;
|
||||
HeapTupleHeader td;
|
||||
Form_pg_class data; /* contents of tuple */
|
||||
Size len;
|
||||
Size size;
|
||||
int hoff;
|
||||
|
||||
/* size of pg_class tuple with options */
|
||||
if (options)
|
||||
size = offsetof(FormData_pg_class, reloptions) + VARATT_SIZE(options);
|
||||
else
|
||||
size = CLASS_TUPLE_SIZE;
|
||||
|
||||
/* header needs no null bitmap */
|
||||
hoff = offsetof(HeapTupleHeaderData, t_bits);
|
||||
hoff += sizeof(Oid);
|
||||
hoff = MAXALIGN(hoff);
|
||||
len = hoff + size;
|
||||
|
||||
tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);
|
||||
tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
|
||||
|
||||
tuple->t_len = len;
|
||||
ItemPointerSetInvalid(&(tuple->t_self));
|
||||
tuple->t_tableOid = InvalidOid;
|
||||
|
||||
/* we don't bother to fill the Datum fields */
|
||||
|
||||
td->t_natts = Natts_pg_class_fixed;
|
||||
td->t_hoff = hoff;
|
||||
td->t_infomask = HEAP_HASOID;
|
||||
|
||||
data = (Form_pg_class) ((char *) td + hoff);
|
||||
memcpy(data, pgclass, CLASS_TUPLE_SIZE);
|
||||
if (options)
|
||||
{
|
||||
td->t_natts++;
|
||||
memcpy(data->reloptions, options, VARATT_SIZE(options));
|
||||
}
|
||||
|
||||
return tuple;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginutil.c,v 1.1 2006/05/02 11:28:54 teodor Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginutil.c,v 1.2 2006/07/02 02:23:18 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@@ -201,3 +201,17 @@ GinPageGetCopyPage( Page page ) {
|
||||
|
||||
return tmppage;
|
||||
}
|
||||
|
||||
Datum
|
||||
ginoption(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ArrayType *options = (ArrayType *) PG_GETARG_POINTER(0);
|
||||
|
||||
if (options != NULL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("GIN does not support parameters at all")));
|
||||
|
||||
/* Do not use PG_RETURN_NULL. */
|
||||
PG_RETURN_BYTEA_P(NULL);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.139 2006/06/28 12:00:14 teodor Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.140 2006/07/02 02:23:18 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -44,6 +44,7 @@ static void gistbuildCallback(Relation index,
|
||||
void *state);
|
||||
static void gistdoinsert(Relation r,
|
||||
IndexTuple itup,
|
||||
Size freespace,
|
||||
GISTSTATE *GISTstate);
|
||||
static void gistfindleaf(GISTInsertState *state,
|
||||
GISTSTATE *giststate);
|
||||
@@ -197,7 +198,8 @@ gistbuildCallback(Relation index,
|
||||
* you're inserting single tups, but not when you're initializing the
|
||||
* whole index at once.
|
||||
*/
|
||||
gistdoinsert(index, itup, &buildstate->giststate);
|
||||
gistdoinsert(index, itup, IndexGetPageFreeSpace(index),
|
||||
&buildstate->giststate);
|
||||
|
||||
buildstate->indtuples += 1;
|
||||
MemoryContextSwitchTo(oldCtx);
|
||||
@@ -236,7 +238,7 @@ gistinsert(PG_FUNCTION_ARGS)
|
||||
values, isnull, true /* size is currently bogus */);
|
||||
itup->t_tid = *ht_ctid;
|
||||
|
||||
gistdoinsert(r, itup, &giststate);
|
||||
gistdoinsert(r, itup, 0, &giststate);
|
||||
|
||||
/* cleanup */
|
||||
freeGISTstate(&giststate);
|
||||
@@ -253,7 +255,7 @@ gistinsert(PG_FUNCTION_ARGS)
|
||||
* so it does not bother releasing palloc'd allocations.
|
||||
*/
|
||||
static void
|
||||
gistdoinsert(Relation r, IndexTuple itup, GISTSTATE *giststate)
|
||||
gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate)
|
||||
{
|
||||
GISTInsertState state;
|
||||
|
||||
@@ -263,6 +265,7 @@ gistdoinsert(Relation r, IndexTuple itup, GISTSTATE *giststate)
|
||||
state.itup[0] = (IndexTuple) palloc(IndexTupleSize(itup));
|
||||
memcpy(state.itup[0], itup, IndexTupleSize(itup));
|
||||
state.ituplen = 1;
|
||||
state.freespace = freespace;
|
||||
state.r = r;
|
||||
state.key = itup->t_tid;
|
||||
state.needInsertComplete = true;
|
||||
@@ -294,7 +297,11 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
|
||||
*/
|
||||
|
||||
|
||||
if (gistnospace(state->stack->page, state->itup, state->ituplen, (is_leaf) ? InvalidOffsetNumber : state->stack->childoffnum))
|
||||
/*
|
||||
* XXX: If we want to change fillfactors between node and leaf,
|
||||
* fillfactor = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor)
|
||||
*/
|
||||
if (gistnospace(state->stack->page, state->itup, state->ituplen, (is_leaf) ? InvalidOffsetNumber : state->stack->childoffnum, state->freespace))
|
||||
{
|
||||
/* no space for insertion */
|
||||
IndexTuple *itvec;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.16 2006/06/28 12:00:14 teodor Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.17 2006/07/02 02:23:18 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
@@ -58,9 +58,9 @@ gistfillbuffer(Relation r, Page page, IndexTuple *itup,
|
||||
* Check space for itup vector on page
|
||||
*/
|
||||
bool
|
||||
gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete)
|
||||
gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace)
|
||||
{
|
||||
unsigned int size = 0, deleted = 0;
|
||||
unsigned int size = freespace, deleted = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
@@ -82,6 +82,7 @@ gistfitpage(IndexTuple *itvec, int len) {
|
||||
for(i=0;i<len;i++)
|
||||
size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
|
||||
|
||||
/* TODO: Consider fillfactor */
|
||||
return (size <= GiSTPageSize);
|
||||
}
|
||||
|
||||
@@ -634,3 +635,16 @@ gistNewBuffer(Relation r)
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
Datum
|
||||
gistoption(PG_FUNCTION_ARGS)
|
||||
{
|
||||
#define GIST_DEFAULT_FILLFACTOR 90
|
||||
#define GIST_MIN_FILLFACTOR 50
|
||||
|
||||
ArrayType *options = (ArrayType *) PG_GETARG_POINTER(0);
|
||||
|
||||
/* Use index common routine. */
|
||||
PG_RETURN_BYTEA_P(genam_option(options,
|
||||
GIST_MIN_FILLFACTOR, GIST_DEFAULT_FILLFACTOR));
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.22 2006/05/19 11:10:25 teodor Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.23 2006/07/02 02:23:18 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -376,7 +376,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
|
||||
if (curlenaddon)
|
||||
{
|
||||
/* insert updated tuples */
|
||||
if (gistnospace(tempPage, addon, curlenaddon, InvalidOffsetNumber)) {
|
||||
if (gistnospace(tempPage, addon, curlenaddon, InvalidOffsetNumber, 0)) {
|
||||
/* there is no space on page to insert tuples */
|
||||
res = vacuumSplitPage(gv, tempPage, buffer, addon, curlenaddon);
|
||||
tempPage=NULL; /* vacuumSplitPage() free tempPage */
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.20 2006/05/19 17:15:41 teodor Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.21 2006/07/02 02:23:18 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
@@ -690,7 +690,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
|
||||
* that wiil be enough space....
|
||||
*/
|
||||
|
||||
if (gistnospace(pages[0], itup, lenitup, *todelete))
|
||||
if (gistnospace(pages[0], itup, lenitup, *todelete, 0))
|
||||
{
|
||||
|
||||
/* no space left on page, so we must split */
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.57 2006/03/31 23:32:05 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.58 2006/07/02 02:23:18 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Postgres hash pages look like ordinary relation pages. The opaque
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include "access/genam.h"
|
||||
#include "access/hash.h"
|
||||
#include "catalog/index.h"
|
||||
#include "miscadmin.h"
|
||||
#include "storage/lmgr.h"
|
||||
#include "utils/lsyscache.h"
|
||||
@@ -231,7 +232,7 @@ _hash_metapinit(Relation rel)
|
||||
RelationGetDescr(rel)->attrs[0]->atttypmod);
|
||||
item_width = MAXALIGN(sizeof(IndexTupleData)) + MAXALIGN(data_width) +
|
||||
sizeof(ItemIdData); /* include the line pointer */
|
||||
ffactor = (BLCKSZ * 3 / 4) / item_width;
|
||||
ffactor = BLCKSZ * IndexGetFillFactor(rel) / 100 / item_width;
|
||||
/* keep to a sane range */
|
||||
if (ffactor < 10)
|
||||
ffactor = 10;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.47 2006/03/05 15:58:21 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.48 2006/07/02 02:23:18 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -173,3 +173,16 @@ _hash_checkpage(Relation rel, Buffer buf, int flags)
|
||||
errhint("Please REINDEX it.")));
|
||||
}
|
||||
}
|
||||
|
||||
Datum
|
||||
hashoption(PG_FUNCTION_ARGS)
|
||||
{
|
||||
#define HASH_MIN_FILLFACTOR 50
|
||||
#define HASH_DEFAULT_FILLFACTOR 75
|
||||
|
||||
ArrayType *options = (ArrayType *) PG_GETARG_POINTER(0);
|
||||
|
||||
/* Use index common routine. */
|
||||
PG_RETURN_BYTEA_P(genam_option(options,
|
||||
HASH_MIN_FILLFACTOR, HASH_DEFAULT_FILLFACTOR));
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.213 2006/05/28 02:27:08 alvherre Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.214 2006/07/02 02:23:18 momjian Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@@ -46,9 +46,13 @@
|
||||
#include "access/xlogutils.h"
|
||||
#include "catalog/catalog.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "commands/defrem.h"
|
||||
#include "miscadmin.h"
|
||||
#include "nodes/parsenodes.h"
|
||||
#include "parser/parse_clause.h"
|
||||
#include "pgstat.h"
|
||||
#include "storage/procarray.h"
|
||||
#include "utils/catcache.h"
|
||||
#include "utils/inval.h"
|
||||
#include "utils/relcache.h"
|
||||
|
||||
@@ -3588,3 +3592,59 @@ heap_desc(StringInfo buf, uint8 xl_info, char *rec)
|
||||
else
|
||||
appendStringInfo(buf, "UNKNOWN");
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse options for heaps.
|
||||
*
|
||||
* relkind Kind of relation
|
||||
* options Options as text[]
|
||||
*/
|
||||
bytea *
|
||||
heap_option(char relkind, ArrayType *options)
|
||||
{
|
||||
/*
|
||||
* XXX: What fillfactor should be default?
|
||||
* overriding databases:
|
||||
* - Oracle, DB2 = 90%
|
||||
* - SQL Server = 100%
|
||||
* non-overriding database:
|
||||
* - Firebird = 70%
|
||||
*/
|
||||
#define HEAP_MIN_FILLFACTOR 50
|
||||
#define HEAP_DEFAULT_FILLFACTOR 100
|
||||
|
||||
int fillfactor;
|
||||
HeapOption *result;
|
||||
|
||||
DefElem kwds[] =
|
||||
{
|
||||
{ T_DefElem, "fillfactor" },
|
||||
};
|
||||
|
||||
/*
|
||||
* parse options
|
||||
*/
|
||||
OptionParse(options, lengthof(kwds), kwds, true);
|
||||
|
||||
/* 0: fillfactor */
|
||||
if (kwds[0].arg)
|
||||
fillfactor = (int) defGetInt64(&kwds[0]);
|
||||
else
|
||||
fillfactor = HEAP_DEFAULT_FILLFACTOR;
|
||||
if (fillfactor < HEAP_MIN_FILLFACTOR || 100 < fillfactor)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("fillfactor=%d should be between %d and 100",
|
||||
fillfactor, HEAP_MIN_FILLFACTOR)));
|
||||
}
|
||||
|
||||
/*
|
||||
* build option
|
||||
*/
|
||||
result = (HeapOption *)
|
||||
MemoryContextAlloc(CacheMemoryContext, sizeof(HeapOption));
|
||||
VARATT_SIZEP(result) = sizeof(HeapOption);
|
||||
result->fillfactor = fillfactor;
|
||||
return (bytea *) result;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/heap/hio.c,v 1.61 2006/03/05 15:58:21 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/heap/hio.c,v 1.62 2006/07/02 02:23:18 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -102,12 +102,18 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
{
|
||||
Buffer buffer = InvalidBuffer;
|
||||
Page pageHeader;
|
||||
Size pageFreeSpace;
|
||||
Size pageFreeSpace,
|
||||
freespace;
|
||||
BlockNumber targetBlock,
|
||||
otherBlock;
|
||||
bool needLock;
|
||||
|
||||
if (relation->rd_options == NULL)
|
||||
elog(ERROR, "RelationGetBufferForTuple %s IS NULL", RelationGetRelationName(relation));
|
||||
Assert(relation->rd_options != NULL);
|
||||
|
||||
len = MAXALIGN(len); /* be conservative */
|
||||
freespace = HeapGetPageFreeSpace(relation);
|
||||
|
||||
/*
|
||||
* If we're gonna fail for oversize tuple, do it right away
|
||||
@@ -146,7 +152,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
* We have no cached target page, so ask the FSM for an initial
|
||||
* target.
|
||||
*/
|
||||
targetBlock = GetPageWithFreeSpace(&relation->rd_node, len);
|
||||
targetBlock = GetPageWithFreeSpace(&relation->rd_node, len + freespace);
|
||||
|
||||
/*
|
||||
* If the FSM knows nothing of the rel, try the last page before we
|
||||
@@ -202,7 +208,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
*/
|
||||
pageHeader = (Page) BufferGetPage(buffer);
|
||||
pageFreeSpace = PageGetFreeSpace(pageHeader);
|
||||
if (len <= pageFreeSpace)
|
||||
if (len + freespace <= pageFreeSpace)
|
||||
{
|
||||
/* use this page as future insert target, too */
|
||||
relation->rd_targblock = targetBlock;
|
||||
@@ -235,7 +241,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
targetBlock = RecordAndGetPageWithFreeSpace(&relation->rd_node,
|
||||
targetBlock,
|
||||
pageFreeSpace,
|
||||
len);
|
||||
len + freespace);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.55 2006/05/07 01:21:30 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.56 2006/07/02 02:23:18 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* many of the old access method routines have been turned into
|
||||
@@ -21,8 +21,12 @@
|
||||
|
||||
#include "access/genam.h"
|
||||
#include "access/heapam.h"
|
||||
#include "commands/defrem.h"
|
||||
#include "miscadmin.h"
|
||||
#include "nodes/parsenodes.h"
|
||||
#include "parser/parse_clause.h"
|
||||
#include "pgstat.h"
|
||||
#include "utils/catcache.h"
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@@ -260,3 +264,44 @@ systable_endscan(SysScanDesc sysscan)
|
||||
|
||||
pfree(sysscan);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse options for generic indexes.
|
||||
*/
|
||||
bytea *
|
||||
genam_option(ArrayType *options,
|
||||
int minFillfactor, int defaultFillfactor)
|
||||
{
|
||||
int fillfactor;
|
||||
IndexOption *result;
|
||||
|
||||
DefElem kwds[] =
|
||||
{
|
||||
{ T_DefElem, "fillfactor" },
|
||||
};
|
||||
|
||||
/*
|
||||
* parse options
|
||||
*/
|
||||
OptionParse(options, lengthof(kwds), kwds, true);
|
||||
|
||||
/* 0: fillfactor */
|
||||
if (kwds[0].arg)
|
||||
fillfactor = (int) defGetInt64(&kwds[0]);
|
||||
else
|
||||
fillfactor = defaultFillfactor;
|
||||
if (fillfactor < minFillfactor || 100 < fillfactor)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("fillfactor=%d should be between %d and 100",
|
||||
fillfactor, minFillfactor)));
|
||||
|
||||
/*
|
||||
* build options
|
||||
*/
|
||||
result = (IndexOption *)
|
||||
MemoryContextAlloc(CacheMemoryContext, sizeof(IndexOption));
|
||||
VARATT_SIZEP(result) = sizeof(IndexOption);
|
||||
result->fillfactor = fillfactor;
|
||||
return (bytea *) result;
|
||||
}
|
||||
|
||||
@@ -8,13 +8,14 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.137 2006/05/08 00:00:09 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.138 2006/07/02 02:23:18 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/genam.h"
|
||||
#include "access/heapam.h"
|
||||
#include "access/nbtree.h"
|
||||
#include "miscadmin.h"
|
||||
@@ -25,6 +26,7 @@ typedef struct
|
||||
{
|
||||
/* context data for _bt_checksplitloc */
|
||||
Size newitemsz; /* size of new item to be inserted */
|
||||
int fillfactor; /* used when insert at right most */
|
||||
bool is_leaf; /* T if splitting a leaf page */
|
||||
bool is_rightmost; /* T if splitting a rightmost page */
|
||||
|
||||
@@ -986,14 +988,11 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
|
||||
* it needs to go into!)
|
||||
*
|
||||
* If the page is the rightmost page on its level, we instead try to arrange
|
||||
* for twice as much free space on the right as on the left. In this way,
|
||||
* for reserving (100-fillfactor)% of free space on left page. In this way,
|
||||
* when we are inserting successively increasing keys (consider sequences,
|
||||
* timestamps, etc) we will end up with a tree whose pages are about 67% full,
|
||||
* timestamps, etc) we will end up with a tree whose pages are about fillfactor% full,
|
||||
* instead of the 50% full result that we'd get without this special case.
|
||||
* (We could bias it even further to make the initially-loaded tree more full.
|
||||
* But since the steady-state load for a btree is about 70%, we'd likely just
|
||||
* be making more page-splitting work for ourselves later on, when we start
|
||||
* seeing updates to existing tuples.)
|
||||
* This is the same as initially-loaded tree.
|
||||
*
|
||||
* We are passed the intended insert position of the new tuple, expressed as
|
||||
* the offsetnumber of the tuple it must go in front of. (This could be
|
||||
@@ -1027,6 +1026,7 @@ _bt_findsplitloc(Relation rel,
|
||||
/* Passed-in newitemsz is MAXALIGNED but does not include line pointer */
|
||||
newitemsz += sizeof(ItemIdData);
|
||||
state.newitemsz = newitemsz;
|
||||
state.fillfactor = IndexGetFillFactor(rel);
|
||||
state.is_leaf = P_ISLEAF(opaque);
|
||||
state.is_rightmost = P_RIGHTMOST(opaque);
|
||||
state.have_split = false;
|
||||
@@ -1157,10 +1157,11 @@ _bt_checksplitloc(FindSplitData *state, OffsetNumber firstright,
|
||||
if (state->is_rightmost)
|
||||
{
|
||||
/*
|
||||
* On a rightmost page, try to equalize right free space with
|
||||
* twice the left free space. See comments for _bt_findsplitloc.
|
||||
* On a rightmost page, try to reserve (100-fillfactor)% of
|
||||
* free space on left page. See comments for _bt_findsplitloc.
|
||||
*/
|
||||
delta = (2 * leftfree) - rightfree;
|
||||
delta = (state->fillfactor * leftfree)
|
||||
- ((100 - state->fillfactor) * rightfree);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -56,13 +56,14 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.102 2006/06/27 16:53:02 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.103 2006/07/02 02:23:19 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/genam.h"
|
||||
#include "access/nbtree.h"
|
||||
#include "access/xlog.h"
|
||||
#include "miscadmin.h"
|
||||
@@ -120,6 +121,7 @@ typedef struct BTWriteState
|
||||
|
||||
|
||||
static Page _bt_blnewpage(uint32 level);
|
||||
static Size _bt_full_threshold(Relation index, Size pagesize, bool leaf);
|
||||
static BTPageState *_bt_pagestate(BTWriteState *wstate, uint32 level);
|
||||
static void _bt_slideleft(Page page);
|
||||
static void _bt_sortaddtup(Page page, Size itemsize,
|
||||
@@ -327,6 +329,22 @@ _bt_blwritepage(BTWriteState *wstate, Page page, BlockNumber blkno)
|
||||
pfree(page);
|
||||
}
|
||||
|
||||
/*
|
||||
* The steady-state load factor for btrees is usually estimated at 70%.
|
||||
* We choose to pack leaf pages to 90% and upper pages to 70% as defaults.
|
||||
*/
|
||||
static Size
|
||||
_bt_full_threshold(Relation index, Size pagesize, bool leaf)
|
||||
{
|
||||
int fillfactor = IndexGetFillFactor(index);
|
||||
if (!leaf)
|
||||
{
|
||||
/* XXX: Is this reasonable? */
|
||||
fillfactor = Max(70, 3 * fillfactor - 200);
|
||||
}
|
||||
return pagesize * (100 - fillfactor) / 100;
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate and initialize a new BTPageState. the returned structure
|
||||
* is suitable for immediate use by _bt_buildadd.
|
||||
@@ -347,10 +365,8 @@ _bt_pagestate(BTWriteState *wstate, uint32 level)
|
||||
state->btps_lastoff = P_HIKEY;
|
||||
state->btps_level = level;
|
||||
/* set "full" threshold based on level. See notes at head of file. */
|
||||
if (level > 0)
|
||||
state->btps_full = (PageGetPageSize(state->btps_page) * 3) / 10;
|
||||
else
|
||||
state->btps_full = PageGetPageSize(state->btps_page) / 10;
|
||||
state->btps_full = _bt_full_threshold(wstate->index,
|
||||
PageGetPageSize(state->btps_page), level == 0);
|
||||
/* no parent level, yet */
|
||||
state->btps_next = NULL;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.74 2006/05/08 00:00:10 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.75 2006/07/02 02:23:19 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1079,3 +1079,16 @@ BTreeShmemInit(void)
|
||||
else
|
||||
Assert(found);
|
||||
}
|
||||
|
||||
Datum
|
||||
btoption(PG_FUNCTION_ARGS)
|
||||
{
|
||||
#define BTREE_MIN_FILLFACTOR 50
|
||||
#define BTREE_DEFAULT_FILLFACTOR 90
|
||||
|
||||
ArrayType *options = (ArrayType *) PG_GETARG_POINTER(0);
|
||||
|
||||
/* Use index common routine. */
|
||||
PG_RETURN_BYTEA_P(genam_option(options,
|
||||
BTREE_MIN_FILLFACTOR, BTREE_DEFAULT_FILLFACTOR));
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.44 2006/04/14 20:27:24 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.45 2006/07/02 02:23:19 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -337,7 +337,7 @@ _xl_remove_hash_entry(XLogRelDesc *rdesc)
|
||||
RelationCloseSmgr(&(rdesc->reldata));
|
||||
|
||||
memset(rdesc, 0, sizeof(XLogRelDesc));
|
||||
memset(tpgc, 0, sizeof(FormData_pg_class));
|
||||
memset(tpgc, 0, CLASS_TUPLE_SIZE);
|
||||
rdesc->reldata.rd_rel = tpgc;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user