blob: 4e236ffe5a29e02e95a0a86de756c33ad6bcaf34 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*-------------------------------------------------------------------------
*
* aomd.c
* This code manages append only relations that reside on magnetic disk.
* It serves the same general purpose as smgr/md.c however we introduce
* AO specific file access functions mainly because would like to bypass
* md.c's and bgwriter's fsyncing. AO relations also use a non constant
* block number to file segment mapping unlike heap relations.
*
* As of now we still let md.c create and unlink AO relations for us. This
* may need to change if inconsistencies arise.
*
* Portions Copyright (c) 2008, Greenplum Inc.
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/aomd.h"
#include "catalog/catalog.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/file.h>
#include "utils/guc.h"
#include "access/appendonlytid.h"
#include "cdb/cdbappendonlystorage.h"
#include "cdb/cdbmirroredappendonly.h"
#include "cdb/cdbvars.h"
int
AOSegmentFilePathNameLen(Relation rel)
{
char *basepath;
int len;
/* Get base path for this relation file */
basepath = relpath(rel->rd_node);
/*
* The basepath will be the RelFileNode number. Optional part is dot "." plus
* 6 digit segment file number.
*/
len = strlen(basepath) + 8; // Generous.
pfree(basepath);
return len;
}
/*
* Formats an Append Only relation file segment file name.
*
* The filepathname parameter assume sufficient space.
*/
void
FormatAOSegmentFileName(
char *basepath,
int segno,
int col,
int numCols,
int32 *fileSegNo,
char *filepathname)
{
int pseudoSegNo;
if (col < 0)
{
/*
* Row oriented Append-Only.
*/
pseudoSegNo = segno;
}
else
{
/*
* Column oriented Append-only.
*/
pseudoSegNo = ((segno - 1) * numCols) + (col + 1);
}
*fileSegNo = pseudoSegNo;
if (pseudoSegNo > 0)
{
sprintf(filepathname, "%s/%u", basepath, pseudoSegNo);
}
else
sprintf(filepathname, "%s", basepath);
}
/*
* Make an Append Only relation file segment file name.
*
* The filepathname parameter assume sufficient space.
*/
void
MakeAOSegmentFileName(
Relation rel,
int segno,
int col,
int32 *fileSegNo,
char *filepathname)
{
char *basepath;
int32 fileSegNoLocal;
int numCols;
/* Get base path for this relation file */
basepath = relpath(rel->rd_node);
numCols = rel->rd_att->natts;
FormatAOSegmentFileName(basepath, segno, col, numCols, &fileSegNoLocal, filepathname);
*fileSegNo = fileSegNoLocal;
pfree(basepath);
}
/*
* Open an Append Only relation file segment
*
* The fd module's PathNameOpenFile() is used to open the file, so the
* the File* routines can be used to read, write, close, etc, the file.
*/
bool
OpenAOSegmentFile(
Relation rel,
char *filepathname,
int32 segmentFileNum,
int64 logicalEof,
MirroredAppendOnlyOpen *mirroredOpen)
{
ItemPointerData persistentTid;
int64 persistentSerialNum;
int primaryError;
if (!ReadGpRelfileNode(
rel->rd_node.relNode,
segmentFileNum,
&persistentTid,
&persistentSerialNum))
{
if (logicalEof == 0)
return false;
elog(ERROR, "Did not find gp_relation_node entry for relation name %s, relation id %u, relfilenode %u, segment file #%d, logical eof " INT64_FORMAT,
rel->rd_rel->relname.data,
rel->rd_id,
rel->rd_node.relNode,
segmentFileNum,
logicalEof);
}
MirroredAppendOnly_OpenReadWrite(
mirroredOpen,
&rel->rd_node,
segmentFileNum,
/*
* TODO, in hawq, fix later
*/
/* relationName */ NULL, // Ok to be NULL -- we don't know the name here.
logicalEof,
true,
&primaryError);
if (primaryError != 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("Could not open Append-Only segment file '%s': %s", filepathname, strerror(primaryError)),
errdetail("%s", HdfsGetLastError())));
return true;
}
/*
* Close an Append Only relation file segment
*/
void
CloseAOSegmentFile(MirroredAppendOnlyOpen *mirroredOpen)
{
/*bool mirrorDataLossOccurred;*/ // UNDONE: We need to do something now...
Assert(mirroredOpen->primaryFile > 0);
MirroredAppendOnly_Close(
mirroredOpen/*,
&mirrorDataLossOccurred*/);
}
/*
* Truncate all bytes from offset to end of file.
*/
void
TruncateAOSegmentFile(MirroredAppendOnlyOpen *mirroredOpen, Relation rel, int64 offset, int elevel)
{
int primaryError;
/*bool mirrorDataLossOccurred;*/ // We'll look at this at close time.
char *relname = RelationGetRelationName(rel);
Assert(mirroredOpen->primaryFile > 0);
Assert(offset >= 0);
/*
* Call the 'fd' module with a 64-bit length since AO segment files
* can be multi-gigabyte to the terabytes...
*/
MirroredAppendOnly_Truncate(
mirroredOpen,
offset,
&primaryError/*,
&mirrorDataLossOccurred*/);
if (primaryError != 0)
ereport(elevel,
(errmsg("\"%s\": failed to truncate data after eof: %s",
relname,
strerror(primaryError))));
}