limiting connections per user/database - Mailing list pgsql-patches
From | Petr Jelínek |
---|---|
Subject | limiting connections per user/database |
Date | |
Msg-id | 42BDC668.1060900@parba.cz Whole thread Raw |
Responses |
Re: limiting connections per user/database
Re: limiting connections per user/database |
List | pgsql-patches |
Hello, patch I attached allows to set connectin limits per user or per database (it's on TODO list). It's proposal because I am not sure if this implementation can be accepted (I never made new feature patch for postgres so I really dunno) and I would like to know what you guys think about it and what I should change. Something about patch: I added two new guc variables name max_db_connections and max_user_connections which can be set by superuser which means it can be in main config file or in user/database config. I was thinking about 3 different aproaches - the other two was using max_connections with set/get hooks or change in catalog tables but new fuc variables seemed best solution to me. Conenction limits are checked in InitPostgres function after user and database configs are loaded. Patch works only when stats are on because it takes number of connections per user and database from there - I had to patch pgstat to store user connection stats. Also this patch relies on bugfix I sent on Thursday but I wasn't subcribed and it still waits for moderation so I attached it to this mail too (pgstat.c.diff) because without it database stats are broken in current CVS. I modified only .c sources, no documentation, I will make documentation changes when (and if) this will be finished and accepted. Diffs should be against latest CVS. -- Regards Petr Jelinek (PJMODOS) *** pgstat.c Sat Jun 18 01:17:26 2005 --- pgstat.c.new Thu Jun 23 21:38:06 2005 *************** *** 2613,2619 **** static void pgstat_recv_bestart(PgStat_MsgBestart *msg, int len) { ! PgStat_StatBeEntry *entry; /* * If the backend is known dead, we ignore the message -- we don't --- 2613,2621 ---- static void pgstat_recv_bestart(PgStat_MsgBestart *msg, int len) { ! PgStat_StatBeEntry *beentry; ! PgStat_StatDBEntry *dbentry; ! bool found; /* * If the backend is known dead, we ignore the message -- we don't *************** *** 2623,2632 **** if (pgstat_add_backend(&msg->m_hdr) != 0) return; ! entry = &(pgStatBeTable[msg->m_hdr.m_backendid - 1]); ! entry->userid = msg->m_userid; ! memcpy(&entry->clientaddr, &msg->m_clientaddr, sizeof(entry->clientaddr)); ! entry->databaseid = msg->m_databaseid; } --- 2625,2675 ---- if (pgstat_add_backend(&msg->m_hdr) != 0) return; ! beentry = &(pgStatBeTable[msg->m_hdr.m_backendid - 1]); ! beentry->userid = msg->m_userid; ! memcpy(&beentry->clientaddr, &msg->m_clientaddr, sizeof(beentry->clientaddr)); ! beentry->databaseid = msg->m_databaseid; ! ! /* ! * Lookup or create the database entry for this backends DB. ! */ ! dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash, ! (void *) &(msg->m_databaseid), ! HASH_ENTER, &found); ! if (dbentry == NULL) ! ereport(ERROR, ! (errcode(ERRCODE_OUT_OF_MEMORY), ! errmsg("out of memory in statistics collector --- abort"))); ! ! /* ! * If not found, initialize the new one. ! */ ! if (!found) ! { ! HASHCTL hash_ctl; ! ! dbentry->tables = NULL; ! dbentry->n_xact_commit = 0; ! dbentry->n_xact_rollback = 0; ! dbentry->n_blocks_fetched = 0; ! dbentry->n_blocks_hit = 0; ! dbentry->n_backends = 0; ! dbentry->destroy = 0; ! ! memset(&hash_ctl, 0, sizeof(hash_ctl)); ! hash_ctl.keysize = sizeof(Oid); ! hash_ctl.entrysize = sizeof(PgStat_StatTabEntry); ! hash_ctl.hash = tag_hash; ! dbentry->tables = hash_create("Per-database table", ! PGSTAT_TAB_HASH_SIZE, ! &hash_ctl, ! HASH_ELEM | HASH_FUNCTION); ! } ! ! /* ! * Count number of connects to the database ! */ ! dbentry->n_backends++; } diff -Nacr -x CVS bah2\src\backend\postmaster\pgstat.c bah\src\backend\postmaster\pgstat.c *** bah2\src\backend\postmaster\pgstat.c Sat Jun 25 21:57:22 2005 --- bah\src\backend\postmaster\pgstat.c Sat Jun 25 21:56:06 2005 *************** *** 131,136 **** --- 131,137 ---- static TransactionId pgStatDBHashXact = InvalidTransactionId; static HTAB *pgStatDBHash = NULL; + static HTAB *pgStatUserHash = NULL; static HTAB *pgStatBeDead = NULL; static PgStat_StatBeEntry *pgStatBeTable = NULL; static int pgStatNumBackends = 0; *************** *** 163,173 **** --- 164,177 ---- static void pgstat_beshutdown_hook(int code, Datum arg); static PgStat_StatDBEntry *pgstat_get_db_entry(int databaseid); + static PgStat_StatUserEntry *pgstat_get_user_entry(int userid); static int pgstat_add_backend(PgStat_MsgHdr *msg); static void pgstat_sub_backend(int procpid); static void pgstat_drop_database(Oid databaseid); + static void pgstat_drop_user(Oid userid); static void pgstat_write_statsfile(void); static void pgstat_read_statsfile(HTAB **dbhash, Oid onlydb, + HTAB **userhash, PgStat_StatBeEntry **betab, int *numbackends); static void backend_read_statsfile(void); *************** *** 181,186 **** --- 185,191 ---- static void pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len); static void pgstat_recv_tabpurge(PgStat_MsgTabpurge *msg, int len); static void pgstat_recv_dropdb(PgStat_MsgDropdb *msg, int len); + static void pgstat_recv_dropuser(PgStat_MsgDropuser *msg, int len); static void pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len); *************** *** 772,782 **** Relation dbrel; HeapScanDesc dbscan; HeapTuple dbtup; ! Oid *dbidlist; ! int dbidalloc; ! int dbidused; HASH_SEQ_STATUS hstat; PgStat_StatDBEntry *dbentry; PgStat_StatTabEntry *tabentry; HeapTuple reltup; int nobjects = 0; --- 777,791 ---- Relation dbrel; HeapScanDesc dbscan; HeapTuple dbtup; ! Relation userrel; ! HeapScanDesc userscan; ! HeapTuple usertup; ! Oid *oidlist; ! int oidalloc; ! int oidused; HASH_SEQ_STATUS hstat; PgStat_StatDBEntry *dbentry; + PgStat_StatUserEntry *userentry; PgStat_StatTabEntry *tabentry; HeapTuple reltup; int nobjects = 0; *************** *** 866,886 **** /* * Read pg_database and remember the Oid's of all existing databases */ ! dbidalloc = 256; ! dbidused = 0; ! dbidlist = (Oid *) palloc(sizeof(Oid) * dbidalloc); dbrel = heap_open(DatabaseRelationId, AccessShareLock); dbscan = heap_beginscan(dbrel, SnapshotNow, 0, NULL); while ((dbtup = heap_getnext(dbscan, ForwardScanDirection)) != NULL) { ! if (dbidused >= dbidalloc) { ! dbidalloc *= 2; ! dbidlist = (Oid *) repalloc((char *) dbidlist, ! sizeof(Oid) * dbidalloc); } ! dbidlist[dbidused++] = HeapTupleGetOid(dbtup); } heap_endscan(dbscan); heap_close(dbrel, AccessShareLock); --- 875,895 ---- /* * Read pg_database and remember the Oid's of all existing databases */ ! oidalloc = 256; ! oidused = 0; ! oidlist = (Oid *) palloc(sizeof(Oid) * oidalloc); dbrel = heap_open(DatabaseRelationId, AccessShareLock); dbscan = heap_beginscan(dbrel, SnapshotNow, 0, NULL); while ((dbtup = heap_getnext(dbscan, ForwardScanDirection)) != NULL) { ! if (oidused >= oidalloc) { ! oidalloc *= 2; ! oidlist = (Oid *) repalloc((char *) oidlist, ! sizeof(Oid) * oidalloc); } ! oidlist[oidused++] = HeapTupleGetOid(dbtup); } heap_endscan(dbscan); heap_close(dbrel, AccessShareLock); *************** *** 894,902 **** { Oid dbid = dbentry->databaseid; ! for (i = 0; i < dbidused; i++) { ! if (dbidlist[i] == dbid) { dbid = InvalidOid; break; --- 903,911 ---- { Oid dbid = dbentry->databaseid; ! for (i = 0; i < oidused; i++) { ! if (oidlist[i] == dbid) { dbid = InvalidOid; break; *************** *** 910,919 **** } } /* ! * Free the dbid list. */ ! pfree(dbidlist); /* * Tell the caller how many removeable objects we found --- 919,977 ---- } } + /* ! * Clear the Oid list. */ ! memset(oidlist, 0, sizeof(Oid) * oidalloc); ! ! /* ! * Read pg_shadow and remember the Oid's of all existing users ! */ ! userrel = heap_open(ShadowRelationId, AccessShareLock); ! userscan = heap_beginscan(userrel, SnapshotNow, 0, NULL); ! while ((usertup = heap_getnext(userscan, ForwardScanDirection)) != NULL) ! { ! if (oidused >= oidalloc) ! { ! oidalloc *= 2; ! oidlist = (Oid *) repalloc((char *) oidlist, ! sizeof(Oid) * oidalloc); ! } ! oidlist[oidused++] = HeapTupleGetOid(usertup); ! } ! heap_endscan(userscan); ! heap_close(userrel, AccessShareLock); ! ! /* ! * Search the user hash table for dead users and tell the ! * collector to drop them as well. ! */ ! hash_seq_init(&hstat, pgStatUserHash); ! while ((userentry = (PgStat_StatUserEntry *) hash_seq_search(&hstat)) != NULL) ! { ! Oid userid = userentry->userid; ! ! for (i = 0; i < oidused; i++) ! { ! if (oidlist[i] == userid) ! { ! userid = InvalidOid; ! break; ! } ! } ! ! if (userid != InvalidOid) ! { ! nobjects++; ! pgstat_drop_user(userid); ! } ! } ! ! /* ! * Free the Oid list. ! */ ! pfree(oidlist); /* * Tell the caller how many removeable objects we found *************** *** 946,951 **** --- 1004,1032 ---- /* ---------- + * pgstat_drop_user() - + * + * Tell the collector that we just dropped a user. + * This is the only message that shouldn't get lost in space. Otherwise + * the collector will keep the statistics for the dead users until his + * stats file got removed while the postmaster is down. + * ---------- + */ + static void + pgstat_drop_user(Oid userid) + { + PgStat_MsgDropuser msg; + + if (pgStatSock < 0) + return; + + pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_DROPUSER); + msg.m_userid = userid; + pgstat_send(&msg, sizeof(msg)); + } + + + /* ---------- * pgstat_reset_counters() - * * Tell the statistics collector to reset counters for our database. *************** *** 1196,1201 **** --- 1277,1308 ---- HASH_FIND, NULL); } + /* ---------- + * pgstat_fetch_stat_userentry() - + * + * Support function for the SQL-callable pgstat* functions. Returns + * the collected statistics for one user or NULL. NULL doesn't mean + * that the user doesn't exist, it is just not yet known by the + * collector, so the caller is better off to report ZERO instead. + * ---------- + */ + PgStat_StatUserEntry * + pgstat_fetch_stat_userentry(Oid userid) + { + /* + * If not done for this transaction, read the statistics collector + * stats file into some hash tables. + */ + backend_read_statsfile(); + + /* + * Lookup the requested database; return NULL if not found + */ + return (PgStat_StatUserEntry *) hash_search(pgStatUserHash, + (void *) &userid, + HASH_FIND, NULL); + } + /* ---------- * pgstat_fetch_stat_tabentry() - *************** *** 1490,1496 **** * to zero. */ pgStatRunningInCollector = TRUE; ! pgstat_read_statsfile(&pgStatDBHash, InvalidOid, NULL, NULL); /* * Create the dead backend hashtable --- 1597,1603 ---- * to zero. */ pgStatRunningInCollector = TRUE; ! pgstat_read_statsfile(&pgStatDBHash, InvalidOid, &pgStatUserHash, NULL, NULL); /* * Create the dead backend hashtable *************** *** 1670,1675 **** --- 1777,1786 ---- pgstat_recv_dropdb((PgStat_MsgDropdb *) &msg, nread); break; + case PGSTAT_MTYPE_DROPUSER: + pgstat_recv_dropuser((PgStat_MsgDropuser *) &msg, nread); + break; + case PGSTAT_MTYPE_RESETCOUNTER: pgstat_recv_resetcounter((PgStat_MsgResetcounter *) &msg, nread); *************** *** 2087,2092 **** --- 2198,2228 ---- return result; } + /* + * Lookup the hash table entry for the specified user. If no hash + * table entry exists, initialize it. + */ + static PgStat_StatUserEntry * + pgstat_get_user_entry(int userid) + { + PgStat_StatUserEntry *result; + bool found; + + /* Lookup or create the hash table entry for this user */ + result = (PgStat_StatUserEntry *) hash_search(pgStatUserHash, + &userid, + HASH_ENTER, &found); + + /* If not found, initialize the new one. */ + if (!found) + { + result->n_backends = 0; + result->destroy = 0; + } + + return result; + } + /* ---------- * pgstat_sub_backend() - * *************** *** 2156,2161 **** --- 2292,2298 ---- HASH_SEQ_STATUS hstat; HASH_SEQ_STATUS tstat; PgStat_StatDBEntry *dbentry; + PgStat_StatUserEntry *userentry; PgStat_StatTabEntry *tabentry; PgStat_StatBeDead *deadbe; FILE *fpout; *************** *** 2254,2259 **** --- 2391,2412 ---- } /* + * Walk through the user table. + */ + ereport(DEBUG3, (errmsg_internal("before write 'U'"))); + hash_seq_init(&hstat, pgStatUserHash); + ereport(DEBUG3, (errmsg_internal("write 'U' - before while"))); + while ((userentry = (PgStat_StatUserEntry *) hash_seq_search(&hstat)) != NULL) + { + ereport(DEBUG3, (errmsg_internal("write 'U' - in while 1"))); + fputc('U', fpout); + ereport(DEBUG3, (errmsg_internal("write 'U' - in while 2"))); + fwrite(userentry, sizeof(PgStat_StatUserEntry), 1, fpout); + ereport(DEBUG3, (errmsg_internal("write 'U' - in while 3"))); + } + ereport(DEBUG3, (errmsg_internal("after write 'U'"))); + + /* * Write out the known running backends to the stats file. */ i = MaxBackends; *************** *** 2327,2336 **** --- 2480,2492 ---- */ static void pgstat_read_statsfile(HTAB **dbhash, Oid onlydb, + HTAB **userhash, PgStat_StatBeEntry **betab, int *numbackends) { PgStat_StatDBEntry *dbentry; PgStat_StatDBEntry dbbuf; + PgStat_StatUserEntry *userentry; + PgStat_StatUserEntry userbuf; PgStat_StatTabEntry *tabentry; PgStat_StatTabEntry tabbuf; HASHCTL hash_ctl; *************** *** 2371,2376 **** --- 2527,2545 ---- HASH_ELEM | HASH_FUNCTION | mcxt_flags); /* + * Create users hashtable + */ + ereport(DEBUG3, (errmsg_internal("before Create users hashtable"))); + memset(&hash_ctl, 0, sizeof(hash_ctl)); + hash_ctl.keysize = sizeof(Oid); + hash_ctl.entrysize = sizeof(PgStat_StatUserEntry); + hash_ctl.hash = oid_hash; + hash_ctl.hcxt = use_mcxt; + *userhash = hash_create("Users hash", PGSTAT_DB_HASH_SIZE, &hash_ctl, + HASH_ELEM | HASH_FUNCTION | mcxt_flags); + ereport(DEBUG3, (errmsg_internal("after Create users hashtable"))); + + /* * Initialize the number of known backends to zero, just in case we do * a silent error return below. */ *************** *** 2501,2506 **** --- 2670,2707 ---- break; /* + * 'U' A PgStat_StatUserEntry struct describing an user follows. + */ + case 'U': + ereport(DEBUG3, (errmsg_internal("in read 'U' start"))); + if (fread(&userbuf, 1, sizeof(userbuf), fpin) != sizeof(userbuf)) + { + ereport(pgStatRunningInCollector ? LOG : WARNING, + (errmsg("corrupted pgstat.stat file"))); + goto done; + } + + /* + * Add to the user hash + */ + userentry = (PgStat_StatUserEntry *) hash_search(*userhash, + (void *) &userbuf.userid, + HASH_ENTER, + &found); + if (found) + { + ereport(pgStatRunningInCollector ? LOG : WARNING, + (errmsg("corrupted pgstat.stat file"))); + goto done; + } + + memcpy(userentry, &userbuf, sizeof(PgStat_StatUserEntry)); + userentry->destroy = 0; + userentry->n_backends = 0; + ereport(DEBUG3, (errmsg_internal("in read 'U' end"))); + break; + + /* * 'M' The maximum number of backends to expect follows. */ case 'M': *************** *** 2557,2562 **** --- 2758,2772 ---- if (dbentry) dbentry->n_backends++; + /* + * Count backends per user here. + */ + userentry = (PgStat_StatUserEntry *) hash_search(*userhash, + (void *) &((*betab)[havebackends].userid), + HASH_FIND, NULL); + if (userentry) + userentry->n_backends++; + havebackends++; if (numbackends != 0) *numbackends = havebackends; *************** *** 2598,2603 **** --- 2808,2814 ---- { Assert(!pgStatRunningInCollector); pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId, + &pgStatUserHash, &pgStatBeTable, &pgStatNumBackends); pgStatDBHashXact = topXid; } *************** *** 2615,2620 **** --- 2826,2832 ---- { PgStat_StatBeEntry *beentry; PgStat_StatDBEntry *dbentry; + PgStat_StatUserEntry *userentry; bool found; /* *************** *** 2670,2675 **** --- 2882,2913 ---- * Count number of connects to the database */ dbentry->n_backends++; + + + /* + * Lookup or create the user entry for this backends user. + */ + userentry = (PgStat_StatUserEntry *) hash_search(pgStatUserHash, + (void *) &(msg->m_userid), + HASH_ENTER, &found); + if (userentry == NULL) + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory in statistics collector --- abort"))); + + /* + * If not found, initialize the new one. + */ + if (!found) + { + userentry->n_backends = 0; + userentry->destroy = 0; + } + + /* + * Count number of connects of the user + */ + userentry->n_backends++; } *************** *** 2865,2870 **** --- 3103,3137 ---- * Mark the database for destruction. */ dbentry->destroy = PGSTAT_DESTROY_COUNT; + } + + + /* ---------- + * pgstat_recv_dropuser() - + * + * Arrange for dead user removal + * ---------- + */ + static void + pgstat_recv_dropuser(PgStat_MsgDropuser *msg, int len) + { + PgStat_StatUserEntry *userentry; + + /* + * Make sure the backend is counted for. + */ + if (pgstat_add_backend(&msg->m_hdr) < 0) + return; + + /* + * Lookup the user in the hashtable. + */ + userentry = pgstat_get_user_entry(msg->m_userid); + + /* + * Mark the user for destruction. + */ + userentry->destroy = PGSTAT_DESTROY_COUNT; } diff -Nacr -x CVS bah2\src\backend\utils\init\globals.c bah\src\backend\utils\init\globals.c *** bah2\src\backend\utils\init\globals.c Sat Jan 01 00:01:40 2005 --- bah\src\backend\utils\init\globals.c Sat Jun 25 21:56:06 2005 *************** *** 92,97 **** --- 92,99 ---- /* Primary determinants of sizes of shared-memory structures: */ int NBuffers = 1000; int MaxBackends = 100; + int MaxDBBackends = 0; + int MaxUserBackends = 0; int VacuumCostPageHit = 1; /* GUC parameters for vacuum */ int VacuumCostPageMiss = 10; diff -Nacr -x CVS bah2\src\backend\utils\init\postinit.c bah\src\backend\utils\init\postinit.c *** bah2\src\backend\utils\init\postinit.c Fri Jun 24 19:42:44 2005 --- bah\src\backend\utils\init\postinit.c Sat Jun 25 21:56:06 2005 *************** *** 43,48 **** --- 43,49 ---- #include "utils/portal.h" #include "utils/relcache.h" #include "utils/syscache.h" + #include "pgstat.h" static bool FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace); *************** *** 50,55 **** --- 51,57 ---- static void InitCommunication(void); static void ShutdownPostgres(int code, Datum arg); static bool ThereIsAtLeastOneUser(void); + static void CheckMaxConnections(const char *dbname, const char *username); /*** InitPostgres support ***/ *************** *** 436,441 **** --- 438,450 ---- if (!bootstrap) ReverifyMyDatabase(dbname); + + /* Now we have database specifig & user specifig configs loaded, + * we can check for max_db_connections and max_user_connections + */ + CheckMaxConnections(dbname, username); + + /* * Final phase of relation cache startup: write a new cache file if * necessary. This is done after ReverifyMyDatabase to avoid writing *************** *** 548,551 **** --- 557,599 ---- heap_close(pg_shadow_rel, AccessExclusiveLock); return result; + } + + + /* + * Check if we are not over max_db_conenctions and max_user_connections limits + */ + static void + CheckMaxConnections(const char *dbname, const char *username) + { + PgStat_StatDBEntry *dbentry; + PgStat_StatUserEntry *userentry; + + if (MaxDBBackends > 0) + { + if ((dbentry = pgstat_fetch_stat_dbentry(MyDatabaseId)) != NULL) + { + if (dbentry->n_backends > MaxDBBackends) + { + ereport(FATAL, + (errcode(ERRCODE_TOO_MANY_CONNECTIONS), + errmsg("sorry, too many clients already for database \"%s\"", + dbname))); + } + } + } + + if (MaxUserBackends > 0) + { + if ((userentry = pgstat_fetch_stat_userentry(GetUserId())) != NULL) + { + if (userentry->n_backends > MaxUserBackends) + { + ereport(FATAL, + (errcode(ERRCODE_TOO_MANY_CONNECTIONS), + errmsg("sorry, too many clients already for user \"%s\"", + username))); + } + } + } } diff -Nacr -x CVS bah2\src\backend\utils\misc\guc.c bah\src\backend\utils\misc\guc.c *** bah2\src\backend\utils\misc\guc.c Thu Jun 23 03:57:06 2005 --- bah\src\backend\utils\misc\guc.c Sat Jun 25 21:56:06 2005 *************** *** 981,986 **** --- 981,1004 ---- }, { + {"max_db_connections", PGC_SUSET, CONN_AUTH_SETTINGS, + gettext_noop("Sets the maximum number of concurrent connections per database."), + NULL + }, + &MaxDBBackends, + 0, 0, INT_MAX / BLCKSZ, NULL, NULL + }, + + { + {"max_user_connections", PGC_SUSET, CONN_AUTH_SETTINGS, + gettext_noop("Sets the maximum number of concurrent connections per user."), + NULL + }, + &MaxUserBackends, + 0, 0, INT_MAX / BLCKSZ, NULL, NULL + }, + + { {"shared_buffers", PGC_POSTMASTER, RESOURCES_MEM, gettext_noop("Sets the number of shared memory buffers used by the server."), NULL diff -Nacr -x CVS bah2\src\bin\psql\tab-complete.c bah\src\bin\psql\tab-complete.c *** bah2\src\bin\psql\tab-complete.c Thu Jun 23 03:57:08 2005 --- bah\src\bin\psql\tab-complete.c Sat Jun 25 21:56:06 2005 *************** *** 576,581 **** --- 576,583 ---- "log_statement_stats", "maintenance_work_mem", "max_connections", + "max_db_connections", + "max_user_connections", "max_files_per_process", "max_fsm_pages", "max_fsm_relations", diff -Nacr -x CVS bah2\src\include\miscadmin.h bah\src\include\miscadmin.h *** bah2\src\include\miscadmin.h Sat Feb 26 20:43:34 2005 --- bah\src\include\miscadmin.h Sat Jun 25 21:56:06 2005 *************** *** 130,135 **** --- 130,137 ---- extern DLLIMPORT int NBuffers; extern int MaxBackends; + extern int MaxDBBackends; + extern int MaxUserBackends; extern DLLIMPORT int MyProcPid; extern struct Port *MyProcPort; diff -Nacr -x CVS bah2\src\include\pgstat.h bah\src\include\pgstat.h *** bah2\src\include\pgstat.h Wed May 11 03:41:42 2005 --- bah\src\include\pgstat.h Sat Jun 25 21:56:06 2005 *************** *** 28,33 **** --- 28,34 ---- #define PGSTAT_MTYPE_TABPURGE 5 #define PGSTAT_MTYPE_DROPDB 6 #define PGSTAT_MTYPE_RESETCOUNTER 7 + #define PGSTAT_MTYPE_DROPUSER 8 /* ---------- * The data type used for counters. *************** *** 175,180 **** --- 176,193 ---- /* ---------- + * PgStat_MsgDropuser Sent by the backend to tell the collector + * about dropped user + * ---------- + */ + typedef struct PgStat_MsgDropuser + { + PgStat_MsgHdr m_hdr; + Oid m_userid; + } PgStat_MsgDropuser; + + + /* ---------- * PgStat_MsgResetcounter Sent by the backend to tell the collector * to reset counters * ---------- *************** *** 224,229 **** --- 237,253 ---- int destroy; } PgStat_StatDBEntry; + /* ---------- + * PgStat_StatUserEntry The collectors data per user + * ---------- + */ + typedef struct PgStat_StatUserEntry + { + Oid userid; + int n_backends; + int destroy; + } PgStat_StatUserEntry; + /* ---------- * PgStat_StatBeEntry The collectors data per backend *************** *** 424,429 **** --- 448,454 ---- */ extern PgStat_StatDBEntry *pgstat_fetch_stat_dbentry(Oid dbid); extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry(Oid relid); + extern PgStat_StatUserEntry *pgstat_fetch_stat_userentry(Oid userid); extern PgStat_StatBeEntry *pgstat_fetch_stat_beentry(int beid); extern int pgstat_fetch_stat_numbackends(void);
pgsql-patches by date: