From: Cédric Villemain Date: Tue, 17 May 2011 21:43:22 +0000 (+0200) Subject: Use get_call_result_type in pgfadvise_loader X-Git-Tag: 1.0~20 X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=dac57c036b4c8be1461c7e08690aaa255e8bca46;p=pgfincore.git Use get_call_result_type in pgfadvise_loader And add a function to handle the file --- diff --git a/pgfincore.c b/pgfincore.c index 0fafda9..83913b5 100644 --- a/pgfincore.c +++ b/pgfincore.c @@ -59,13 +59,25 @@ PG_MODULE_MAGIC; */ typedef struct { - TupleDesc tupd; /* the tuple descriptor */ int advice; /* the posix_fadvise advice */ + TupleDesc tupd; /* the tuple descriptor */ Relation rel; /* the relation */ unsigned int segcount; /* the segment current number */ char *relationpath; /* the relation path */ } pgfadvise_fctx; +/* + * pgfloader structure is needed + * to return values + */ +typedef struct +{ + size_t pageSize; /* os page size */ + size_t pagesFree; /* free page cache */ + size_t pagesLoaded; /* pages loaded */ + size_t pagesUnloaded; /* pages unloaded */ +} pgfloaderStruct; + /* * pgfincore_fctx structure is needed * to keep track of relation path, segment number, ... @@ -86,7 +98,11 @@ Datum pgsysconf(PG_FUNCTION_ARGS); Datum pgfadvise(PG_FUNCTION_ARGS); static int pgfadvise_file(char *filename, int advice, size_t *filesize); -Datum pgfadvise_loader(PG_FUNCTION_ARGS); + +Datum pgfadvise_loader(PG_FUNCTION_ARGS); +static int pgfadvise_loader_file(char *filename, + bool willneed, bool dontneed, VarBit *databit, + pgfloaderStruct *pgfloader); Datum pgfincore(PG_FUNCTION_ARGS); static int pgfincore_file(char *filename, pgfincore_fctx *fctx); @@ -134,7 +150,7 @@ pgsysconf(PG_FUNCTION_ARGS) /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) - elog(ERROR, "return type must be a row type"); + elog(ERROR, "pgsysconf: return type must be a row type"); /* Page size */ values[0] = Int64GetDatum(sysconf(_SC_PAGESIZE)); @@ -175,7 +191,7 @@ pgfadvise_file(char *filename, int advice, size_t *filesize) if (fstat(fd, &st) == -1) { close(fd); - elog(ERROR, "Can not stat object file : %s", filename); + elog(ERROR, "pgfadvise: Can not stat object file : %s", filename); return 2; } @@ -294,7 +310,7 @@ pgfadvise(PG_FUNCTION_ARGS) /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) - elog(ERROR, "return type must be a row type"); + elog(ERROR, "pgfadvise: return type must be a row type"); /* provide the tuple descriptor to the fonction structure */ fctx->tupd = tupdesc; @@ -311,7 +327,7 @@ pgfadvise(PG_FUNCTION_ARGS) { relation_close(fctx->rel, AccessShareLock); elog(NOTICE, - "pgfadvise does not work with temporary tables."); + "pgfadvise: does not work with temporary tables."); pfree(fctx); SRF_RETURN_DONE(funcctx); } @@ -356,7 +372,7 @@ pgfadvise(PG_FUNCTION_ARGS) filename, fctx->advice); /* - * Call posix_fadvise with the handler + * Call posix_fadvise with the advice, returning the filesize */ result = pgfadvise_file(filename, fctx->advice, &filesize); @@ -403,38 +419,17 @@ pgfadvise(PG_FUNCTION_ARGS) } /* -* -* pgfadv_loader to handle work with varbit map of buffer cache. -* it is actually used for loading/unloading block to/from buffer cache -* -*/ -PG_FUNCTION_INFO_V1(pgfadvise_loader); -Datum -pgfadvise_loader(PG_FUNCTION_ARGS) + * pgfadvise_file + */ +static int +pgfadvise_loader_file(char *filename, + bool willneed, bool dontneed, VarBit *databit, + pgfloaderStruct *pgfloader) { - Oid relOid = PG_GETARG_OID(0); - text *forkName = PG_GETARG_TEXT_P(1); - int segmentNumber = PG_GETARG_INT32(2); - bool willneed = PG_GETARG_BOOL(3); - bool dontneed = PG_GETARG_BOOL(4); - VarBit *s = PG_GETARG_VARBIT_P(5); - - Relation rel; - char *relationpath; - char filename[MAXPGPATH]; - bits8 *sp; + int bitlen; bits8 x; int i, k; - int bitlen; - - /* - * we count the action we did - * both are theorical : we don't know if the page was or not in memory - * when we call posix_fadvise - */ - int64 pages_loaded = 0; - int64 pages_unloaded = 0; /* * We work directly with the file @@ -446,87 +441,35 @@ pgfadvise_loader(PG_FUNCTION_ARGS) /* * OS things : Page size */ - int64 pageSize = sysconf(_SC_PAGESIZE); - int64 pagesFree = sysconf(_SC_AVPHYS_PAGES); - - /* - * Postgresql stuff to return a tuple - */ - HeapTuple tuple; - TupleDesc tupdesc; - Datum values[PGFADVISE_LOADER_COLS]; - bool nulls[PGFADVISE_LOADER_COLS]; - - tupdesc = CreateTemplateTupleDesc(PGFADVISE_LOADER_COLS, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relpath", TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "os_page_size", INT8OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 3, "os_pages_free", INT8OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pages_loaded", INT8OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 5, "pages_unloaded", INT8OID, -1, 0); - tupdesc = BlessTupleDesc(tupdesc); - - /* open the current relation in accessShareLock */ - rel = relation_open(relOid, AccessShareLock); - - /* - * Because temp tables are not in the same directory, we fail - * XXX: can be fixed - */ - if (RelationUsesTempNamespace(rel)) - { - relation_close(rel, AccessShareLock); - elog(NOTICE, - "pgfincore does not work with temporary tables."); - PG_RETURN_VOID(); - } + pgfloader->pageSize = sysconf(_SC_PAGESIZE); - /* we get the common part of the filename of each segment of a relation */ - relationpath = relpathperm(rel->rd_node, - forkname_to_number(text_to_cstring(forkName)) - ); /* - * If we are looking the first segment, - * relationpath should not be suffixed - */ - if (segmentNumber == 0) - snprintf(filename, - MAXPGPATH, - "%s", - relationpath); - else - snprintf(filename, - MAXPGPATH, - "%s.%u", - relationpath, - (int) segmentNumber); - - /* - * We don't need the relation anymore - * the only purpose was to get a consistent filename - * (if file disappear, an error is logged) + * we count the action we perform + * both are theorical : we don't know if the page was or not in memory + * when we call posix_fadvise */ - relation_close(rel, AccessShareLock); + pgfloader->pagesLoaded = 0; + pgfloader->pagesUnloaded = 0; /* - * Open, fstat file + * Open and fstat file + * fd will be provided to posix_fadvise + * if there is no file, just return 1, it is expected to leave the SRF */ fd = open(filename, O_RDONLY); - if (fd == -1) - { - elog(ERROR, "Can not open file: %s", filename); - PG_RETURN_VOID(); - } - + return 1; if (fstat(fd, &st) == -1) { close(fd); - elog(ERROR, "Can not stat object file : %s", filename); - PG_RETURN_VOID(); + elog(ERROR, "pgfadvise_loader: Can not stat object file: %s", filename); + return 2; } - bitlen = VARBITLEN(s); - sp = VARBITS(s); + elog(DEBUG1, "pgfadvise_loader: working on %s", filename); + + bitlen = VARBITLEN(databit); + sp = VARBITS(databit); for (i = 0; i < bitlen - BITS_PER_BYTE; i += BITS_PER_BYTE, sp++) { x = *sp; @@ -538,19 +481,19 @@ pgfadvise_loader(PG_FUNCTION_ARGS) if (willneed) { (void) posix_fadvise(fd, - ((i+k) * pageSize), - pageSize, + ((i+k) * pgfloader->pageSize), + pgfloader->pageSize, POSIX_FADV_WILLNEED); - pages_loaded++; + pgfloader->pagesLoaded++; } } else if (dontneed) { (void) posix_fadvise(fd, - ((i+k) * pageSize), - pageSize, + ((i+k) * pgfloader->pageSize), + pgfloader->pageSize, POSIX_FADV_DONTNEED); - pages_unloaded++; + pgfloader->pagesUnloaded++; } x <<= 1; @@ -570,36 +513,138 @@ pgfadvise_loader(PG_FUNCTION_ARGS) if (willneed) { (void) posix_fadvise(fd, - (k * pageSize), - pageSize, + (k * pgfloader->pageSize), + pgfloader->pageSize, POSIX_FADV_WILLNEED); - pages_loaded++; + pgfloader->pagesLoaded++; } } else if (dontneed) { (void) posix_fadvise(fd, - (k * pageSize), - pageSize, + (k * pgfloader->pageSize), + pgfloader->pageSize, POSIX_FADV_DONTNEED); - pages_unloaded++; + pgfloader->pagesUnloaded++; } x <<= 1; } } close(fd); + /* + * OS things : Pages free + */ + pgfloader->pagesFree = sysconf(_SC_AVPHYS_PAGES); + + return 0; +} + +/* +* +* pgfadv_loader to handle work with varbit map of buffer cache. +* it is actually used for loading/unloading block to/from buffer cache +* +*/ +PG_FUNCTION_INFO_V1(pgfadvise_loader); +Datum +pgfadvise_loader(PG_FUNCTION_ARGS) +{ + Oid relOid = PG_GETARG_OID(0); + text *forkName = PG_GETARG_TEXT_P(1); + int segmentNumber = PG_GETARG_INT32(2); + bool willneed = PG_GETARG_BOOL(3); + bool dontneed = PG_GETARG_BOOL(4); + VarBit *databit = PG_GETARG_VARBIT_P(5); + + pgfloaderStruct *pgfloader; + + Relation rel; + char *relationpath; + char filename[MAXPGPATH]; + + /* our return value, 0 for success */ + int result; + + /* + * Postgresql stuff to return a tuple + */ + HeapTuple tuple; + TupleDesc tupdesc; + Datum values[PGFADVISE_LOADER_COLS]; + bool nulls[PGFADVISE_LOADER_COLS]; + + /* initialize nulls array to build the tuple */ + memset(nulls, 0, sizeof(nulls)); + + /* Build a tuple descriptor for our result type */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + elog(ERROR, "return type must be a row type"); + + /* allocate memory for user context */ + pgfloader = (pgfloaderStruct *) palloc(sizeof(pgfloaderStruct)); + + /* open the current relation in accessShareLock */ + rel = relation_open(relOid, AccessShareLock); + + /* + * Because temp tables are not in the same directory, we fail + * XXX: can be fixed + */ + if (RelationUsesTempNamespace(rel)) + { + relation_close(rel, AccessShareLock); + elog(NOTICE, + "pgfincore does not work with temporary tables."); + PG_RETURN_VOID(); + } + + /* we get the common part of the filename of each segment of a relation */ + relationpath = relpathperm(rel->rd_node, + forkname_to_number(text_to_cstring(forkName)) + ); + /* + * If we are looking the first segment, + * relationpath should not be suffixed + */ + if (segmentNumber == 0) + snprintf(filename, + MAXPGPATH, + "%s", + relationpath); + else + snprintf(filename, + MAXPGPATH, + "%s.%u", + relationpath, + (int) segmentNumber); + + /* + * We don't need the relation anymore + * the only purpose was to get a consistent filename + * (if file disappear, an error is logged) + */ + relation_close(rel, AccessShareLock); + + /* + * Call pgfadvise_loader with the varbit + */ + result = pgfadvise_loader_file(filename, + willneed, dontneed, databit, + pgfloader); + /* Filename */ values[0] = CStringGetTextDatum( filename ); /* os page size */ - values[1] = Int64GetDatum( pageSize ); + values[1] = Int64GetDatum( pgfloader->pageSize ); /* free page cache */ - values[2] = Int64GetDatum( pagesFree ); + values[2] = Int64GetDatum( pgfloader->pagesFree ); /* pages loaded */ - values[3] = Int64GetDatum( pages_loaded ); + values[3] = Int64GetDatum( pgfloader->pagesLoaded ); /* pages unloaded */ - values[4] = Int64GetDatum( pages_unloaded ); - memset(nulls, 0, sizeof(nulls)); + values[4] = Int64GetDatum( pgfloader->pagesUnloaded ); + + /* Build and return the result tuple. */ tuple = heap_form_tuple(tupdesc, values, nulls); PG_RETURN_DATUM( HeapTupleGetDatum(tuple) ); } diff --git a/pgfincore.sql.in b/pgfincore.sql.in index 09dcd46..235e27a 100644 --- a/pgfincore.sql.in +++ b/pgfincore.sql.in @@ -92,7 +92,12 @@ LANGUAGE SQL; -- PGFADVISE_LOADER -- CREATE OR REPLACE FUNCTION -pgfadvise_loader(IN regclass, IN text, IN int, IN bool, IN bool, IN varbit) +pgfadvise_loader(IN regclass, IN text, IN int, IN bool, IN bool, IN varbit, + OUT relpath text, + OUT os_page_size bigint, + OUT os_pages_free bigint, + OUT pages_loaded bigint, + OUT pages_unloaded bigint) RETURNS setof record AS 'MODULE_PATHNAME' LANGUAGE C;