From 1873195d3c383fcb8c2d16e89599826583e96ec9 Mon Sep 17 00:00:00 2001 From: jkshen <2458684728@qq.com> Date: Wed, 17 Aug 2022 17:44:35 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E5=B0=86pgfincore=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E5=AE=9E=E7=8E=B0=E4=B8=BAopenGauss=E5=86=85?= =?UTF-8?q?=E7=BD=AESQL=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/backend/catalog/builtin_funcs.ini | 47 + src/common/backend/utils/init/globals.cpp | 2 +- src/common/backend/utils/misc/Makefile | 2 +- src/common/backend/utils/misc/pgfincore.cpp | 1322 +++++++++++++++++ .../rollback-post_catalog_maindb_92_613.sql | 16 + .../rollback-post_catalog_maindb_92_613.sql | 16 + .../upgrade-post_catalog_maindb_92_613.sql | 206 +++ .../upgrade-post_catalog_otherdb_92_613.sql | 206 +++ src/test/regress/expected/pgfincore.out | 122 ++ src/test/regress/parallel_schedule0 | 1 + src/test/regress/sql/pgfincore.sql | 51 + 11 files changed, 1989 insertions(+), 2 deletions(-) create mode 100644 src/common/backend/utils/misc/pgfincore.cpp create mode 100644 src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_92_613.sql create mode 100644 src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_maindb_92_613.sql create mode 100644 src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_92_613.sql create mode 100644 src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_92_613.sql create mode 100644 src/test/regress/expected/pgfincore.out create mode 100644 src/test/regress/sql/pgfincore.sql diff --git a/src/common/backend/catalog/builtin_funcs.ini b/src/common/backend/catalog/builtin_funcs.ini index bd59d4584..69f0830c8 100755 --- a/src/common/backend/catalog/builtin_funcs.ini +++ b/src/common/backend/catalog/builtin_funcs.ini @@ -7527,6 +7527,53 @@ "percentile_of_value", 1, AddBuiltinFunc(_0(9990), _1("percentile_of_value"), _2(3), _3(false), _4(false), _5(aggregate_dummy), _6(701), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(true), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(3, 701, 701, 701), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("aggregate_dummy"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), + AddFuncGroup( + "pgfadvise", 1, + AddBuiltinFunc(_0(2372), _1("pgfadvise"), _2(3), _3(false), _4(true), _5(pgfadvise), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(1), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(3,2205,25,23), _21(7,2205,25,23,25,20,20,20), _22(7,'i','i','i','o','o','o','o'), _23(7,"relname","fork","action","relpath","os_page_size","rel_os_pages","os_pages_free"), _24(NULL), _25("pgfadvise"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("Predeclare an access pattern for file data"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), + AddFuncGroup( + "pgfadvise_dontneed", 1, + AddBuiltinFunc(_0(2536), _1("pgfadvise_dontneed"), _2(1), _3(false), _4(true), _5(NULL), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(SQLlanguageId), _10(1), _11(1), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(1,2205), _21(5,2205,25,20,20,20), _22(5,'i','o','o','o','o'), _23(5,"relname","relpath","os_page_size","rel_os_pages","os_pages_free"), _24(NULL), _25("SELECT pg_catalog.pgfadvise($1, 'main', 20)"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), + AddFuncGroup( + "pgfadvise_normal", 1, + AddBuiltinFunc(_0(2537), _1("pgfadvise_normal"), _2(1), _3(false), _4(true), _5(NULL), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(SQLlanguageId), _10(1), _11(1), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(1,2205), _21(5,2205,25,20,20,20), _22(5,'i','o','o','o','o'), _23(5,"relname","relpath","os_page_size","rel_os_pages","os_pages_free"), _24(NULL), _25("SELECT pg_catalog.pgfadvise($1, 'main', 30)"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), + AddFuncGroup( + "pgfadvise_random", 1, + AddBuiltinFunc(_0(2542), _1("pgfadvise_random"), _2(1), _3(false), _4(true), _5(NULL), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(SQLlanguageId), _10(1), _11(1), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(1,2205), _21(5,2205,25,20,20,20), _22(5,'i','o','o','o','o'), _23(5,"relname","relpath","os_page_size","rel_os_pages","os_pages_free"), _24(NULL), _25("SELECT pg_catalog.pgfadvise($1, 'main', 50)"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), + AddFuncGroup( + "pgfadvise_sequential", 1, + AddBuiltinFunc(_0(2538), _1("pgfadvise_sequential"), _2(1), _3(false), _4(true), _5(NULL), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(SQLlanguageId), _10(1), _11(1), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(1,2205), _21(5,2205,25,20,20,20), _22(5,'i','o','o','o','o'), _23(5,"relname","relpath","os_page_size","rel_os_pages","os_pages_free"), _24(NULL), _25("SELECT pg_catalog.pgfadvise($1, 'main', 40)"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), + AddFuncGroup( + "pgfadvise_willneed", 1, + AddBuiltinFunc(_0(2535), _1("pgfadvise_willneed"), _2(1), _3(false), _4(true), _5(NULL), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(SQLlanguageId), _10(1), _11(1), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(1,2205), _21(5,2205,25,20,20,20), _22(5,'i','o','o','o','o'), _23(5,"relname","relpath","os_page_size","rel_os_pages","os_pages_free"), _24(NULL), _25("SELECT pg_catalog.pgfadvise($1, 'main', 10)"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), + AddFuncGroup( + "pgfadvise_loader", 2, + AddBuiltinFunc(_0(2373), _1("pgfadvise_loader"), _2(6), _3(false), _4(true), _5(pgfadvise_loader), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(1), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(6,2205,25,23,16,16,1562), _21(11,2205,25,23,16,16,1562,25,20,20,20,20), _22(11,'i','i','i','i','i','i','o','o','o','o','o'), _23(11,"relname","fork","segment","load","unload","databit","relpath","os_page_size","os_pages_free","pages_loaded","pages_unloaded"), _24(NULL), _25("pgfadvise_loader"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("Restore cache from the snapshot, options to load/unload each block to/from cache"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)), + AddBuiltinFunc(_0(2539), _1("pgfadvise_loader"), _2(5), _3(false), _4(true), _5(NULL), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(SQLlanguageId), _10(1), _11(1), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(5,2205,23,16,16,1562), _21(10,2205,23,16,16,1562,25,20,20,20,20), _22(10,'i','i','i','i','i','o','o','o','o','o'), _23(10,"relname","segment","load","unload","databit","relpath","os_page_size","os_pages_free","pages_loaded","pages_unloaded"), _24(NULL), _25("SELECT pg_catalog.pgfadvise_loader($1, 'main', $2, $3, $4, $5)"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), + AddFuncGroup( + "pgfincore", 3, + AddBuiltinFunc(_0(2374), _1("pgfincore"), _2(3), _3(false), _4(true), _5(pgfincore), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(1), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(3,2205,25,16), _21(13,2205,25,16,25,23,20,20,20,20,20,1562,20,20), _22(13,'i','i','i','o','o','o','o','o','o','o','o','o','o'), _23(13,"relname","fork","getdatabit","relpath","segment","os_page_size","rel_os_pages","pages_mem","group_mem","os_pages_free","databit","pages_dirty","group_dirty"), _24(NULL), _25("pgfincore"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("Utility to inspect and get a snapshot of the system cache"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)), + AddBuiltinFunc(_0(2540), _1("pgfincore"), _2(2), _3(false), _4(true), _5(NULL), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(SQLlanguageId), _10(1), _11(1), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(2,2205,16), _21(12,2205,16,25,23,20,20,20,20,20,1562,20,20), _22(12,'i','i','o','o','o','o','o','o','o','o','o','o'), _23(12,"relname","getdatabit","relpath","segment","os_page_size","rel_os_pages","pages_mem","group_mem","os_pages_free","databit","pages_dirty","group_dirty"), _24(NULL), _25("SELECT * from pg_catalog.pgfincore($1, 'main', $2)"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)), + AddBuiltinFunc(_0(2541), _1("pgfincore"), _2(1), _3(false), _4(true), _5(NULL), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(SQLlanguageId), _10(1), _11(1), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(1,2205), _21(11,2205,25,23,20,20,20,20,20,1562,20,20), _22(11,'i','o','o','o','o','o','o','o','o','o','o'), _23(11,"relname","relpath","segment","os_page_size","rel_os_pages","pages_mem","group_mem","os_pages_free","databit","pages_dirty","group_dirty"), _24(NULL), _25("SELECT * from pg_catalog.pgfincore($1, 'main', false)"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), + AddFuncGroup( + "pgfincore_drawer", 1, + AddBuiltinFunc(_0(2543), _1("pgfincore_drawer"), _2(1), _3(false), _4(false), _5(pgfincore_drawer), _6(2275), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(0), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(1,1562), _21(2,1562,2275), _22(2,'i','o'), _23(2,"input","drawer"), _24(NULL), _25("pgfincore_drawer"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("A naive drawing function to visualize page cache per object"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), + AddFuncGroup( + "pgsysconf_pretty", 1, + AddBuiltinFunc(_0(2534), _1("pgsysconf_pretty"), _2(0), _3(false), _4(false), _5(NULL), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(SQLlanguageId), _10(0), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(0), _21(3,25,25,25), _22(3,'o','o','o'), _23(3,"os_page_size","os_pages_free","os_total_pages"), _24(NULL), _25("select pg_catalog.pg_size_pretty(os_page_size) as os_page_size, pg_catalog.pg_size_pretty(os_pages_free * os_page_size) as os_pages_free, pg_catalog.pg_size_pretty(os_total_pages * os_page_size) as os_total_pages from pg_catalog.pgsysconf()"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("Pgsysconf() with human readable output"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), + AddFuncGroup( + "pgsysconf", 1, + AddBuiltinFunc(_0(2371), _1("pgsysconf"), _2(0), _3(false), _4(false), _5(pgsysconf), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(0), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(0), _21(3,20,20,20), _22(3,'o','o','o'), _23(3,"os_page_size","os_pages_free","os_total_pages"), _24(NULL), _25("pgsysconf"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("Get system configuration information at run time, man 3 sysconf for details"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), AddFuncGroup( "pg_advisory_lock", 3, AddBuiltinFunc(_0(2880), _1("pg_advisory_lock"), _2(1), _3(true), _4(false), _5(pg_advisory_lock_int8), _6(2278), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(1, 20), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("pg_advisory_lock_int8"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("obtain exclusive advisory lock"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)), diff --git a/src/common/backend/utils/init/globals.cpp b/src/common/backend/utils/init/globals.cpp index 3c47f83c5..05817c537 100644 --- a/src/common/backend/utils/init/globals.cpp +++ b/src/common/backend/utils/init/globals.cpp @@ -59,7 +59,7 @@ bool open_join_children = true; bool will_shutdown = false; /* hard-wired binary version number */ -const uint32 GRAND_VERSION_NUM = 92612; +const uint32 GRAND_VERSION_NUM = 92613; const uint32 PREDPUSH_SAME_LEVEL_VERSION_NUM = 92522; const uint32 UPSERT_WHERE_VERSION_NUM = 92514; diff --git a/src/common/backend/utils/misc/Makefile b/src/common/backend/utils/misc/Makefile index 597657d6c..d553acf7d 100644 --- a/src/common/backend/utils/misc/Makefile +++ b/src/common/backend/utils/misc/Makefile @@ -21,7 +21,7 @@ ifneq "$(MAKECMDGOALS)" "clean" endif endif endif -OBJS = guc.o help_config.o pg_rusage.o ps_status.o superuser.o tzparser.o \ +OBJS = guc.o help_config.o pg_rusage.o pgfincore.o ps_status.o superuser.o tzparser.o \ rbtree.o anls_opt.o sec_rls_utils.o elf_parser.o pg_controldata.o oidrbtree.o # This location might depend on the installation directories. Therefore diff --git a/src/common/backend/utils/misc/pgfincore.cpp b/src/common/backend/utils/misc/pgfincore.cpp new file mode 100644 index 000000000..9e4be31d7 --- /dev/null +++ b/src/common/backend/utils/misc/pgfincore.cpp @@ -0,0 +1,1322 @@ +/* ------------------------------------------------------------------------- + * + * pgfincore.cpp + * This file let you see and mainpulate objects in the FS page cache + * + * Portions Copyright (c) 2022, Wuhan University + * Portions Copyright (c) 2009-2011, Cédric Villemain + * + * + * IDENTIFICATION + * src/common/backend/utils/misc/pgfincore.cpp + * + * ------------------------------------------------------------------------- + */ + +#include +#include +#include +#include +#include +#include +#include "postgres.h" +#include "access/heapam.h" +#include "catalog/catalog.h" +#include "catalog/namespace.h" +#include "catalog/pg_partition_fn.h" +#include "catalog/pg_partition.h" +#include "utils/builtins.h" +#include "utils/rel.h" +#include "utils/rel_gs.h" +#include "utils/varbit.h" +#include "utils/relcache.h" +#include "funcapi.h" +#include "catalog/pg_type.h" +#include "storage/smgr/fd.h" +#include "securec.h" +#include "nodes/pg_list.h" +#include "storage/lock/lock.h" +#include "utils/relcache.h" + +#define PGSYSCONF_COLS 3 +#define PGFADVISE_COLS 4 +#define PGFADVISE_LOADER_COLS 5 +#define PGFINCORE_COLS 10 + +#define PGF_WILLNEED 10 +#define PGF_DONTNEED 20 +#define PGF_NORMAL 30 +#define PGF_SEQUENTIAL 40 +#define PGF_RANDOM 50 + +#define FINCORE_PRESENT 0x1 +#define FINCORE_DIRTY 0x2 +#ifndef HAVE_FINCORE +#define FINCORE_BITS 1 +#else +#define FINCORE_BITS 2 +#endif +/* + * pgfadvise_fctx structure is needed + * to keep track of relation path, segment number, ... + */ +typedef struct { + 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 */ + bool isPartitionTable; /* partition table ?*/ + bool isSubPartitionTable; /*subPartition table ?*/ + ListCell *partitionCell; + ListCell *subPartitionCell; + List *partitionIdList; + List *subPartitionIdList; + text *forkName; + List *indexoidlist; + ListCell *indexCell; + bool isFirstIndexOid; +} pgfadvise_fctx; + +/* + * pgfadvise structure is needed + * to return values + */ +typedef struct { + size_t pageSize; /* os page size */ + size_t pagesFree; /* free page cache */ + size_t filesize; /* the filesize */ +} pgfadviseStruct; + +/* + * 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, ... + */ +typedef struct { + bool getvector; /* output varbit data ? */ + TupleDesc tupd; /* the tuple descriptor */ + Relation rel; /* the relation */ + unsigned int segcount; /* the segment current number */ + char *relationpath; /* the relation path */ + bool isPartitionTable; /* partition table ?*/ + bool isSubPartitionTable; /*subPartition table ?*/ + ListCell *partitionCell; + ListCell *subPartitionCell; + List *partitionIdList; + List *subPartitionIdList; + text *forkName; + List *indexoidlist; + ListCell *indexCell; + bool isFirstIndexOid; +} pgfincore_fctx; + +/* + * pgfadvise_loader_struct structure is needed + * to keep track of relation path, segment number, ... + */ +typedef struct { + size_t pageSize; /* os page size */ + size_t pagesFree; /* free page cache */ + size_t rel_os_pages; + size_t pages_mem; + size_t group_mem; + size_t pages_dirty; + size_t group_dirty; + VarBit *databit; +} pgfincoreStruct; + +Datum pgsysconf(PG_FUNCTION_ARGS); + +extern Datum pgfadvise(PG_FUNCTION_ARGS); +static int pgfadvise_file(char *filename, int advice, pgfadviseStruct *pgfdv); + +extern Datum pgfadvise_loader(PG_FUNCTION_ARGS); +static int pgfadvise_loader_file(char *filename, bool willneed, + bool dontneed, VarBit *databit, pgfloaderStruct *pgfloader); + +extern Datum pgfincore(PG_FUNCTION_ARGS); +static int pgfincore_file(char *filename, pgfincoreStruct *pgfncr); + +extern Datum pgfincore_drawer(PG_FUNCTION_ARGS); + +#define relpathpg(rel, forkName) \ + relpathbackend((rel)->rd_node, (rel)->rd_backend, (forkname_to_number(text_to_cstring(forkName)))) + +/* + * pgsysconf + * just output the actual system value for + * _SC_PAGESIZE --> Page Size + * _SC_AVPHYS_PAGES --> Free page in memory + * _SC_PHYS_PAGES --> Total memory + * + */ +Datum pgsysconf(PG_FUNCTION_ARGS) +{ + HeapTuple tuple; + TupleDesc tupdesc; + Datum values[PGSYSCONF_COLS]; + bool nulls[PGSYSCONF_COLS]; + + /* initialize nulls array to build the tuple */ + int ret = memset_s(nulls, sizeof(nulls), 0, sizeof(nulls)); + securec_check(ret, "\0", "\0"); + /* Build a tuple descriptor for our result type */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + ereport(ERROR, (errmsg("pgsysconf: return type must be a row type"))); + + /* Page size */ + values[0] = Int64GetDatum(sysconf(_SC_PAGESIZE)); + + /* free page in memory */ + values[1] = Int64GetDatum(sysconf(_SC_AVPHYS_PAGES)); + + /* total memory */ + values[2] = Int64GetDatum(sysconf(_SC_PHYS_PAGES)); + + /* Build and return the result tuple. */ + tuple = heap_form_tuple(tupdesc, values, nulls); + PG_RETURN_DATUM( HeapTupleGetDatum(tuple) ); +} + +#if defined(USE_POSIX_FADVISE) + +static int pgfadvise_file(char *filename, int advice, pgfadviseStruct *pgfdv) +{ + /* + * We use the AllocateFile(2) provided by PostgreSQL. We're going to + * close it ourselves even if PostgreSQL close it anyway at transaction + * end. + */ + FILE *fp; + int fd; + struct stat st; + int adviceFlag; + + /* + * OS Page size and Free pages + */ + pgfdv->pageSize = sysconf(_SC_PAGESIZE); + + /* + * Fopen 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 + */ + fp = AllocateFile(filename, "rb"); + if (fp == NULL) + return 1; + + fd = fileno(fp); + if (fstat(fd, &st) == -1) { + FreeFile(fp); + ereport(ERROR, (errmsg("pgfadvise: Can not stat object file : %s", filename))); + return 1; + } + + /* + * the file size is used in the SRF to output the number of pages used by + * the segment + */ + pgfdv->filesize = st.st_size; + ereport(DEBUG1, + (errmsg("pgfadvise: working on %s of %lld bytes", filename,(long long int) pgfdv->filesize))); + /* FADVISE_WILLNEED */ + if (advice == PGF_WILLNEED) { + adviceFlag = POSIX_FADV_WILLNEED; + ereport(DEBUG1, (errmsg("pgfadvise: setting advice POSIX_FADV_WILLNEED"))); + } + /* FADVISE_DONTNEED */ + else if (advice == PGF_DONTNEED) { + adviceFlag = POSIX_FADV_DONTNEED; + ereport(DEBUG1, (errmsg("pgfadvise: setting advice POSIX_FADV_DONTNEED"))); + } + /* POSIX_FADV_NORMAL */ + else if (advice == PGF_NORMAL) { + adviceFlag = POSIX_FADV_NORMAL; + ereport(DEBUG1, (errmsg("pgfadvise: setting advice POSIX_FADV_NORMAL"))); + } + /* POSIX_FADV_SEQUENTIAL */ + else if (advice == PGF_SEQUENTIAL) { + adviceFlag = POSIX_FADV_SEQUENTIAL; + ereport(DEBUG1, (errmsg("pgfadvise: setting advice POSIX_FADV_SEQUENTIAL"))); + } + /* POSIX_FADV_RANDOM */ + else if (advice == PGF_RANDOM) { + adviceFlag = POSIX_FADV_RANDOM; + ereport(DEBUG1, (errmsg("pgfadvise: setting advice POSIX_FADV_RANDOM"))); + } else { + ereport(ERROR, (errmsg("pgfadvise: invalid advice: %d", advice))); + return 1; + } + + /* + * Call posix_fadvise with the relevant advice on the file descriptor + */ + posix_fadvise(fd, 0, 0, adviceFlag); + + /* close the file */ + FreeFile(fp); + + /* + * OS things : Pages free + */ + pgfdv->pagesFree = sysconf(_SC_AVPHYS_PAGES); + + return 0; +} +#else +static int pgfadvise_file(char *filename, int advice, pgfadviseStruct *pgfdv) +{ + ereport(ERROR, (errmsg("POSIX_FADVISE UNSUPPORTED on your platform"))); + return 1; +} +#endif + +/* + * pgfadvise is a function that handle the process to have a sharelock + * on the relation and to walk the segments. + * for each segment it call the posix_fadvise with the required flag + * parameter + */ +Datum pgfadvise(PG_FUNCTION_ARGS) +{ + FuncCallContext *funcctx; + pgfadvise_fctx *fctx; + + /* our structure use to return values */ + pgfadviseStruct *pgfdv; + + /* our return value, 0 for success */ + int result; + + /* The file we are working on */ + char filename[MAXPGPATH]; + + /* stuff done only on the first call of the function */ + if (SRF_IS_FIRSTCALL()) { + MemoryContext oldcontext; + + Oid relOid = PG_GETARG_OID(0); + text *forkName = PG_GETARG_TEXT_P(1); + int advice = PG_GETARG_INT32(2); + + /* + * Postgresql stuff to return a tuple + */ + TupleDesc tupdesc; + + /* create a function context for cross-call persistence */ + funcctx = SRF_FIRSTCALL_INIT(); + + /* + * switch to memory context appropriate for multiple function calls + */ + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + /* allocate memory for user context */ + fctx = (pgfadvise_fctx*)palloc(sizeof(pgfadvise_fctx)); + + fctx->forkName = (text*)palloc(VARSIZE(forkName)); + SET_VARSIZE(fctx->forkName, VARSIZE(forkName)); + errno_t ret = memcpy_s((void*)VARDATA(fctx->forkName), VARSIZE(forkName) - VARHDRSZ, (void*)VARDATA(forkName), VARSIZE(forkName) - VARHDRSZ); + securec_check(ret, "\0", "\0"); + + /* Build a tuple descriptor for our result type */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + ereport(ERROR, (errmsg("pgfadvise: return type must be a row type"))); + + /* provide the tuple descriptor to the fonction structure */ + fctx->tupd = tupdesc; + + /* open the current relation, accessShareLock */ + // TODO use try_relation_open instead ? + fctx->rel = relation_open(relOid, AccessShareLock); + + if (RelationIsColStore(fctx->rel)) { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Un-support feature"), + errdetail("column-store relation doesn't support pgfadvise yet"))); + } + + if (RelationIsSegmentTable(fctx->rel)) { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Un-support feature"), + errdetail("segment-page tables doesn't support pgfadvise yet"))); + } + + if(RelationIsSubPartitioned(fctx->rel)) { + fctx->isSubPartitionTable = RelationIsSubPartitioned(fctx->rel); + fctx->isPartitionTable = false; + } else if(RELATION_IS_PARTITIONED(fctx->rel)) { + fctx->isPartitionTable = RELATION_IS_PARTITIONED(fctx->rel); + fctx->isSubPartitionTable = false; + }else { + fctx->isPartitionTable = false; + fctx->isSubPartitionTable = false; + } + fctx->partitionCell = NULL; + fctx->subPartitionCell = NULL; + fctx->indexCell = NULL; + fctx->partitionIdList = NULL; + fctx->subPartitionIdList = NULL; + fctx->isFirstIndexOid = true;; + if (!RelationIsIndex(fctx->rel)) { + fctx->indexoidlist = RelationGetIndexList(fctx->rel); + }else { + fctx->indexoidlist = NULL; + } + + + /* Here we keep track of current action in all calls */ + fctx->advice = advice; + + if(!(fctx->isPartitionTable || fctx->isSubPartitionTable)) { + /* we get the common part of the filename of each segment of a relation */ + fctx->relationpath = relpathpg(fctx->rel, forkName); + + /* segcount is used to get the next segment of the current relation */ + fctx->segcount = 0; + } else if (fctx->isSubPartitionTable) { + fctx->subPartitionIdList = RelationGetSubPartitionList(fctx->rel, AccessShareLock); + fctx->subPartitionCell = list_head(fctx->subPartitionIdList); + Partition subPartition = (Partition)lfirst(fctx->subPartitionCell); + Relation subPartionRel = SubPartitionGetRelation(fctx->rel, subPartition, AccessShareLock); + fctx->relationpath = relpathpg(subPartionRel, forkName); + fctx->segcount = 0; + releaseDummyRelation(&subPartionRel); + } else if (fctx->isPartitionTable) { + fctx->partitionIdList = relationGetPartitionList(fctx->rel, AccessShareLock); + fctx->partitionCell = list_head(fctx->partitionIdList); + Partition partition = (Partition)lfirst(fctx->partitionCell); + Relation partitionRel = partitionGetRelation(fctx->rel, partition); + fctx->relationpath = relpathpg(partitionRel, forkName); + fctx->segcount = 0; + releaseDummyRelation(&partitionRel); + } + + + /* And finally we keep track of our initialization */ + ereport(DEBUG1, (errmsg("pgfadvise: init done for %s, in fork %s", + fctx->relationpath, text_to_cstring(forkName)))); + funcctx->user_fctx = fctx; + MemoryContextSwitchTo(oldcontext); + } + + /* After the first call, we recover our context */ + funcctx = SRF_PERCALL_SETUP(); + fctx = (pgfadvise_fctx *) funcctx->user_fctx; + + /* + * If we are still looking the first segment + * relationpath should not be suffixed + */ + if (fctx->segcount == 0){ + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } else { + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s.%u", fctx->relationpath, fctx->segcount); + securec_check_ss(rc, "\0", "\0"); + } + + FILE *fp = AllocateFile(filename, "rb"); + if(fp == NULL) { + if(fctx->isPartitionTable || fctx->isSubPartitionTable) { + if(fctx->isSubPartitionTable && lnext(fctx->subPartitionCell)) { + fctx->subPartitionCell = lnext(fctx->subPartitionCell); + Partition subPartition = (Partition)lfirst(fctx->subPartitionCell); + Relation subPartionRel = SubPartitionGetRelation(fctx->rel,subPartition,AccessShareLock); + fctx->relationpath = relpathpg(subPartionRel, fctx->forkName); + fctx->segcount = 0; + releaseDummyRelation(&subPartionRel); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + }else if(fctx->isPartitionTable && lnext(fctx->partitionCell)) { + fctx->partitionCell = lnext(fctx->partitionCell); + Partition partition = (Partition)lfirst(fctx->partitionCell); + Relation partitionRel = partitionGetRelation(fctx->rel,partition); + fctx->relationpath = relpathpg(partitionRel, fctx->forkName); + fctx->segcount = 0; + releaseDummyRelation(&partitionRel); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + }else { + if(fctx->indexoidlist != NULL) { + if(fctx->isFirstIndexOid) { + fctx->indexCell = list_head(fctx->indexoidlist); + fctx->isFirstIndexOid=false; + Oid indexId = lfirst_oid(fctx->indexCell); + Relation currentIndex = index_open(indexId, AccessShareLock); + fctx->relationpath = relpathpg(currentIndex, fctx->forkName); + fctx->segcount = 0; + index_close(currentIndex, NoLock); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + }else { + if(lnext(fctx->indexCell)) { + fctx->indexCell = lnext(fctx->indexCell); + Oid indexId = lfirst_oid(fctx->indexCell); + Relation currentIndex = index_open(indexId, AccessShareLock); + fctx->relationpath = relpathpg(currentIndex, fctx->forkName); + fctx->segcount = 0; + index_close(currentIndex, NoLock); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } + } + } + } + }else { + //process index + if(fctx->indexoidlist != NULL) { + if(fctx->isFirstIndexOid) { + fctx->indexCell = list_head(fctx->indexoidlist); + fctx->isFirstIndexOid=false; + Oid indexId = lfirst_oid(fctx->indexCell); + Relation currentIndex = index_open(indexId, AccessShareLock); + fctx->relationpath = relpathpg(currentIndex, fctx->forkName); + fctx->segcount = 0; + index_close(currentIndex, NoLock); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + }else { + if(lnext(fctx->indexCell)) { + fctx->indexCell = lnext(fctx->indexCell); + Oid indexId = lfirst_oid(fctx->indexCell); + Relation currentIndex = index_open(indexId, AccessShareLock); + fctx->relationpath = relpathpg(currentIndex, fctx->forkName); + fctx->segcount = 0; + index_close(currentIndex, NoLock); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } + } + } + } + } + + ereport(DEBUG1, (errmsg("pgfadvise: about to work with %s, current advice : %d", + filename, fctx->advice))); + /* + * Call posix_fadvise with the advice, returning the structure + */ + pgfdv = (pgfadviseStruct *) palloc(sizeof(pgfadviseStruct)); + result = pgfadvise_file(filename, fctx->advice, pgfdv); + + /* + * When we have work with all segments of the current relation + * We exit from the SRF + * Else we build and return the tuple for this segment + */ + if (result) { + ereport(DEBUG1, (errmsg("pgfadvise: closing %s", fctx->relationpath))); + if(fctx->isPartitionTable) { + releasePartitionList(fctx->rel, &(fctx->partitionIdList), AccessShareLock); + }else if(fctx->isSubPartitionTable) { + releasePartitionList(fctx->rel, &(fctx->subPartitionIdList), AccessShareLock); + } + relation_close(fctx->rel, AccessShareLock); + list_free(fctx->indexoidlist); + pfree(fctx); + SRF_RETURN_DONE(funcctx); + } else { + /* + * Postgresql stuff to return a tuple + */ + HeapTuple tuple; + Datum values[PGFADVISE_COLS]; + bool nulls[PGFADVISE_COLS]; + + /* initialize nulls array to build the tuple */ + int ret = memset_s(nulls, sizeof(nulls), 0, sizeof(nulls)); + securec_check(ret, "\0", "\0"); + /* prepare the number of the next segment */ + fctx->segcount++; + + /* Filename */ + values[0] = CStringGetTextDatum( filename ); + /* os page size */ + values[1] = Int64GetDatum( (int64) pgfdv->pageSize ); + /* number of pages used by segment */ + values[2] = Int64GetDatum( (int64) ((pgfdv->filesize+pgfdv->pageSize-1)/pgfdv->pageSize) ); + /* free page cache */ + values[3] = Int64GetDatum( (int64) pgfdv->pagesFree ); + /* Build the result tuple. */ + tuple = heap_form_tuple(fctx->tupd, values, nulls); + + /* Ok, return results, and go for next call */ + SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + } +} + +#if defined(USE_POSIX_FADVISE) + +static int pgfadvise_loader_file(char *filename, + bool willneed, bool dontneed, VarBit *databit, + pgfloaderStruct *pgfloader) +{ + bits8 *sp; + int bitlen; + bits8 x; + int i, k; + + /* + * We use the AllocateFile(2) provided by PostgreSQL. We're going to + * close it ourselves even if PostgreSQL close it anyway at transaction + * end. + */ + FILE *fp; + int fd; + struct stat st; + + /* + * OS things : Page size + */ + pgfloader->pageSize = sysconf(_SC_PAGESIZE); + + /* + * 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 + */ + pgfloader->pagesLoaded = 0; + pgfloader->pagesUnloaded = 0; + + /* + * Fopen 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 + */ + fp = AllocateFile(filename, "rb"); + if (fp == NULL) + return 1; + + fd = fileno(fp); + if (fstat(fd, &st) == -1) { + FreeFile(fp); + ereport(ERROR, (errmsg("pgfadvise_loader: Can not stat object file: %s", filename))); + return 1; + } + + ereport(DEBUG1, (errmsg("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; + /* Is this bit set ? */ + for (k = 0; k < BITS_PER_BYTE; k++) { + if (IS_HIGHBIT_SET(x)) { + if (willneed) { + (void) posix_fadvise(fd, + ((i+k) * pgfloader->pageSize), + pgfloader->pageSize, + POSIX_FADV_WILLNEED); + pgfloader->pagesLoaded++; + } + } + else if (dontneed) { + (void) posix_fadvise(fd, + ((i+k) * pgfloader->pageSize), + pgfloader->pageSize, + POSIX_FADV_DONTNEED); + pgfloader->pagesUnloaded++; + } + + x <<= 1; + } + } + /* + * XXX this copy/paste of code to finnish to walk the bits is not pretty + */ + if (i < bitlen) + { + /* print the last partial byte */ + x = *sp; + for (k = i; k < bitlen; k++) { + if (IS_HIGHBIT_SET(x)) { + if (willneed) { + (void) posix_fadvise(fd, + (k * pgfloader->pageSize), + pgfloader->pageSize, + POSIX_FADV_WILLNEED); + pgfloader->pagesLoaded++; + } + } + else if (dontneed) { + (void) posix_fadvise(fd, + (k * pgfloader->pageSize), + pgfloader->pageSize, + POSIX_FADV_DONTNEED); + pgfloader->pagesUnloaded++; + } + x <<= 1; + } + } + FreeFile(fp); + + /* + * OS things : Pages free + */ + pgfloader->pagesFree = sysconf(_SC_AVPHYS_PAGES); + + return 0; +} +#else +static int pgfadvise_loader_file(char *filename, + bool willneed, bool dontneed, VarBit *databit, + pgfloaderStruct *pgfloader) +{ + ereport(ERROR, (errmsg("POSIX_FADVISE UNSUPPORTED on your platform"))); + return 1; +} +#endif + +/* + * + * pgfadv_loader to handle work with varbit map of buffer cache. + * it is actually used for loading/unloading block to/from buffer cache + * + */ +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); + /* if this variable is set to false, no page will be set to willneed */ + bool willneed = PG_GETARG_BOOL(3); + /* if this variable is set to false, no page will be set to dontneed */ + bool dontneed = PG_GETARG_BOOL(4); + /* + * if the variable willneed and dontneed is set to true, the pages + * corresponding to 1 will be set WILLNEED, and the pages corresponding + * to 0 will be set DONTNEED. + */ + VarBit *databit; + + /* our structure use to return values */ + 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]; + + if (PG_ARGISNULL(5)) + ereport(ERROR, (errmsg("pgfadvise_loader: databit argument shouldn't be NULL"))); + + databit = PG_GETARG_VARBIT_P(5); + + /* initialize nulls array to build the tuple */ + int ret = memset_s(nulls, sizeof(nulls), 0, sizeof(nulls)); + securec_check(ret, "\0", "\0"); + /* Build a tuple descriptor for our result type */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + ereport(ERROR, (errmsg("return type must be a row type"))); + + /* open the current relation in accessShareLock */ + rel = relation_open(relOid, AccessShareLock); + + /* we get the common part of the filename of each segment of a relation */ + relationpath = relpathpg(rel, forkName); + + /* + * If we are looking the first segment, + * relationpath should not be suffixed + */ + if (segmentNumber == 0){ + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", relationpath); + securec_check_ss(rc, "\0", "\0"); + } else { + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s.%u", relationpath, (int) segmentNumber); + securec_check_ss(rc, "\0", "\0"); + } + + /* + * 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 + */ + pgfloader = (pgfloaderStruct *) palloc(sizeof(pgfloaderStruct)); + result = pgfadvise_loader_file(filename, + willneed, dontneed, databit, + pgfloader); + if (result != 0) + ereport(ERROR, (errmsg("Can't read file %s, fork(%s)", + filename, text_to_cstring(forkName)))); + /* Filename */ + values[0] = CStringGetTextDatum( filename ); + /* os page size */ + values[1] = Int64GetDatum( pgfloader->pageSize ); + /* free page cache */ + values[2] = Int64GetDatum( pgfloader->pagesFree ); + /* pages loaded */ + values[3] = Int64GetDatum( pgfloader->pagesLoaded ); + /* pages unloaded */ + values[4] = Int64GetDatum( pgfloader->pagesUnloaded ); + + /* Build and return the result tuple. */ + tuple = heap_form_tuple(tupdesc, values, nulls); + PG_RETURN_DATUM( HeapTupleGetDatum(tuple) ); +} + +/* + * pgfincore_file handle the mmaping, mincore process (and access file, etc.) + */ +static int pgfincore_file(char *filename, pgfincoreStruct *pgfncr) +{ + int flag=1; + int flag_dirty=1; + + int len, bitlen; + bits8 *r; + bits8 x = 0; + register size_t pageIndex; + + /* + * We use the AllocateFile(2) provided by PostgreSQL. We're going to + * close it ourselves even if PostgreSQL close it anyway at transaction + * end. + */ + FILE *fp; + int fd; + struct stat st; + +#ifndef HAVE_FINCORE + void *pa = (char *) 0; +#endif + unsigned char *vec = (unsigned char *) 0; + + /* + * OS Page size + */ + pgfncr->pageSize = sysconf(_SC_PAGESIZE); + + /* + * Initialize counters + */ + pgfncr->pages_mem = 0; + pgfncr->group_mem = 0; + pgfncr->pages_dirty = 0; + pgfncr->group_dirty = 0; + pgfncr->rel_os_pages = 0; + + /* + * Fopen 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 + */ + fp = AllocateFile(filename, "rb"); + if (fp == NULL) + return 1; + + fd = fileno(fp); + + if (fstat(fd, &st) == -1) { + FreeFile(fp); + ereport(ERROR, (errmsg("Can not stat object file : %s", filename))); + return 1; + } + + /* + * if file ok + * then process + */ + if (st.st_size != 0) { + /* number of pages in the current file */ + pgfncr->rel_os_pages = (st.st_size+pgfncr->pageSize-1)/pgfncr->pageSize; + +#ifndef HAVE_FINCORE + pa = mmap(NULL, st.st_size, PROT_NONE, MAP_SHARED, fd, 0); + if (pa == MAP_FAILED) { + int save_errno = errno; + FreeFile(fp); + ereport(ERROR, (errmsg("Can not mmap object file : %s, errno = %i,%s\nThis error can happen if there is not enought space in memory to do the projection. Please mail cedric@villemain.org with '[pgfincore] ENOMEM' as subject.", + filename, save_errno, strerror(save_errno)))); + return 1; + } +#endif + + /* Prepare our vector containing all blocks information */ + vec = (unsigned char * ) calloc(1, (st.st_size+pgfncr->pageSize-1)/pgfncr->pageSize); + if ((void *)0 == vec) { +#ifndef HAVE_FINCORE + munmap(pa, st.st_size); +#endif + FreeFile(fp); + ereport(ERROR, (errmsg("Can not calloc object file : %s", filename))); + return 1; + } + +#ifndef HAVE_FINCORE + /* Affect vec with mincore */ + if (mincore(pa, st.st_size, vec) != 0) { + int save_errno = errno; + munmap(pa, st.st_size); + ereport(ERROR, (errmsg("mincore(%p, %lld, %p): %s\n", + pa, (long long int)st.st_size, vec, strerror(save_errno)))); +#else + /* Affect vec with fincore */ + if (fincore(fd, 0, st.st_size, vec) != 0) { + int save_errno = errno; + ereport(ERROR, (errmsg("fincore(%u, 0, %lld, %p): %s\n", + fd, (long long int)st.st_size, vec, strerror(save_errno)))); +#endif + free(vec); + FreeFile(fp); + return 1; + } + + /* + * prepare the bit string + */ + bitlen = FINCORE_BITS * ((st.st_size+pgfncr->pageSize-1)/pgfncr->pageSize); + len = VARBITTOTALLEN(bitlen); + /* + * set to 0 so that *r is always initialised and string is zero-padded + * XXX: do we need to free that ? + */ + pgfncr->databit = (VarBit *) palloc0(len); + SET_VARSIZE(pgfncr->databit, len); + VARBITLEN(pgfncr->databit) = bitlen; + + r = VARBITS(pgfncr->databit); + x = HIGHBIT; + + /* handle the results */ + for (pageIndex = 0; pageIndex < pgfncr->rel_os_pages; pageIndex++) { + // block in memory + if (vec[pageIndex] & FINCORE_PRESENT) { + pgfncr->pages_mem++; + *r |= x; + if (FINCORE_BITS > 1) { + if (vec[pageIndex] & FINCORE_DIRTY) { + pgfncr->pages_dirty++; + *r |= (x >> 1); + /* we flag to detect contigous blocks in the same state */ + if (flag_dirty) + pgfncr->group_dirty++; + flag_dirty = 0; + } + else + flag_dirty = 1; + } + ereport(DEBUG5, (errmsg("in memory blocks : %lld / %lld", + (long long int) pageIndex, (long long int) pgfncr->rel_os_pages))); + /* we flag to detect contigous blocks in the same state */ + if (flag) + pgfncr->group_mem++; + flag = 0; + } + else + flag=1; + + + x >>= FINCORE_BITS; + if (x == 0) { + x = HIGHBIT; + r++; + } + } + } + ereport(DEBUG1, (errmsg("pgfincore %s: %lld of %lld block in linux cache, %lld groups", + filename, (long long int) pgfncr->pages_mem, (long long int) pgfncr->rel_os_pages, (long long int) pgfncr->group_mem))); + + /* + * free and close + */ + free(vec); +#ifndef HAVE_FINCORE + munmap(pa, st.st_size); +#endif + FreeFile(fp); + + /* + * OS things : Pages free + */ + pgfncr->pagesFree = sysconf(_SC_AVPHYS_PAGES); + + return 0; +} + +/* + * pgfincore is a function that handle the process to have a sharelock + * on the relation and to walk the segments. + * for each segment it call the appropriate function depending on 'action' + * parameter + */ +Datum pgfincore(PG_FUNCTION_ARGS) +{ + FuncCallContext *funcctx; + pgfincore_fctx *fctx; + + /* our structure use to return values */ + pgfincoreStruct *pgfncr; + + /* our return value, 0 for success */ + int result; + + /* The file we are working on */ + char filename[MAXPGPATH]; + + /* stuff done only on the first call of the function */ + if (SRF_IS_FIRSTCALL()) { + MemoryContext oldcontext; + + Oid relOid = PG_GETARG_OID(0); + text *forkName = PG_GETARG_TEXT_P(1); + bool getvector = PG_GETARG_BOOL(2); + + /* + * Postgresql stuff to return a tuple + */ + TupleDesc tupdesc; + + /* create a function context for cross-call persistence */ + funcctx = SRF_FIRSTCALL_INIT(); + + /* + * switch to memory context appropriate for multiple function calls + */ + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + /* allocate memory for user context */ + fctx = (pgfincore_fctx *) palloc(sizeof(pgfincore_fctx)); + + fctx->forkName = (text*)palloc(VARSIZE(forkName)); + SET_VARSIZE(fctx->forkName, VARSIZE(forkName)); + errno_t ret = memcpy_s((void*)VARDATA(fctx->forkName), VARSIZE(forkName) - VARHDRSZ, (void*)VARDATA(forkName), VARSIZE(forkName) - VARHDRSZ); + securec_check(ret, "\0", "\0"); + + + /* Build a tuple descriptor for our result type */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + ereport(ERROR, (errmsg("pgfadvise: return type must be a row type"))); + + /* provide the tuple descriptor to the fonction structure */ + fctx->tupd = tupdesc; + + /* are we going to grab and output the varbit data (can be large) */ + fctx->getvector = getvector; + + /* open the current relation, accessShareLock */ + // TODO use try_relation_open instead ? + fctx->rel = relation_open(relOid, AccessShareLock); + + if (RelationIsColStore(fctx->rel)) { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Un-support feature"), + errdetail("column-store relation doesn't support pgfincore yet"))); + } + + if (RelationIsSegmentTable(fctx->rel)) { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Un-support feature"), + errdetail("segment-page tables doesn't support pgfincore yet"))); + } + + if(RelationIsSubPartitioned(fctx->rel)) { + fctx->isSubPartitionTable = RelationIsSubPartitioned(fctx->rel); + fctx->isPartitionTable = false; + } else if(RELATION_IS_PARTITIONED(fctx->rel)) { + fctx->isPartitionTable = RELATION_IS_PARTITIONED(fctx->rel); + fctx->isSubPartitionTable = false; + }else { + fctx->isPartitionTable = false; + fctx->isSubPartitionTable = false; + } + fctx->partitionCell = NULL; + fctx->subPartitionCell = NULL; + fctx->partitionIdList = NULL; + fctx->subPartitionIdList = NULL; + fctx->indexCell = NULL; + + fctx->isFirstIndexOid = true;; + if (!RelationIsIndex(fctx->rel)) { + fctx->indexoidlist = RelationGetIndexList(fctx->rel); + }else { + fctx->indexoidlist = NULL; + } + + if(!(fctx->isPartitionTable || fctx->isSubPartitionTable)) { + /* we get the common part of the filename of each segment of a relation */ + fctx->relationpath = relpathpg(fctx->rel, forkName); + + /* segcount is used to get the next segment of the current relation */ + fctx->segcount = 0; + } else if (fctx->isSubPartitionTable) { + fctx->subPartitionIdList = RelationGetSubPartitionList(fctx->rel, AccessShareLock); + fctx->subPartitionCell = list_head(fctx->subPartitionIdList); + Partition subPartition = (Partition)lfirst(fctx->subPartitionCell); + Relation subPartionRel = SubPartitionGetRelation(fctx->rel, subPartition, AccessShareLock); + fctx->relationpath = relpathpg(subPartionRel, forkName); + fctx->segcount = 0; + releaseDummyRelation(&subPartionRel); + } else if (fctx->isPartitionTable) { + fctx->partitionIdList = relationGetPartitionList(fctx->rel, AccessShareLock); + fctx->partitionCell = list_head(fctx->partitionIdList); + Partition partition = (Partition)lfirst(fctx->partitionCell); + Relation partitionRel = partitionGetRelation(fctx->rel, partition); + fctx->relationpath = relpathpg(partitionRel, forkName); + fctx->segcount = 0; + releaseDummyRelation(&partitionRel); + } + + + /* And finally we keep track of our initialization */ + ereport(DEBUG1, (errmsg("pgfincore: init done for %s, in fork %s", + fctx->relationpath, text_to_cstring(forkName)))); + funcctx->user_fctx = fctx; + MemoryContextSwitchTo(oldcontext); + } + + /* After the first call, we recover our context */ + funcctx = SRF_PERCALL_SETUP(); + fctx = (pgfincore_fctx*) funcctx->user_fctx; + + /* + * If we are still looking the first segment + * relationpath should not be suffixed + */ + if (fctx->segcount == 0) { + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } else { + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s.%u", fctx->relationpath, fctx->segcount); + securec_check_ss(rc, "\0", "\0"); + } + + FILE *fp = AllocateFile(filename, "rb"); + if(fp == NULL) { + if(fctx->isPartitionTable || fctx->isSubPartitionTable) { + if(fctx->isSubPartitionTable && lnext(fctx->subPartitionCell)) { + fctx->subPartitionCell = lnext(fctx->subPartitionCell); + Partition subPartition = (Partition)lfirst(fctx->subPartitionCell); + Relation subPartionRel = SubPartitionGetRelation(fctx->rel,subPartition,AccessShareLock); + fctx->relationpath = relpathpg(subPartionRel, fctx->forkName); + fctx->segcount = 0; + releaseDummyRelation(&subPartionRel); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + }else if(fctx->isPartitionTable && lnext(fctx->partitionCell)) { + fctx->partitionCell = lnext(fctx->partitionCell); + Partition partition = (Partition)lfirst(fctx->partitionCell); + Relation partitionRel = partitionGetRelation(fctx->rel,partition); + fctx->relationpath = relpathpg(partitionRel, fctx->forkName); + fctx->segcount = 0; + releaseDummyRelation(&partitionRel); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + }else { + if(fctx->indexoidlist != NULL) { + if(fctx->isFirstIndexOid) { + fctx->indexCell = list_head(fctx->indexoidlist); + fctx->isFirstIndexOid=false; + Oid indexId = lfirst_oid(fctx->indexCell); + Relation currentIndex = index_open(indexId, AccessShareLock); + fctx->relationpath = relpathpg(currentIndex, fctx->forkName); + fctx->segcount = 0; + index_close(currentIndex, NoLock); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + }else { + if(lnext(fctx->indexCell)) { + fctx->indexCell = lnext(fctx->indexCell); + Oid indexId = lfirst_oid(fctx->indexCell); + Relation currentIndex = index_open(indexId, AccessShareLock); + fctx->relationpath = relpathpg(currentIndex, fctx->forkName); + fctx->segcount = 0; + index_close(currentIndex, NoLock); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } + } + } + } + }else { + //process index + if(fctx->indexoidlist != NULL) { + if(fctx->isFirstIndexOid) { + fctx->indexCell = list_head(fctx->indexoidlist); + fctx->isFirstIndexOid=false; + Oid indexId = lfirst_oid(fctx->indexCell); + Relation currentIndex = index_open(indexId, AccessShareLock); + fctx->relationpath = relpathpg(currentIndex, fctx->forkName); + fctx->segcount = 0; + index_close(currentIndex, NoLock); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + }else { + if(lnext(fctx->indexCell)) { + fctx->indexCell = lnext(fctx->indexCell); + Oid indexId = lfirst_oid(fctx->indexCell); + Relation currentIndex = index_open(indexId, AccessShareLock); + fctx->relationpath = relpathpg(currentIndex, fctx->forkName); + fctx->segcount = 0; + index_close(currentIndex, NoLock); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } + } + } + } + } + + ereport(DEBUG1, (errmsg("pgfincore: about to work with %s", filename))); + + /* + * Call pgfincore with the advice, returning the structure + */ + pgfncr = (pgfincoreStruct *) palloc(sizeof(pgfincoreStruct)); + result = pgfincore_file(filename, pgfncr); + + /* + * When we have work with all segment of the current relation, test success + * We exit from the SRF + */ + if (result) { + ereport(DEBUG1, (errmsg("pgfincore: closing %s", fctx->relationpath))); + + if(fctx->isPartitionTable) { + releasePartitionList(fctx->rel, &(fctx->partitionIdList), AccessShareLock); + }else if(fctx->isSubPartitionTable) { + releasePartitionList(fctx->rel, &(fctx->subPartitionIdList), AccessShareLock); + } + relation_close(fctx->rel, AccessShareLock); + list_free(fctx->indexoidlist); + pfree(fctx); + SRF_RETURN_DONE(funcctx); + } else { + /* + * Postgresql stuff to return a tuple + */ + HeapTuple tuple; + Datum values[PGFINCORE_COLS]; + bool nulls[PGFINCORE_COLS]; + + /* initialize nulls array to build the tuple */ + int ret = memset_s(nulls, sizeof(nulls), 0, sizeof(nulls)); + securec_check(ret, "\0", "\0"); + + /* Filename */ + values[0] = CStringGetTextDatum(filename); + /* Segment Number */ + values[1] = Int32GetDatum(fctx->segcount); + /* os page size */ + values[2] = Int64GetDatum(pgfncr->pageSize); + /* number of pages used by segment */ + values[3] = Int64GetDatum(pgfncr->rel_os_pages); + /* number of pages in OS cache */ + values[4] = Int64GetDatum(pgfncr->pages_mem); + /* number of group of contigous page in os cache */ + values[5] = Int64GetDatum(pgfncr->group_mem); + /* free page cache */ + values[6] = Int64GetDatum(pgfncr->pagesFree); + /* the map of the file with bit set for in os cache page */ + if (fctx->getvector && pgfncr->rel_os_pages) { + values[7] = VarBitPGetDatum(pgfncr->databit); + } else { + nulls[7] = true; + values[7] = (Datum) NULL; + } + /* number of pages dirty in OS cache */ + values[8] = Int64GetDatum(pgfncr->pages_dirty); + /* number of group of contigous dirty pages in os cache */ + values[9] = Int64GetDatum(pgfncr->group_dirty); + /* Build the result tuple. */ + tuple = heap_form_tuple(fctx->tupd, values, nulls); + + /* prepare the number of the next segment */ + fctx->segcount++; + + /* Ok, return results, and go for next call */ + SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + } +} + +/* + * pgfincore_drawer A very naive renderer. (for testing) + */ +Datum pgfincore_drawer(PG_FUNCTION_ARGS) +{ + char *result,*r; + int len,i,k; + VarBit *databit; + bits8 *sp; + bits8 x; + + if (PG_ARGISNULL(0)) + ereport(ERROR, (errmsg("pgfincore_drawer: databit argument shouldn't be NULL"))); + + databit = PG_GETARG_VARBIT_P(0); + + len = VARBITLEN(databit); + result = (char *) palloc((len/FINCORE_BITS) + 1); + sp = VARBITS(databit); + r = result; + + for (i = 0; i <= len - BITS_PER_BYTE; i += BITS_PER_BYTE, sp++) { + x = *sp; + /* Is this bit set ? */ + for (k = 0; k < (BITS_PER_BYTE/FINCORE_BITS); k++) { + char out = ' '; + if (IS_HIGHBIT_SET(x)) + out = '.' ; + x <<= 1; + if (FINCORE_BITS > 1) { + if (IS_HIGHBIT_SET(x)) + out = '*'; + x <<= 1; + } + *r++ = out; + } + } + if (i < len) { + /* print the last partial byte */ + x = *sp; + for (k = i; k < (len/FINCORE_BITS); k++) { + char out = ' '; + if (IS_HIGHBIT_SET(x)) + out = '.' ; + x <<= 1; + if (FINCORE_BITS > 1) { + if (IS_HIGHBIT_SET(x)) + out = '*'; + x <<= 1; + } + *r++ = out; + } + } + + *r = '\0'; + PG_RETURN_CSTRING(result); +} diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_92_613.sql b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_92_613.sql new file mode 100644 index 000000000..88521bb7a --- /dev/null +++ b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_92_613.sql @@ -0,0 +1,16 @@ +DROP FUNCTION IF EXISTS pg_catalog.pgsysconf_pretty() CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgsysconf() CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_willneed(regclass) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_dontneed(regclass) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_normal(regclass) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_sequential(regclass) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_random(regclass) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise(regclass, text, int) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_loader(regclass, text, int, bool, bool, varbit) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_loader(regclass, int, bool, bool, varbit) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfincore(regclass) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfincore(regclass, bool) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfincore(regclass, text, bool) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfincore_drawer(varbit) CASCADE; + + diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_maindb_92_613.sql b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_maindb_92_613.sql new file mode 100644 index 000000000..88521bb7a --- /dev/null +++ b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_maindb_92_613.sql @@ -0,0 +1,16 @@ +DROP FUNCTION IF EXISTS pg_catalog.pgsysconf_pretty() CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgsysconf() CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_willneed(regclass) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_dontneed(regclass) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_normal(regclass) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_sequential(regclass) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_random(regclass) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise(regclass, text, int) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_loader(regclass, text, int, bool, bool, varbit) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_loader(regclass, int, bool, bool, varbit) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfincore(regclass) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfincore(regclass, bool) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfincore(regclass, text, bool) CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.pgfincore_drawer(varbit) CASCADE; + + diff --git a/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_92_613.sql b/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_92_613.sql new file mode 100644 index 000000000..b4ad240f1 --- /dev/null +++ b/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_92_613.sql @@ -0,0 +1,206 @@ +DROP FUNCTION IF EXISTS pg_catalog.pgsysconf() CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2371; +CREATE FUNCTION +pg_catalog.pgsysconf(OUT os_page_size bigint, + OUT os_pages_free bigint, + OUT os_total_pages bigint) +RETURNS record LANGUAGE INTERNAL VOLATILE +AS 'pgfincore'; +COMMENT ON FUNCTION pg_catalog.pgsysconf() +IS 'Get system configuration information at run time, man 3 sysconf for details'; + + +DROP FUNCTION IF EXISTS pg_catalog.pgsysconf_pretty() CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2534; +CREATE FUNCTION +pg_catalog.pgsysconf_pretty(OUT os_page_size text, + OUT os_pages_free text, + OUT os_total_pages text) +RETURNS record LANGUAGE SQL VOLATILE +AS ' +select pg_catalog.pg_size_pretty(os_page_size) as os_page_size, + pg_catalog.pg_size_pretty(os_pages_free * os_page_size) as os_pages_free, + pg_catalog.pg_size_pretty(os_total_pages * os_page_size) as os_total_pages +from pgsysconf()' +; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise(regclass, text, int) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2372; +CREATE OR REPLACE FUNCTION +pg_catalog.pgfadvise(IN regclass, IN text, IN int, + OUT relpath text, + OUT os_page_size bigint, + OUT rel_os_pages bigint, + OUT os_pages_free bigint) +RETURNS setof record LANGUAGE INTERNAL VOLATILE +AS 'pgfadvise' +; +COMMENT ON FUNCTION pg_catalog.pgfadvise(regclass, text, int) +IS 'Predeclare an access pattern for file data'; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_willneed(regclass) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2535; +CREATE FUNCTION +pg_catalog.pgfadvise_willneed(IN regclass, + OUT relpath text, + OUT os_page_size bigint, + OUT rel_os_pages bigint, + OUT os_pages_free bigint) +RETURNS setof record LANGUAGE SQL VOLATILE +AS 'SELECT pg_catalog.pgfadvise($1, ''main'', 10)' +; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_dontneed(regclass) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2536; +CREATE FUNCTION +pg_catalog.pgfadvise_dontneed(IN regclass, + OUT relpath text, + OUT os_page_size bigint, + OUT rel_os_pages bigint, + OUT os_pages_free bigint) +RETURNS setof record LANGUAGE SQL VOLATILE +AS 'SELECT pg_catalog.pgfadvise($1, ''main'', 20)' +; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_normal(regclass) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2537; +CREATE FUNCTION +pg_catalog.pgfadvise_normal(IN regclass, + OUT relpath text, + OUT os_page_size bigint, + OUT rel_os_pages bigint, + OUT os_pages_free bigint) +RETURNS setof record LANGUAGE SQL VOLATILE +AS 'SELECT pg_catalog.pgfadvise($1, ''main'', 30)' +; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_sequential(regclass) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2538; +CREATE FUNCTION +pg_catalog.pgfadvise_sequential(IN regclass, + OUT relpath text, + OUT os_page_size bigint, + OUT rel_os_pages bigint, + OUT os_pages_free bigint) +RETURNS setof record LANGUAGE SQL VOLATILE +AS 'SELECT pg_catalog.pgfadvise($1, ''main'', 40)' +; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_random(regclass) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2542; +CREATE FUNCTION +pg_catalog.pgfadvise_random(IN regclass, + OUT relpath text, + OUT os_page_size bigint, + OUT rel_os_pages bigint, + OUT os_pages_free bigint) +RETURNS setof record LANGUAGE SQL VOLATILE +AS 'SELECT pg_catalog.pgfadvise($1, ''main'', 50)' +; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_loader(regclass, text, int, bool, bool, varbit) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2373; +CREATE FUNCTION +pg_catalog.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 LANGUAGE INTERNAL VOLATILE +AS 'pgfadvise_loader' +; +COMMENT ON FUNCTION pg_catalog.pgfadvise_loader(regclass, text, int, bool, bool, varbit) +IS 'Restore cache from the snapshot, options to load/unload each block to/from cache'; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_loader(regclass, int, bool, bool, varbit) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2539; +CREATE FUNCTION +pg_catalog.pgfadvise_loader(IN regclass, 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 LANGUAGE SQL VOLATILE +AS 'SELECT pg_catalog.pgfadvise_loader($1, ''main'', $2, $3, $4, $5)' +; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfincore(regclass, text, bool) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2374; +CREATE FUNCTION +pg_catalog.pgfincore(IN regclass, IN text, IN bool, + OUT relpath text, + OUT segment int, + OUT os_page_size bigint, + OUT rel_os_pages bigint, + OUT pages_mem bigint, + OUT group_mem bigint, + OUT os_pages_free bigint, + OUT databit varbit, + OUT pages_dirty bigint, + OUT group_dirty bigint) +RETURNS setof record LANGUAGE INTERNAL VOLATILE +AS 'pgfincore' +; +COMMENT ON FUNCTION pg_catalog.pgfincore(regclass, text, bool) +IS 'Utility to inspect and get a snapshot of the system cache'; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfincore(regclass) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2541; +CREATE FUNCTION +pg_catalog.pgfincore(IN regclass, + OUT relpath text, + OUT segment int, + OUT os_page_size bigint, + OUT rel_os_pages bigint, + OUT pages_mem bigint, + OUT group_mem bigint, + OUT os_pages_free bigint, + OUT databit varbit, + OUT pages_dirty bigint, + OUT group_dirty bigint) +RETURNS setof record LANGUAGE SQL VOLATILE +AS 'SELECT * from pg_catalog.pgfincore($1, ''main'', false)' +; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfincore(regclass, bool) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2540; +CREATE FUNCTION +pg_catalog.pgfincore(IN regclass, IN bool, + OUT relpath text, + OUT segment int, + OUT os_page_size bigint, + OUT rel_os_pages bigint, + OUT pages_mem bigint, + OUT group_mem bigint, + OUT os_pages_free bigint, + OUT databit varbit, + OUT pages_dirty bigint, + OUT group_dirty bigint) +RETURNS setof record LANGUAGE SQL VOLATILE +AS 'SELECT * from pg_catalog.pgfincore($1, ''main'', $2)' +; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfincore_drawer(varbit) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2543; +CREATE FUNCTION +pg_catalog.pgfincore_drawer(IN varbit, + OUT drawer cstring) +RETURNS cstring LANGUAGE INTERNAL IMMUTABLE +AS 'pgfincore_drawer' +; +COMMENT ON FUNCTION pg_catalog.pgfincore_drawer(varbit) +IS 'A naive drawing function to visualize page cache per object'; diff --git a/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_92_613.sql b/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_92_613.sql new file mode 100644 index 000000000..b4ad240f1 --- /dev/null +++ b/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_92_613.sql @@ -0,0 +1,206 @@ +DROP FUNCTION IF EXISTS pg_catalog.pgsysconf() CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2371; +CREATE FUNCTION +pg_catalog.pgsysconf(OUT os_page_size bigint, + OUT os_pages_free bigint, + OUT os_total_pages bigint) +RETURNS record LANGUAGE INTERNAL VOLATILE +AS 'pgfincore'; +COMMENT ON FUNCTION pg_catalog.pgsysconf() +IS 'Get system configuration information at run time, man 3 sysconf for details'; + + +DROP FUNCTION IF EXISTS pg_catalog.pgsysconf_pretty() CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2534; +CREATE FUNCTION +pg_catalog.pgsysconf_pretty(OUT os_page_size text, + OUT os_pages_free text, + OUT os_total_pages text) +RETURNS record LANGUAGE SQL VOLATILE +AS ' +select pg_catalog.pg_size_pretty(os_page_size) as os_page_size, + pg_catalog.pg_size_pretty(os_pages_free * os_page_size) as os_pages_free, + pg_catalog.pg_size_pretty(os_total_pages * os_page_size) as os_total_pages +from pgsysconf()' +; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise(regclass, text, int) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2372; +CREATE OR REPLACE FUNCTION +pg_catalog.pgfadvise(IN regclass, IN text, IN int, + OUT relpath text, + OUT os_page_size bigint, + OUT rel_os_pages bigint, + OUT os_pages_free bigint) +RETURNS setof record LANGUAGE INTERNAL VOLATILE +AS 'pgfadvise' +; +COMMENT ON FUNCTION pg_catalog.pgfadvise(regclass, text, int) +IS 'Predeclare an access pattern for file data'; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_willneed(regclass) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2535; +CREATE FUNCTION +pg_catalog.pgfadvise_willneed(IN regclass, + OUT relpath text, + OUT os_page_size bigint, + OUT rel_os_pages bigint, + OUT os_pages_free bigint) +RETURNS setof record LANGUAGE SQL VOLATILE +AS 'SELECT pg_catalog.pgfadvise($1, ''main'', 10)' +; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_dontneed(regclass) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2536; +CREATE FUNCTION +pg_catalog.pgfadvise_dontneed(IN regclass, + OUT relpath text, + OUT os_page_size bigint, + OUT rel_os_pages bigint, + OUT os_pages_free bigint) +RETURNS setof record LANGUAGE SQL VOLATILE +AS 'SELECT pg_catalog.pgfadvise($1, ''main'', 20)' +; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_normal(regclass) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2537; +CREATE FUNCTION +pg_catalog.pgfadvise_normal(IN regclass, + OUT relpath text, + OUT os_page_size bigint, + OUT rel_os_pages bigint, + OUT os_pages_free bigint) +RETURNS setof record LANGUAGE SQL VOLATILE +AS 'SELECT pg_catalog.pgfadvise($1, ''main'', 30)' +; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_sequential(regclass) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2538; +CREATE FUNCTION +pg_catalog.pgfadvise_sequential(IN regclass, + OUT relpath text, + OUT os_page_size bigint, + OUT rel_os_pages bigint, + OUT os_pages_free bigint) +RETURNS setof record LANGUAGE SQL VOLATILE +AS 'SELECT pg_catalog.pgfadvise($1, ''main'', 40)' +; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_random(regclass) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2542; +CREATE FUNCTION +pg_catalog.pgfadvise_random(IN regclass, + OUT relpath text, + OUT os_page_size bigint, + OUT rel_os_pages bigint, + OUT os_pages_free bigint) +RETURNS setof record LANGUAGE SQL VOLATILE +AS 'SELECT pg_catalog.pgfadvise($1, ''main'', 50)' +; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_loader(regclass, text, int, bool, bool, varbit) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2373; +CREATE FUNCTION +pg_catalog.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 LANGUAGE INTERNAL VOLATILE +AS 'pgfadvise_loader' +; +COMMENT ON FUNCTION pg_catalog.pgfadvise_loader(regclass, text, int, bool, bool, varbit) +IS 'Restore cache from the snapshot, options to load/unload each block to/from cache'; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfadvise_loader(regclass, int, bool, bool, varbit) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2539; +CREATE FUNCTION +pg_catalog.pgfadvise_loader(IN regclass, 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 LANGUAGE SQL VOLATILE +AS 'SELECT pg_catalog.pgfadvise_loader($1, ''main'', $2, $3, $4, $5)' +; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfincore(regclass, text, bool) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2374; +CREATE FUNCTION +pg_catalog.pgfincore(IN regclass, IN text, IN bool, + OUT relpath text, + OUT segment int, + OUT os_page_size bigint, + OUT rel_os_pages bigint, + OUT pages_mem bigint, + OUT group_mem bigint, + OUT os_pages_free bigint, + OUT databit varbit, + OUT pages_dirty bigint, + OUT group_dirty bigint) +RETURNS setof record LANGUAGE INTERNAL VOLATILE +AS 'pgfincore' +; +COMMENT ON FUNCTION pg_catalog.pgfincore(regclass, text, bool) +IS 'Utility to inspect and get a snapshot of the system cache'; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfincore(regclass) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2541; +CREATE FUNCTION +pg_catalog.pgfincore(IN regclass, + OUT relpath text, + OUT segment int, + OUT os_page_size bigint, + OUT rel_os_pages bigint, + OUT pages_mem bigint, + OUT group_mem bigint, + OUT os_pages_free bigint, + OUT databit varbit, + OUT pages_dirty bigint, + OUT group_dirty bigint) +RETURNS setof record LANGUAGE SQL VOLATILE +AS 'SELECT * from pg_catalog.pgfincore($1, ''main'', false)' +; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfincore(regclass, bool) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2540; +CREATE FUNCTION +pg_catalog.pgfincore(IN regclass, IN bool, + OUT relpath text, + OUT segment int, + OUT os_page_size bigint, + OUT rel_os_pages bigint, + OUT pages_mem bigint, + OUT group_mem bigint, + OUT os_pages_free bigint, + OUT databit varbit, + OUT pages_dirty bigint, + OUT group_dirty bigint) +RETURNS setof record LANGUAGE SQL VOLATILE +AS 'SELECT * from pg_catalog.pgfincore($1, ''main'', $2)' +; + + +DROP FUNCTION IF EXISTS pg_catalog.pgfincore_drawer(varbit) CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 2543; +CREATE FUNCTION +pg_catalog.pgfincore_drawer(IN varbit, + OUT drawer cstring) +RETURNS cstring LANGUAGE INTERNAL IMMUTABLE +AS 'pgfincore_drawer' +; +COMMENT ON FUNCTION pg_catalog.pgfincore_drawer(varbit) +IS 'A naive drawing function to visualize page cache per object'; diff --git a/src/test/regress/expected/pgfincore.out b/src/test/regress/expected/pgfincore.out new file mode 100644 index 000000000..2c6fec9fc --- /dev/null +++ b/src/test/regress/expected/pgfincore.out @@ -0,0 +1,122 @@ +-- +-- test SYSCONF +-- +select true from pgsysconf(); + bool +------ + t +(1 row) + +select true from pgsysconf_pretty(); + bool +------ + t +(1 row) + +-- +-- make a temp table to use below +-- +CREATE TEMP TABLE test AS SELECT generate_series(1,256) as a; +-- +-- this is not perfect testing but it is hard to predict what the OS will do +-- for *sure* +-- +-- +-- test fadvise_loader +-- +select true from pgfadvise_loader('test', 0, true, true, B'1010'); + bool +------ + t +(1 row) + +select true from pgfadvise_loader('test', 0, true, false, B'1010'); + bool +------ + t +(1 row) + +select true from pgfadvise_loader('test', 0, false, true, B'1010'); + bool +------ + t +(1 row) + +select true from pgfadvise_loader('test', 0, false, false, B'1010'); + bool +------ + t +(1 row) + +-- must not fail on empty databit input +select true from pgfadvise_loader('test', 0, false, false, B''); + bool +------ + t +(1 row) + +-- ERROR on NULL databit input +select true from pgfadvise_loader('test', 0, false, false, NULL); +ERROR: pgfadvise_loader: databit argument shouldn't be NULL +CONTEXT: referenced column: pgfadvise_loader +SQL function "pgfadvise_loader" statement 1 +-- +-- test pgfincore +-- +select true from pgfincore('test', true); + bool +------ + t +(1 row) + +select true from pgfincore('test'); + bool +------ + t +(1 row) + +-- +-- test DONTNEED, WILLNEED +-- +select true from pgfadvise_willneed('test'); + bool +------ + t +(1 row) + +select true from pgfadvise_dontneed('test'); + bool +------ + t +(1 row) + +-- +-- test PGFADVISE flags +-- +select true from pgfadvise_sequential('test'); + bool +------ + t +(1 row) + +select true from pgfadvise_random('test'); + bool +------ + t +(1 row) + +select true from pgfadvise_normal('test'); + bool +------ + t +(1 row) + +-- +-- tests drawers +-- +select true from pgfincore('test','main',true); + bool +------ + t +(1 row) + diff --git a/src/test/regress/parallel_schedule0 b/src/test/regress/parallel_schedule0 index 79c49f338..cccf21017 100644 --- a/src/test/regress/parallel_schedule0 +++ b/src/test/regress/parallel_schedule0 @@ -929,3 +929,4 @@ test: composite_datum_record mysql_function b_comments test: join_test_alias alter_ctable_compress test: ignore/ignore_type_transform ignore/ignore_not_null_constraints ignore/ignore_unique_constraints ignore/ignore_no_matched_partition +test: pgfincore diff --git a/src/test/regress/sql/pgfincore.sql b/src/test/regress/sql/pgfincore.sql new file mode 100644 index 000000000..192845760 --- /dev/null +++ b/src/test/regress/sql/pgfincore.sql @@ -0,0 +1,51 @@ +-- +-- test SYSCONF +-- +select true from pgsysconf(); +select true from pgsysconf_pretty(); + +-- +-- make a temp table to use below +-- +CREATE TEMP TABLE test AS SELECT generate_series(1,256) as a; + +-- +-- this is not perfect testing but it is hard to predict what the OS will do +-- for *sure* +-- + +-- +-- test fadvise_loader +-- +select true from pgfadvise_loader('test', 0, true, true, B'1010'); +select true from pgfadvise_loader('test', 0, true, false, B'1010'); +select true from pgfadvise_loader('test', 0, false, true, B'1010'); +select true from pgfadvise_loader('test', 0, false, false, B'1010'); +-- must not fail on empty databit input +select true from pgfadvise_loader('test', 0, false, false, B''); +-- ERROR on NULL databit input +select true from pgfadvise_loader('test', 0, false, false, NULL); + +-- +-- test pgfincore +-- +select true from pgfincore('test', true); +select true from pgfincore('test'); + +-- +-- test DONTNEED, WILLNEED +-- +select true from pgfadvise_willneed('test'); +select true from pgfadvise_dontneed('test'); + +-- +-- test PGFADVISE flags +-- +select true from pgfadvise_sequential('test'); +select true from pgfadvise_random('test'); +select true from pgfadvise_normal('test'); + +-- +-- tests drawers +-- +select true from pgfincore('test','main',true); From af9d20e8ef302a586b9c6432a9d9f3aa58b16697 Mon Sep 17 00:00:00 2001 From: jkshen <2458684728@qq.com> Date: Wed, 24 Aug 2022 18:05:24 +0800 Subject: [PATCH 2/4] =?UTF-8?q?pgfincore=E4=BB=A3=E7=A0=81=E4=BF=AE?= =?UTF-8?q?=E6=94=B9v1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/backend/utils/misc/pgfincore.cpp | 145 ++++++++++---------- 1 file changed, 70 insertions(+), 75 deletions(-) diff --git a/src/common/backend/utils/misc/pgfincore.cpp b/src/common/backend/utils/misc/pgfincore.cpp index 9e4be31d7..ea328db6e 100644 --- a/src/common/backend/utils/misc/pgfincore.cpp +++ b/src/common/backend/utils/misc/pgfincore.cpp @@ -3,17 +3,15 @@ * pgfincore.cpp * This file let you see and mainpulate objects in the FS page cache * - * Portions Copyright (c) 2022, Wuhan University + * Portions Copyright (c) 2022, Huawei Technologies Co.,Ltd. * Portions Copyright (c) 2009-2011, Cédric Villemain * - * * IDENTIFICATION * src/common/backend/utils/misc/pgfincore.cpp * * ------------------------------------------------------------------------- */ -#include #include #include #include @@ -38,23 +36,23 @@ #include "storage/lock/lock.h" #include "utils/relcache.h" -#define PGSYSCONF_COLS 3 -#define PGFADVISE_COLS 4 -#define PGFADVISE_LOADER_COLS 5 -#define PGFINCORE_COLS 10 +#define PGSYSCONF_COLS 3 +#define PGFADVISE_COLS 4 +#define PGFADVISE_LOADER_COLS 5 +#define PGFINCORE_COLS 10 -#define PGF_WILLNEED 10 -#define PGF_DONTNEED 20 -#define PGF_NORMAL 30 -#define PGF_SEQUENTIAL 40 -#define PGF_RANDOM 50 +#define PGF_WILLNEED 10 +#define PGF_DONTNEED 20 +#define PGF_NORMAL 30 +#define PGF_SEQUENTIAL 40 +#define PGF_RANDOM 50 #define FINCORE_PRESENT 0x1 -#define FINCORE_DIRTY 0x2 +#define FINCORE_DIRTY 0x2 #ifndef HAVE_FINCORE -#define FINCORE_BITS 1 +#define FINCORE_BITS 1 #else -#define FINCORE_BITS 2 +#define FINCORE_BITS 2 #endif /* * pgfadvise_fctx structure is needed @@ -209,9 +207,9 @@ static int pgfadvise_file(char *filename, int advice, pgfadviseStruct *pgfdv) pgfdv->pageSize = sysconf(_SC_PAGESIZE); /* - * Fopen and fstat file + * Fopen 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 + * if there is no file, just return 1, it is expected to leave the SRF */ fp = AllocateFile(filename, "rb"); if (fp == NULL) @@ -357,13 +355,13 @@ Datum pgfadvise(PG_FUNCTION_ARGS) errdetail("segment-page tables doesn't support pgfadvise yet"))); } - if(RelationIsSubPartitioned(fctx->rel)) { - fctx->isSubPartitionTable = RelationIsSubPartitioned(fctx->rel); + if (RelationIsSubPartitioned(fctx->rel)) { + fctx->isSubPartitionTable = true; fctx->isPartitionTable = false; - } else if(RELATION_IS_PARTITIONED(fctx->rel)) { - fctx->isPartitionTable = RELATION_IS_PARTITIONED(fctx->rel); + } else if (RELATION_IS_PARTITIONED(fctx->rel)) { + fctx->isPartitionTable = true; fctx->isSubPartitionTable = false; - }else { + } else { fctx->isPartitionTable = false; fctx->isSubPartitionTable = false; } @@ -375,7 +373,7 @@ Datum pgfadvise(PG_FUNCTION_ARGS) fctx->isFirstIndexOid = true;; if (!RelationIsIndex(fctx->rel)) { fctx->indexoidlist = RelationGetIndexList(fctx->rel); - }else { + } else { fctx->indexoidlist = NULL; } @@ -383,7 +381,7 @@ Datum pgfadvise(PG_FUNCTION_ARGS) /* Here we keep track of current action in all calls */ fctx->advice = advice; - if(!(fctx->isPartitionTable || fctx->isSubPartitionTable)) { + if (!(fctx->isPartitionTable || fctx->isSubPartitionTable)) { /* we get the common part of the filename of each segment of a relation */ fctx->relationpath = relpathpg(fctx->rel, forkName); @@ -432,9 +430,9 @@ Datum pgfadvise(PG_FUNCTION_ARGS) } FILE *fp = AllocateFile(filename, "rb"); - if(fp == NULL) { - if(fctx->isPartitionTable || fctx->isSubPartitionTable) { - if(fctx->isSubPartitionTable && lnext(fctx->subPartitionCell)) { + if (fp == NULL) { + if (fctx->isPartitionTable || fctx->isSubPartitionTable) { + if (fctx->isSubPartitionTable && lnext(fctx->subPartitionCell)) { fctx->subPartitionCell = lnext(fctx->subPartitionCell); Partition subPartition = (Partition)lfirst(fctx->subPartitionCell); Relation subPartionRel = SubPartitionGetRelation(fctx->rel,subPartition,AccessShareLock); @@ -443,7 +441,7 @@ Datum pgfadvise(PG_FUNCTION_ARGS) releaseDummyRelation(&subPartionRel); errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); securec_check_ss(rc, "\0", "\0"); - }else if(fctx->isPartitionTable && lnext(fctx->partitionCell)) { + } else if (fctx->isPartitionTable && lnext(fctx->partitionCell)) { fctx->partitionCell = lnext(fctx->partitionCell); Partition partition = (Partition)lfirst(fctx->partitionCell); Relation partitionRel = partitionGetRelation(fctx->rel,partition); @@ -452,9 +450,9 @@ Datum pgfadvise(PG_FUNCTION_ARGS) releaseDummyRelation(&partitionRel); errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); securec_check_ss(rc, "\0", "\0"); - }else { - if(fctx->indexoidlist != NULL) { - if(fctx->isFirstIndexOid) { + } else { + if (fctx->indexoidlist != NULL) { + if (fctx->isFirstIndexOid) { fctx->indexCell = list_head(fctx->indexoidlist); fctx->isFirstIndexOid=false; Oid indexId = lfirst_oid(fctx->indexCell); @@ -464,8 +462,8 @@ Datum pgfadvise(PG_FUNCTION_ARGS) index_close(currentIndex, NoLock); errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); securec_check_ss(rc, "\0", "\0"); - }else { - if(lnext(fctx->indexCell)) { + } else { + if (lnext(fctx->indexCell)) { fctx->indexCell = lnext(fctx->indexCell); Oid indexId = lfirst_oid(fctx->indexCell); Relation currentIndex = index_open(indexId, AccessShareLock); @@ -478,10 +476,10 @@ Datum pgfadvise(PG_FUNCTION_ARGS) } } } - }else { + } else { //process index - if(fctx->indexoidlist != NULL) { - if(fctx->isFirstIndexOid) { + if (fctx->indexoidlist != NULL) { + if (fctx->isFirstIndexOid) { fctx->indexCell = list_head(fctx->indexoidlist); fctx->isFirstIndexOid=false; Oid indexId = lfirst_oid(fctx->indexCell); @@ -491,8 +489,8 @@ Datum pgfadvise(PG_FUNCTION_ARGS) index_close(currentIndex, NoLock); errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); securec_check_ss(rc, "\0", "\0"); - }else { - if(lnext(fctx->indexCell)) { + } else { + if (lnext(fctx->indexCell)) { fctx->indexCell = lnext(fctx->indexCell); Oid indexId = lfirst_oid(fctx->indexCell); Relation currentIndex = index_open(indexId, AccessShareLock); @@ -522,9 +520,9 @@ Datum pgfadvise(PG_FUNCTION_ARGS) */ if (result) { ereport(DEBUG1, (errmsg("pgfadvise: closing %s", fctx->relationpath))); - if(fctx->isPartitionTable) { + if (fctx->isPartitionTable) { releasePartitionList(fctx->rel, &(fctx->partitionIdList), AccessShareLock); - }else if(fctx->isSubPartitionTable) { + } else if (fctx->isSubPartitionTable) { releasePartitionList(fctx->rel, &(fctx->subPartitionIdList), AccessShareLock); } relation_close(fctx->rel, AccessShareLock); @@ -597,7 +595,7 @@ static int pgfadvise_loader_file(char *filename, /* * Fopen 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 + * if there is no file, just return 1, it is expected to leave the SRF */ fp = AllocateFile(filename, "rb"); if (fp == NULL) @@ -626,8 +624,7 @@ static int pgfadvise_loader_file(char *filename, POSIX_FADV_WILLNEED); pgfloader->pagesLoaded++; } - } - else if (dontneed) { + } else if (dontneed) { (void) posix_fadvise(fd, ((i+k) * pgfloader->pageSize), pgfloader->pageSize, @@ -654,8 +651,7 @@ static int pgfadvise_loader_file(char *filename, POSIX_FADV_WILLNEED); pgfloader->pagesLoaded++; } - } - else if (dontneed) { + } else if (dontneed) { (void) posix_fadvise(fd, (k * pgfloader->pageSize), pgfloader->pageSize, @@ -831,7 +827,7 @@ static int pgfincore_file(char *filename, pgfincoreStruct *pgfncr) /* * Fopen 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 + * if there is no file, just return 1, it is expected to leave the SRF */ fp = AllocateFile(filename, "rb"); if (fp == NULL) @@ -858,7 +854,7 @@ static int pgfincore_file(char *filename, pgfincoreStruct *pgfncr) if (pa == MAP_FAILED) { int save_errno = errno; FreeFile(fp); - ereport(ERROR, (errmsg("Can not mmap object file : %s, errno = %i,%s\nThis error can happen if there is not enought space in memory to do the projection. Please mail cedric@villemain.org with '[pgfincore] ENOMEM' as subject.", + ereport(ERROR, (errmsg("Can not mmap object file : %s, errno = %i,%s\nThis error can happen if there is not enought space in memory to do the projection.", filename, save_errno, strerror(save_errno)))); return 1; } @@ -924,9 +920,9 @@ static int pgfincore_file(char *filename, pgfincoreStruct *pgfncr) if (flag_dirty) pgfncr->group_dirty++; flag_dirty = 0; - } - else + } else { flag_dirty = 1; + } } ereport(DEBUG5, (errmsg("in memory blocks : %lld / %lld", (long long int) pageIndex, (long long int) pgfncr->rel_os_pages))); @@ -934,10 +930,9 @@ static int pgfincore_file(char *filename, pgfincoreStruct *pgfncr) if (flag) pgfncr->group_mem++; flag = 0; - } - else + } else { flag=1; - + } x >>= FINCORE_BITS; if (x == 0) { @@ -1044,13 +1039,13 @@ Datum pgfincore(PG_FUNCTION_ARGS) errdetail("segment-page tables doesn't support pgfincore yet"))); } - if(RelationIsSubPartitioned(fctx->rel)) { - fctx->isSubPartitionTable = RelationIsSubPartitioned(fctx->rel); + if (RelationIsSubPartitioned(fctx->rel)) { + fctx->isSubPartitionTable = true; fctx->isPartitionTable = false; - } else if(RELATION_IS_PARTITIONED(fctx->rel)) { - fctx->isPartitionTable = RELATION_IS_PARTITIONED(fctx->rel); + } else if (RELATION_IS_PARTITIONED(fctx->rel)) { + fctx->isPartitionTable = true; fctx->isSubPartitionTable = false; - }else { + } else { fctx->isPartitionTable = false; fctx->isSubPartitionTable = false; } @@ -1063,11 +1058,11 @@ Datum pgfincore(PG_FUNCTION_ARGS) fctx->isFirstIndexOid = true;; if (!RelationIsIndex(fctx->rel)) { fctx->indexoidlist = RelationGetIndexList(fctx->rel); - }else { + } else { fctx->indexoidlist = NULL; } - if(!(fctx->isPartitionTable || fctx->isSubPartitionTable)) { + if (!(fctx->isPartitionTable || fctx->isSubPartitionTable)) { /* we get the common part of the filename of each segment of a relation */ fctx->relationpath = relpathpg(fctx->rel, forkName); @@ -1116,9 +1111,9 @@ Datum pgfincore(PG_FUNCTION_ARGS) } FILE *fp = AllocateFile(filename, "rb"); - if(fp == NULL) { - if(fctx->isPartitionTable || fctx->isSubPartitionTable) { - if(fctx->isSubPartitionTable && lnext(fctx->subPartitionCell)) { + if (fp == NULL) { + if (fctx->isPartitionTable || fctx->isSubPartitionTable) { + if (fctx->isSubPartitionTable && lnext(fctx->subPartitionCell)) { fctx->subPartitionCell = lnext(fctx->subPartitionCell); Partition subPartition = (Partition)lfirst(fctx->subPartitionCell); Relation subPartionRel = SubPartitionGetRelation(fctx->rel,subPartition,AccessShareLock); @@ -1127,7 +1122,7 @@ Datum pgfincore(PG_FUNCTION_ARGS) releaseDummyRelation(&subPartionRel); errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); securec_check_ss(rc, "\0", "\0"); - }else if(fctx->isPartitionTable && lnext(fctx->partitionCell)) { + } else if (fctx->isPartitionTable && lnext(fctx->partitionCell)) { fctx->partitionCell = lnext(fctx->partitionCell); Partition partition = (Partition)lfirst(fctx->partitionCell); Relation partitionRel = partitionGetRelation(fctx->rel,partition); @@ -1136,9 +1131,9 @@ Datum pgfincore(PG_FUNCTION_ARGS) releaseDummyRelation(&partitionRel); errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); securec_check_ss(rc, "\0", "\0"); - }else { - if(fctx->indexoidlist != NULL) { - if(fctx->isFirstIndexOid) { + } else { + if (fctx->indexoidlist != NULL) { + if (fctx->isFirstIndexOid) { fctx->indexCell = list_head(fctx->indexoidlist); fctx->isFirstIndexOid=false; Oid indexId = lfirst_oid(fctx->indexCell); @@ -1148,8 +1143,8 @@ Datum pgfincore(PG_FUNCTION_ARGS) index_close(currentIndex, NoLock); errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); securec_check_ss(rc, "\0", "\0"); - }else { - if(lnext(fctx->indexCell)) { + } else { + if (lnext(fctx->indexCell)) { fctx->indexCell = lnext(fctx->indexCell); Oid indexId = lfirst_oid(fctx->indexCell); Relation currentIndex = index_open(indexId, AccessShareLock); @@ -1162,10 +1157,10 @@ Datum pgfincore(PG_FUNCTION_ARGS) } } } - }else { + } else { //process index - if(fctx->indexoidlist != NULL) { - if(fctx->isFirstIndexOid) { + if (fctx->indexoidlist != NULL) { + if (fctx->isFirstIndexOid) { fctx->indexCell = list_head(fctx->indexoidlist); fctx->isFirstIndexOid=false; Oid indexId = lfirst_oid(fctx->indexCell); @@ -1175,8 +1170,8 @@ Datum pgfincore(PG_FUNCTION_ARGS) index_close(currentIndex, NoLock); errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); securec_check_ss(rc, "\0", "\0"); - }else { - if(lnext(fctx->indexCell)) { + } else { + if (lnext(fctx->indexCell)) { fctx->indexCell = lnext(fctx->indexCell); Oid indexId = lfirst_oid(fctx->indexCell); Relation currentIndex = index_open(indexId, AccessShareLock); @@ -1206,9 +1201,9 @@ Datum pgfincore(PG_FUNCTION_ARGS) if (result) { ereport(DEBUG1, (errmsg("pgfincore: closing %s", fctx->relationpath))); - if(fctx->isPartitionTable) { + if (fctx->isPartitionTable) { releasePartitionList(fctx->rel, &(fctx->partitionIdList), AccessShareLock); - }else if(fctx->isSubPartitionTable) { + } else if (fctx->isSubPartitionTable) { releasePartitionList(fctx->rel, &(fctx->subPartitionIdList), AccessShareLock); } relation_close(fctx->rel, AccessShareLock); From 380d4899eb73aa1608fc19e9c451cf6a21d85469 Mon Sep 17 00:00:00 2001 From: jkshen <2458684728@qq.com> Date: Wed, 24 Aug 2022 22:24:55 +0800 Subject: [PATCH 3/4] =?UTF-8?q?pgfincore=E6=A0=BC=E5=BC=8F=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/backend/utils/misc/pgfincore.cpp | 1990 ++++++++++--------- 1 file changed, 1002 insertions(+), 988 deletions(-) diff --git a/src/common/backend/utils/misc/pgfincore.cpp b/src/common/backend/utils/misc/pgfincore.cpp index ea328db6e..377ae9eca 100644 --- a/src/common/backend/utils/misc/pgfincore.cpp +++ b/src/common/backend/utils/misc/pgfincore.cpp @@ -59,21 +59,21 @@ * to keep track of relation path, segment number, ... */ typedef struct { - 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 */ - bool isPartitionTable; /* partition table ?*/ - bool isSubPartitionTable; /*subPartition table ?*/ - ListCell *partitionCell; - ListCell *subPartitionCell; - List *partitionIdList; - List *subPartitionIdList; - text *forkName; - List *indexoidlist; - ListCell *indexCell; - bool isFirstIndexOid; + 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 */ + bool isPartitionTable; /* partition table ?*/ + bool isSubPartitionTable; /*subPartition table ?*/ + ListCell *partitionCell; + ListCell *subPartitionCell; + List *partitionIdList; + List *subPartitionIdList; + text *forkName; + List *indexoidlist; + ListCell *indexCell; + bool isFirstIndexOid; } pgfadvise_fctx; /* @@ -81,9 +81,9 @@ typedef struct { * to return values */ typedef struct { - size_t pageSize; /* os page size */ - size_t pagesFree; /* free page cache */ - size_t filesize; /* the filesize */ + size_t pageSize; /* os page size */ + size_t pagesFree; /* free page cache */ + size_t filesize; /* the filesize */ } pgfadviseStruct; /* @@ -91,10 +91,10 @@ typedef struct { * 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 */ + size_t pageSize; /* os page size */ + size_t pagesFree; /* free page cache */ + size_t pagesLoaded; /* pages loaded */ + size_t pagesUnloaded; /* pages unloaded */ } pgfloaderStruct; /* @@ -102,21 +102,21 @@ typedef struct { * to keep track of relation path, segment number, ... */ typedef struct { - bool getvector; /* output varbit data ? */ - TupleDesc tupd; /* the tuple descriptor */ - Relation rel; /* the relation */ - unsigned int segcount; /* the segment current number */ - char *relationpath; /* the relation path */ - bool isPartitionTable; /* partition table ?*/ - bool isSubPartitionTable; /*subPartition table ?*/ - ListCell *partitionCell; - ListCell *subPartitionCell; - List *partitionIdList; - List *subPartitionIdList; - text *forkName; - List *indexoidlist; - ListCell *indexCell; - bool isFirstIndexOid; + bool getvector; /* output varbit data ? */ + TupleDesc tupd; /* the tuple descriptor */ + Relation rel; /* the relation */ + unsigned int segcount; /* the segment current number */ + char *relationpath; /* the relation path */ + bool isPartitionTable; /* partition table ?*/ + bool isSubPartitionTable; /*subPartition table ?*/ + ListCell *partitionCell; + ListCell *subPartitionCell; + List *partitionIdList; + List *subPartitionIdList; + text *forkName; + List *indexoidlist; + ListCell *indexCell; + bool isFirstIndexOid; } pgfincore_fctx; /* @@ -124,27 +124,27 @@ typedef struct { * to keep track of relation path, segment number, ... */ typedef struct { - size_t pageSize; /* os page size */ - size_t pagesFree; /* free page cache */ - size_t rel_os_pages; - size_t pages_mem; - size_t group_mem; - size_t pages_dirty; - size_t group_dirty; - VarBit *databit; + size_t pageSize; /* os page size */ + size_t pagesFree; /* free page cache */ + size_t rel_os_pages; + size_t pages_mem; + size_t group_mem; + size_t pages_dirty; + size_t group_dirty; + VarBit *databit; } pgfincoreStruct; Datum pgsysconf(PG_FUNCTION_ARGS); extern Datum pgfadvise(PG_FUNCTION_ARGS); -static int pgfadvise_file(char *filename, int advice, pgfadviseStruct *pgfdv); +static bool pgfadvise_file(char *filename, int advice, pgfadviseStruct *pgfdv); extern Datum pgfadvise_loader(PG_FUNCTION_ARGS); -static int pgfadvise_loader_file(char *filename, bool willneed, - bool dontneed, VarBit *databit, pgfloaderStruct *pgfloader); +static bool pgfadvise_loader_file(char *filename, bool willneed, + bool dontneed, VarBit *databit, pgfloaderStruct *pgfloader); extern Datum pgfincore(PG_FUNCTION_ARGS); -static int pgfincore_file(char *filename, pgfincoreStruct *pgfncr); +static bool pgfincore_file(char *filename, pgfincoreStruct *pgfncr); extern Datum pgfincore_drawer(PG_FUNCTION_ARGS); @@ -161,123 +161,123 @@ extern Datum pgfincore_drawer(PG_FUNCTION_ARGS); */ Datum pgsysconf(PG_FUNCTION_ARGS) { - HeapTuple tuple; - TupleDesc tupdesc; - Datum values[PGSYSCONF_COLS]; - bool nulls[PGSYSCONF_COLS]; + HeapTuple tuple; + TupleDesc tupdesc; + Datum values[PGSYSCONF_COLS]; + bool nulls[PGSYSCONF_COLS]; - /* initialize nulls array to build the tuple */ - int ret = memset_s(nulls, sizeof(nulls), 0, sizeof(nulls)); - securec_check(ret, "\0", "\0"); - /* Build a tuple descriptor for our result type */ - if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) - ereport(ERROR, (errmsg("pgsysconf: return type must be a row type"))); + /* initialize nulls array to build the tuple */ + int ret = memset_s(nulls, sizeof(nulls), 0, sizeof(nulls)); + securec_check(ret, "\0", "\0"); + /* Build a tuple descriptor for our result type */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + ereport(ERROR, (errmsg("pgsysconf: return type must be a row type"))); - /* Page size */ - values[0] = Int64GetDatum(sysconf(_SC_PAGESIZE)); + /* Page size */ + values[0] = Int64GetDatum(sysconf(_SC_PAGESIZE)); - /* free page in memory */ - values[1] = Int64GetDatum(sysconf(_SC_AVPHYS_PAGES)); + /* free page in memory */ + values[1] = Int64GetDatum(sysconf(_SC_AVPHYS_PAGES)); - /* total memory */ - values[2] = Int64GetDatum(sysconf(_SC_PHYS_PAGES)); + /* total memory */ + values[2] = Int64GetDatum(sysconf(_SC_PHYS_PAGES)); - /* Build and return the result tuple. */ - tuple = heap_form_tuple(tupdesc, values, nulls); - PG_RETURN_DATUM( HeapTupleGetDatum(tuple) ); + /* Build and return the result tuple. */ + tuple = heap_form_tuple(tupdesc, values, nulls); + PG_RETURN_DATUM( HeapTupleGetDatum(tuple) ); } #if defined(USE_POSIX_FADVISE) -static int pgfadvise_file(char *filename, int advice, pgfadviseStruct *pgfdv) +static bool pgfadvise_file(char *filename, int advice, pgfadviseStruct *pgfdv) { - /* - * We use the AllocateFile(2) provided by PostgreSQL. We're going to - * close it ourselves even if PostgreSQL close it anyway at transaction - * end. - */ - FILE *fp; - int fd; - struct stat st; - int adviceFlag; + /* + * We use the AllocateFile(2) provided by PostgreSQL. We're going to + * close it ourselves even if PostgreSQL close it anyway at transaction + * end. + */ + FILE *fp; + int fd; + struct stat st; + int adviceFlag; - /* - * OS Page size and Free pages - */ - pgfdv->pageSize = sysconf(_SC_PAGESIZE); + /* + * OS Page size and Free pages + */ + pgfdv->pageSize = sysconf(_SC_PAGESIZE); - /* - * Fopen 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 - */ - fp = AllocateFile(filename, "rb"); - if (fp == NULL) - return 1; + /* + * Fopen 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 + */ + fp = AllocateFile(filename, "rb"); + if (fp == NULL) + return false; - fd = fileno(fp); - if (fstat(fd, &st) == -1) { - FreeFile(fp); - ereport(ERROR, (errmsg("pgfadvise: Can not stat object file : %s", filename))); - return 1; - } + fd = fileno(fp); + if (fstat(fd, &st) == -1) { + FreeFile(fp); + ereport(ERROR, (errmsg("pgfadvise: Can not stat object file : %s", filename))); + return false; + } - /* - * the file size is used in the SRF to output the number of pages used by - * the segment - */ - pgfdv->filesize = st.st_size; - ereport(DEBUG1, - (errmsg("pgfadvise: working on %s of %lld bytes", filename,(long long int) pgfdv->filesize))); - /* FADVISE_WILLNEED */ - if (advice == PGF_WILLNEED) { - adviceFlag = POSIX_FADV_WILLNEED; - ereport(DEBUG1, (errmsg("pgfadvise: setting advice POSIX_FADV_WILLNEED"))); - } - /* FADVISE_DONTNEED */ - else if (advice == PGF_DONTNEED) { - adviceFlag = POSIX_FADV_DONTNEED; - ereport(DEBUG1, (errmsg("pgfadvise: setting advice POSIX_FADV_DONTNEED"))); - } - /* POSIX_FADV_NORMAL */ - else if (advice == PGF_NORMAL) { - adviceFlag = POSIX_FADV_NORMAL; - ereport(DEBUG1, (errmsg("pgfadvise: setting advice POSIX_FADV_NORMAL"))); - } - /* POSIX_FADV_SEQUENTIAL */ - else if (advice == PGF_SEQUENTIAL) { - adviceFlag = POSIX_FADV_SEQUENTIAL; - ereport(DEBUG1, (errmsg("pgfadvise: setting advice POSIX_FADV_SEQUENTIAL"))); - } - /* POSIX_FADV_RANDOM */ - else if (advice == PGF_RANDOM) { - adviceFlag = POSIX_FADV_RANDOM; - ereport(DEBUG1, (errmsg("pgfadvise: setting advice POSIX_FADV_RANDOM"))); - } else { - ereport(ERROR, (errmsg("pgfadvise: invalid advice: %d", advice))); - return 1; - } + /* + * the file size is used in the SRF to output the number of pages used by + * the segment + */ + pgfdv->filesize = st.st_size; + ereport(DEBUG1, + (errmsg("pgfadvise: working on %s of %lld bytes", filename,(long long int) pgfdv->filesize))); + /* FADVISE_WILLNEED */ + if (advice == PGF_WILLNEED) { + adviceFlag = POSIX_FADV_WILLNEED; + ereport(DEBUG1, (errmsg("pgfadvise: setting advice POSIX_FADV_WILLNEED"))); + } + /* FADVISE_DONTNEED */ + else if (advice == PGF_DONTNEED) { + adviceFlag = POSIX_FADV_DONTNEED; + ereport(DEBUG1, (errmsg("pgfadvise: setting advice POSIX_FADV_DONTNEED"))); + } + /* POSIX_FADV_NORMAL */ + else if (advice == PGF_NORMAL) { + adviceFlag = POSIX_FADV_NORMAL; + ereport(DEBUG1, (errmsg("pgfadvise: setting advice POSIX_FADV_NORMAL"))); + } + /* POSIX_FADV_SEQUENTIAL */ + else if (advice == PGF_SEQUENTIAL) { + adviceFlag = POSIX_FADV_SEQUENTIAL; + ereport(DEBUG1, (errmsg("pgfadvise: setting advice POSIX_FADV_SEQUENTIAL"))); + } + /* POSIX_FADV_RANDOM */ + else if (advice == PGF_RANDOM) { + adviceFlag = POSIX_FADV_RANDOM; + ereport(DEBUG1, (errmsg("pgfadvise: setting advice POSIX_FADV_RANDOM"))); + } else { + ereport(ERROR, (errmsg("pgfadvise: invalid advice: %d", advice))); + return false; + } - /* - * Call posix_fadvise with the relevant advice on the file descriptor - */ - posix_fadvise(fd, 0, 0, adviceFlag); + /* + * Call posix_fadvise with the relevant advice on the file descriptor + */ + posix_fadvise(fd, 0, 0, adviceFlag); - /* close the file */ - FreeFile(fp); + /* close the file */ + FreeFile(fp); - /* - * OS things : Pages free - */ - pgfdv->pagesFree = sysconf(_SC_AVPHYS_PAGES); + /* + * OS things : Pages free + */ + pgfdv->pagesFree = sysconf(_SC_AVPHYS_PAGES); - return 0; + return true; } #else -static int pgfadvise_file(char *filename, int advice, pgfadviseStruct *pgfdv) +static bool pgfadvise_file(char *filename, int advice, pgfadviseStruct *pgfdv) { - ereport(ERROR, (errmsg("POSIX_FADVISE UNSUPPORTED on your platform"))); - return 1; + ereport(ERROR, (errmsg("POSIX_FADVISE UNSUPPORTED on your platform"))); + return false; } #endif @@ -289,394 +289,394 @@ static int pgfadvise_file(char *filename, int advice, pgfadviseStruct *pgfdv) */ Datum pgfadvise(PG_FUNCTION_ARGS) { - FuncCallContext *funcctx; - pgfadvise_fctx *fctx; + FuncCallContext *funcctx; + pgfadvise_fctx *fctx; - /* our structure use to return values */ - pgfadviseStruct *pgfdv; + /* our structure use to return values */ + pgfadviseStruct *pgfdv; - /* our return value, 0 for success */ - int result; + /* our return value, true for success */ + bool result; - /* The file we are working on */ - char filename[MAXPGPATH]; + /* The file we are working on */ + char filename[MAXPGPATH]; - /* stuff done only on the first call of the function */ - if (SRF_IS_FIRSTCALL()) { - MemoryContext oldcontext; + /* stuff done only on the first call of the function */ + if (SRF_IS_FIRSTCALL()) { + MemoryContext oldcontext; - Oid relOid = PG_GETARG_OID(0); - text *forkName = PG_GETARG_TEXT_P(1); - int advice = PG_GETARG_INT32(2); + Oid relOid = PG_GETARG_OID(0); + text *forkName = PG_GETARG_TEXT_P(1); + int advice = PG_GETARG_INT32(2); - /* - * Postgresql stuff to return a tuple - */ - TupleDesc tupdesc; + /* + * Postgresql stuff to return a tuple + */ + TupleDesc tupdesc; - /* create a function context for cross-call persistence */ - funcctx = SRF_FIRSTCALL_INIT(); + /* create a function context for cross-call persistence */ + funcctx = SRF_FIRSTCALL_INIT(); - /* - * switch to memory context appropriate for multiple function calls - */ - oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + /* + * switch to memory context appropriate for multiple function calls + */ + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - /* allocate memory for user context */ - fctx = (pgfadvise_fctx*)palloc(sizeof(pgfadvise_fctx)); + /* allocate memory for user context */ + fctx = (pgfadvise_fctx*)palloc(sizeof(pgfadvise_fctx)); - fctx->forkName = (text*)palloc(VARSIZE(forkName)); - SET_VARSIZE(fctx->forkName, VARSIZE(forkName)); - errno_t ret = memcpy_s((void*)VARDATA(fctx->forkName), VARSIZE(forkName) - VARHDRSZ, (void*)VARDATA(forkName), VARSIZE(forkName) - VARHDRSZ); - securec_check(ret, "\0", "\0"); + fctx->forkName = (text*)palloc(VARSIZE(forkName)); + SET_VARSIZE(fctx->forkName, VARSIZE(forkName)); + errno_t ret = memcpy_s((void*)VARDATA(fctx->forkName), VARSIZE(forkName) - VARHDRSZ, (void*)VARDATA(forkName), VARSIZE(forkName) - VARHDRSZ); + securec_check(ret, "\0", "\0"); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) - ereport(ERROR, (errmsg("pgfadvise: return type must be a row type"))); + ereport(ERROR, (errmsg("pgfadvise: return type must be a row type"))); - /* provide the tuple descriptor to the fonction structure */ + /* provide the tuple descriptor to the fonction structure */ fctx->tupd = tupdesc; - /* open the current relation, accessShareLock */ - // TODO use try_relation_open instead ? - fctx->rel = relation_open(relOid, AccessShareLock); + /* open the current relation, accessShareLock */ + // TODO use try_relation_open instead ? + fctx->rel = relation_open(relOid, AccessShareLock); - if (RelationIsColStore(fctx->rel)) { - ereport(ERROR, + if (RelationIsColStore(fctx->rel)) { + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Un-support feature"), errdetail("column-store relation doesn't support pgfadvise yet"))); - } - - if (RelationIsSegmentTable(fctx->rel)) { - ereport(ERROR, + } + + if (RelationIsSegmentTable(fctx->rel)) { + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Un-support feature"), errdetail("segment-page tables doesn't support pgfadvise yet"))); - } + } - if (RelationIsSubPartitioned(fctx->rel)) { - fctx->isSubPartitionTable = true; - fctx->isPartitionTable = false; - } else if (RELATION_IS_PARTITIONED(fctx->rel)) { - fctx->isPartitionTable = true; - fctx->isSubPartitionTable = false; - } else { - fctx->isPartitionTable = false; - fctx->isSubPartitionTable = false; - } - fctx->partitionCell = NULL; - fctx->subPartitionCell = NULL; - fctx->indexCell = NULL; - fctx->partitionIdList = NULL; - fctx->subPartitionIdList = NULL; - fctx->isFirstIndexOid = true;; - if (!RelationIsIndex(fctx->rel)) { - fctx->indexoidlist = RelationGetIndexList(fctx->rel); - } else { - fctx->indexoidlist = NULL; - } - + if (RelationIsSubPartitioned(fctx->rel)) { + fctx->isSubPartitionTable = true; + fctx->isPartitionTable = false; + } else if (RELATION_IS_PARTITIONED(fctx->rel)) { + fctx->isPartitionTable = true; + fctx->isSubPartitionTable = false; + } else { + fctx->isPartitionTable = false; + fctx->isSubPartitionTable = false; + } + fctx->partitionCell = NULL; + fctx->subPartitionCell = NULL; + fctx->indexCell = NULL; + fctx->partitionIdList = NULL; + fctx->subPartitionIdList = NULL; + fctx->isFirstIndexOid = true;; + if (!RelationIsIndex(fctx->rel)) { + fctx->indexoidlist = RelationGetIndexList(fctx->rel); + } else { + fctx->indexoidlist = NULL; + } + - /* Here we keep track of current action in all calls */ - fctx->advice = advice; + /* Here we keep track of current action in all calls */ + fctx->advice = advice; - if (!(fctx->isPartitionTable || fctx->isSubPartitionTable)) { - /* we get the common part of the filename of each segment of a relation */ - fctx->relationpath = relpathpg(fctx->rel, forkName); + if (!(fctx->isPartitionTable || fctx->isSubPartitionTable)) { + /* we get the common part of the filename of each segment of a relation */ + fctx->relationpath = relpathpg(fctx->rel, forkName); - /* segcount is used to get the next segment of the current relation */ - fctx->segcount = 0; - } else if (fctx->isSubPartitionTable) { - fctx->subPartitionIdList = RelationGetSubPartitionList(fctx->rel, AccessShareLock); - fctx->subPartitionCell = list_head(fctx->subPartitionIdList); - Partition subPartition = (Partition)lfirst(fctx->subPartitionCell); - Relation subPartionRel = SubPartitionGetRelation(fctx->rel, subPartition, AccessShareLock); - fctx->relationpath = relpathpg(subPartionRel, forkName); - fctx->segcount = 0; - releaseDummyRelation(&subPartionRel); - } else if (fctx->isPartitionTable) { - fctx->partitionIdList = relationGetPartitionList(fctx->rel, AccessShareLock); - fctx->partitionCell = list_head(fctx->partitionIdList); - Partition partition = (Partition)lfirst(fctx->partitionCell); - Relation partitionRel = partitionGetRelation(fctx->rel, partition); - fctx->relationpath = relpathpg(partitionRel, forkName); - fctx->segcount = 0; - releaseDummyRelation(&partitionRel); - } + /* segcount is used to get the next segment of the current relation */ + fctx->segcount = 0; + } else if (fctx->isSubPartitionTable) { + fctx->subPartitionIdList = RelationGetSubPartitionList(fctx->rel, AccessShareLock); + fctx->subPartitionCell = list_head(fctx->subPartitionIdList); + Partition subPartition = (Partition)lfirst(fctx->subPartitionCell); + Relation subPartionRel = SubPartitionGetRelation(fctx->rel, subPartition, AccessShareLock); + fctx->relationpath = relpathpg(subPartionRel, forkName); + fctx->segcount = 0; + releaseDummyRelation(&subPartionRel); + } else if (fctx->isPartitionTable) { + fctx->partitionIdList = relationGetPartitionList(fctx->rel, AccessShareLock); + fctx->partitionCell = list_head(fctx->partitionIdList); + Partition partition = (Partition)lfirst(fctx->partitionCell); + Relation partitionRel = partitionGetRelation(fctx->rel, partition); + fctx->relationpath = relpathpg(partitionRel, forkName); + fctx->segcount = 0; + releaseDummyRelation(&partitionRel); + } - /* And finally we keep track of our initialization */ - ereport(DEBUG1, (errmsg("pgfadvise: init done for %s, in fork %s", - fctx->relationpath, text_to_cstring(forkName)))); - funcctx->user_fctx = fctx; - MemoryContextSwitchTo(oldcontext); - } + /* And finally we keep track of our initialization */ + ereport(DEBUG1, (errmsg("pgfadvise: init done for %s, in fork %s", + fctx->relationpath, text_to_cstring(forkName)))); + funcctx->user_fctx = fctx; + MemoryContextSwitchTo(oldcontext); + } - /* After the first call, we recover our context */ - funcctx = SRF_PERCALL_SETUP(); - fctx = (pgfadvise_fctx *) funcctx->user_fctx; + /* After the first call, we recover our context */ + funcctx = SRF_PERCALL_SETUP(); + fctx = (pgfadvise_fctx *) funcctx->user_fctx; - /* - * If we are still looking the first segment - * relationpath should not be suffixed - */ - if (fctx->segcount == 0){ - errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); - securec_check_ss(rc, "\0", "\0"); - } else { - errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s.%u", fctx->relationpath, fctx->segcount); - securec_check_ss(rc, "\0", "\0"); - } + /* + * If we are still looking the first segment + * relationpath should not be suffixed + */ + if (fctx->segcount == 0){ + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } else { + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s.%u", fctx->relationpath, fctx->segcount); + securec_check_ss(rc, "\0", "\0"); + } - FILE *fp = AllocateFile(filename, "rb"); - if (fp == NULL) { - if (fctx->isPartitionTable || fctx->isSubPartitionTable) { - if (fctx->isSubPartitionTable && lnext(fctx->subPartitionCell)) { - fctx->subPartitionCell = lnext(fctx->subPartitionCell); - Partition subPartition = (Partition)lfirst(fctx->subPartitionCell); - Relation subPartionRel = SubPartitionGetRelation(fctx->rel,subPartition,AccessShareLock); - fctx->relationpath = relpathpg(subPartionRel, fctx->forkName); - fctx->segcount = 0; - releaseDummyRelation(&subPartionRel); - errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); - securec_check_ss(rc, "\0", "\0"); - } else if (fctx->isPartitionTable && lnext(fctx->partitionCell)) { - fctx->partitionCell = lnext(fctx->partitionCell); - Partition partition = (Partition)lfirst(fctx->partitionCell); - Relation partitionRel = partitionGetRelation(fctx->rel,partition); - fctx->relationpath = relpathpg(partitionRel, fctx->forkName); - fctx->segcount = 0; - releaseDummyRelation(&partitionRel); - errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); - securec_check_ss(rc, "\0", "\0"); - } else { - if (fctx->indexoidlist != NULL) { - if (fctx->isFirstIndexOid) { - fctx->indexCell = list_head(fctx->indexoidlist); - fctx->isFirstIndexOid=false; - Oid indexId = lfirst_oid(fctx->indexCell); - Relation currentIndex = index_open(indexId, AccessShareLock); - fctx->relationpath = relpathpg(currentIndex, fctx->forkName); - fctx->segcount = 0; - index_close(currentIndex, NoLock); - errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); - securec_check_ss(rc, "\0", "\0"); - } else { - if (lnext(fctx->indexCell)) { - fctx->indexCell = lnext(fctx->indexCell); - Oid indexId = lfirst_oid(fctx->indexCell); - Relation currentIndex = index_open(indexId, AccessShareLock); - fctx->relationpath = relpathpg(currentIndex, fctx->forkName); - fctx->segcount = 0; - index_close(currentIndex, NoLock); - errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); - securec_check_ss(rc, "\0", "\0"); - } - } - } - } - } else { - //process index - if (fctx->indexoidlist != NULL) { - if (fctx->isFirstIndexOid) { - fctx->indexCell = list_head(fctx->indexoidlist); - fctx->isFirstIndexOid=false; - Oid indexId = lfirst_oid(fctx->indexCell); - Relation currentIndex = index_open(indexId, AccessShareLock); - fctx->relationpath = relpathpg(currentIndex, fctx->forkName); - fctx->segcount = 0; - index_close(currentIndex, NoLock); - errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); - securec_check_ss(rc, "\0", "\0"); - } else { - if (lnext(fctx->indexCell)) { - fctx->indexCell = lnext(fctx->indexCell); - Oid indexId = lfirst_oid(fctx->indexCell); - Relation currentIndex = index_open(indexId, AccessShareLock); - fctx->relationpath = relpathpg(currentIndex, fctx->forkName); - fctx->segcount = 0; - index_close(currentIndex, NoLock); - errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); - securec_check_ss(rc, "\0", "\0"); - } - } - } - } - } - - ereport(DEBUG1, (errmsg("pgfadvise: about to work with %s, current advice : %d", - filename, fctx->advice))); - /* - * Call posix_fadvise with the advice, returning the structure - */ - pgfdv = (pgfadviseStruct *) palloc(sizeof(pgfadviseStruct)); - result = pgfadvise_file(filename, fctx->advice, pgfdv); + FILE *fp = AllocateFile(filename, "rb"); + if (fp == NULL) { + if (fctx->isPartitionTable || fctx->isSubPartitionTable) { + if (fctx->isSubPartitionTable && lnext(fctx->subPartitionCell)) { + fctx->subPartitionCell = lnext(fctx->subPartitionCell); + Partition subPartition = (Partition)lfirst(fctx->subPartitionCell); + Relation subPartionRel = SubPartitionGetRelation(fctx->rel,subPartition,AccessShareLock); + fctx->relationpath = relpathpg(subPartionRel, fctx->forkName); + fctx->segcount = 0; + releaseDummyRelation(&subPartionRel); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } else if (fctx->isPartitionTable && lnext(fctx->partitionCell)) { + fctx->partitionCell = lnext(fctx->partitionCell); + Partition partition = (Partition)lfirst(fctx->partitionCell); + Relation partitionRel = partitionGetRelation(fctx->rel,partition); + fctx->relationpath = relpathpg(partitionRel, fctx->forkName); + fctx->segcount = 0; + releaseDummyRelation(&partitionRel); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } else { + if (fctx->indexoidlist != NULL) { + if (fctx->isFirstIndexOid) { + fctx->indexCell = list_head(fctx->indexoidlist); + fctx->isFirstIndexOid=false; + Oid indexId = lfirst_oid(fctx->indexCell); + Relation currentIndex = index_open(indexId, AccessShareLock); + fctx->relationpath = relpathpg(currentIndex, fctx->forkName); + fctx->segcount = 0; + index_close(currentIndex, NoLock); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } else { + if (lnext(fctx->indexCell)) { + fctx->indexCell = lnext(fctx->indexCell); + Oid indexId = lfirst_oid(fctx->indexCell); + Relation currentIndex = index_open(indexId, AccessShareLock); + fctx->relationpath = relpathpg(currentIndex, fctx->forkName); + fctx->segcount = 0; + index_close(currentIndex, NoLock); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } + } + } + } + } else { + //process index + if (fctx->indexoidlist != NULL) { + if (fctx->isFirstIndexOid) { + fctx->indexCell = list_head(fctx->indexoidlist); + fctx->isFirstIndexOid=false; + Oid indexId = lfirst_oid(fctx->indexCell); + Relation currentIndex = index_open(indexId, AccessShareLock); + fctx->relationpath = relpathpg(currentIndex, fctx->forkName); + fctx->segcount = 0; + index_close(currentIndex, NoLock); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } else { + if (lnext(fctx->indexCell)) { + fctx->indexCell = lnext(fctx->indexCell); + Oid indexId = lfirst_oid(fctx->indexCell); + Relation currentIndex = index_open(indexId, AccessShareLock); + fctx->relationpath = relpathpg(currentIndex, fctx->forkName); + fctx->segcount = 0; + index_close(currentIndex, NoLock); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } + } + } + } + } + + ereport(DEBUG1, (errmsg("pgfadvise: about to work with %s, current advice : %d", + filename, fctx->advice))); + /* + * Call posix_fadvise with the advice, returning the structure + */ + pgfdv = (pgfadviseStruct *) palloc(sizeof(pgfadviseStruct)); + result = pgfadvise_file(filename, fctx->advice, pgfdv); - /* - * When we have work with all segments of the current relation - * We exit from the SRF - * Else we build and return the tuple for this segment - */ - if (result) { - ereport(DEBUG1, (errmsg("pgfadvise: closing %s", fctx->relationpath))); - if (fctx->isPartitionTable) { - releasePartitionList(fctx->rel, &(fctx->partitionIdList), AccessShareLock); - } else if (fctx->isSubPartitionTable) { - releasePartitionList(fctx->rel, &(fctx->subPartitionIdList), AccessShareLock); - } - relation_close(fctx->rel, AccessShareLock); - list_free(fctx->indexoidlist); - pfree(fctx); - SRF_RETURN_DONE(funcctx); - } else { - /* - * Postgresql stuff to return a tuple - */ - HeapTuple tuple; - Datum values[PGFADVISE_COLS]; - bool nulls[PGFADVISE_COLS]; + /* + * When we have work with all segments of the current relation + * We exit from the SRF + * Else we build and return the tuple for this segment + */ + if (!result) { + ereport(DEBUG1, (errmsg("pgfadvise: closing %s", fctx->relationpath))); + if (fctx->isPartitionTable) { + releasePartitionList(fctx->rel, &(fctx->partitionIdList), AccessShareLock); + } else if (fctx->isSubPartitionTable) { + releasePartitionList(fctx->rel, &(fctx->subPartitionIdList), AccessShareLock); + } + relation_close(fctx->rel, AccessShareLock); + list_free(fctx->indexoidlist); + pfree(fctx); + SRF_RETURN_DONE(funcctx); + } else { + /* + * Postgresql stuff to return a tuple + */ + HeapTuple tuple; + Datum values[PGFADVISE_COLS]; + bool nulls[PGFADVISE_COLS]; - /* initialize nulls array to build the tuple */ - int ret = memset_s(nulls, sizeof(nulls), 0, sizeof(nulls)); - securec_check(ret, "\0", "\0"); - /* prepare the number of the next segment */ - fctx->segcount++; + /* initialize nulls array to build the tuple */ + int ret = memset_s(nulls, sizeof(nulls), 0, sizeof(nulls)); + securec_check(ret, "\0", "\0"); + /* prepare the number of the next segment */ + fctx->segcount++; - /* Filename */ - values[0] = CStringGetTextDatum( filename ); - /* os page size */ - values[1] = Int64GetDatum( (int64) pgfdv->pageSize ); - /* number of pages used by segment */ - values[2] = Int64GetDatum( (int64) ((pgfdv->filesize+pgfdv->pageSize-1)/pgfdv->pageSize) ); - /* free page cache */ - values[3] = Int64GetDatum( (int64) pgfdv->pagesFree ); - /* Build the result tuple. */ - tuple = heap_form_tuple(fctx->tupd, values, nulls); + /* Filename */ + values[0] = CStringGetTextDatum( filename ); + /* os page size */ + values[1] = Int64GetDatum( (int64) pgfdv->pageSize ); + /* number of pages used by segment */ + values[2] = Int64GetDatum( (int64) ((pgfdv->filesize+pgfdv->pageSize-1)/pgfdv->pageSize) ); + /* free page cache */ + values[3] = Int64GetDatum( (int64) pgfdv->pagesFree ); + /* Build the result tuple. */ + tuple = heap_form_tuple(fctx->tupd, values, nulls); - /* Ok, return results, and go for next call */ - SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); - } + /* Ok, return results, and go for next call */ + SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + } } #if defined(USE_POSIX_FADVISE) -static int pgfadvise_loader_file(char *filename, - bool willneed, bool dontneed, VarBit *databit, - pgfloaderStruct *pgfloader) +static bool pgfadvise_loader_file(char *filename, + bool willneed, bool dontneed, VarBit *databit, + pgfloaderStruct *pgfloader) { - bits8 *sp; - int bitlen; - bits8 x; - int i, k; + bits8 *sp; + int bitlen; + bits8 x; + int i, k; - /* - * We use the AllocateFile(2) provided by PostgreSQL. We're going to - * close it ourselves even if PostgreSQL close it anyway at transaction - * end. - */ - FILE *fp; - int fd; - struct stat st; + /* + * We use the AllocateFile(2) provided by PostgreSQL. We're going to + * close it ourselves even if PostgreSQL close it anyway at transaction + * end. + */ + FILE *fp; + int fd; + struct stat st; - /* - * OS things : Page size - */ - pgfloader->pageSize = sysconf(_SC_PAGESIZE); + /* + * OS things : Page size + */ + pgfloader->pageSize = sysconf(_SC_PAGESIZE); - /* - * 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 - */ - pgfloader->pagesLoaded = 0; - pgfloader->pagesUnloaded = 0; + /* + * 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 + */ + pgfloader->pagesLoaded = 0; + pgfloader->pagesUnloaded = 0; - /* - * Fopen 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 - */ - fp = AllocateFile(filename, "rb"); - if (fp == NULL) - return 1; + /* + * Fopen 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 + */ + fp = AllocateFile(filename, "rb"); + if (fp == NULL) + return false; - fd = fileno(fp); - if (fstat(fd, &st) == -1) { - FreeFile(fp); - ereport(ERROR, (errmsg("pgfadvise_loader: Can not stat object file: %s", filename))); - return 1; - } + fd = fileno(fp); + if (fstat(fd, &st) == -1) { + FreeFile(fp); + ereport(ERROR, (errmsg("pgfadvise_loader: Can not stat object file: %s", filename))); + return false; + } - ereport(DEBUG1, (errmsg("pgfadvise_loader: working on %s", filename))); + ereport(DEBUG1, (errmsg("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; - /* Is this bit set ? */ - for (k = 0; k < BITS_PER_BYTE; k++) { - if (IS_HIGHBIT_SET(x)) { - if (willneed) { - (void) posix_fadvise(fd, - ((i+k) * pgfloader->pageSize), - pgfloader->pageSize, - POSIX_FADV_WILLNEED); - pgfloader->pagesLoaded++; - } - } else if (dontneed) { - (void) posix_fadvise(fd, - ((i+k) * pgfloader->pageSize), - pgfloader->pageSize, - POSIX_FADV_DONTNEED); - pgfloader->pagesUnloaded++; - } + bitlen = VARBITLEN(databit); + sp = VARBITS(databit); + for (i = 0; i < bitlen - BITS_PER_BYTE; i += BITS_PER_BYTE, sp++) { + x = *sp; + /* Is this bit set ? */ + for (k = 0; k < BITS_PER_BYTE; k++) { + if (IS_HIGHBIT_SET(x)) { + if (willneed) { + (void) posix_fadvise(fd, + ((i+k) * pgfloader->pageSize), + pgfloader->pageSize, + POSIX_FADV_WILLNEED); + pgfloader->pagesLoaded++; + } + } else if (dontneed) { + (void) posix_fadvise(fd, + ((i+k) * pgfloader->pageSize), + pgfloader->pageSize, + POSIX_FADV_DONTNEED); + pgfloader->pagesUnloaded++; + } - x <<= 1; - } - } - /* - * XXX this copy/paste of code to finnish to walk the bits is not pretty - */ - if (i < bitlen) - { - /* print the last partial byte */ - x = *sp; - for (k = i; k < bitlen; k++) { - if (IS_HIGHBIT_SET(x)) { - if (willneed) { - (void) posix_fadvise(fd, - (k * pgfloader->pageSize), - pgfloader->pageSize, - POSIX_FADV_WILLNEED); - pgfloader->pagesLoaded++; - } - } else if (dontneed) { - (void) posix_fadvise(fd, - (k * pgfloader->pageSize), - pgfloader->pageSize, - POSIX_FADV_DONTNEED); - pgfloader->pagesUnloaded++; - } - x <<= 1; - } - } - FreeFile(fp); + x <<= 1; + } + } + /* + * XXX this copy/paste of code to finnish to walk the bits is not pretty + */ + if (i < bitlen) + { + /* print the last partial byte */ + x = *sp; + for (k = i; k < bitlen; k++) { + if (IS_HIGHBIT_SET(x)) { + if (willneed) { + (void) posix_fadvise(fd, + (k * pgfloader->pageSize), + pgfloader->pageSize, + POSIX_FADV_WILLNEED); + pgfloader->pagesLoaded++; + } + } else if (dontneed) { + (void) posix_fadvise(fd, + (k * pgfloader->pageSize), + pgfloader->pageSize, + POSIX_FADV_DONTNEED); + pgfloader->pagesUnloaded++; + } + x <<= 1; + } + } + FreeFile(fp); - /* - * OS things : Pages free - */ - pgfloader->pagesFree = sysconf(_SC_AVPHYS_PAGES); + /* + * OS things : Pages free + */ + pgfloader->pagesFree = sysconf(_SC_AVPHYS_PAGES); - return 0; + return true; } #else -static int pgfadvise_loader_file(char *filename, - bool willneed, bool dontneed, VarBit *databit, - pgfloaderStruct *pgfloader) +static bool pgfadvise_loader_file(char *filename, + bool willneed, bool dontneed, VarBit *databit, + pgfloaderStruct *pgfloader) { - ereport(ERROR, (errmsg("POSIX_FADVISE UNSUPPORTED on your platform"))); - return 1; + ereport(ERROR, (errmsg("POSIX_FADVISE UNSUPPORTED on your platform"))); + return false; } #endif @@ -688,277 +688,291 @@ static int pgfadvise_loader_file(char *filename, */ 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); - /* if this variable is set to false, no page will be set to willneed */ - bool willneed = PG_GETARG_BOOL(3); - /* if this variable is set to false, no page will be set to dontneed */ - bool dontneed = PG_GETARG_BOOL(4); - /* - * if the variable willneed and dontneed is set to true, the pages - * corresponding to 1 will be set WILLNEED, and the pages corresponding - * to 0 will be set DONTNEED. - */ - VarBit *databit; + Oid relOid = PG_GETARG_OID(0); + text *forkName = PG_GETARG_TEXT_P(1); + int segmentNumber = PG_GETARG_INT32(2); + /* if this variable is set to false, no page will be set to willneed */ + bool willneed = PG_GETARG_BOOL(3); + /* if this variable is set to false, no page will be set to dontneed */ + bool dontneed = PG_GETARG_BOOL(4); + /* + * if the variable willneed and dontneed is set to true, the pages + * corresponding to 1 will be set WILLNEED, and the pages corresponding + * to 0 will be set DONTNEED. + */ + VarBit *databit; - /* our structure use to return values */ - pgfloaderStruct *pgfloader; + /* our structure use to return values */ + pgfloaderStruct *pgfloader; - Relation rel; - char *relationpath; - char filename[MAXPGPATH]; + Relation rel; + char *relationpath; + char filename[MAXPGPATH]; - /* our return value, 0 for success */ - int result; + /* our return value, true for success */ + bool result; - /* - * Postgresql stuff to return a tuple - */ - HeapTuple tuple; - TupleDesc tupdesc; - Datum values[PGFADVISE_LOADER_COLS]; - bool nulls[PGFADVISE_LOADER_COLS]; + /* + * Postgresql stuff to return a tuple + */ + HeapTuple tuple; + TupleDesc tupdesc; + Datum values[PGFADVISE_LOADER_COLS]; + bool nulls[PGFADVISE_LOADER_COLS]; - if (PG_ARGISNULL(5)) - ereport(ERROR, (errmsg("pgfadvise_loader: databit argument shouldn't be NULL"))); + if (PG_ARGISNULL(5)) + ereport(ERROR, (errmsg("pgfadvise_loader: databit argument shouldn't be NULL"))); databit = PG_GETARG_VARBIT_P(5); - /* initialize nulls array to build the tuple */ - int ret = memset_s(nulls, sizeof(nulls), 0, sizeof(nulls)); - securec_check(ret, "\0", "\0"); - /* Build a tuple descriptor for our result type */ - if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) - ereport(ERROR, (errmsg("return type must be a row type"))); + /* initialize nulls array to build the tuple */ + int ret = memset_s(nulls, sizeof(nulls), 0, sizeof(nulls)); + securec_check(ret, "\0", "\0"); + /* Build a tuple descriptor for our result type */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + ereport(ERROR, (errmsg("return type must be a row type"))); - /* open the current relation in accessShareLock */ - rel = relation_open(relOid, AccessShareLock); + /* open the current relation in accessShareLock */ + rel = relation_open(relOid, AccessShareLock); - /* we get the common part of the filename of each segment of a relation */ - relationpath = relpathpg(rel, forkName); + if (RelationIsColStore(rel)) { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Un-support feature"), + errdetail("column-store relation doesn't support pgfadvise_loader yet"))); + } + + if (RelationIsSegmentTable(rel)) { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Un-support feature"), + errdetail("segment-page tables doesn't support pgfadvise_loader yet"))); + } - /* - * If we are looking the first segment, - * relationpath should not be suffixed - */ - if (segmentNumber == 0){ - errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", relationpath); - securec_check_ss(rc, "\0", "\0"); - } else { - errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s.%u", relationpath, (int) segmentNumber); - securec_check_ss(rc, "\0", "\0"); - } + /* we get the common part of the filename of each segment of a relation */ + relationpath = relpathpg(rel, forkName); - /* - * 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); + /* + * If we are looking the first segment, + * relationpath should not be suffixed + */ + if (segmentNumber == 0){ + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", relationpath); + securec_check_ss(rc, "\0", "\0"); + } else { + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s.%u", relationpath, (int) segmentNumber); + securec_check_ss(rc, "\0", "\0"); + } - /* - * Call pgfadvise_loader with the varbit - */ - pgfloader = (pgfloaderStruct *) palloc(sizeof(pgfloaderStruct)); - result = pgfadvise_loader_file(filename, - willneed, dontneed, databit, - pgfloader); - if (result != 0) - ereport(ERROR, (errmsg("Can't read file %s, fork(%s)", - filename, text_to_cstring(forkName)))); - /* Filename */ - values[0] = CStringGetTextDatum( filename ); - /* os page size */ - values[1] = Int64GetDatum( pgfloader->pageSize ); - /* free page cache */ - values[2] = Int64GetDatum( pgfloader->pagesFree ); - /* pages loaded */ - values[3] = Int64GetDatum( pgfloader->pagesLoaded ); - /* pages unloaded */ - values[4] = Int64GetDatum( pgfloader->pagesUnloaded ); + /* + * 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); - /* Build and return the result tuple. */ - tuple = heap_form_tuple(tupdesc, values, nulls); - PG_RETURN_DATUM( HeapTupleGetDatum(tuple) ); + /* + * Call pgfadvise_loader with the varbit + */ + pgfloader = (pgfloaderStruct *) palloc(sizeof(pgfloaderStruct)); + result = pgfadvise_loader_file(filename, + willneed, dontneed, databit, + pgfloader); + if (!result) + ereport(ERROR, (errmsg("Can't read file %s, fork(%s)", + filename, text_to_cstring(forkName)))); + /* Filename */ + values[0] = CStringGetTextDatum( filename ); + /* os page size */ + values[1] = Int64GetDatum( pgfloader->pageSize ); + /* free page cache */ + values[2] = Int64GetDatum( pgfloader->pagesFree ); + /* pages loaded */ + values[3] = Int64GetDatum( pgfloader->pagesLoaded ); + /* pages unloaded */ + values[4] = Int64GetDatum( pgfloader->pagesUnloaded ); + + /* Build and return the result tuple. */ + tuple = heap_form_tuple(tupdesc, values, nulls); + PG_RETURN_DATUM( HeapTupleGetDatum(tuple) ); } /* * pgfincore_file handle the mmaping, mincore process (and access file, etc.) */ -static int pgfincore_file(char *filename, pgfincoreStruct *pgfncr) +static bool pgfincore_file(char *filename, pgfincoreStruct *pgfncr) { - int flag=1; - int flag_dirty=1; + int flag=1; + int flag_dirty=1; - int len, bitlen; - bits8 *r; - bits8 x = 0; - register size_t pageIndex; + int len, bitlen; + bits8 *r; + bits8 x = 0; + register size_t pageIndex; - /* - * We use the AllocateFile(2) provided by PostgreSQL. We're going to - * close it ourselves even if PostgreSQL close it anyway at transaction - * end. - */ - FILE *fp; - int fd; - struct stat st; + /* + * We use the AllocateFile(2) provided by PostgreSQL. We're going to + * close it ourselves even if PostgreSQL close it anyway at transaction + * end. + */ + FILE *fp; + int fd; + struct stat st; #ifndef HAVE_FINCORE - void *pa = (char *) 0; + void *pa = (char *) 0; #endif - unsigned char *vec = (unsigned char *) 0; + unsigned char *vec = (unsigned char *) 0; - /* - * OS Page size - */ - pgfncr->pageSize = sysconf(_SC_PAGESIZE); + /* + * OS Page size + */ + pgfncr->pageSize = sysconf(_SC_PAGESIZE); - /* - * Initialize counters - */ - pgfncr->pages_mem = 0; - pgfncr->group_mem = 0; - pgfncr->pages_dirty = 0; - pgfncr->group_dirty = 0; - pgfncr->rel_os_pages = 0; + /* + * Initialize counters + */ + pgfncr->pages_mem = 0; + pgfncr->group_mem = 0; + pgfncr->pages_dirty = 0; + pgfncr->group_dirty = 0; + pgfncr->rel_os_pages = 0; - /* - * Fopen 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 - */ - fp = AllocateFile(filename, "rb"); - if (fp == NULL) - return 1; + /* + * Fopen 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 + */ + fp = AllocateFile(filename, "rb"); + if (fp == NULL) + return false; - fd = fileno(fp); + fd = fileno(fp); - if (fstat(fd, &st) == -1) { - FreeFile(fp); - ereport(ERROR, (errmsg("Can not stat object file : %s", filename))); - return 1; - } + if (fstat(fd, &st) == -1) { + FreeFile(fp); + ereport(ERROR, (errmsg("Can not stat object file : %s", filename))); + return false; + } - /* - * if file ok - * then process - */ - if (st.st_size != 0) { - /* number of pages in the current file */ - pgfncr->rel_os_pages = (st.st_size+pgfncr->pageSize-1)/pgfncr->pageSize; + /* + * if file ok + * then process + */ + if (st.st_size != 0) { + /* number of pages in the current file */ + pgfncr->rel_os_pages = (st.st_size+pgfncr->pageSize-1)/pgfncr->pageSize; #ifndef HAVE_FINCORE - pa = mmap(NULL, st.st_size, PROT_NONE, MAP_SHARED, fd, 0); - if (pa == MAP_FAILED) { - int save_errno = errno; - FreeFile(fp); - ereport(ERROR, (errmsg("Can not mmap object file : %s, errno = %i,%s\nThis error can happen if there is not enought space in memory to do the projection.", - filename, save_errno, strerror(save_errno)))); - return 1; - } + pa = mmap(NULL, st.st_size, PROT_NONE, MAP_SHARED, fd, 0); + if (pa == MAP_FAILED) { + int save_errno = errno; + FreeFile(fp); + ereport(ERROR, (errmsg("Can not mmap object file : %s, errno = %i,%s\nThis error can happen if there is not enought space in memory to do the projection.", + filename, save_errno, strerror(save_errno)))); + return false; + } #endif - /* Prepare our vector containing all blocks information */ - vec = (unsigned char * ) calloc(1, (st.st_size+pgfncr->pageSize-1)/pgfncr->pageSize); - if ((void *)0 == vec) { + /* Prepare our vector containing all blocks information */ + vec = (unsigned char * ) calloc(1, (st.st_size+pgfncr->pageSize-1)/pgfncr->pageSize); + if ((void *)0 == vec) { #ifndef HAVE_FINCORE - munmap(pa, st.st_size); + munmap(pa, st.st_size); #endif - FreeFile(fp); - ereport(ERROR, (errmsg("Can not calloc object file : %s", filename))); - return 1; - } + FreeFile(fp); + ereport(ERROR, (errmsg("Can not calloc object file : %s", filename))); + return false; + } #ifndef HAVE_FINCORE - /* Affect vec with mincore */ - if (mincore(pa, st.st_size, vec) != 0) { - int save_errno = errno; - munmap(pa, st.st_size); - ereport(ERROR, (errmsg("mincore(%p, %lld, %p): %s\n", - pa, (long long int)st.st_size, vec, strerror(save_errno)))); + /* Affect vec with mincore */ + if (mincore(pa, st.st_size, vec) != 0) { + int save_errno = errno; + munmap(pa, st.st_size); + ereport(ERROR, (errmsg("mincore(%p, %lld, %p): %s\n", + pa, (long long int)st.st_size, vec, strerror(save_errno)))); #else - /* Affect vec with fincore */ - if (fincore(fd, 0, st.st_size, vec) != 0) { - int save_errno = errno; - ereport(ERROR, (errmsg("fincore(%u, 0, %lld, %p): %s\n", - fd, (long long int)st.st_size, vec, strerror(save_errno)))); + /* Affect vec with fincore */ + if (fincore(fd, 0, st.st_size, vec) != 0) { + int save_errno = errno; + ereport(ERROR, (errmsg("fincore(%u, 0, %lld, %p): %s\n", + fd, (long long int)st.st_size, vec, strerror(save_errno)))); #endif - free(vec); - FreeFile(fp); - return 1; - } + free(vec); + FreeFile(fp); + return false; + } - /* - * prepare the bit string - */ - bitlen = FINCORE_BITS * ((st.st_size+pgfncr->pageSize-1)/pgfncr->pageSize); - len = VARBITTOTALLEN(bitlen); - /* - * set to 0 so that *r is always initialised and string is zero-padded - * XXX: do we need to free that ? - */ - pgfncr->databit = (VarBit *) palloc0(len); - SET_VARSIZE(pgfncr->databit, len); - VARBITLEN(pgfncr->databit) = bitlen; + /* + * prepare the bit string + */ + bitlen = FINCORE_BITS * ((st.st_size+pgfncr->pageSize-1)/pgfncr->pageSize); + len = VARBITTOTALLEN(bitlen); + /* + * set to 0 so that *r is always initialised and string is zero-padded + * XXX: do we need to free that ? + */ + pgfncr->databit = (VarBit *) palloc0(len); + SET_VARSIZE(pgfncr->databit, len); + VARBITLEN(pgfncr->databit) = bitlen; - r = VARBITS(pgfncr->databit); - x = HIGHBIT; + r = VARBITS(pgfncr->databit); + x = HIGHBIT; - /* handle the results */ - for (pageIndex = 0; pageIndex < pgfncr->rel_os_pages; pageIndex++) { - // block in memory - if (vec[pageIndex] & FINCORE_PRESENT) { - pgfncr->pages_mem++; - *r |= x; - if (FINCORE_BITS > 1) { - if (vec[pageIndex] & FINCORE_DIRTY) { - pgfncr->pages_dirty++; - *r |= (x >> 1); - /* we flag to detect contigous blocks in the same state */ - if (flag_dirty) - pgfncr->group_dirty++; - flag_dirty = 0; - } else { - flag_dirty = 1; - } - } - ereport(DEBUG5, (errmsg("in memory blocks : %lld / %lld", - (long long int) pageIndex, (long long int) pgfncr->rel_os_pages))); - /* we flag to detect contigous blocks in the same state */ - if (flag) - pgfncr->group_mem++; - flag = 0; - } else { - flag=1; - } + /* handle the results */ + for (pageIndex = 0; pageIndex < pgfncr->rel_os_pages; pageIndex++) { + // block in memory + if (vec[pageIndex] & FINCORE_PRESENT) { + pgfncr->pages_mem++; + *r |= x; + if (FINCORE_BITS > 1) { + if (vec[pageIndex] & FINCORE_DIRTY) { + pgfncr->pages_dirty++; + *r |= (x >> 1); + /* we flag to detect contigous blocks in the same state */ + if (flag_dirty) + pgfncr->group_dirty++; + flag_dirty = 0; + } else { + flag_dirty = 1; + } + } + ereport(DEBUG5, (errmsg("in memory blocks : %lld / %lld", + (long long int) pageIndex, (long long int) pgfncr->rel_os_pages))); + /* we flag to detect contigous blocks in the same state */ + if (flag) + pgfncr->group_mem++; + flag = 0; + } else { + flag=1; + } - x >>= FINCORE_BITS; - if (x == 0) { - x = HIGHBIT; - r++; - } - } - } - ereport(DEBUG1, (errmsg("pgfincore %s: %lld of %lld block in linux cache, %lld groups", - filename, (long long int) pgfncr->pages_mem, (long long int) pgfncr->rel_os_pages, (long long int) pgfncr->group_mem))); + x >>= FINCORE_BITS; + if (x == 0) { + x = HIGHBIT; + r++; + } + } + } + ereport(DEBUG1, (errmsg("pgfincore %s: %lld of %lld block in linux cache, %lld groups", + filename, (long long int) pgfncr->pages_mem, (long long int) pgfncr->rel_os_pages, (long long int) pgfncr->group_mem))); - /* - * free and close - */ - free(vec); + /* + * free and close + */ + free(vec); #ifndef HAVE_FINCORE - munmap(pa, st.st_size); + munmap(pa, st.st_size); #endif - FreeFile(fp); + FreeFile(fp); - /* - * OS things : Pages free - */ - pgfncr->pagesFree = sysconf(_SC_AVPHYS_PAGES); + /* + * OS things : Pages free + */ + pgfncr->pagesFree = sysconf(_SC_AVPHYS_PAGES); - return 0; + return true; } /* @@ -969,293 +983,293 @@ static int pgfincore_file(char *filename, pgfincoreStruct *pgfncr) */ Datum pgfincore(PG_FUNCTION_ARGS) { - FuncCallContext *funcctx; - pgfincore_fctx *fctx; + FuncCallContext *funcctx; + pgfincore_fctx *fctx; - /* our structure use to return values */ - pgfincoreStruct *pgfncr; + /* our structure use to return values */ + pgfincoreStruct *pgfncr; - /* our return value, 0 for success */ - int result; + /* our return value, true for success */ + bool result; - /* The file we are working on */ - char filename[MAXPGPATH]; + /* The file we are working on */ + char filename[MAXPGPATH]; - /* stuff done only on the first call of the function */ - if (SRF_IS_FIRSTCALL()) { - MemoryContext oldcontext; + /* stuff done only on the first call of the function */ + if (SRF_IS_FIRSTCALL()) { + MemoryContext oldcontext; - Oid relOid = PG_GETARG_OID(0); - text *forkName = PG_GETARG_TEXT_P(1); - bool getvector = PG_GETARG_BOOL(2); + Oid relOid = PG_GETARG_OID(0); + text *forkName = PG_GETARG_TEXT_P(1); + bool getvector = PG_GETARG_BOOL(2); - /* - * Postgresql stuff to return a tuple - */ - TupleDesc tupdesc; + /* + * Postgresql stuff to return a tuple + */ + TupleDesc tupdesc; - /* create a function context for cross-call persistence */ - funcctx = SRF_FIRSTCALL_INIT(); + /* create a function context for cross-call persistence */ + funcctx = SRF_FIRSTCALL_INIT(); - /* - * switch to memory context appropriate for multiple function calls - */ - oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + /* + * switch to memory context appropriate for multiple function calls + */ + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - /* allocate memory for user context */ - fctx = (pgfincore_fctx *) palloc(sizeof(pgfincore_fctx)); + /* allocate memory for user context */ + fctx = (pgfincore_fctx *) palloc(sizeof(pgfincore_fctx)); - fctx->forkName = (text*)palloc(VARSIZE(forkName)); - SET_VARSIZE(fctx->forkName, VARSIZE(forkName)); - errno_t ret = memcpy_s((void*)VARDATA(fctx->forkName), VARSIZE(forkName) - VARHDRSZ, (void*)VARDATA(forkName), VARSIZE(forkName) - VARHDRSZ); - securec_check(ret, "\0", "\0"); + fctx->forkName = (text*)palloc(VARSIZE(forkName)); + SET_VARSIZE(fctx->forkName, VARSIZE(forkName)); + errno_t ret = memcpy_s((void*)VARDATA(fctx->forkName), VARSIZE(forkName) - VARHDRSZ, (void*)VARDATA(forkName), VARSIZE(forkName) - VARHDRSZ); + securec_check(ret, "\0", "\0"); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) - ereport(ERROR, (errmsg("pgfadvise: return type must be a row type"))); + ereport(ERROR, (errmsg("pgfadvise: return type must be a row type"))); - /* provide the tuple descriptor to the fonction structure */ + /* provide the tuple descriptor to the fonction structure */ fctx->tupd = tupdesc; - /* are we going to grab and output the varbit data (can be large) */ + /* are we going to grab and output the varbit data (can be large) */ fctx->getvector = getvector; - /* open the current relation, accessShareLock */ - // TODO use try_relation_open instead ? - fctx->rel = relation_open(relOid, AccessShareLock); + /* open the current relation, accessShareLock */ + // TODO use try_relation_open instead ? + fctx->rel = relation_open(relOid, AccessShareLock); - if (RelationIsColStore(fctx->rel)) { - ereport(ERROR, + if (RelationIsColStore(fctx->rel)) { + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Un-support feature"), errdetail("column-store relation doesn't support pgfincore yet"))); - } - - if (RelationIsSegmentTable(fctx->rel)) { - ereport(ERROR, + } + + if (RelationIsSegmentTable(fctx->rel)) { + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Un-support feature"), errdetail("segment-page tables doesn't support pgfincore yet"))); - } + } - if (RelationIsSubPartitioned(fctx->rel)) { - fctx->isSubPartitionTable = true; - fctx->isPartitionTable = false; - } else if (RELATION_IS_PARTITIONED(fctx->rel)) { - fctx->isPartitionTable = true; - fctx->isSubPartitionTable = false; - } else { - fctx->isPartitionTable = false; - fctx->isSubPartitionTable = false; - } - fctx->partitionCell = NULL; - fctx->subPartitionCell = NULL; - fctx->partitionIdList = NULL; - fctx->subPartitionIdList = NULL; - fctx->indexCell = NULL; + if (RelationIsSubPartitioned(fctx->rel)) { + fctx->isSubPartitionTable = true; + fctx->isPartitionTable = false; + } else if (RELATION_IS_PARTITIONED(fctx->rel)) { + fctx->isPartitionTable = true; + fctx->isSubPartitionTable = false; + } else { + fctx->isPartitionTable = false; + fctx->isSubPartitionTable = false; + } + fctx->partitionCell = NULL; + fctx->subPartitionCell = NULL; + fctx->partitionIdList = NULL; + fctx->subPartitionIdList = NULL; + fctx->indexCell = NULL; - fctx->isFirstIndexOid = true;; - if (!RelationIsIndex(fctx->rel)) { - fctx->indexoidlist = RelationGetIndexList(fctx->rel); - } else { - fctx->indexoidlist = NULL; - } - - if (!(fctx->isPartitionTable || fctx->isSubPartitionTable)) { - /* we get the common part of the filename of each segment of a relation */ - fctx->relationpath = relpathpg(fctx->rel, forkName); + fctx->isFirstIndexOid = true;; + if (!RelationIsIndex(fctx->rel)) { + fctx->indexoidlist = RelationGetIndexList(fctx->rel); + } else { + fctx->indexoidlist = NULL; + } + + if (!(fctx->isPartitionTable || fctx->isSubPartitionTable)) { + /* we get the common part of the filename of each segment of a relation */ + fctx->relationpath = relpathpg(fctx->rel, forkName); - /* segcount is used to get the next segment of the current relation */ - fctx->segcount = 0; - } else if (fctx->isSubPartitionTable) { - fctx->subPartitionIdList = RelationGetSubPartitionList(fctx->rel, AccessShareLock); - fctx->subPartitionCell = list_head(fctx->subPartitionIdList); - Partition subPartition = (Partition)lfirst(fctx->subPartitionCell); - Relation subPartionRel = SubPartitionGetRelation(fctx->rel, subPartition, AccessShareLock); - fctx->relationpath = relpathpg(subPartionRel, forkName); - fctx->segcount = 0; - releaseDummyRelation(&subPartionRel); - } else if (fctx->isPartitionTable) { - fctx->partitionIdList = relationGetPartitionList(fctx->rel, AccessShareLock); - fctx->partitionCell = list_head(fctx->partitionIdList); - Partition partition = (Partition)lfirst(fctx->partitionCell); - Relation partitionRel = partitionGetRelation(fctx->rel, partition); - fctx->relationpath = relpathpg(partitionRel, forkName); - fctx->segcount = 0; - releaseDummyRelation(&partitionRel); - } + /* segcount is used to get the next segment of the current relation */ + fctx->segcount = 0; + } else if (fctx->isSubPartitionTable) { + fctx->subPartitionIdList = RelationGetSubPartitionList(fctx->rel, AccessShareLock); + fctx->subPartitionCell = list_head(fctx->subPartitionIdList); + Partition subPartition = (Partition)lfirst(fctx->subPartitionCell); + Relation subPartionRel = SubPartitionGetRelation(fctx->rel, subPartition, AccessShareLock); + fctx->relationpath = relpathpg(subPartionRel, forkName); + fctx->segcount = 0; + releaseDummyRelation(&subPartionRel); + } else if (fctx->isPartitionTable) { + fctx->partitionIdList = relationGetPartitionList(fctx->rel, AccessShareLock); + fctx->partitionCell = list_head(fctx->partitionIdList); + Partition partition = (Partition)lfirst(fctx->partitionCell); + Relation partitionRel = partitionGetRelation(fctx->rel, partition); + fctx->relationpath = relpathpg(partitionRel, forkName); + fctx->segcount = 0; + releaseDummyRelation(&partitionRel); + } - /* And finally we keep track of our initialization */ - ereport(DEBUG1, (errmsg("pgfincore: init done for %s, in fork %s", - fctx->relationpath, text_to_cstring(forkName)))); - funcctx->user_fctx = fctx; - MemoryContextSwitchTo(oldcontext); - } + /* And finally we keep track of our initialization */ + ereport(DEBUG1, (errmsg("pgfincore: init done for %s, in fork %s", + fctx->relationpath, text_to_cstring(forkName)))); + funcctx->user_fctx = fctx; + MemoryContextSwitchTo(oldcontext); + } - /* After the first call, we recover our context */ - funcctx = SRF_PERCALL_SETUP(); - fctx = (pgfincore_fctx*) funcctx->user_fctx; + /* After the first call, we recover our context */ + funcctx = SRF_PERCALL_SETUP(); + fctx = (pgfincore_fctx*) funcctx->user_fctx; - /* - * If we are still looking the first segment - * relationpath should not be suffixed - */ - if (fctx->segcount == 0) { - errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); - securec_check_ss(rc, "\0", "\0"); - } else { - errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s.%u", fctx->relationpath, fctx->segcount); - securec_check_ss(rc, "\0", "\0"); - } + /* + * If we are still looking the first segment + * relationpath should not be suffixed + */ + if (fctx->segcount == 0) { + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } else { + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s.%u", fctx->relationpath, fctx->segcount); + securec_check_ss(rc, "\0", "\0"); + } - FILE *fp = AllocateFile(filename, "rb"); - if (fp == NULL) { - if (fctx->isPartitionTable || fctx->isSubPartitionTable) { - if (fctx->isSubPartitionTable && lnext(fctx->subPartitionCell)) { - fctx->subPartitionCell = lnext(fctx->subPartitionCell); - Partition subPartition = (Partition)lfirst(fctx->subPartitionCell); - Relation subPartionRel = SubPartitionGetRelation(fctx->rel,subPartition,AccessShareLock); - fctx->relationpath = relpathpg(subPartionRel, fctx->forkName); - fctx->segcount = 0; - releaseDummyRelation(&subPartionRel); - errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); - securec_check_ss(rc, "\0", "\0"); - } else if (fctx->isPartitionTable && lnext(fctx->partitionCell)) { - fctx->partitionCell = lnext(fctx->partitionCell); - Partition partition = (Partition)lfirst(fctx->partitionCell); - Relation partitionRel = partitionGetRelation(fctx->rel,partition); - fctx->relationpath = relpathpg(partitionRel, fctx->forkName); - fctx->segcount = 0; - releaseDummyRelation(&partitionRel); - errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); - securec_check_ss(rc, "\0", "\0"); - } else { - if (fctx->indexoidlist != NULL) { - if (fctx->isFirstIndexOid) { - fctx->indexCell = list_head(fctx->indexoidlist); - fctx->isFirstIndexOid=false; - Oid indexId = lfirst_oid(fctx->indexCell); - Relation currentIndex = index_open(indexId, AccessShareLock); - fctx->relationpath = relpathpg(currentIndex, fctx->forkName); - fctx->segcount = 0; - index_close(currentIndex, NoLock); - errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); - securec_check_ss(rc, "\0", "\0"); - } else { - if (lnext(fctx->indexCell)) { - fctx->indexCell = lnext(fctx->indexCell); - Oid indexId = lfirst_oid(fctx->indexCell); - Relation currentIndex = index_open(indexId, AccessShareLock); - fctx->relationpath = relpathpg(currentIndex, fctx->forkName); - fctx->segcount = 0; - index_close(currentIndex, NoLock); - errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); - securec_check_ss(rc, "\0", "\0"); - } - } - } - } - } else { - //process index - if (fctx->indexoidlist != NULL) { - if (fctx->isFirstIndexOid) { - fctx->indexCell = list_head(fctx->indexoidlist); - fctx->isFirstIndexOid=false; - Oid indexId = lfirst_oid(fctx->indexCell); - Relation currentIndex = index_open(indexId, AccessShareLock); - fctx->relationpath = relpathpg(currentIndex, fctx->forkName); - fctx->segcount = 0; - index_close(currentIndex, NoLock); - errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); - securec_check_ss(rc, "\0", "\0"); - } else { - if (lnext(fctx->indexCell)) { - fctx->indexCell = lnext(fctx->indexCell); - Oid indexId = lfirst_oid(fctx->indexCell); - Relation currentIndex = index_open(indexId, AccessShareLock); - fctx->relationpath = relpathpg(currentIndex, fctx->forkName); - fctx->segcount = 0; - index_close(currentIndex, NoLock); - errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); - securec_check_ss(rc, "\0", "\0"); - } - } - } - } - } + FILE *fp = AllocateFile(filename, "rb"); + if (fp == NULL) { + if (fctx->isPartitionTable || fctx->isSubPartitionTable) { + if (fctx->isSubPartitionTable && lnext(fctx->subPartitionCell)) { + fctx->subPartitionCell = lnext(fctx->subPartitionCell); + Partition subPartition = (Partition)lfirst(fctx->subPartitionCell); + Relation subPartionRel = SubPartitionGetRelation(fctx->rel,subPartition,AccessShareLock); + fctx->relationpath = relpathpg(subPartionRel, fctx->forkName); + fctx->segcount = 0; + releaseDummyRelation(&subPartionRel); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } else if (fctx->isPartitionTable && lnext(fctx->partitionCell)) { + fctx->partitionCell = lnext(fctx->partitionCell); + Partition partition = (Partition)lfirst(fctx->partitionCell); + Relation partitionRel = partitionGetRelation(fctx->rel,partition); + fctx->relationpath = relpathpg(partitionRel, fctx->forkName); + fctx->segcount = 0; + releaseDummyRelation(&partitionRel); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } else { + if (fctx->indexoidlist != NULL) { + if (fctx->isFirstIndexOid) { + fctx->indexCell = list_head(fctx->indexoidlist); + fctx->isFirstIndexOid=false; + Oid indexId = lfirst_oid(fctx->indexCell); + Relation currentIndex = index_open(indexId, AccessShareLock); + fctx->relationpath = relpathpg(currentIndex, fctx->forkName); + fctx->segcount = 0; + index_close(currentIndex, NoLock); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } else { + if (lnext(fctx->indexCell)) { + fctx->indexCell = lnext(fctx->indexCell); + Oid indexId = lfirst_oid(fctx->indexCell); + Relation currentIndex = index_open(indexId, AccessShareLock); + fctx->relationpath = relpathpg(currentIndex, fctx->forkName); + fctx->segcount = 0; + index_close(currentIndex, NoLock); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } + } + } + } + } else { + //process index + if (fctx->indexoidlist != NULL) { + if (fctx->isFirstIndexOid) { + fctx->indexCell = list_head(fctx->indexoidlist); + fctx->isFirstIndexOid=false; + Oid indexId = lfirst_oid(fctx->indexCell); + Relation currentIndex = index_open(indexId, AccessShareLock); + fctx->relationpath = relpathpg(currentIndex, fctx->forkName); + fctx->segcount = 0; + index_close(currentIndex, NoLock); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } else { + if (lnext(fctx->indexCell)) { + fctx->indexCell = lnext(fctx->indexCell); + Oid indexId = lfirst_oid(fctx->indexCell); + Relation currentIndex = index_open(indexId, AccessShareLock); + fctx->relationpath = relpathpg(currentIndex, fctx->forkName); + fctx->segcount = 0; + index_close(currentIndex, NoLock); + errno_t rc = snprintf_s(filename, MAXPGPATH, MAXPGPATH-1, "%s", fctx->relationpath); + securec_check_ss(rc, "\0", "\0"); + } + } + } + } + } - ereport(DEBUG1, (errmsg("pgfincore: about to work with %s", filename))); + ereport(DEBUG1, (errmsg("pgfincore: about to work with %s", filename))); - /* - * Call pgfincore with the advice, returning the structure - */ - pgfncr = (pgfincoreStruct *) palloc(sizeof(pgfincoreStruct)); - result = pgfincore_file(filename, pgfncr); + /* + * Call pgfincore with the advice, returning the structure + */ + pgfncr = (pgfincoreStruct *) palloc(sizeof(pgfincoreStruct)); + result = pgfincore_file(filename, pgfncr); - /* - * When we have work with all segment of the current relation, test success - * We exit from the SRF - */ - if (result) { - ereport(DEBUG1, (errmsg("pgfincore: closing %s", fctx->relationpath))); - - if (fctx->isPartitionTable) { - releasePartitionList(fctx->rel, &(fctx->partitionIdList), AccessShareLock); - } else if (fctx->isSubPartitionTable) { - releasePartitionList(fctx->rel, &(fctx->subPartitionIdList), AccessShareLock); - } - relation_close(fctx->rel, AccessShareLock); - list_free(fctx->indexoidlist); - pfree(fctx); - SRF_RETURN_DONE(funcctx); - } else { - /* - * Postgresql stuff to return a tuple - */ - HeapTuple tuple; - Datum values[PGFINCORE_COLS]; - bool nulls[PGFINCORE_COLS]; + /* + * When we have work with all segment of the current relation, test success + * We exit from the SRF + */ + if (!result) { + ereport(DEBUG1, (errmsg("pgfincore: closing %s", fctx->relationpath))); + + if (fctx->isPartitionTable) { + releasePartitionList(fctx->rel, &(fctx->partitionIdList), AccessShareLock); + } else if (fctx->isSubPartitionTable) { + releasePartitionList(fctx->rel, &(fctx->subPartitionIdList), AccessShareLock); + } + relation_close(fctx->rel, AccessShareLock); + list_free(fctx->indexoidlist); + pfree(fctx); + SRF_RETURN_DONE(funcctx); + } else { + /* + * Postgresql stuff to return a tuple + */ + HeapTuple tuple; + Datum values[PGFINCORE_COLS]; + bool nulls[PGFINCORE_COLS]; - /* initialize nulls array to build the tuple */ - int ret = memset_s(nulls, sizeof(nulls), 0, sizeof(nulls)); - securec_check(ret, "\0", "\0"); + /* initialize nulls array to build the tuple */ + int ret = memset_s(nulls, sizeof(nulls), 0, sizeof(nulls)); + securec_check(ret, "\0", "\0"); - /* Filename */ - values[0] = CStringGetTextDatum(filename); - /* Segment Number */ - values[1] = Int32GetDatum(fctx->segcount); - /* os page size */ - values[2] = Int64GetDatum(pgfncr->pageSize); - /* number of pages used by segment */ - values[3] = Int64GetDatum(pgfncr->rel_os_pages); - /* number of pages in OS cache */ - values[4] = Int64GetDatum(pgfncr->pages_mem); - /* number of group of contigous page in os cache */ - values[5] = Int64GetDatum(pgfncr->group_mem); - /* free page cache */ - values[6] = Int64GetDatum(pgfncr->pagesFree); - /* the map of the file with bit set for in os cache page */ - if (fctx->getvector && pgfncr->rel_os_pages) { - values[7] = VarBitPGetDatum(pgfncr->databit); - } else { - nulls[7] = true; - values[7] = (Datum) NULL; - } - /* number of pages dirty in OS cache */ - values[8] = Int64GetDatum(pgfncr->pages_dirty); - /* number of group of contigous dirty pages in os cache */ - values[9] = Int64GetDatum(pgfncr->group_dirty); - /* Build the result tuple. */ - tuple = heap_form_tuple(fctx->tupd, values, nulls); + /* Filename */ + values[0] = CStringGetTextDatum(filename); + /* Segment Number */ + values[1] = Int32GetDatum(fctx->segcount); + /* os page size */ + values[2] = Int64GetDatum(pgfncr->pageSize); + /* number of pages used by segment */ + values[3] = Int64GetDatum(pgfncr->rel_os_pages); + /* number of pages in OS cache */ + values[4] = Int64GetDatum(pgfncr->pages_mem); + /* number of group of contigous page in os cache */ + values[5] = Int64GetDatum(pgfncr->group_mem); + /* free page cache */ + values[6] = Int64GetDatum(pgfncr->pagesFree); + /* the map of the file with bit set for in os cache page */ + if (fctx->getvector && pgfncr->rel_os_pages) { + values[7] = VarBitPGetDatum(pgfncr->databit); + } else { + nulls[7] = true; + values[7] = (Datum) NULL; + } + /* number of pages dirty in OS cache */ + values[8] = Int64GetDatum(pgfncr->pages_dirty); + /* number of group of contigous dirty pages in os cache */ + values[9] = Int64GetDatum(pgfncr->group_dirty); + /* Build the result tuple. */ + tuple = heap_form_tuple(fctx->tupd, values, nulls); /* prepare the number of the next segment */ fctx->segcount++; - /* Ok, return results, and go for next call */ - SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); - } + /* Ok, return results, and go for next call */ + SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + } } /* @@ -1264,54 +1278,54 @@ Datum pgfincore(PG_FUNCTION_ARGS) Datum pgfincore_drawer(PG_FUNCTION_ARGS) { char *result,*r; - int len,i,k; - VarBit *databit; - bits8 *sp; - bits8 x; + int len,i,k; + VarBit *databit; + bits8 *sp; + bits8 x; - if (PG_ARGISNULL(0)) - ereport(ERROR, (errmsg("pgfincore_drawer: databit argument shouldn't be NULL"))); + if (PG_ARGISNULL(0)) + ereport(ERROR, (errmsg("pgfincore_drawer: databit argument shouldn't be NULL"))); databit = PG_GETARG_VARBIT_P(0); - len = VARBITLEN(databit); - result = (char *) palloc((len/FINCORE_BITS) + 1); - sp = VARBITS(databit); - r = result; + len = VARBITLEN(databit); + result = (char *) palloc((len/FINCORE_BITS) + 1); + sp = VARBITS(databit); + r = result; - for (i = 0; i <= len - BITS_PER_BYTE; i += BITS_PER_BYTE, sp++) { - x = *sp; - /* Is this bit set ? */ - for (k = 0; k < (BITS_PER_BYTE/FINCORE_BITS); k++) { - char out = ' '; - if (IS_HIGHBIT_SET(x)) - out = '.' ; - x <<= 1; - if (FINCORE_BITS > 1) { - if (IS_HIGHBIT_SET(x)) - out = '*'; - x <<= 1; - } - *r++ = out; - } - } - if (i < len) { - /* print the last partial byte */ - x = *sp; - for (k = i; k < (len/FINCORE_BITS); k++) { - char out = ' '; - if (IS_HIGHBIT_SET(x)) - out = '.' ; - x <<= 1; - if (FINCORE_BITS > 1) { - if (IS_HIGHBIT_SET(x)) - out = '*'; - x <<= 1; - } - *r++ = out; - } - } + for (i = 0; i <= len - BITS_PER_BYTE; i += BITS_PER_BYTE, sp++) { + x = *sp; + /* Is this bit set ? */ + for (k = 0; k < (BITS_PER_BYTE/FINCORE_BITS); k++) { + char out = ' '; + if (IS_HIGHBIT_SET(x)) + out = '.' ; + x <<= 1; + if (FINCORE_BITS > 1) { + if (IS_HIGHBIT_SET(x)) + out = '*'; + x <<= 1; + } + *r++ = out; + } + } + if (i < len) { + /* print the last partial byte */ + x = *sp; + for (k = i; k < (len/FINCORE_BITS); k++) { + char out = ' '; + if (IS_HIGHBIT_SET(x)) + out = '.' ; + x <<= 1; + if (FINCORE_BITS > 1) { + if (IS_HIGHBIT_SET(x)) + out = '*'; + x <<= 1; + } + *r++ = out; + } + } - *r = '\0'; - PG_RETURN_CSTRING(result); + *r = '\0'; + PG_RETURN_CSTRING(result); } From 9607d5239207cae868bd011caf6e1f27c305935d Mon Sep 17 00:00:00 2001 From: jkshen <2458684728@qq.com> Date: Thu, 25 Aug 2022 15:11:30 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E5=8E=BB=E9=99=A4HAVE=5FFINCORE=E5=AE=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/backend/utils/misc/pgfincore.cpp | 23 ++------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/src/common/backend/utils/misc/pgfincore.cpp b/src/common/backend/utils/misc/pgfincore.cpp index 377ae9eca..b3efc2788 100644 --- a/src/common/backend/utils/misc/pgfincore.cpp +++ b/src/common/backend/utils/misc/pgfincore.cpp @@ -49,11 +49,8 @@ #define FINCORE_PRESENT 0x1 #define FINCORE_DIRTY 0x2 -#ifndef HAVE_FINCORE #define FINCORE_BITS 1 -#else -#define FINCORE_BITS 2 -#endif + /* * pgfadvise_fctx structure is needed * to keep track of relation path, segment number, ... @@ -819,9 +816,8 @@ static bool pgfincore_file(char *filename, pgfincoreStruct *pgfncr) int fd; struct stat st; -#ifndef HAVE_FINCORE void *pa = (char *) 0; -#endif + unsigned char *vec = (unsigned char *) 0; /* @@ -863,7 +859,6 @@ static bool pgfincore_file(char *filename, pgfincoreStruct *pgfncr) /* number of pages in the current file */ pgfncr->rel_os_pages = (st.st_size+pgfncr->pageSize-1)/pgfncr->pageSize; -#ifndef HAVE_FINCORE pa = mmap(NULL, st.st_size, PROT_NONE, MAP_SHARED, fd, 0); if (pa == MAP_FAILED) { int save_errno = errno; @@ -872,33 +867,22 @@ static bool pgfincore_file(char *filename, pgfincoreStruct *pgfncr) filename, save_errno, strerror(save_errno)))); return false; } -#endif /* Prepare our vector containing all blocks information */ vec = (unsigned char * ) calloc(1, (st.st_size+pgfncr->pageSize-1)/pgfncr->pageSize); if ((void *)0 == vec) { -#ifndef HAVE_FINCORE munmap(pa, st.st_size); -#endif FreeFile(fp); ereport(ERROR, (errmsg("Can not calloc object file : %s", filename))); return false; } -#ifndef HAVE_FINCORE /* Affect vec with mincore */ if (mincore(pa, st.st_size, vec) != 0) { int save_errno = errno; munmap(pa, st.st_size); ereport(ERROR, (errmsg("mincore(%p, %lld, %p): %s\n", pa, (long long int)st.st_size, vec, strerror(save_errno)))); -#else - /* Affect vec with fincore */ - if (fincore(fd, 0, st.st_size, vec) != 0) { - int save_errno = errno; - ereport(ERROR, (errmsg("fincore(%u, 0, %lld, %p): %s\n", - fd, (long long int)st.st_size, vec, strerror(save_errno)))); -#endif free(vec); FreeFile(fp); return false; @@ -962,9 +946,7 @@ static bool pgfincore_file(char *filename, pgfincoreStruct *pgfncr) * free and close */ free(vec); -#ifndef HAVE_FINCORE munmap(pa, st.st_size); -#endif FreeFile(fp); /* @@ -1100,7 +1082,6 @@ Datum pgfincore(PG_FUNCTION_ARGS) releaseDummyRelation(&partitionRel); } - /* And finally we keep track of our initialization */ ereport(DEBUG1, (errmsg("pgfincore: init done for %s, in fork %s", fctx->relationpath, text_to_cstring(forkName))));