|
14 | 14 | *
|
15 | 15 | *
|
16 | 16 | * IDENTIFICATION
|
17 |
| - * $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.29 2008/06/19 00:46:05 alvherre Exp $ |
| 17 | + * $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.30 2008/11/25 20:28:29 alvherre Exp $ |
18 | 18 | *
|
19 | 19 | *-------------------------------------------------------------------------
|
20 | 20 | */
|
|
26 | 26 | #include"utils/memutils.h"
|
27 | 27 | #include"utils/rel.h"
|
28 | 28 | #include"utils/resowner.h"
|
| 29 | +#include"utils/snapmgr.h" |
29 | 30 |
|
30 | 31 |
|
31 | 32 | /*
|
@@ -66,6 +67,11 @@ typedef struct ResourceOwnerData
|
66 | 67 | intntupdescs;/* number of owned tupdesc references */
|
67 | 68 | TupleDesc*tupdescs;/* dynamically allocated array */
|
68 | 69 | intmaxtupdescs;/* currently allocated array size */
|
| 70 | + |
| 71 | +/* We have built-in support for remembering snapshot references */ |
| 72 | +intnsnapshots;/* number of owned snapshot references */ |
| 73 | +Snapshot*snapshots;/* dynamically allocated array */ |
| 74 | +intmaxsnapshots;/* currently allocated array size */ |
69 | 75 | }ResourceOwnerData;
|
70 | 76 |
|
71 | 77 |
|
@@ -98,6 +104,7 @@ static void ResourceOwnerReleaseInternal(ResourceOwner owner,
|
98 | 104 | staticvoidPrintRelCacheLeakWarning(Relationrel);
|
99 | 105 | staticvoidPrintPlanCacheLeakWarning(CachedPlan*plan);
|
100 | 106 | staticvoidPrintTupleDescLeakWarning(TupleDesctupdesc);
|
| 107 | +staticvoidPrintSnapshotLeakWarning(Snapshotsnapshot); |
101 | 108 |
|
102 | 109 |
|
103 | 110 | /*****************************************************************************
|
@@ -301,6 +308,13 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
|
301 | 308 | PrintTupleDescLeakWarning(owner->tupdescs[owner->ntupdescs-1]);
|
302 | 309 | DecrTupleDescRefCount(owner->tupdescs[owner->ntupdescs-1]);
|
303 | 310 | }
|
| 311 | +/* Ditto for snapshot references */ |
| 312 | +while (owner->nsnapshots>0) |
| 313 | +{ |
| 314 | +if (isCommit) |
| 315 | +PrintSnapshotLeakWarning(owner->snapshots[owner->nsnapshots-1]); |
| 316 | +UnregisterSnapshot(owner->snapshots[owner->nsnapshots-1]); |
| 317 | +} |
304 | 318 |
|
305 | 319 | /* Clean up index scans too */
|
306 | 320 | ReleaseResources_hash();
|
@@ -332,6 +346,7 @@ ResourceOwnerDelete(ResourceOwner owner)
|
332 | 346 | Assert(owner->nrelrefs==0);
|
333 | 347 | Assert(owner->nplanrefs==0);
|
334 | 348 | Assert(owner->ntupdescs==0);
|
| 349 | +Assert(owner->nsnapshots==0); |
335 | 350 |
|
336 | 351 | /*
|
337 | 352 | * Delete children. The recursive call will delink the child from me, so
|
@@ -360,6 +375,8 @@ ResourceOwnerDelete(ResourceOwner owner)
|
360 | 375 | pfree(owner->planrefs);
|
361 | 376 | if (owner->tupdescs)
|
362 | 377 | pfree(owner->tupdescs);
|
| 378 | +if (owner->snapshots) |
| 379 | +pfree(owner->snapshots); |
363 | 380 |
|
364 | 381 | pfree(owner);
|
365 | 382 | }
|
@@ -936,3 +953,85 @@ PrintTupleDescLeakWarning(TupleDesc tupdesc)
|
936 | 953 | "TupleDesc reference leak: TupleDesc %p (%u,%d) still referenced",
|
937 | 954 | tupdesc,tupdesc->tdtypeid,tupdesc->tdtypmod);
|
938 | 955 | }
|
| 956 | + |
| 957 | +/* |
| 958 | + * Make sure there is room for at least one more entry in a ResourceOwner's |
| 959 | + * snapshot reference array. |
| 960 | + * |
| 961 | + * This is separate from actually inserting an entry because if we run out |
| 962 | + * of memory, it's critical to do so *before* acquiring the resource. |
| 963 | + */ |
| 964 | +void |
| 965 | +ResourceOwnerEnlargeSnapshots(ResourceOwnerowner) |
| 966 | +{ |
| 967 | +intnewmax; |
| 968 | + |
| 969 | +if (owner->nsnapshots<owner->maxsnapshots) |
| 970 | +return;/* nothing to do */ |
| 971 | + |
| 972 | +if (owner->snapshots==NULL) |
| 973 | +{ |
| 974 | +newmax=16; |
| 975 | +owner->snapshots= (Snapshot*) |
| 976 | +MemoryContextAlloc(TopMemoryContext,newmax*sizeof(Snapshot)); |
| 977 | +owner->maxsnapshots=newmax; |
| 978 | +} |
| 979 | +else |
| 980 | +{ |
| 981 | +newmax=owner->maxsnapshots*2; |
| 982 | +owner->snapshots= (Snapshot*) |
| 983 | +repalloc(owner->snapshots,newmax*sizeof(Snapshot)); |
| 984 | +owner->maxsnapshots=newmax; |
| 985 | +} |
| 986 | +} |
| 987 | + |
| 988 | +/* |
| 989 | + * Remember that a snapshot reference is owned by a ResourceOwner |
| 990 | + * |
| 991 | + * Caller must have previously done ResourceOwnerEnlargeSnapshots() |
| 992 | + */ |
| 993 | +void |
| 994 | +ResourceOwnerRememberSnapshot(ResourceOwnerowner,Snapshotsnapshot) |
| 995 | +{ |
| 996 | +Assert(owner->nsnapshots<owner->maxsnapshots); |
| 997 | +owner->snapshots[owner->nsnapshots]=snapshot; |
| 998 | +owner->nsnapshots++; |
| 999 | +} |
| 1000 | + |
| 1001 | +/* |
| 1002 | + * Forget that a snapshot reference is owned by a ResourceOwner |
| 1003 | + */ |
| 1004 | +void |
| 1005 | +ResourceOwnerForgetSnapshot(ResourceOwnerowner,Snapshotsnapshot) |
| 1006 | +{ |
| 1007 | +Snapshot*snapshots=owner->snapshots; |
| 1008 | +intns1=owner->nsnapshots-1; |
| 1009 | +inti; |
| 1010 | + |
| 1011 | +for (i=ns1;i >=0;i--) |
| 1012 | +{ |
| 1013 | +if (snapshots[i]==snapshot) |
| 1014 | +{ |
| 1015 | +while (i<ns1) |
| 1016 | +{ |
| 1017 | +snapshots[i]=snapshots[i+1]; |
| 1018 | +i++; |
| 1019 | +} |
| 1020 | +owner->nsnapshots=ns1; |
| 1021 | +return; |
| 1022 | +} |
| 1023 | +} |
| 1024 | +elog(ERROR,"snapshot reference %p is not owned by resource owner %s", |
| 1025 | +snapshot,owner->name); |
| 1026 | +} |
| 1027 | + |
| 1028 | +/* |
| 1029 | + * Debugging subroutine |
| 1030 | + */ |
| 1031 | +staticvoid |
| 1032 | +PrintSnapshotLeakWarning(Snapshotsnapshot) |
| 1033 | +{ |
| 1034 | +elog(WARNING, |
| 1035 | +"Snapshot reference leak: Snapshot %p still referenced", |
| 1036 | +snapshot); |
| 1037 | +} |