From 8f27e65bddd7d4b8515ce620fb485fdd78fcdf89 Mon Sep 17 00:00:00 2001 From: Constantin Jucovschi Date: Fri, 24 Apr 2009 07:20:22 -0400 Subject: Initial commit --- relblobif/blobtile.file.pgc | 402 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 402 insertions(+) create mode 100644 relblobif/blobtile.file.pgc (limited to 'relblobif/blobtile.file.pgc') diff --git a/relblobif/blobtile.file.pgc b/relblobif/blobtile.file.pgc new file mode 100644 index 0000000..0547fdf --- /dev/null +++ b/relblobif/blobtile.file.pgc @@ -0,0 +1,402 @@ +/* +* This file is part of rasdaman community. +* +* Rasdaman community is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* Rasdaman community is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with rasdaman community. If not, see . +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see +* or contact Peter Baumann via . +*/ +#include "mymalloc/mymalloc.h" +// This is -*- C++ -*- +/************************************************************* + * + * + * PURPOSE: + * implements blobtile interface using the PostgreSQL DBMS. + * + * + * COMMENTS: + * - uses LO blob method, this has been tested to be faster than bytea + * - RMDBG macros generate so weird output that I added DEBUG macros + * although this is very ugly (2 trace facilities in parallel) + * - exceptions thrown are r_Error, either directly or through common + * function generateException() (reladminif) which throws r_Ebase_dbms + * + ************************************************************/ + +using namespace std; + +static const char rcsid[] = "@(#)blobif,BLOBTile: $Id: blobtile.ec,v 1.8 2003/12/27 23:19:03 rasdev Exp $"; + +#include +#include /* atoi */ + +// PG stuff: +#include "libpq-fe.h" /* C interface to PgSQL */ +#include "libpq/libpq-fs.h" /* large object (lo) api */ + +// simple trace facility +// trace macros are activated through externally defined compile variable DEBUG +#include "debug-srv.hh" + +// general embedded SQL related definitions +EXEC SQL include "../reladminif/sqlglobals.h"; + +// libpg connection maintenance +// must have been initiated before use (see databasif.pgc) +extern PGconn *pgConn; + +// all the DBMS independent code is factored out and +// will be included in the resulting .c file +#include "blobtile.hh" +#include "simplefilestorage.hh" +#include "raslib/error.hh" +#include "externs.h" +#include "raslib/rmdebug.hh" +#include "sqlerror.hh" +#include "tileid.hh" +#include "inlinetile.hh" +#include "objectbroker.hh" +#include "dbref.hh" + + +IFileStorage* initFileStorage() { + SimpleFileStorage *fileStorage; + char *path = getenv("RASDATA"); + if (path == NULL) + path="/tmp"; + fileStorage = new SimpleFileStorage(path); + return fileStorage; +} + +// update blob in ras_tiles table, identified by variable myOId (from blobtile.cc), update map ref +void +BLOBTile::updateInDb() throw (r_Error) +{ + RMDBGENTER(3, RMDebug::module_blobif, "BLOBTile", "updateInDb() " << myOId); + ENTER( "BLOBTile::updateInDb" ); + if (fileStorage == NULL) + fileStorage = initFileStorage(); + + Oid tile; + long indbmyoId = 0; + long indbmyoid = 0; + short dataformat = 0; + char pgQuery[SQL_QUERY_BUFFER_SIZE]; + PGresult *pgResult = NULL; + + // (1) --- get tuple + dataformat = dataFormat; + indbmyoid = myOId.getCounter(); + + fileStorage->update(cells, size, indbmyoid); + + // alternative solution for now: + (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "UPDATE RAS_TILES SET DataFormat = %d WHERE BlobId = %d", dataformat, indbmyoid ); + TALK( pgQuery ); + pgResult = PQexec( pgConn, pgQuery ); + if (PQresultStatus(pgResult) != PGRES_COMMAND_OK) + { + LEAVE( "BLOBTile::updateInDb() libpq 'update dataformat' error: " << PQerrorMessage(pgConn) ); + PQclear( pgResult ); + generateException(); + } + + // (4) --- update map ref + DBObject::updateInDb(); + + LEAVE( "BLOBTile::updateInDb, myOId=" << myOId ); + RMDBGEXIT(3, RMDebug::module_blobif, "BLOBTile", "updateInDb() " << myOId); +} // updateInDb() + +// insert new blob into ras_tiles table, update map ref +// tuple is identified by blobtile.cc var myOId +// data is taken from buffer 'cells' containing 'size' bytes +void +BLOBTile::insertInDb() throw (r_Error) +{ + RMDBGENTER(3, RMDebug::module_blobif, "BLOBTile", "insertInDb() " << myOId); + ENTER( "BLOBTile::insertInDb" ); + + if (fileStorage == NULL) + fileStorage = initFileStorage(); + + Oid blobOid; + long indbmyOId2; + short dataformat2; + Oid tile2; + dataformat2 = dataFormat; + + // prelim: + char pgQuery[SQL_QUERY_BUFFER_SIZE]; + PGresult *pgResult = NULL; + + indbmyOId2 = myOId.getCounter(); + TALK( "myOId.getCounter = " << indbmyOId2 ); + + fileStorage->insert(cells, size, indbmyOId2); + + // (2) --- insert tuple into db + (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "INSERT INTO RAS_TILES ( BlobId, DataFormat, Tile) VALUES ( %d, %d, %d )", indbmyOId2, dataformat2, indbmyOId2 ); + TALK( pgQuery ); + pgResult = PQexec( pgConn, pgQuery ); + if (PQresultStatus(pgResult) != PGRES_COMMAND_OK) + { + LEAVE( "BLOBTile::insertInDb() libpq 'insert' error: " << PQerrorMessage(pgConn) ); + PQclear( pgResult ); + generateException(); + } + PQclear( pgResult ); + + // FIXME: other sources have here an updateInDb(); + + // (3) --- update map ref + DBObject::insertInDb(); + + LEAVE( "BLOBTile::insertInDb(), myOId=" << myOId ); + RMDBGEXIT(3, RMDebug::module_blobif, "BLOBTile", "insertInDb() " << myOId); +} // insertInDb() + +// delete one tuple from ras_tiles table, update map ref +// tuple is identified by blobtile.cc var myOId +void +BLOBTile::deleteFromDb() throw (r_Error) +{ + RMDBGENTER(3, RMDebug::module_blobif, "BLOBTile", "deleteFromDb() " << myOId); + ENTER( "BLOBTile::deleteFromDb" ); + if (fileStorage == NULL) + fileStorage = initFileStorage(); + + long blobId; // blob tuple primary key + Oid blobOid; // blob oid "ptr" + + // get counter value (primary key) from oid + blobId = myOId.getCounter(); + + fileStorage->remove(blobId); + PGresult *pgResult = NULL; + char pgQuery[SQL_QUERY_BUFFER_SIZE]; + + (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DELETE FROM RAS_TILES WHERE BlobId = ", blobOid ); + TALK( pgQuery ); + pgResult = PQexec( pgConn, pgQuery ); + if (PQresultStatus(pgResult) != PGRES_COMMAND_OK) + { + LEAVE( "BLOBTile::deleteFromDb() libpq 'delete tuple' error: " << PQerrorMessage(pgConn) ); + PQclear( pgResult ); + generateException(); + } + PQclear( pgResult ); + + // FIXME: other sources have here an updateInDb(); + + // update map ref + DBObject::deleteFromDb(); + + LEAVE( "BLOBTile::deleteFromDb, myOId=" << myOId ); + RMDBGEXIT(3, RMDebug::module_blobif, "BLOBTile", "deleteFromDb() " << myOId); +} + +// delete a range of tuple(s) from ras_tiles table, update map ref +// tuples are identified by target and a range +void +BLOBTile::kill(const OId& target, unsigned int range) +{ + RMDBGENTER(0, RMDebug::module_blobif, "BLOBTile", "kill(" << target << ", " << range <<")"); + ENTER( "BLOBTile::kill, target=" << target << ", range=" << range ); + + long indbmyOId5; + long indbmyOId6; + long blobId; // blob tuple primary key + Oid blobOid; // blob oid "ptr" + char pgQuery[SQL_QUERY_BUFFER_SIZE]; + PGresult *pgResult = NULL; // query result + + DBObject* targetobj = NULL; + IFileStorage *fileStorage = initFileStorage(); + + if (range == 0) // single tuple + { + // (1) --- delete form cache + targetobj = ObjectBroker::isInMemory(target); + if (targetobj) + { + targetobj->setPersistent(false); + } + + // (2) --- free blob + indbmyOId5 = target.getCounter(); + fileStorage->remove(indbmyOId5); + + (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DELETE FROM RAS_TILES WHERE BlobId = %d", indbmyOId5 ); + TALK( pgQuery ); + pgResult = PQexec( pgConn, pgQuery ); + if (PQresultStatus(pgResult) != PGRES_COMMAND_OK) + { + LEAVE( "BLOBTile::kill() libpq 'delete single' error: " << PQerrorMessage(pgConn) ); + PQclear( pgResult ); + generateException(); + } + else if (PQntuples(pgResult) == 0) + { + if (target.getType() == OId::INLINETILEOID) + { + InlineTileId t(target); + if (!t.is_null()) + t->setPersistent(false); + } + //else: this tile has been deleted before + } + PQclear( pgResult ); + } + else + { + // (1) --- iterate over cache and remove + DBObjectPMap& mapRef = ObjectBroker::getMap(target.getType()); + DBObjectPMap::iterator it = mapRef.begin(); + DBObjectPMap::iterator theEnd = mapRef.end(); + OId end(target.getCounter() + range, target.getType()); + while (it != theEnd) + { + if (target <= (const OId&)(*it).first && (*it).first <= (const OId&)end) + { + (*it).second->setPersistent(false); + } + } + + // (2) --- iterate over db and remove + (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DECLARE DeleteLoop CURSOR FOR SELECT Tile FROM RAS_TILES WHERE %d <= BlobId AND BlobId <= %d", indbmyOId5, indbmyOId6 ); + TALK( pgQuery ); + pgResult = PQexec( pgConn, pgQuery ); + if (PQresultStatus(pgResult) != PGRES_TUPLES_OK) + { + LEAVE( "BLOBTile::kill() libpq 'select for deleteLoop' error: " << PQerrorMessage(pgConn) ); + PQclear( pgResult ); + generateException(); + } + + // loop over elements & delete each one + do + { + (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "FETCH NEXT FROM DeleteLoop" ); + TALK( pgQuery ); + pgResult = PQexec( pgConn, pgQuery ); + if (PQresultStatus(pgResult) != PGRES_TUPLES_OK) + { + LEAVE( "BLOBTile::kill() libpq 'fetch next' error: " << PQerrorMessage(pgConn) ); + PQclear( pgResult ); + generateException(); + } + else if (PQntuples(pgResult) != 1) + { + LEAVE( "BLOBTile::kill() libpq 'fetch' did not yield 1 result but " << PQntuples(pgResult) ); + PQclear( pgResult ); + generateException(); + } + blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract value from result + + // delete blob identified by blobOid + fileStorage->remove(blobOid); + // FIXME: what about errors? continue?? + } while (PQresultStatus(pgResult) != PGRES_TUPLES_OK); + PQclear( pgResult ); + + // (3) --- delete tuples in db + indbmyOId5 = target.getCounter(); + indbmyOId6 = end.getCounter(); + (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "DELETE FROM RAS_TILES WHERE %d <= BlobId AND BlobId <= %d", indbmyOId5, indbmyOId6 ); + TALK( pgQuery ); + pgResult = PQexec( pgConn, pgQuery ); + if (PQresultStatus(pgResult) != PGRES_COMMAND_OK) + { + LEAVE( "BLOBTile::kill() libpq 'delete range' error: " << PQerrorMessage(pgConn) ); + PQclear( pgResult ); + generateException(); + } + PQclear( pgResult ); + + } + + LEAVE( "BLOBTile::kill" ); + RMDBGEXIT(0, RMDebug::module_blobif, "BLOBTile", "kill(" << target << " " << target.getType() << ")"); +} + +// read tuple from ras_tiles, identified by blobtile.cc var myOId +// allocates necessary mem into ptr 'cells' and fills it; must be freed elsewhere +// external var 'size' is set to the number of bytes read +void +BLOBTile::readFromDb() throw (r_Error) +{ + RMDBGENTER(3, RMDebug::module_blobif, "BLOBTile", "readFromDb() " << myOId); + ENTER( "BLOBTile::readFromDb" ); + if (fileStorage == NULL) + fileStorage = initFileStorage(); + +#ifdef RMANBENCHMARK + DBObject::readTimer.resume(); +#endif + + Oid blobOid; + long indbmyOId3; + short dataformat3; + short indicatorr3; + PGresult *pgResult = NULL; // PostgreSQL call return values + + indbmyOId3 = myOId.getCounter(); + + // (1) --- access tuple + char pgQuery[SQL_QUERY_BUFFER_SIZE]; + + (void) snprintf( pgQuery, (size_t) sizeof(pgQuery), "SELECT Tile, DataFormat FROM RAS_TILES WHERE BlobId = %d", indbmyOId3 ); + TALK( pgQuery ); + pgResult = PQexec( pgConn, pgQuery ); + if (PQresultStatus(pgResult) != PGRES_TUPLES_OK) + { + LEAVE( "BLOBTile::readFromDb() libpq 'select' error: " << PQerrorMessage(pgConn) ); + PQclear( pgResult ); + generateException(); + } + else if (PQntuples(pgResult) != 1) + { + LEAVE( "BLOBTile::readFromDb() libpq 'select' did not yield 1 result but " << PQntuples(pgResult) ); + PQclear( pgResult ); + throw r_Error(r_Error::r_Error_ObjectUnknown); + } + blobOid = atoi( PQgetvalue( pgResult, 0, 0 ) ); // extract 1st value from result + dataformat3 = atoi( PQgetvalue( pgResult, 0, 1 ) ); // extract 2nd value from result + PQclear( pgResult ); + + // we have a tuple, extract data format + dataFormat = (r_Data_Format)dataformat3; + currentFormat = (r_Data_Format)dataformat3; + TALK( "got dataFormat " << dataFormat ); + + fileStorage->retrieve(indbmyOId3, &cells, &size); + + RMDBGIF(20, RMDebug::module_blobif, "BLOBTileOutput", for (int a = 0; a < size; a++)\ + RMInit::dbgOut << " " << hex << (int)(cells[a]); RMInit::dbgOut << dec << endl;) + + DBObject::readFromDb(); + +#ifdef RMANBENCHMARK + DBObject::readTimer.pause(); +#endif + + LEAVE( "BLOBTile::readFromDb" ); + RMDBGEXIT(3, RMDebug::module_blobif, "BLOBTile", "readFromDb() " << myOId); +} + -- cgit