greenplumn appendonly_visimap 源码
greenplumn appendonly_visimap 代码
文件路径:/src/backend/access/appendonly/appendonly_visimap.c
/*------------------------------------------------------------------------------
*
* AppendOnlyVisimap
* maintain a visibility bitmap.
*
* Copyright (c) 2013-Present VMware, Inc. or its affiliates.
*
*
* IDENTIFICATION
* src/backend/access/appendonly/appendonly_visimap.c
*
*------------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/appendonly_visimap.h"
#include "access/appendonly_visimap_entry.h"
#include "access/appendonly_visimap_store.h"
#include "access/appendonlytid.h"
#include "access/hash.h"
#include "cdb/cdbappendonlyblockdirectory.h"
#include "storage/fd.h"
#include "utils/guc.h"
#include "utils/memutils.h"
#include "utils/snapmgr.h"
/*
* Key structure for the visimap deletion hash table.
*/
typedef struct AppendOnlyVisiMapDeleteKey
{
/*
* Segno of the dirty visimap entry.
*
* MPP-23546: Changed the type of segno from int to uint64. With uint
* (4-bytes), additional 4-bytes were being used for padding. The padding
* bits may differ for two keys causing two otherwise equal objects to be
* treated as unequal by hash functions. Keeping type to uint64 does not
* change the value of sizeof(AppendOnlyVisiMapDeleteKey) but eliminates
* padding.
*/
uint64 segno;
/*
* First row num of the dirty visimap entry.
*/
uint64 firstRowNum;
} AppendOnlyVisiMapDeleteKey;
/*
* Key/Value structure for the visimap deletion hash table.
*/
typedef struct AppendOnlyVisiMapDeleteData
{
/*
* Key of the visimap entry
*/
AppendOnlyVisiMapDeleteKey key;
/*
* Location of the latest dirty version of the visimap bitmap in the
* BufFile.
*/
int workFileno;
off_t workFileOffset;
/*
* Tuple id of the visimap entry if the visimap entry existed before.
*/
ItemPointerData tupleTid;
} AppendOnlyVisiMapDeleteData;
static void AppendOnlyVisimap_Store(
AppendOnlyVisimap *visiMap);
static void AppendOnlyVisimap_Find(
AppendOnlyVisimap *visiMap,
AOTupleId *tupleId);
/*
* Finishes the visimap operations.
* No other function should be called with the given
* visibility map after this function has been called.
*/
void
AppendOnlyVisimap_Finish(
AppendOnlyVisimap *visiMap,
LOCKMODE lockmode)
{
if (AppendOnlyVisimapEntry_HasChanged(&visiMap->visimapEntry))
{
AppendOnlyVisimap_Store(visiMap);
}
AppendOnlyVisimapStore_Finish(&visiMap->visimapStore, lockmode);
AppendOnlyVisimapEntry_Finish(&visiMap->visimapEntry);
MemoryContextDelete(visiMap->memoryContext);
visiMap->memoryContext = NULL;
}
/*
* Initializes the visimap data structure.
*
* It assumes a zero-allocated visibility map.
* Should not be called twice.
*/
void
AppendOnlyVisimap_Init(
AppendOnlyVisimap *visiMap,
Oid visimapRelid,
Oid visimapIdxid,
LOCKMODE lockmode,
Snapshot appendOnlyMetaDataSnapshot)
{
MemoryContext oldContext;
Assert(visiMap);
Assert(OidIsValid(visimapRelid));
Assert(OidIsValid(visimapIdxid));
visiMap->memoryContext = AllocSetContextCreate(
CurrentMemoryContext,
"VisiMapContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
oldContext = MemoryContextSwitchTo(
visiMap->memoryContext);
AppendOnlyVisimapEntry_Init(&visiMap->visimapEntry,
visiMap->memoryContext);
AppendOnlyVisimapStore_Init(&visiMap->visimapStore,
visimapRelid,
visimapIdxid,
lockmode,
appendOnlyMetaDataSnapshot,
visiMap->memoryContext);
MemoryContextSwitchTo(oldContext);
}
/*
* Moves the visibility map entry so that the given
* AO tuple id is covered by it.
* If necessary a new map entry is initialized.
*
* Assumes that all previous changed information have been
* stored.
* Should not be called when the append-only table has no relation
* Assumes that the visibility has been initialized and not finished.
*/
static void
AppendOnlyVisimap_Find(
AppendOnlyVisimap *visiMap,
AOTupleId *aoTupleId)
{
Assert(visiMap);
Assert(aoTupleId);
elogif(Debug_appendonly_print_visimap, LOG,
"Append-only visi map: Find entry for "
"(tupleId) = %s",
AOTupleIdToString(aoTupleId));
if (!AppendOnlyVisimapStore_Find(&visiMap->visimapStore,
AOTupleIdGet_segmentFileNum(aoTupleId),
AppendOnlyVisimapEntry_GetFirstRowNum(
&visiMap->visimapEntry, aoTupleId),
&visiMap->visimapEntry))
{
/*
* There is no entry that covers the given tuple id.
*/
AppendOnlyVisimapEntry_New(&visiMap->visimapEntry, aoTupleId);
}
}
/*
* Checks if a tuple is visible according to the visibility map.
* A positive result is a necessary but not sufficient condition for
* a tuple to be visible to the user.
*
* Assumes that the visibility has been initialized and not finished.
*/
bool
AppendOnlyVisimap_IsVisible(
AppendOnlyVisimap *visiMap,
AOTupleId *aoTupleId)
{
Assert(visiMap);
elogif(Debug_appendonly_print_visimap, LOG,
"Append-only visi map: Visibility check: "
"(tupleId) = %s",
AOTupleIdToString(aoTupleId));
if (!AppendOnlyVisimapEntry_CoversTuple(&visiMap->visimapEntry,
aoTupleId))
{
/* if necessary persist the current entry before moving. */
if (AppendOnlyVisimapEntry_HasChanged(&visiMap->visimapEntry))
{
AppendOnlyVisimap_Store(visiMap);
}
AppendOnlyVisimap_Find(visiMap, aoTupleId);
}
/* visimap entry is now positioned to cover the aoTupleId */
return AppendOnlyVisimapEntry_IsVisible(&visiMap->visimapEntry,
aoTupleId);
}
/*
* Stores the current visibility map entry information
* in the relation either as update or delete.
*
* Should not be called if AppendOnlyVisimap_Find has not been
* called earlier.
* It may be called when the visibility map entry has not changed. However
* that is usually wasteful.
*
* Assumes that the visibility has been initialized and not finished.
*/
void
AppendOnlyVisimap_Store(
AppendOnlyVisimap *visiMap)
{
Assert(visiMap);
Assert(AppendOnlyVisimapEntry_IsValid(&visiMap->visimapEntry));
AppendOnlyVisimapStore_Store(&visiMap->visimapStore, &visiMap->visimapEntry);
}
/*
* Deletes all visibility information for the given segment file.
*/
void
AppendOnlyVisimap_DeleteSegmentFile(
AppendOnlyVisimap *visiMap,
int segno)
{
Assert(visiMap);
elogif(Debug_appendonly_print_visimap, LOG,
"Delete visimap for segment file %d", segno);
AppendOnlyVisimapStore_DeleteSegmentFile(&visiMap->visimapStore,
segno);
}
/*
* Returns the number of hidden tuples in the relation.
*/
int64
AppendOnlyVisimap_GetRelationHiddenTupleCount(
AppendOnlyVisimap *visiMap)
{
Assert(visiMap);
return AppendOnlyVisimapStore_GetRelationHiddenTupleCount(
&visiMap->visimapStore, &visiMap->visimapEntry);
}
/*
* Returns the number of hidden tuples in a given segment file.
*/
int64
AppendOnlyVisimap_GetSegmentFileHiddenTupleCount(
AppendOnlyVisimap *visiMap,
int segno)
{
Assert(visiMap);
return AppendOnlyVisimapStore_GetSegmentFileHiddenTupleCount(
&visiMap->visimapStore, &visiMap->visimapEntry, segno);
}
/*
* Starts a new scan for invisible tuple ids.
*/
void
AppendOnlyVisimapScan_Init(
AppendOnlyVisimapScan *visiMapScan,
Oid visimapRelid,
Oid visimapIdxid,
LOCKMODE lockmode,
Snapshot appendonlyMetadataSnapshot)
{
Assert(visiMapScan);
Assert(OidIsValid(visimapRelid));
Assert(OidIsValid(visimapIdxid));
AppendOnlyVisimap_Init(&visiMapScan->visimap, visimapRelid, visimapIdxid,
lockmode,
appendonlyMetadataSnapshot);
visiMapScan->indexScan = AppendOnlyVisimapStore_BeginScan(
&visiMapScan->visimap.visimapStore,
0,
NULL);
visiMapScan->isFinished = false;
}
/*
* Returns the next tuple id in the visimap scan that is invisible.
*
* If there was a previous successful call to this function during this can,
* the tupleId parameter should contain the value of the last call.
* The contents of tupleId is undefined if false is returned.
*/
bool
AppendOnlyVisimapScan_GetNextInvisible(
AppendOnlyVisimapScan *visiMapScan,
AOTupleId *tupleId)
{
bool found;
Assert(visiMapScan);
Assert(tupleId);
Assert(!visiMapScan->isFinished);
found = false;
while (!found && !visiMapScan->isFinished)
{
if (!AppendOnlyVisimapEntry_IsValid(
&visiMapScan->visimap.visimapEntry))
{
if (!AppendOnlyVisimapStore_GetNext(
&visiMapScan->visimap.visimapStore,
visiMapScan->indexScan,
ForwardScanDirection,
&visiMapScan->visimap.visimapEntry,
NULL))
{
visiMapScan->isFinished = true;
return false;
}
AOTupleIdSetInvalid(tupleId);
}
if (!AppendOnlyVisimapEntry_GetNextInvisible(
&visiMapScan->visimap.visimapEntry,
tupleId))
{
/*
* no more invisible tuples in this visimap entry. Try next one
*/
AppendOnlyVisimapEntry_Reset(&visiMapScan->visimap.visimapEntry);
}
else
{
/* Found a tuple. The tuple is is already in the out parameter. */
found = true;
}
}
return true;
}
/*
* Finishes a visimap scan.
*/
void
AppendOnlyVisimapScan_Finish(AppendOnlyVisimapScan *visiMapScan,
LOCKMODE lockmode)
{
AppendOnlyVisimapStore_EndScan(&visiMapScan->visimap.visimapStore,
visiMapScan->indexScan);
AppendOnlyVisimap_Finish(&visiMapScan->visimap, lockmode);
}
/*
* Hash function for the visimap deletion hash table.
*/
static uint32
hash_delete_key(const void *key, Size keysize)
{
Assert(keysize == sizeof(AppendOnlyVisiMapDeleteKey));
return DatumGetUInt32(hash_any((const unsigned char *) key,
keysize));
}
/*
* Hash function for comparing two keys of type
* AppendOnlyVisiMapDeleteKey. Equality of keys is of interest and
* not ordering between them (greater/less).
*/
static int
hash_compare_keys(const void *key1, const void *key2, Size keysize)
{
Assert(keysize == sizeof(AppendOnlyVisiMapDeleteKey));
AppendOnlyVisiMapDeleteKey *k1 = (AppendOnlyVisiMapDeleteKey *) key1;
AppendOnlyVisiMapDeleteKey *k2 = (AppendOnlyVisiMapDeleteKey *) key2;
if ((k1->segno == k2->segno) && (k1->firstRowNum == k2->firstRowNum))
{
return 0;
}
return 1;
}
/*
* Inits the visimap delete helper structure.
*
* This prepares the hash table and opens the temporary file.
*/
void
AppendOnlyVisimapDelete_Init(
AppendOnlyVisimapDelete *visiMapDelete,
AppendOnlyVisimap *visiMap)
{
HASHCTL hash_ctl;
Assert(visiMapDelete);
Assert(visiMap);
visiMapDelete->visiMap = visiMap;
MemSet(&hash_ctl, 0, sizeof(hash_ctl));
hash_ctl.keysize = sizeof(AppendOnlyVisiMapDeleteKey);
hash_ctl.entrysize = sizeof(AppendOnlyVisiMapDeleteData);
hash_ctl.hash = hash_delete_key;
hash_ctl.match = hash_compare_keys;
hash_ctl.hcxt = visiMap->memoryContext;
visiMapDelete->dirtyEntryCache = hash_create("VisimapEntryCache",
4, /* start small and extend */
&hash_ctl,
HASH_ELEM | HASH_FUNCTION | HASH_COMPARE);
visiMapDelete->workfile = BufFileCreateTemp("visimap_delete", false /* interXact */);
}
/*
* Rebuild the visimap entry based on the data contents and
* a few other pieces of information.
*/
static void
AppendOnlyVisimapDelete_RebuildEntry(AppendOnlyVisimapEntry *visimapEntry, int segno, int64 firstRowNum, ItemPointer tid)
{
MemoryContext oldContext;
size_t dataSize;
visimapEntry->segmentFileNum = segno;
visimapEntry->firstRowNum = firstRowNum;
dataSize = VARSIZE(visimapEntry->data) -
offsetof(AppendOnlyVisimapData, data);
oldContext = MemoryContextSwitchTo(visimapEntry->memoryContext);
AppendOnlyVisiMapEnty_ReadData(visimapEntry, dataSize);
MemoryContextSwitchTo(oldContext);
/*
* We only stash away a visimap entry when it is dirty. Thus, we mark the
* visimap entry again as dirty during unstash
*/
visimapEntry->dirty = true;
memcpy(&visimapEntry->tupleTid, tid, sizeof(ItemPointerData));
}
/*
* Unstashes a dirty visimap from the spill file.
*/
static void
AppendOnlyVisimapDelete_Unstash(
AppendOnlyVisimapDelete *visiMapDelete, int segno, int64 firstRowNum, AppendOnlyVisiMapDeleteData *deleteData)
{
AppendOnlyVisimap *visiMap;
uint64 len,
dataLen;
AppendOnlyVisiMapDeleteKey key;
Assert(visiMapDelete);
visiMap = visiMapDelete->visiMap;
elogif(Debug_appendonly_print_visimap, LOG,
"Append-only visi map delete: Unstash dirty visimap entry %d/" INT64_FORMAT
", (fileno %d, offset " INT64_FORMAT ")",
segno, firstRowNum, deleteData->workFileno, (int64)deleteData->workFileOffset);
if (BufFileSeek(visiMapDelete->workfile, deleteData->workFileno,
deleteData->workFileOffset, SEEK_SET) != 0)
{
ereport(ERROR,
(errmsg("failed to seek visimap delete buf file"),
errdetail("location (fileno %d, offset " INT64_FORMAT ") visimap entry: %d/" INT64_FORMAT,
deleteData->workFileno, (int64)deleteData->workFileOffset,
segno, firstRowNum)));
}
len = BufFileRead(visiMapDelete->workfile, &key, sizeof(key));
if (len != sizeof(key))
{
ereport(ERROR,
(errmsg("failed to read visimap delete buf file"),
errdetail("location (fileno %d, offset " INT64_FORMAT ") visimap entry: %d/" INT64_FORMAT,
deleteData->workFileno, (int64)deleteData->workFileOffset,
segno, firstRowNum)));
}
Assert(key.segno == segno);
Assert(key.firstRowNum == firstRowNum);
len = BufFileRead(visiMapDelete->workfile, visiMap->visimapEntry.data, 4);
if (len != 4)
{
elog(ERROR, "failed to read visimap delete buf file");
}
dataLen = VARSIZE(visiMap->visimapEntry.data);
/* Now read the remaining part of the entry */
len = BufFileRead(visiMapDelete->workfile,
((char *) visiMap->visimapEntry.data) + 4, dataLen - 4);
if (len != dataLen - 4)
{
ereport(ERROR,
(errmsg("failed to read visimap delete buf file"),
errdetail("location (fileno %d, offset " INT64_FORMAT ") visimap entry: %d/"
INT64_FORMAT ", len " INT64_FORMAT,
deleteData->workFileno, (int64)deleteData->workFileOffset,
segno, firstRowNum, dataLen)));
}
AppendOnlyVisimapDelete_RebuildEntry(&visiMap->visimapEntry,
segno,
firstRowNum,
&deleteData->tupleTid);
}
/*
* Moves the visibility map entry so that the given
* AO tuple id is covered by it.
* If necessary a new map entry is initialized.
* Uses the visimap dirty cache.
*
* Assumes that all previous changed information have been
* stored.
* Should not be called when the append-only table has no relation
* Assumes that the visibility has been initialized and not finished.
*/
static void
AppendOnlyVisimapDelete_Find(
AppendOnlyVisimapDelete *visiMapDelete,
AOTupleId *aoTupleId)
{
AppendOnlyVisimap *visiMap;
uint64 firstRowNum;
AppendOnlyVisiMapDeleteData *r;
AppendOnlyVisiMapDeleteKey key;
Assert(visiMapDelete);
Assert(aoTupleId);
visiMap = visiMapDelete->visiMap;
firstRowNum = AppendOnlyVisimapEntry_GetFirstRowNum(
&visiMap->visimapEntry, aoTupleId);
key.segno = AOTupleIdGet_segmentFileNum(aoTupleId);
key.firstRowNum = firstRowNum;
elogif(Debug_appendonly_print_visimap, LOG,
"Append-only visi map delete: Search dirty visimap entry "
INT64_FORMAT "/" INT64_FORMAT, key.segno, key.firstRowNum);
bool found = false;
r = hash_search(visiMapDelete->dirtyEntryCache, &key,
HASH_FIND, &found);
if (found)
{
Assert(r);
elogif(Debug_appendonly_print_visimap, LOG,
"Append-only visi map delete: Found dirty visimap entry "
INT64_FORMAT "/" INT64_FORMAT,
r->key.segno, r->key.firstRowNum);
Assert(r->key.firstRowNum == key.firstRowNum);
Assert(r->key.segno == key.segno);
AppendOnlyVisimapDelete_Unstash(visiMapDelete, key.segno, key.firstRowNum, r);
}
else
{
if (!AppendOnlyVisimapStore_Find(&visiMap->visimapStore,
AOTupleIdGet_segmentFileNum(aoTupleId),
AppendOnlyVisimapEntry_GetFirstRowNum(
&visiMap->visimapEntry, aoTupleId),
&visiMap->visimapEntry))
{
/*
* There is no entry that covers the given tuple id.
*/
AppendOnlyVisimapEntry_New(&visiMap->visimapEntry, aoTupleId);
}
}
}
/*
* This function stashes away a dirty visimap entry.
* It stores the compression bitmap in the spill file and
* sets the meta information in the hash table.
*/
static void
AppendOnlyVisimapDelete_Stash(
AppendOnlyVisimapDelete *visiMapDelete)
{
AppendOnlyVisimap *visiMap;
AppendOnlyVisiMapDeleteData *r;
AppendOnlyVisiMapDeleteKey key;
MemoryContext oldContext;
bool found;
off_t offset;
int fileno;
Assert(visiMapDelete);
visiMap = visiMapDelete->visiMap;
Assert(visiMap);
key.segno = visiMap->visimapEntry.segmentFileNum;
key.firstRowNum = visiMap->visimapEntry.firstRowNum;
found = false;
r = hash_search(visiMapDelete->dirtyEntryCache, &key,
HASH_ENTER, &found);
if (!found)
{
r->workFileOffset = 0;
r->workFileno = -1;
memset(&r->tupleTid, 0, sizeof(ItemPointerData));
}
Assert(r->key.firstRowNum == key.firstRowNum);
Assert(r->key.segno == key.segno);
oldContext = MemoryContextSwitchTo(visiMap->memoryContext);
AppendOnlyVisimapEntry_WriteData(&visiMap->visimapEntry);
/*
* If the BufFile was seeked to an internal position for reading a
* previously stashed visimap entry before we were called, we must seek
* till the end of it before writing new visimap entries.
*/
if (BufFileSeek(visiMapDelete->workfile, 0, 0, SEEK_END) != 0)
elog(ERROR, "failed to seek to end of visimap buf file");
BufFileTell(visiMapDelete->workfile, &fileno, &offset);
elogif(Debug_appendonly_print_visimap, LOG,
"Append-only visi map delete: Stash dirty visimap entry %d/" INT64_FORMAT,
visiMap->visimapEntry.segmentFileNum, visiMap->visimapEntry.firstRowNum);
if (BufFileWrite(visiMapDelete->workfile, &key, sizeof(key)) != sizeof(key))
{
elog(ERROR, "Failed to write visimap delete spill key information: "
"segno " INT64_FORMAT ", first row " INT64_FORMAT ", offset "
INT64_FORMAT ", length %lu",
key.segno, key.firstRowNum, (int64)offset, sizeof(key));
}
int size = VARSIZE(visiMap->visimapEntry.data);
if (BufFileWrite(visiMapDelete->workfile, visiMap->visimapEntry.data, size) != size)
{
elog(ERROR, "Failed to write visimap delete spill key information: "
"segno " INT64_FORMAT ", first row " INT64_FORMAT ", offset "
INT64_FORMAT ", length %d", key.segno, key.firstRowNum,
(int64)(offset + sizeof(key)), VARSIZE(visiMap->visimapEntry.data));
}
memcpy(&r->tupleTid, &visiMap->visimapEntry.tupleTid, sizeof(ItemPointerData));
r->workFileOffset = offset;
r->workFileno = fileno;
MemoryContextSwitchTo(oldContext);
visiMap->visimapEntry.dirty = false;
}
/*
* Hides a given tuple id.
* If the tuple is not in the current visimap range, the current
* visimap entry is stashed away and the correct one is loaded or
* read from the spill file.
*
* Then, the bit of the tuple is set.
*
* Should only be called when in-order delete of tuples can
* be guranteed. This means that the tuples are deleted in increasing order.
* A special case there this function can be used is when only
* a single tuple is deleted.
* In all other cases, AppendOnlyVisimapDelete_Hide needs to be used.
*/
TM_Result
AppendOnlyVisimapDelete_Hide(AppendOnlyVisimapDelete *visiMapDelete, AOTupleId *aoTupleId)
{
AppendOnlyVisimap *visiMap;
Assert(visiMapDelete);
Assert(aoTupleId);
elogif(Debug_appendonly_print_visimap, LOG,
"Append-only visi map delete: Hide tuple "
"(tupleId) = %s",
AOTupleIdToString(aoTupleId));
visiMap = visiMapDelete->visiMap;
Assert(visiMap);
if (!AppendOnlyVisimapEntry_CoversTuple(&visiMap->visimapEntry,
aoTupleId))
{
/* if necessary persist the current entry before moving. */
if (AppendOnlyVisimapEntry_HasChanged(&visiMap->visimapEntry))
{
AppendOnlyVisimapDelete_Stash(visiMapDelete);
}
AppendOnlyVisimapDelete_Find(visiMapDelete, aoTupleId);
}
return AppendOnlyVisimapEntry_HideTuple(&visiMap->visimapEntry, aoTupleId);
}
static void
AppendOnlyVisimapDelete_WriteBackStashedEntries(AppendOnlyVisimapDelete *visiMapDelete)
{
AppendOnlyVisiMapDeleteData *deleteData;
int64 len,
dataLen;
off_t currentOffset;
int currentFileno;
AppendOnlyVisimap *visiMap;
bool found;
AppendOnlyVisiMapDeleteKey key;
visiMap = visiMapDelete->visiMap;
Assert(visiMap);
if (hash_get_num_entries(visiMapDelete->dirtyEntryCache) == 0)
{
return;
}
if (BufFileSeek(visiMapDelete->workfile, 0, 0, SEEK_SET) != 0)
{
elog(ERROR, "Failed to seek to visimap delete spill beginning");
}
/* Get next entry */
BufFileTell(visiMapDelete->workfile, ¤tFileno, ¤tOffset);
len = BufFileRead(visiMapDelete->workfile, &key, sizeof(key));
while (len == sizeof(key))
{
elogif(Debug_appendonly_print_visimap, LOG,
"Append-only visi map delete: Got next dirty visimap: "
INT64_FORMAT "/" INT64_FORMAT ", offset " INT64_FORMAT,
key.segno, key.firstRowNum, (int64)currentOffset);
/* VARSIZE is only using the first four byte */
len = BufFileRead(visiMapDelete->workfile, visiMap->visimapEntry.data, 4);
if (len != 4)
{
elog(ERROR, "Failed to read visimap delete spill data");
}
dataLen = VARSIZE(visiMap->visimapEntry.data);
Assert(dataLen <= APPENDONLY_VISIMAP_DATA_BUFFER_SIZE);
/* Now read the remaining part of the entry */
len = BufFileRead(visiMapDelete->workfile,
((char *) visiMap->visimapEntry.data) + 4, dataLen - 4);
if (len != (dataLen - 4))
{
elog(ERROR, "Failed to read visimap delete spill data");
}
/*
* Now we search the hash entry and check if we here have the most
* recent version of the visimap entry
*/
found = false;
deleteData = hash_search(visiMapDelete->dirtyEntryCache, &key,
HASH_FIND, &found);
if (!found)
{
elog(ERROR, "Found a stashed visimap entry without corresponding meta data: "
"offset " INT64_FORMAT, (int64)currentOffset);
}
Assert(deleteData);
Assert(deleteData->key.firstRowNum == key.firstRowNum);
Assert(deleteData->key.segno == key.segno);
if (currentFileno != deleteData->workFileno ||
currentOffset != deleteData->workFileOffset)
{
elogif(Debug_appendonly_print_visimap, LOG,
"Append-only visi map delete: Found out-dated stashed dirty visimap: "
"current (fileno %d, offset " INT64_FORMAT ") expected (fileno %d, offset " INT64_FORMAT ")",
currentFileno, (int64)currentOffset,
deleteData->workFileno, (int64)deleteData->workFileOffset);
}
else
{
/*
* Until this point on the data field of the visimap entry has
* valid information. After this the visimap entry is fully
* rebuild.
*/
AppendOnlyVisimapDelete_RebuildEntry(&visiMap->visimapEntry,
deleteData->key.segno,
deleteData->key.firstRowNum,
&deleteData->tupleTid);
AppendOnlyVisimap_Store(visiMapDelete->visiMap);
}
BufFileTell(visiMapDelete->workfile, ¤tFileno, ¤tOffset);
len = BufFileRead(visiMapDelete->workfile, &key, sizeof(key));
}
if (len != 0)
{
elog(ERROR, "Failed to read visimap delete spill data");
}
}
/*
* Finishes the delete operation.
* All the dirty visimap entries are read from the spill file and
* stored in the visimap heap table.
*/
void
AppendOnlyVisimapDelete_Finish(
AppendOnlyVisimapDelete *visiMapDelete)
{
AppendOnlyVisiMapDeleteData *deleteData;
AppendOnlyVisimap *visiMap;
bool found;
AppendOnlyVisiMapDeleteKey key;
visiMap = visiMapDelete->visiMap;
Assert(visiMap);
elogif(Debug_appendonly_print_visimap, LOG, "Write-back all dirty visimap entries");
/*
* Write back the current change because it is be definition the newest.
*/
if (AppendOnlyVisimapEntry_HasChanged(&visiMap->visimapEntry))
{
AppendOnlyVisimap_Store(visiMapDelete->visiMap);
/*
* Make the hash map entry invalid so that we do not overwrite the
* entry later
*/
key.segno = visiMap->visimapEntry.segmentFileNum;
key.firstRowNum = visiMap->visimapEntry.firstRowNum;
found = false;
deleteData = hash_search(visiMapDelete->dirtyEntryCache, &key,
HASH_FIND, &found);
if (found)
{
deleteData->workFileOffset = INT64_MAX;
deleteData->workFileno = -1;
memset(&deleteData->tupleTid, 0, sizeof(ItemPointerData));
}
}
AppendOnlyVisimapDelete_WriteBackStashedEntries(visiMapDelete);
hash_destroy(visiMapDelete->dirtyEntryCache);
BufFileClose(visiMapDelete->workfile);
}
相关信息
相关文章
greenplumn aomd_filehandler 源码
greenplumn appendonly_blkdir_udf 源码
greenplumn appendonly_compaction 源码
greenplumn appendonly_visimap_entry 源码
greenplumn appendonly_visimap_store 源码
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦