66 *
77 * Copyright (C) 2013, PostgreSQL Global Development Group
88 *
9- * IDENTIFICATION
10- * contrib/diskquota/activetable.c
119 *
1210 * -------------------------------------------------------------------------
1311 */
2422#include "storage/smgr.h"
2523#include "utils/builtins.h"
2624#include "utils/fmgroids.h"
25+ #include "utils/relfilenodemap.h"
2726
2827#include "activetable.h"
29- #include "diskquota.h"
3028
3129HTAB * active_tables_map = NULL ;
3230static SmgrStat_hook_type prev_SmgrStat_hook = NULL ;
33- static ScanKeyData relfilenode_skey [2 ];
3431
3532static void report_active_table_SmgrStat (SMgrRelation reln );
36- HTAB * get_active_tables (void );
33+ static HTAB * get_active_tables_stats (void );
34+ static HTAB * get_all_tables_stats (void );
35+
3736void init_active_table_hook (void );
3837void init_shm_worker_active_tables (void );
3938void init_lock_active_tables (void );
40- void init_relfilenode_key ( void );
39+ HTAB * pg_fetch_active_tables ( bool );
4140
4241/*
4342 * Register smgr hook to detect active table.
@@ -86,39 +85,84 @@ void init_lock_active_tables(void)
8685}
8786
8887/*
89- * Init relfilenode key to index search table oid
90- * given relfilenode and tablespace .
88+ * Fetch active table file size statistics.
89+ * If force is true, then fetch all the tables .
9190 */
92- void
93- init_relfilenode_key (void )
91+ HTAB * pg_fetch_active_tables (bool force )
92+ {
93+ if (force )
94+ {
95+ return get_all_tables_stats ();
96+ }
97+ else
98+ {
99+ return get_active_tables_stats ();
100+ }
101+ }
102+
103+ /*
104+ * Get the table size statistics for all the tables
105+ */
106+ static HTAB *
107+ get_all_tables_stats ()
94108{
95- int i ;
109+ HTAB * local_table_stats_map = NULL ;
110+ HASHCTL ctl ;
111+ HeapTuple tuple ;
112+ Relation classRel ;
113+ HeapScanDesc relScan ;
114+
115+ memset (& ctl , 0 , sizeof (ctl ));
116+ ctl .keysize = sizeof (Oid );
117+ ctl .entrysize = sizeof (DiskQuotaActiveTableEntry );
118+ ctl .hcxt = CurrentMemoryContext ;
119+ ctl .hash = oid_hash ;
96120
97- /* build skey */
98- MemSet (& relfilenode_skey , 0 , sizeof (relfilenode_skey ));
121+ local_table_stats_map = hash_create ("local table map with table size info" ,
122+ 1024 ,
123+ & ctl ,
124+ HASH_ELEM | HASH_CONTEXT | HASH_FUNCTION );
125+
126+ classRel = heap_open (RelationRelationId , AccessShareLock );
127+ relScan = heap_beginscan_catalog (classRel , 0 , NULL );
99128
100- for ( i = 0 ; i < 2 ; i ++ )
129+ while (( tuple = heap_getnext ( relScan , ForwardScanDirection )) != NULL )
101130 {
102- fmgr_info_cxt (F_OIDEQ ,
103- & relfilenode_skey [i ].sk_func ,
104- CacheMemoryContext );
105- relfilenode_skey [i ].sk_strategy = BTEqualStrategyNumber ;
106- relfilenode_skey [i ].sk_subtype = InvalidOid ;
107- relfilenode_skey [i ].sk_collation = InvalidOid ;
131+ Oid relOid ;
132+ DiskQuotaActiveTableEntry * entry ;
133+
134+ Form_pg_class classForm = (Form_pg_class ) GETSTRUCT (tuple );
135+ if (classForm -> relkind != RELKIND_RELATION &&
136+ classForm -> relkind != RELKIND_MATVIEW )
137+ continue ;
138+ relOid = HeapTupleGetOid (tuple );
139+
140+ /* ignore system table*/
141+ if (relOid < FirstNormalObjectId )
142+ continue ;
143+
144+ entry = (DiskQuotaActiveTableEntry * ) hash_search (local_table_stats_map , & relOid , HASH_ENTER , NULL );
145+
146+ entry -> tableoid = relOid ;
147+ entry -> tablesize = (Size ) DatumGetInt64 (DirectFunctionCall1 (pg_total_relation_size ,
148+ ObjectIdGetDatum (relOid )));
149+
108150 }
109151
110- relfilenode_skey [0 ].sk_attno = Anum_pg_class_reltablespace ;
111- relfilenode_skey [1 ].sk_attno = Anum_pg_class_relfilenode ;
112- }
152+ heap_endscan (relScan );
153+ heap_close (classRel , AccessShareLock );
113154
155+ return local_table_stats_map ;
156+ }
114157/*
115158 * Get local active table with table oid and table size info.
116159 * This function first copies active table map from shared memory
117160 * to local active table map with refilenode info. Then traverses
118161 * the local map and find corresponding table oid and table file
119162 * size. Finnaly stores them into local active table map and return.
120163 */
121- HTAB * get_active_tables ()
164+ static HTAB *
165+ get_active_tables_stats ()
122166{
123167 HASHCTL ctl ;
124168 HTAB * local_active_table_file_map = NULL ;
@@ -127,9 +171,6 @@ HTAB* get_active_tables()
127171 DiskQuotaActiveTableFileEntry * active_table_file_entry ;
128172 DiskQuotaActiveTableEntry * active_table_entry ;
129173
130- Relation relation ;
131- HeapTuple tuple ;
132- SysScanDesc relScan ;
133174 Oid relOid ;
134175
135176 memset (& ctl , 0 , sizeof (ctl ));
@@ -178,56 +219,34 @@ HTAB* get_active_tables()
178219 & ctl ,
179220 HASH_ELEM | HASH_CONTEXT | HASH_FUNCTION );
180221
181- relation = heap_open (RelationRelationId , AccessShareLock );
182222 /* traverse local active table map and calculate their file size. */
183223 hash_seq_init (& iter , local_active_table_file_map );
184224 /* scan whole local map, get the oid of each table and calculate the size of them */
185225 while ((active_table_file_entry = (DiskQuotaActiveTableFileEntry * ) hash_seq_search (& iter )) != NULL )
186226 {
187227 Size tablesize ;
188228 bool found ;
189- ScanKeyData skey [2 ];
190- Oid reltablespace ;
191229
192- reltablespace = active_table_file_entry -> tablespaceoid ;
193-
194- /* pg_class will show 0 when the value is actually MyDatabaseTableSpace */
195- if (reltablespace == MyDatabaseTableSpace )
196- reltablespace = 0 ;
197-
198- /* set scan arguments */
199- memcpy (skey , relfilenode_skey , sizeof (skey ));
200- skey [0 ].sk_argument = ObjectIdGetDatum (reltablespace );
201- skey [1 ].sk_argument = ObjectIdGetDatum (active_table_file_entry -> relfilenode );
202- relScan = systable_beginscan (relation ,
203- ClassTblspcRelfilenodeIndexId ,
204- true,
205- NULL ,
206- 2 ,
207- skey );
208-
209- tuple = systable_getnext (relScan );
210-
211- if (!HeapTupleIsValid (tuple ))
230+ relOid = RelidByRelfilenode (active_table_file_entry -> tablespaceoid , active_table_file_entry -> relfilenode );
231+
232+ //TODO replace DirectFunctionCall1 by a new total relation size function, which could handle Invalid relOid
233+ /* avoid to generate ERROR if relOid is not existed (i.e. table has been droped) */
234+ PG_TRY ();
212235 {
213- systable_endscan ( relScan );
214- continue ;
236+ tablesize = ( Size ) DatumGetInt64 ( DirectFunctionCall1 ( pg_total_relation_size ,
237+ ObjectIdGetDatum ( relOid ))) ;
215238 }
216- relOid = HeapTupleGetOid (tuple );
217-
218- /* Call function directly to get size of table by oid */
219- tablesize = (Size ) DatumGetInt64 (DirectFunctionCall1 (pg_total_relation_size , ObjectIdGetDatum (relOid )));
220-
221- active_table_entry = hash_search (local_active_table_stats_map , & relOid , HASH_ENTER , & found );
222- if (active_table_entry )
239+ PG_CATCH ();
223240 {
224- active_table_entry -> tableoid = relOid ;
225- active_table_entry -> tablesize = tablesize ;
241+ FlushErrorState () ;
242+ tablesize = 0 ;
226243 }
227- systable_endscan (relScan );
244+ PG_END_TRY ();
245+ active_table_entry = hash_search (local_active_table_stats_map , & relOid , HASH_ENTER , & found );
246+ active_table_entry -> tableoid = relOid ;
247+ active_table_entry -> tablesize = tablesize ;
228248 }
229249 elog (DEBUG1 , "active table number is:%ld" , hash_get_num_entries (local_active_table_file_map ));
230- heap_close (relation , AccessShareLock );
231250 hash_destroy (local_active_table_file_map );
232251 return local_active_table_stats_map ;
233252}
0 commit comments