mirror of https://github.com/postgres/postgres
kibitzing from Tom Lane. Large objects are now all stored in a single system relation "pg_largeobject" --- no more xinv or xinx files, no more relkind 'l'. This should offer substantial performance improvement for large numbers of LOs, since there won't be directory bloat anymore. It'll also fix problems like running out of locktable space when you access thousands of LOs in one transaction. Also clean up cruft in read/write routines. LOs with "holes" in them (never-written byte ranges) now work just like Unix files with holes do: a hole reads as zeroes but doesn't occupy storage space. INITDB forced!REL7_1_STABLE
parent
d7186cfa9b
commit
4f44aa04b5
@ -0,0 +1,184 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* pg_largeobject.c |
||||
* routines to support manipulation of the pg_largeobject relation |
||||
* |
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* |
||||
* IDENTIFICATION |
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_largeobject.c,v 1.5 2000/10/24 01:38:23 tgl Exp $ |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#include "postgres.h" |
||||
|
||||
#include "access/genam.h" |
||||
#include "access/heapam.h" |
||||
#include "catalog/catname.h" |
||||
#include "catalog/indexing.h" |
||||
#include "catalog/pg_largeobject.h" |
||||
#include "miscadmin.h" |
||||
#include "utils/builtins.h" |
||||
#include "utils/fmgroids.h" |
||||
|
||||
|
||||
/*
|
||||
* Create a large object having the given LO identifier. |
||||
* |
||||
* We do this by inserting an empty first page, so that the object will |
||||
* appear to exist with size 0. Note that the unique index will reject |
||||
* an attempt to create a duplicate page. |
||||
* |
||||
* Return value is OID assigned to the page tuple (any use in it?) |
||||
*/ |
||||
Oid |
||||
LargeObjectCreate(Oid loid) |
||||
{ |
||||
Oid retval; |
||||
Relation pg_largeobject; |
||||
HeapTuple ntup; |
||||
Relation idescs[Num_pg_largeobject_indices]; |
||||
Datum values[Natts_pg_largeobject]; |
||||
char nulls[Natts_pg_largeobject]; |
||||
int i; |
||||
|
||||
pg_largeobject = heap_openr(LargeObjectRelationName, RowExclusiveLock); |
||||
|
||||
/*
|
||||
* Form new tuple |
||||
*/ |
||||
for (i = 0; i < Natts_pg_largeobject; i++) |
||||
{ |
||||
values[i] = (Datum)NULL; |
||||
nulls[i] = ' '; |
||||
} |
||||
|
||||
i = 0; |
||||
values[i++] = ObjectIdGetDatum(loid); |
||||
values[i++] = Int32GetDatum(0); |
||||
values[i++] = DirectFunctionCall1(byteain, |
||||
CStringGetDatum("")); |
||||
|
||||
ntup = heap_formtuple(pg_largeobject->rd_att, values, nulls); |
||||
|
||||
/*
|
||||
* Insert it |
||||
*/ |
||||
retval = heap_insert(pg_largeobject, ntup); |
||||
|
||||
/*
|
||||
* Update indices |
||||
*/ |
||||
if (!IsIgnoringSystemIndexes()) |
||||
{ |
||||
CatalogOpenIndices(Num_pg_largeobject_indices, Name_pg_largeobject_indices, idescs); |
||||
CatalogIndexInsert(idescs, Num_pg_largeobject_indices, pg_largeobject, ntup); |
||||
CatalogCloseIndices(Num_pg_largeobject_indices, idescs); |
||||
} |
||||
|
||||
heap_close(pg_largeobject, RowExclusiveLock); |
||||
|
||||
heap_freetuple(ntup); |
||||
|
||||
return retval; |
||||
} |
||||
|
||||
void |
||||
LargeObjectDrop(Oid loid) |
||||
{ |
||||
bool found = false; |
||||
Relation pg_largeobject; |
||||
Relation pg_lo_idx; |
||||
ScanKeyData skey[1]; |
||||
IndexScanDesc sd; |
||||
RetrieveIndexResult indexRes; |
||||
HeapTupleData tuple; |
||||
Buffer buffer; |
||||
|
||||
ScanKeyEntryInitialize(&skey[0], |
||||
(bits16) 0x0, |
||||
(AttrNumber) 1, |
||||
(RegProcedure) F_OIDEQ, |
||||
ObjectIdGetDatum(loid)); |
||||
|
||||
pg_largeobject = heap_openr(LargeObjectRelationName, RowShareLock); |
||||
pg_lo_idx = index_openr(LargeObjectLOidPNIndex); |
||||
|
||||
sd = index_beginscan(pg_lo_idx, false, 1, skey); |
||||
|
||||
tuple.t_datamcxt = CurrentMemoryContext; |
||||
tuple.t_data = NULL; |
||||
|
||||
while ((indexRes = index_getnext(sd, ForwardScanDirection))) |
||||
{ |
||||
tuple.t_self = indexRes->heap_iptr; |
||||
heap_fetch(pg_largeobject, SnapshotNow, &tuple, &buffer); |
||||
pfree(indexRes); |
||||
if (tuple.t_data != NULL) |
||||
{ |
||||
heap_delete(pg_largeobject, &tuple.t_self, NULL); |
||||
ReleaseBuffer(buffer); |
||||
found = true; |
||||
} |
||||
} |
||||
|
||||
index_endscan(sd); |
||||
|
||||
index_close(pg_lo_idx); |
||||
heap_close(pg_largeobject, RowShareLock); |
||||
|
||||
if (!found) |
||||
elog(ERROR, "LargeObjectDrop: large object %u not found", loid); |
||||
} |
||||
|
||||
bool |
||||
LargeObjectExists(Oid loid) |
||||
{ |
||||
bool retval = false; |
||||
Relation pg_largeobject; |
||||
Relation pg_lo_idx; |
||||
ScanKeyData skey[1]; |
||||
IndexScanDesc sd; |
||||
RetrieveIndexResult indexRes; |
||||
HeapTupleData tuple; |
||||
Buffer buffer; |
||||
|
||||
/*
|
||||
* See if we can find any tuples belonging to the specified LO |
||||
*/ |
||||
ScanKeyEntryInitialize(&skey[0], |
||||
(bits16) 0x0, |
||||
(AttrNumber) 1, |
||||
(RegProcedure) F_OIDEQ, |
||||
ObjectIdGetDatum(loid)); |
||||
|
||||
pg_largeobject = heap_openr(LargeObjectRelationName, RowShareLock); |
||||
pg_lo_idx = index_openr(LargeObjectLOidPNIndex); |
||||
|
||||
sd = index_beginscan(pg_lo_idx, false, 1, skey); |
||||
|
||||
tuple.t_datamcxt = CurrentMemoryContext; |
||||
tuple.t_data = NULL; |
||||
|
||||
while ((indexRes = index_getnext(sd, ForwardScanDirection))) |
||||
{ |
||||
tuple.t_self = indexRes->heap_iptr; |
||||
heap_fetch(pg_largeobject, SnapshotNow, &tuple, &buffer); |
||||
pfree(indexRes); |
||||
if (tuple.t_data != NULL) |
||||
{ |
||||
retval = true; |
||||
ReleaseBuffer(buffer); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
index_endscan(sd); |
||||
|
||||
index_close(pg_lo_idx); |
||||
heap_close(pg_largeobject, RowShareLock); |
||||
|
||||
return retval; |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,63 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* pg_largeobject.h |
||||
* definition of the system "largeobject" relation (pg_largeobject) |
||||
* along with the relation's initial contents. |
||||
* |
||||
* |
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc |
||||
* Portions Copyright (c) 1994, Regents of the University of California |
||||
* |
||||
* $Id: pg_largeobject.h,v 1.5 2000/10/24 01:38:41 tgl Exp $ |
||||
* |
||||
* NOTES |
||||
* the genbki.sh script reads this file and generates .bki |
||||
* information from the DATA() statements. |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#ifndef PG_LARGEOBJECT_H |
||||
#define PG_LARGEOBJECT_H |
||||
|
||||
/* ----------------
|
||||
* postgres.h contains the system type definintions and the |
||||
* CATALOG(), BOOTSTRAP and DATA() sugar words so this file |
||||
* can be read by both genbki.sh and the C compiler. |
||||
* ---------------- |
||||
*/ |
||||
|
||||
/* ----------------
|
||||
* pg_largeobject definition. cpp turns this into |
||||
* typedef struct FormData_pg_largeobject. Large object id |
||||
* is stored in loid; |
||||
* ---------------- |
||||
*/ |
||||
|
||||
CATALOG(pg_largeobject) |
||||
{ |
||||
Oid loid; /* Identifier of large object */ |
||||
int4 pageno; /* Page number (starting from 0) */ |
||||
bytea data; /* Data for page (may be zero-length) */ |
||||
} FormData_pg_largeobject; |
||||
|
||||
/* ----------------
|
||||
* Form_pg_largeobject corresponds to a pointer to a tuple with |
||||
* the format of pg_largeobject relation. |
||||
* ---------------- |
||||
*/ |
||||
typedef FormData_pg_largeobject *Form_pg_largeobject; |
||||
|
||||
/* ----------------
|
||||
* compiler constants for pg_largeobject |
||||
* ---------------- |
||||
*/ |
||||
#define Natts_pg_largeobject 3 |
||||
#define Anum_pg_largeobject_loid 1 |
||||
#define Anum_pg_largeobject_pageno 2 |
||||
#define Anum_pg_largeobject_data 3 |
||||
|
||||
extern Oid LargeObjectCreate(Oid loid); |
||||
extern void LargeObjectDrop(Oid loid); |
||||
extern bool LargeObjectExists(Oid loid); |
||||
|
||||
#endif /* PG_LARGEOBJECT_H */ |
Loading…
Reference in new issue