Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
659f79be
Commit
659f79be
authored
May 29, 2000
by
Bruce Momjian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Allow vacuum to perform analyze with shared lock. Update cvs manual.
parent
091126fa
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
444 additions
and
381 deletions
+444
-381
doc/src/sgml/cvs.sgml
doc/src/sgml/cvs.sgml
+3
-3
src/backend/commands/vacuum.c
src/backend/commands/vacuum.c
+440
-375
src/include/commands/vacuum.h
src/include/commands/vacuum.h
+1
-3
No files found.
doc/src/sgml/cvs.sgml
View file @
659f79be
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/cvs.sgml,v 1.
8 2000/05/02 20:01:51 thomas
Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/cvs.sgml,v 1.
9 2000/05/29 15:44:54 momjian
Exp $
CVS code repository
Thomas Lockhart
-->
...
...
@@ -184,7 +184,7 @@ cvs commit
Do an initial login to the <productname>CVS</productname> server:
<programlisting>
$ cvs -d :pserver:anoncvs@postgresql.org:/
usr/loca
l/cvsroot login
$ cvs -d :pserver:anoncvs@postgresql.org:/
home/projects/pgsq
l/cvsroot login
</programlisting>
You will be prompted for a password; enter '<literal>postgresql</literal>'.
...
...
@@ -197,7 +197,7 @@ $ cvs -d :pserver:anoncvs@postgresql.org:/usr/local/cvsroot login
<para>
Fetch the <productname>Postgres</productname> sources:
<programlisting>
cvs -z3 -d :pserver:anoncvs@postgresql.org:/
usr/loca
l/cvsroot co -P pgsql
cvs -z3 -d :pserver:anoncvs@postgresql.org:/
home/projects/pgsq
l/cvsroot co -P pgsql
</programlisting>
which installs the <productname>Postgres</productname> sources into a
...
...
src/backend/commands/vacuum.c
View file @
659f79be
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.15
1 2000/05/29 01:55:07
momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.15
2 2000/05/29 15:44:55
momjian Exp $
*
*-------------------------------------------------------------------------
...
...
@@ -77,15 +77,17 @@ static void vacuum_shutdown(void);
static
void
vac_vacuum
(
NameData
*
VacRelP
,
bool
analyze
,
List
*
va_cols
);
static
VRelList
getrels
(
NameData
*
VacRelP
);
static
void
vacuum_rel
(
Oid
relid
,
bool
analyze
,
List
*
va_cols
);
static
void
analyze_rel
(
Oid
relid
,
List
*
va_cols
);
static
void
scan_heap
(
VRelStats
*
vacrelstats
,
Relation
onerel
,
VPageList
vacuum_pages
,
VPageList
fraged_pages
);
static
void
repair_frag
(
VRelStats
*
vacrelstats
,
Relation
onerel
,
VPageList
vacuum_pages
,
VPageList
fraged_pages
,
int
nindices
,
Relation
*
Irel
);
static
void
vacuum_heap
(
VRelStats
*
vacrelstats
,
Relation
onerel
,
VPageList
vpl
);
static
void
vacuum_page
(
Page
page
,
VPageDescr
vpd
);
static
void
vacuum_index
(
VPageList
vpl
,
Relation
indrel
,
int
num_tuples
,
int
keep_tuples
);
static
void
scan_index
(
Relation
indrel
,
int
num_tuples
);
static
void
attr_stats
(
Relation
onerel
,
VRelStats
*
vacrel
stats
,
HeapTuple
tuple
);
static
void
attr_stats
(
Relation
onerel
,
int
attr_cnt
,
VacAttrStats
*
vacattr
stats
,
HeapTuple
tuple
);
static
void
bucketcpy
(
Form_pg_attribute
attr
,
Datum
value
,
Datum
*
bucket
,
int
*
bucket_len
);
static
void
update_stats
(
Oid
relid
,
int
num_pages
,
int
num_tuples
,
bool
hasindex
,
VRelStats
*
vacrelstats
);
static
void
update_relstats
(
Oid
relid
,
int
num_pages
,
int
num_tuples
,
bool
hasindex
,
VRelStats
*
vacrelstats
);
static
void
update_attstats
(
Oid
relid
,
int
natts
,
VacAttrStats
*
vacattrstats
);
static
void
del_stats
(
Oid
relid
,
int
attcnt
,
int
*
attnums
);
static
VPageDescr
tid_reaped
(
ItemPointer
itemptr
,
VPageList
vpl
);
static
void
reap_page
(
VPageList
vpl
,
VPageDescr
vpc
);
...
...
@@ -100,63 +102,7 @@ static int vac_cmp_offno(const void *left, const void *right);
static
int
vac_cmp_vtlinks
(
const
void
*
left
,
const
void
*
right
);
static
bool
enough_space
(
VPageDescr
vpd
,
Size
len
);
static
char
*
show_rusage
(
struct
rusage
*
ru0
);
/*
* This routines handle a special cross-transaction portal.
* However it is automatically closed in case of abort.
*/
void
CommonSpecialPortalOpen
(
void
)
{
char
*
pname
;
if
(
CommonSpecialPortalInUse
)
elog
(
ERROR
,
"CommonSpecialPortal is in use"
);
/*
* Create a portal for safe memory across transactions. We need to
* palloc the name space for it because our hash function expects the
* name to be on a longword boundary. CreatePortal copies the name to
* safe storage for us.
*/
pname
=
pstrdup
(
VACPNAME
);
vac_portal
=
CreatePortal
(
pname
);
pfree
(
pname
);
/*
* Set flag to indicate that vac_portal must be removed after an error.
* This global variable is checked in the transaction manager on xact
* abort, and the routine CommonSpecialPortalClose() is called if
* necessary.
*/
CommonSpecialPortalInUse
=
true
;
}
void
CommonSpecialPortalClose
(
void
)
{
/* Clear flag first, to avoid recursion if PortalDrop elog's */
CommonSpecialPortalInUse
=
false
;
/*
* Release our portal for cross-transaction memory.
*/
PortalDrop
(
&
vac_portal
);
}
PortalVariableMemory
CommonSpecialPortalGetMemory
(
void
)
{
return
PortalGetVariableMemory
(
vac_portal
);
}
bool
CommonSpecialPortalIsOpen
(
void
)
{
return
CommonSpecialPortalInUse
;
}
/* CommonSpecialPortal function at the bottom */
void
vacuum
(
char
*
vacrel
,
bool
verbose
,
bool
analyze
,
List
*
va_spec
)
...
...
@@ -299,6 +245,11 @@ vac_vacuum(NameData *VacRelP, bool analyze, List *va_cols)
/* vacuum each heap relation */
for
(
cur
=
vrl
;
cur
!=
(
VRelList
)
NULL
;
cur
=
cur
->
vrl_next
)
vacuum_rel
(
cur
->
vrl_relid
,
analyze
,
va_cols
);
/* analyze separately so locking is minimized */
if
(
analyze
)
for
(
cur
=
vrl
;
cur
!=
(
VRelList
)
NULL
;
cur
=
cur
->
vrl_next
)
analyze_rel
(
cur
->
vrl_relid
,
va_cols
);
}
static
VRelList
...
...
@@ -410,8 +361,7 @@ getrels(NameData *VacRelP)
static
void
vacuum_rel
(
Oid
relid
,
bool
analyze
,
List
*
va_cols
)
{
HeapTuple
tuple
,
typetuple
;
HeapTuple
tuple
;
Relation
onerel
;
VPageListData
vacuum_pages
;
/* List of pages to vacuum and/or clean
* indices */
...
...
@@ -474,125 +424,6 @@ vacuum_rel(Oid relid, bool analyze, List *va_cols)
vacrelstats
->
num_pages
=
vacrelstats
->
num_tuples
=
0
;
vacrelstats
->
hasindex
=
false
;
/*
* we can VACUUM ANALYZE any table except pg_statistic; see
* update_stats
*/
if
(
analyze
&&
strcmp
(
RelationGetRelationName
(
onerel
),
StatisticRelationName
)
!=
0
)
{
int
attr_cnt
,
*
attnums
=
NULL
;
Form_pg_attribute
*
attr
;
attr_cnt
=
onerel
->
rd_att
->
natts
;
attr
=
onerel
->
rd_att
->
attrs
;
if
(
va_cols
!=
NIL
)
{
int
tcnt
=
0
;
List
*
le
;
if
(
length
(
va_cols
)
>
attr_cnt
)
elog
(
ERROR
,
"vacuum: too many attributes specified for relation %s"
,
RelationGetRelationName
(
onerel
));
attnums
=
(
int
*
)
palloc
(
attr_cnt
*
sizeof
(
int
));
foreach
(
le
,
va_cols
)
{
char
*
col
=
(
char
*
)
lfirst
(
le
);
for
(
i
=
0
;
i
<
attr_cnt
;
i
++
)
{
if
(
namestrcmp
(
&
(
attr
[
i
]
->
attname
),
col
)
==
0
)
break
;
}
if
(
i
<
attr_cnt
)
/* found */
attnums
[
tcnt
++
]
=
i
;
else
{
elog
(
ERROR
,
"vacuum: there is no attribute %s in %s"
,
col
,
RelationGetRelationName
(
onerel
));
}
}
attr_cnt
=
tcnt
;
}
vacrelstats
->
vacattrstats
=
(
VacAttrStats
*
)
palloc
(
attr_cnt
*
sizeof
(
VacAttrStats
));
for
(
i
=
0
;
i
<
attr_cnt
;
i
++
)
{
Operator
func_operator
;
Form_pg_operator
pgopform
;
VacAttrStats
*
stats
;
stats
=
&
vacrelstats
->
vacattrstats
[
i
];
stats
->
attr
=
palloc
(
ATTRIBUTE_TUPLE_SIZE
);
memmove
(
stats
->
attr
,
attr
[((
attnums
)
?
attnums
[
i
]
:
i
)],
ATTRIBUTE_TUPLE_SIZE
);
stats
->
best
=
stats
->
guess1
=
stats
->
guess2
=
0
;
stats
->
max
=
stats
->
min
=
0
;
stats
->
best_len
=
stats
->
guess1_len
=
stats
->
guess2_len
=
0
;
stats
->
max_len
=
stats
->
min_len
=
0
;
stats
->
initialized
=
false
;
stats
->
best_cnt
=
stats
->
guess1_cnt
=
stats
->
guess1_hits
=
stats
->
guess2_hits
=
0
;
stats
->
max_cnt
=
stats
->
min_cnt
=
stats
->
null_cnt
=
stats
->
nonnull_cnt
=
0
;
func_operator
=
oper
(
"="
,
stats
->
attr
->
atttypid
,
stats
->
attr
->
atttypid
,
true
);
if
(
func_operator
!=
NULL
)
{
pgopform
=
(
Form_pg_operator
)
GETSTRUCT
(
func_operator
);
fmgr_info
(
pgopform
->
oprcode
,
&
(
stats
->
f_cmpeq
));
}
else
stats
->
f_cmpeq
.
fn_addr
=
NULL
;
func_operator
=
oper
(
"<"
,
stats
->
attr
->
atttypid
,
stats
->
attr
->
atttypid
,
true
);
if
(
func_operator
!=
NULL
)
{
pgopform
=
(
Form_pg_operator
)
GETSTRUCT
(
func_operator
);
fmgr_info
(
pgopform
->
oprcode
,
&
(
stats
->
f_cmplt
));
stats
->
op_cmplt
=
oprid
(
func_operator
);
}
else
{
stats
->
f_cmplt
.
fn_addr
=
NULL
;
stats
->
op_cmplt
=
InvalidOid
;
}
func_operator
=
oper
(
">"
,
stats
->
attr
->
atttypid
,
stats
->
attr
->
atttypid
,
true
);
if
(
func_operator
!=
NULL
)
{
pgopform
=
(
Form_pg_operator
)
GETSTRUCT
(
func_operator
);
fmgr_info
(
pgopform
->
oprcode
,
&
(
stats
->
f_cmpgt
));
}
else
stats
->
f_cmpgt
.
fn_addr
=
NULL
;
typetuple
=
SearchSysCacheTuple
(
TYPEOID
,
ObjectIdGetDatum
(
stats
->
attr
->
atttypid
),
0
,
0
,
0
);
if
(
HeapTupleIsValid
(
typetuple
))
{
stats
->
outfunc
=
((
Form_pg_type
)
GETSTRUCT
(
typetuple
))
->
typoutput
;
stats
->
typelem
=
((
Form_pg_type
)
GETSTRUCT
(
typetuple
))
->
typelem
;
}
else
{
stats
->
outfunc
=
InvalidOid
;
stats
->
typelem
=
InvalidOid
;
}
}
vacrelstats
->
va_natts
=
attr_cnt
;
/* delete existing pg_statistic rows for relation */
del_stats
(
relid
,
((
attnums
)
?
attr_cnt
:
0
),
attnums
);
if
(
attnums
)
pfree
(
attnums
);
}
else
{
vacrelstats
->
va_natts
=
0
;
vacrelstats
->
vacattrstats
=
(
VacAttrStats
*
)
NULL
;
}
GetXmaxRecent
(
&
XmaxRecent
);
/* scan it */
...
...
@@ -631,7 +462,7 @@ vacuum_rel(Oid relid, bool analyze, List *va_cols)
vacuum_index
(
&
vacuum_pages
,
Irel
[
i
],
vacrelstats
->
num_tuples
,
0
);
}
else
/* just scan indices to update statistic */
/* just scan indices to update statistic */
{
for
(
i
=
0
;
i
<
nindices
;
i
++
)
scan_index
(
Irel
[
i
],
vacrelstats
->
num_tuples
);
...
...
@@ -662,17 +493,197 @@ vacuum_rel(Oid relid, bool analyze, List *va_cols)
pfree
(
fraged_pages
.
vpl_pagedesc
);
}
/* update statistics in pg_class */
update_stats
(
vacrelstats
->
relid
,
vacrelstats
->
num_pages
,
vacrelstats
->
num_tuples
,
vacrelstats
->
hasindex
,
vacrelstats
);
/* all done with this class, but hold lock until commit */
heap_close
(
onerel
,
NoLock
);
/* update statistics in pg_class */
update_relstats
(
vacrelstats
->
relid
,
vacrelstats
->
num_pages
,
vacrelstats
->
num_tuples
,
vacrelstats
->
hasindex
,
vacrelstats
);
/* next command frees attribute stats */
CommitTransactionCommand
();
}
/*
* analyze_rel() -- analyze relation
*/
static
void
analyze_rel
(
Oid
relid
,
List
*
va_cols
)
{
HeapTuple
tuple
,
typetuple
;
Relation
onerel
;
int32
i
;
int
attr_cnt
,
*
attnums
=
NULL
;
Form_pg_attribute
*
attr
;
VacAttrStats
*
vacattrstats
;
HeapScanDesc
scan
;
StartTransactionCommand
();
/*
* Check for user-requested abort. Note we want this to be inside a
* transaction, so xact.c doesn't issue useless NOTICE.
*/
if
(
QueryCancel
)
CancelQuery
();
/*
* Race condition -- if the pg_class tuple has gone away since the
* last time we saw it, we don't need to vacuum it.
*/
tuple
=
SearchSysCacheTuple
(
RELOID
,
ObjectIdGetDatum
(
relid
),
0
,
0
,
0
);
/*
* We can VACUUM ANALYZE any table except pg_statistic.
* see update_relstats
*/
if
(
!
HeapTupleIsValid
(
tuple
)
||
strcmp
(
NameStr
(((
Form_pg_class
)
GETSTRUCT
(
tuple
))
->
relname
),
StatisticRelationName
)
==
0
)
{
CommitTransactionCommand
();
return
;
}
/*
* Open the class, get an exclusive lock on it, and check permissions.
*
* Note we choose to treat permissions failure as a NOTICE and keep
* trying to vacuum the rest of the DB --- is this appropriate?
*/
onerel
=
heap_open
(
relid
,
AccessShareLock
);
#ifndef NO_SECURITY
if
(
!
pg_ownercheck
(
GetPgUserName
(),
RelationGetRelationName
(
onerel
),
RELNAME
))
{
/* we already did an elog during vacuum
elog(NOTICE, "Skipping \"%s\" --- only table owner can VACUUM it",
RelationGetRelationName(onerel));
*/
heap_close
(
onerel
,
AccessExclusiveLock
);
CommitTransactionCommand
();
return
;
}
#endif
attr_cnt
=
onerel
->
rd_att
->
natts
;
attr
=
onerel
->
rd_att
->
attrs
;
if
(
va_cols
!=
NIL
)
{
int
tcnt
=
0
;
List
*
le
;
if
(
length
(
va_cols
)
>
attr_cnt
)
elog
(
ERROR
,
"vacuum: too many attributes specified for relation %s"
,
RelationGetRelationName
(
onerel
));
attnums
=
(
int
*
)
palloc
(
attr_cnt
*
sizeof
(
int
));
foreach
(
le
,
va_cols
)
{
char
*
col
=
(
char
*
)
lfirst
(
le
);
for
(
i
=
0
;
i
<
attr_cnt
;
i
++
)
{
if
(
namestrcmp
(
&
(
attr
[
i
]
->
attname
),
col
)
==
0
)
break
;
}
if
(
i
<
attr_cnt
)
/* found */
attnums
[
tcnt
++
]
=
i
;
else
{
elog
(
ERROR
,
"vacuum: there is no attribute %s in %s"
,
col
,
RelationGetRelationName
(
onerel
));
}
}
attr_cnt
=
tcnt
;
}
vacattrstats
=
(
VacAttrStats
*
)
palloc
(
attr_cnt
*
sizeof
(
VacAttrStats
));
for
(
i
=
0
;
i
<
attr_cnt
;
i
++
)
{
Operator
func_operator
;
Form_pg_operator
pgopform
;
VacAttrStats
*
stats
;
stats
=
&
vacattrstats
[
i
];
stats
->
attr
=
palloc
(
ATTRIBUTE_TUPLE_SIZE
);
memmove
(
stats
->
attr
,
attr
[((
attnums
)
?
attnums
[
i
]
:
i
)],
ATTRIBUTE_TUPLE_SIZE
);
stats
->
best
=
stats
->
guess1
=
stats
->
guess2
=
0
;
stats
->
max
=
stats
->
min
=
0
;
stats
->
best_len
=
stats
->
guess1_len
=
stats
->
guess2_len
=
0
;
stats
->
max_len
=
stats
->
min_len
=
0
;
stats
->
initialized
=
false
;
stats
->
best_cnt
=
stats
->
guess1_cnt
=
stats
->
guess1_hits
=
stats
->
guess2_hits
=
0
;
stats
->
max_cnt
=
stats
->
min_cnt
=
stats
->
null_cnt
=
stats
->
nonnull_cnt
=
0
;
func_operator
=
oper
(
"="
,
stats
->
attr
->
atttypid
,
stats
->
attr
->
atttypid
,
true
);
if
(
func_operator
!=
NULL
)
{
pgopform
=
(
Form_pg_operator
)
GETSTRUCT
(
func_operator
);
fmgr_info
(
pgopform
->
oprcode
,
&
(
stats
->
f_cmpeq
));
}
else
stats
->
f_cmpeq
.
fn_addr
=
NULL
;
func_operator
=
oper
(
"<"
,
stats
->
attr
->
atttypid
,
stats
->
attr
->
atttypid
,
true
);
if
(
func_operator
!=
NULL
)
{
pgopform
=
(
Form_pg_operator
)
GETSTRUCT
(
func_operator
);
fmgr_info
(
pgopform
->
oprcode
,
&
(
stats
->
f_cmplt
));
stats
->
op_cmplt
=
oprid
(
func_operator
);
}
else
{
stats
->
f_cmplt
.
fn_addr
=
NULL
;
stats
->
op_cmplt
=
InvalidOid
;
}
func_operator
=
oper
(
">"
,
stats
->
attr
->
atttypid
,
stats
->
attr
->
atttypid
,
true
);
if
(
func_operator
!=
NULL
)
{
pgopform
=
(
Form_pg_operator
)
GETSTRUCT
(
func_operator
);
fmgr_info
(
pgopform
->
oprcode
,
&
(
stats
->
f_cmpgt
));
}
else
stats
->
f_cmpgt
.
fn_addr
=
NULL
;
typetuple
=
SearchSysCacheTuple
(
TYPEOID
,
ObjectIdGetDatum
(
stats
->
attr
->
atttypid
),
0
,
0
,
0
);
if
(
HeapTupleIsValid
(
typetuple
))
{
stats
->
outfunc
=
((
Form_pg_type
)
GETSTRUCT
(
typetuple
))
->
typoutput
;
stats
->
typelem
=
((
Form_pg_type
)
GETSTRUCT
(
typetuple
))
->
typelem
;
}
else
{
stats
->
outfunc
=
InvalidOid
;
stats
->
typelem
=
InvalidOid
;
}
}
/* delete existing pg_statistic rows for relation */
del_stats
(
relid
,
((
attnums
)
?
attr_cnt
:
0
),
attnums
);
scan
=
heap_beginscan
(
onerel
,
false
,
SnapshotNow
,
0
,
NULL
);
while
(
HeapTupleIsValid
(
tuple
=
heap_getnext
(
scan
,
0
)))
attr_stats
(
onerel
,
attr_cnt
,
vacattrstats
,
tuple
);
heap_endscan
(
scan
);
heap_close
(
onerel
,
AccessShareLock
);
/* update statistics in pg_class */
update_attstats
(
relid
,
attr_cnt
,
vacattrstats
);
CommitTransactionCommand
();
}
/*
* scan_heap() -- scan an open heap relation
*
...
...
@@ -979,7 +990,6 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
min_tlen
=
tuple
.
t_len
;
if
(
tuple
.
t_len
>
max_tlen
)
max_tlen
=
tuple
.
t_len
;
attr_stats
(
onerel
,
vacrelstats
,
&
tuple
);
}
}
...
...
@@ -2106,7 +2116,7 @@ scan_index(Relation indrel, int num_tuples)
/* now update statistics in pg_class */
nipages
=
RelationGetNumberOfBlocks
(
indrel
);
update_stats
(
RelationGetRelid
(
indrel
),
nipages
,
nitups
,
false
,
NULL
);
update_
rel
stats
(
RelationGetRelid
(
indrel
),
nipages
,
nitups
,
false
,
NULL
);
elog
(
MESSAGE_LEVEL
,
"Index %s: Pages %u; Tuples %u. %s"
,
RelationGetRelationName
(
indrel
),
nipages
,
nitups
,
...
...
@@ -2183,7 +2193,7 @@ vacuum_index(VPageList vpl, Relation indrel, int num_tuples, int keep_tuples)
/* now update statistics in pg_class */
num_pages
=
RelationGetNumberOfBlocks
(
indrel
);
update_stats
(
RelationGetRelid
(
indrel
),
num_pages
,
num_index_tuples
,
false
,
NULL
);
update_
rel
stats
(
RelationGetRelid
(
indrel
),
num_pages
,
num_index_tuples
,
false
,
NULL
);
elog
(
MESSAGE_LEVEL
,
"Index %s: Pages %u; Tuples %u: Deleted %u. %s"
,
RelationGetRelationName
(
indrel
),
num_pages
,
...
...
@@ -2263,11 +2273,9 @@ tid_reaped(ItemPointer itemptr, VPageList vpl)
*
*/
static
void
attr_stats
(
Relation
onerel
,
VRelStats
*
vacrel
stats
,
HeapTuple
tuple
)
attr_stats
(
Relation
onerel
,
int
attr_cnt
,
VacAttrStats
*
vacattr
stats
,
HeapTuple
tuple
)
{
int
i
,
attr_cnt
=
vacrelstats
->
va_natts
;
VacAttrStats
*
vacattrstats
=
vacrelstats
->
vacattrstats
;
int
i
;
TupleDesc
tupDesc
=
onerel
->
rd_att
;
Datum
value
;
bool
isnull
;
...
...
@@ -2387,7 +2395,7 @@ bucketcpy(Form_pg_attribute attr, Datum value, Datum *bucket, int *bucket_len)
}
/*
* update_stats() -- update statistics for one relation
* update_
rel
stats() -- update statistics for one relation
*
* Statistics are stored in several places: the pg_class row for the
* relation has stats about the whole relation, the pg_attribute rows
...
...
@@ -2408,29 +2416,15 @@ bucketcpy(Form_pg_attribute attr, Datum value, Datum *bucket, int *bucket_len)
* Updating pg_class's own statistics would be especially tricky.
* Of course, this only works for fixed-size never-null columns, but
* these are.
*
* Updates of pg_attribute statistics are handled in the same way
* for the same reasons.
*
* To keep things simple, we punt for pg_statistic, and don't try
* to compute or store rows for pg_statistic itself in pg_statistic.
* This could possibly be made to work, but it's not worth the trouble.
*/
static
void
update_stats
(
Oid
relid
,
int
num_pages
,
int
num_tuples
,
bool
hasindex
,
update_
rel
stats
(
Oid
relid
,
int
num_pages
,
int
num_tuples
,
bool
hasindex
,
VRelStats
*
vacrelstats
)
{
Relation
rd
,
ad
,
sd
;
HeapScanDesc
scan
;
Relation
rd
;
HeapTupleData
rtup
;
HeapTuple
ctup
,
atup
,
stup
;
HeapTuple
ctup
;
Form_pg_class
pgcform
;
ScanKeyData
askey
;
Form_pg_attribute
attp
;
Buffer
buffer
;
/*
...
...
@@ -2461,202 +2455,217 @@ update_stats(Oid relid, int num_pages, int num_tuples, bool hasindex,
WriteBuffer
(
buffer
);
heap_close
(
rd
,
RowExclusiveLock
);
}
if
(
vacrelstats
!=
NULL
&&
vacrelstats
->
va_natts
>
0
)
{
VacAttrStats
*
vacattrstats
=
vacrelstats
->
vacattrstats
;
int
natts
=
vacrelstats
->
va_natts
;
/*
* update_attstats() -- update attribute statistics for one relation
*
* Updates of pg_attribute statistics are handled by over-write.
* for reasons described above.
*
* To keep things simple, we punt for pg_statistic, and don't try
* to compute or store rows for pg_statistic itself in pg_statistic.
* This could possibly be made to work, but it's not worth the trouble.
*/
static
void
update_attstats
(
Oid
relid
,
int
natts
,
VacAttrStats
*
vacattrstats
)
{
Relation
ad
,
sd
;
HeapScanDesc
scan
;
HeapTuple
atup
,
stup
;
ScanKeyData
askey
;
Form_pg_attribute
attp
;
ad
=
heap_openr
(
AttributeRelationName
,
RowExclusiveLock
);
sd
=
heap_openr
(
StatisticRelationName
,
RowExclusiveLock
);
ad
=
heap_openr
(
AttributeRelationName
,
RowExclusiveLock
);
sd
=
heap_openr
(
StatisticRelationName
,
RowExclusiveLock
);
/* Find pg_attribute rows for this relation */
ScanKeyEntryInitialize
(
&
askey
,
0
,
Anum_pg_attribute_attrelid
,
F_INT4EQ
,
relid
);
/* Find pg_attribute rows for this relation */
ScanKeyEntryInitialize
(
&
askey
,
0
,
Anum_pg_attribute_attrelid
,
F_INT4EQ
,
relid
);
scan
=
heap_beginscan
(
ad
,
false
,
SnapshotNow
,
1
,
&
askey
);
scan
=
heap_beginscan
(
ad
,
false
,
SnapshotNow
,
1
,
&
askey
);
while
(
HeapTupleIsValid
(
atup
=
heap_getnext
(
scan
,
0
)))
while
(
HeapTupleIsValid
(
atup
=
heap_getnext
(
scan
,
0
)))
{
int
i
;
VacAttrStats
*
stats
;
attp
=
(
Form_pg_attribute
)
GETSTRUCT
(
atup
);
if
(
attp
->
attnum
<=
0
)
/* skip system attributes for now */
continue
;
for
(
i
=
0
;
i
<
natts
;
i
++
)
{
int
i
;
VacAttrStats
*
stats
;
if
(
attp
->
attnum
==
vacattrstats
[
i
].
attr
->
attnum
)
break
;
}
if
(
i
>=
natts
)
continue
;
/* skip attr if no stats collected */
stats
=
&
(
vacattrstats
[
i
]);
attp
=
(
Form_pg_attribute
)
GETSTRUCT
(
atup
);
if
(
attp
->
attnum
<=
0
)
/* skip system attributes for now */
continue
;
if
(
VacAttrStatsEqValid
(
stats
))
{
float32data
selratio
;
/* average ratio of rows selected
* for a random constant */
for
(
i
=
0
;
i
<
natts
;
i
++
)
/* Compute disbursion */
if
(
stats
->
nonnull_cnt
==
0
&&
stats
->
null_cnt
==
0
)
{
if
(
attp
->
attnum
==
vacattrstats
[
i
].
attr
->
attnum
)
break
;
}
if
(
i
>=
natts
)
continue
;
/* skip attr if no stats collected */
stats
=
&
(
vacattrstats
[
i
]);
if
(
VacAttrStatsEqValid
(
stats
))
/*
* empty relation, so put a dummy value in
* attdisbursion
*/
selratio
=
0
;
}
else
if
(
stats
->
null_cnt
<=
1
&&
stats
->
best_cnt
==
1
)
{
float32data
selratio
;
/* average ratio of rows selected
* for a random constant */
/* Compute disbursion */
if
(
stats
->
nonnull_cnt
==
0
&&
stats
->
null_cnt
==
0
)
/*
* looks like we have a unique-key attribute --- flag
* this with special -1.0 flag value.
*
* The correct disbursion is 1.0/numberOfRows, but since
* the relation row count can get updated without
* recomputing disbursion, we want to store a
* "symbolic" value and figure 1.0/numberOfRows on the
* fly.
*/
selratio
=
-
1
;
}
else
{
if
(
VacAttrStatsLtGtValid
(
stats
)
&&
stats
->
min_cnt
+
stats
->
max_cnt
==
stats
->
nonnull_cnt
)
{
/*
* e
mpty relation, so put a dummy value in
*
attdisbursion
* e
xact result when there are just 1 or 2
*
values...
*/
selratio
=
0
;
}
else
if
(
stats
->
null_cnt
<=
1
&&
stats
->
best_cnt
==
1
)
{
double
min_cnt_d
=
stats
->
min_cnt
,
max_cnt_d
=
stats
->
max_cnt
,
null_cnt_d
=
stats
->
null_cnt
;
double
total
=
((
double
)
stats
->
nonnull_cnt
)
+
null_cnt_d
;
/*
* looks like we have a unique-key attribute --- flag
* this with special -1.0 flag value.
*
* The correct disbursion is 1.0/numberOfRows, but since
* the relation row count can get updated without
* recomputing disbursion, we want to store a
* "symbolic" value and figure 1.0/numberOfRows on the
* fly.
*/
selratio
=
-
1
;
selratio
=
(
min_cnt_d
*
min_cnt_d
+
max_cnt_d
*
max_cnt_d
+
null_cnt_d
*
null_cnt_d
)
/
(
total
*
total
);
}
else
{
if
(
VacAttrStatsLtGtValid
(
stats
)
&&
stats
->
min_cnt
+
stats
->
max_cnt
==
stats
->
nonnull_cnt
)
{
/*
* exact result when there are just 1 or 2
* values...
*/
double
min_cnt_d
=
stats
->
min_cnt
,
max_cnt_d
=
stats
->
max_cnt
,
null_cnt_d
=
stats
->
null_cnt
;
double
total
=
((
double
)
stats
->
nonnull_cnt
)
+
null_cnt_d
;
selratio
=
(
min_cnt_d
*
min_cnt_d
+
max_cnt_d
*
max_cnt_d
+
null_cnt_d
*
null_cnt_d
)
/
(
total
*
total
);
}
else
{
double
most
=
(
double
)
(
stats
->
best_cnt
>
stats
->
null_cnt
?
stats
->
best_cnt
:
stats
->
null_cnt
);
double
total
=
((
double
)
stats
->
nonnull_cnt
)
+
((
double
)
stats
->
null_cnt
);
double
most
=
(
double
)
(
stats
->
best_cnt
>
stats
->
null_cnt
?
stats
->
best_cnt
:
stats
->
null_cnt
);
double
total
=
((
double
)
stats
->
nonnull_cnt
)
+
((
double
)
stats
->
null_cnt
);
/*
* we assume count of other values are 20% of best
* count in table
*/
selratio
=
(
most
*
most
+
0
.
20
*
most
*
(
total
-
most
))
/
(
total
*
total
);
}
/* Make sure calculated values are in-range */
if
(
selratio
<
0
.
0
)
selratio
=
0
.
0
;
else
if
(
selratio
>
1
.
0
)
selratio
=
1
.
0
;
/*
* we assume count of other values are 20% of best
* count in table
*/
selratio
=
(
most
*
most
+
0
.
20
*
most
*
(
total
-
most
))
/
(
total
*
total
);
}
/* Make sure calculated values are in-range */
if
(
selratio
<
0
.
0
)
selratio
=
0
.
0
;
else
if
(
selratio
>
1
.
0
)
selratio
=
1
.
0
;
}
/* overwrite the existing statistics in the tuple */
attp
->
attdisbursion
=
selratio
;
/* overwrite the existing statistics in the tuple */
attp
->
attdisbursion
=
selratio
;
/* invalidate the tuple in the cache and write the buffer */
RelationInvalidateHeapTuple
(
ad
,
atup
);
WriteNoReleaseBuffer
(
scan
->
rs_cbuf
);
/* invalidate the tuple in the cache and write the buffer */
RelationInvalidateHeapTuple
(
ad
,
atup
);
WriteNoReleaseBuffer
(
scan
->
rs_cbuf
);
/*
* Create pg_statistic tuples for the relation, if we have
* gathered the right data. del_stats() previously
* deleted all the pg_statistic tuples for the rel, so we
* just have to insert new ones here.
/*
* Create pg_statistic tuples for the relation, if we have
* gathered the right data. del_stats() previously
* deleted all the pg_statistic tuples for the rel, so we
* just have to insert new ones here.
*
* Note vacuum_rel() has seen to it that we won't come here
* when vacuuming pg_statistic itself.
*/
if
(
VacAttrStatsLtGtValid
(
stats
)
&&
stats
->
initialized
)
{
float32data
nullratio
;
float32data
bestratio
;
FmgrInfo
out_function
;
char
*
out_string
;
double
best_cnt_d
=
stats
->
best_cnt
,
null_cnt_d
=
stats
->
null_cnt
,
nonnull_cnt_d
=
stats
->
nonnull_cnt
;
/* prevent overflow */
Datum
values
[
Natts_pg_statistic
];
char
nulls
[
Natts_pg_statistic
];
nullratio
=
null_cnt_d
/
(
nonnull_cnt_d
+
null_cnt_d
);
bestratio
=
best_cnt_d
/
(
nonnull_cnt_d
+
null_cnt_d
);
fmgr_info
(
stats
->
outfunc
,
&
out_function
);
for
(
i
=
0
;
i
<
Natts_pg_statistic
;
++
i
)
nulls
[
i
]
=
' '
;
/* ----------------
* initialize values[]
* ----------------
*/
i
=
0
;
values
[
i
++
]
=
(
Datum
)
relid
;
/* starelid */
values
[
i
++
]
=
(
Datum
)
attp
->
attnum
;
/* staattnum */
values
[
i
++
]
=
(
Datum
)
stats
->
op_cmplt
;
/* staop */
/* hack: this code knows float4 is pass-by-ref */
values
[
i
++
]
=
PointerGetDatum
(
&
nullratio
);
/* stanullfrac */
values
[
i
++
]
=
PointerGetDatum
(
&
bestratio
);
/* stacommonfrac */
out_string
=
(
*
fmgr_faddr
(
&
out_function
))
(
stats
->
best
,
stats
->
typelem
,
stats
->
attr
->
atttypmod
);
values
[
i
++
]
=
PointerGetDatum
(
textin
(
out_string
));
/* stacommonval */
pfree
(
out_string
);
out_string
=
(
*
fmgr_faddr
(
&
out_function
))
(
stats
->
min
,
stats
->
typelem
,
stats
->
attr
->
atttypmod
);
values
[
i
++
]
=
PointerGetDatum
(
textin
(
out_string
));
/* staloval */
pfree
(
out_string
);
out_string
=
(
char
*
)
(
*
fmgr_faddr
(
&
out_function
))
(
stats
->
max
,
stats
->
typelem
,
stats
->
attr
->
atttypmod
);
values
[
i
++
]
=
PointerGetDatum
(
textin
(
out_string
));
/* stahival */
pfree
(
out_string
);
stup
=
heap_formtuple
(
sd
->
rd_att
,
values
,
nulls
);
/* ----------------
* Watch out for oversize tuple, which can happen if
* all three of the saved data values are long.
* Our fallback strategy is just to not store the
* pg_statistic tuple at all in that case. (We could
* replace the values by NULLs and still store the
* numeric stats, but presently selfuncs.c couldn't
* do anything useful with that case anyway.)
*
* Note vacuum_rel() has seen to it that we won't come here
* when vacuuming pg_statistic itself.
* We could reduce the probability of overflow, but not
* prevent it, by storing the data values as compressed
* text; is that worth doing? The problem should go
* away whenever long tuples get implemented...
* ----------------
*/
if
(
VacAttrStatsLtGtValid
(
stats
)
&&
stats
->
initialized
)
if
(
MAXALIGN
(
stup
->
t_len
)
<=
MaxTupleSize
)
{
float32data
nullratio
;
float32data
bestratio
;
FmgrInfo
out_function
;
char
*
out_string
;
double
best_cnt_d
=
stats
->
best_cnt
,
null_cnt_d
=
stats
->
null_cnt
,
nonnull_cnt_d
=
stats
->
nonnull_cnt
;
/* prevent overflow */
Datum
values
[
Natts_pg_statistic
];
char
nulls
[
Natts_pg_statistic
];
nullratio
=
null_cnt_d
/
(
nonnull_cnt_d
+
null_cnt_d
);
bestratio
=
best_cnt_d
/
(
nonnull_cnt_d
+
null_cnt_d
);
fmgr_info
(
stats
->
outfunc
,
&
out_function
);
for
(
i
=
0
;
i
<
Natts_pg_statistic
;
++
i
)
nulls
[
i
]
=
' '
;
/* ----------------
* initialize values[]
* ----------------
*/
i
=
0
;
values
[
i
++
]
=
(
Datum
)
relid
;
/* starelid */
values
[
i
++
]
=
(
Datum
)
attp
->
attnum
;
/* staattnum */
values
[
i
++
]
=
(
Datum
)
stats
->
op_cmplt
;
/* staop */
/* hack: this code knows float4 is pass-by-ref */
values
[
i
++
]
=
PointerGetDatum
(
&
nullratio
);
/* stanullfrac */
values
[
i
++
]
=
PointerGetDatum
(
&
bestratio
);
/* stacommonfrac */
out_string
=
(
*
fmgr_faddr
(
&
out_function
))
(
stats
->
best
,
stats
->
typelem
,
stats
->
attr
->
atttypmod
);
values
[
i
++
]
=
PointerGetDatum
(
textin
(
out_string
));
/* stacommonval */
pfree
(
out_string
);
out_string
=
(
*
fmgr_faddr
(
&
out_function
))
(
stats
->
min
,
stats
->
typelem
,
stats
->
attr
->
atttypmod
);
values
[
i
++
]
=
PointerGetDatum
(
textin
(
out_string
));
/* staloval */
pfree
(
out_string
);
out_string
=
(
char
*
)
(
*
fmgr_faddr
(
&
out_function
))
(
stats
->
max
,
stats
->
typelem
,
stats
->
attr
->
atttypmod
);
values
[
i
++
]
=
PointerGetDatum
(
textin
(
out_string
));
/* stahival */
pfree
(
out_string
);
stup
=
heap_formtuple
(
sd
->
rd_att
,
values
,
nulls
);
/* ----------------
* Watch out for oversize tuple, which can happen if
* all three of the saved data values are long.
* Our fallback strategy is just to not store the
* pg_statistic tuple at all in that case. (We could
* replace the values by NULLs and still store the
* numeric stats, but presently selfuncs.c couldn't
* do anything useful with that case anyway.)
*
* We could reduce the probability of overflow, but not
* prevent it, by storing the data values as compressed
* text; is that worth doing? The problem should go
* away whenever long tuples get implemented...
* ----------------
*/
if
(
MAXALIGN
(
stup
->
t_len
)
<=
MaxTupleSize
)
{
/* OK, store tuple and update indexes too */
Relation
irelations
[
Num_pg_statistic_indices
];
/* OK, store tuple and update indexes too */
Relation
irelations
[
Num_pg_statistic_indices
];
heap_insert
(
sd
,
stup
);
CatalogOpenIndices
(
Num_pg_statistic_indices
,
Name_pg_statistic_indices
,
irelations
);
CatalogIndexInsert
(
irelations
,
Num_pg_statistic_indices
,
sd
,
stup
);
CatalogCloseIndices
(
Num_pg_statistic_indices
,
irelations
);
}
/* release allocated space */
pfree
(
DatumGetPointer
(
values
[
Anum_pg_statistic_stacommonval
-
1
]));
pfree
(
DatumGetPointer
(
values
[
Anum_pg_statistic_staloval
-
1
]));
pfree
(
DatumGetPointer
(
values
[
Anum_pg_statistic_stahival
-
1
]));
heap_freetuple
(
stup
);
heap_insert
(
sd
,
stup
);
CatalogOpenIndices
(
Num_pg_statistic_indices
,
Name_pg_statistic_indices
,
irelations
);
CatalogIndexInsert
(
irelations
,
Num_pg_statistic_indices
,
sd
,
stup
);
CatalogCloseIndices
(
Num_pg_statistic_indices
,
irelations
);
}
/* release allocated space */
pfree
(
DatumGetPointer
(
values
[
Anum_pg_statistic_stacommonval
-
1
]));
pfree
(
DatumGetPointer
(
values
[
Anum_pg_statistic_staloval
-
1
]));
pfree
(
DatumGetPointer
(
values
[
Anum_pg_statistic_stahival
-
1
]));
heap_freetuple
(
stup
);
}
}
heap_endscan
(
scan
);
/* close rels, but hold locks till upcoming commit */
heap_close
(
ad
,
NoLock
);
heap_close
(
sd
,
NoLock
);
}
heap_endscan
(
scan
);
/* close rels, but hold locks till upcoming commit */
heap_close
(
ad
,
NoLock
);
heap_close
(
sd
,
NoLock
);
}
/*
...
...
@@ -2867,6 +2876,62 @@ vac_cmp_vtlinks(const void *left, const void *right)
}
/*
* This routines handle a special cross-transaction portal.
* However it is automatically closed in case of abort.
*/
void
CommonSpecialPortalOpen
(
void
)
{
char
*
pname
;
if
(
CommonSpecialPortalInUse
)
elog
(
ERROR
,
"CommonSpecialPortal is in use"
);
/*
* Create a portal for safe memory across transactions. We need to
* palloc the name space for it because our hash function expects the
* name to be on a longword boundary. CreatePortal copies the name to
* safe storage for us.
*/
pname
=
pstrdup
(
VACPNAME
);
vac_portal
=
CreatePortal
(
pname
);
pfree
(
pname
);
/*
* Set flag to indicate that vac_portal must be removed after an error.
* This global variable is checked in the transaction manager on xact
* abort, and the routine CommonSpecialPortalClose() is called if
* necessary.
*/
CommonSpecialPortalInUse
=
true
;
}
void
CommonSpecialPortalClose
(
void
)
{
/* Clear flag first, to avoid recursion if PortalDrop elog's */
CommonSpecialPortalInUse
=
false
;
/*
* Release our portal for cross-transaction memory.
*/
PortalDrop
(
&
vac_portal
);
}
PortalVariableMemory
CommonSpecialPortalGetMemory
(
void
)
{
return
PortalGetVariableMemory
(
vac_portal
);
}
bool
CommonSpecialPortalIsOpen
(
void
)
{
return
CommonSpecialPortalInUse
;
}
static
void
get_indices
(
Oid
relid
,
int
*
nindices
,
Relation
**
Irel
)
{
...
...
src/include/commands/vacuum.h
View file @
659f79be
...
...
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: vacuum.h,v 1.2
7 2000/04/12 17:16:32
momjian Exp $
* $Id: vacuum.h,v 1.2
8 2000/05/29 15:44:55
momjian Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -125,8 +125,6 @@ typedef struct VRelStats
Size
min_tlen
;
Size
max_tlen
;
bool
hasindex
;
int
va_natts
;
/* number of attrs being analyzed */
VacAttrStats
*
vacattrstats
;
int
num_vtlinks
;
VTupleLink
vtlinks
;
}
VRelStats
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment