|
19 | 19 | #include "access/relscan.h"
|
20 | 20 | #include "access/table.h"
|
21 | 21 | #include "access/xact.h"
|
| 22 | +#include "catalog/catalog.h" |
22 | 23 | #include "catalog/pg_collation.h"
|
23 | 24 | #include "catalog/pg_type.h"
|
24 | 25 | #include "common/hashfn.h"
|
@@ -2007,6 +2008,23 @@ ReleaseCatCacheListWithOwner(CatCList *list, ResourceOwner resowner)
|
2007 | 2008 | }
|
2008 | 2009 |
|
2009 | 2010 |
|
| 2011 | +/* |
| 2012 | + * equalTuple |
| 2013 | + * Are these tuples memcmp()-equal? |
| 2014 | + */ |
| 2015 | +static bool |
| 2016 | +equalTuple(HeapTuple a, HeapTuple b) |
| 2017 | +{ |
| 2018 | + uint32 alen; |
| 2019 | + uint32 blen; |
| 2020 | + |
| 2021 | + alen = a->t_len; |
| 2022 | + blen = b->t_len; |
| 2023 | + return (alen == blen && |
| 2024 | + memcmp((char *) a->t_data, |
| 2025 | + (char *) b->t_data, blen) == 0); |
| 2026 | +} |
| 2027 | + |
2010 | 2028 | /*
|
2011 | 2029 | * CatalogCacheCreateEntry
|
2012 | 2030 | * Create a new CatCTup entry, copying the given HeapTuple and other
|
@@ -2057,14 +2075,34 @@ CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp, SysScanDesc scandesc,
|
2057 | 2075 | */
|
2058 | 2076 | if (HeapTupleHasExternal(ntp))
|
2059 | 2077 | {
|
| 2078 | + bool need_cmp = IsInplaceUpdateOid(cache->cc_reloid); |
| 2079 | + HeapTuple before = NULL; |
| 2080 | + bool matches = true; |
| 2081 | + |
| 2082 | + if (need_cmp) |
| 2083 | + before = heap_copytuple(ntp); |
2060 | 2084 | dtp = toast_flatten_tuple(ntp, cache->cc_tupdesc);
|
2061 | 2085 |
|
2062 | 2086 | /*
|
2063 | 2087 | * The tuple could become stale while we are doing toast table
|
2064 |
| - * access (since AcceptInvalidationMessages can run then), so we |
2065 |
| - * must recheck its visibility afterwards. |
| 2088 | + * access (since AcceptInvalidationMessages can run then). |
| 2089 | + * equalTuple() detects staleness from inplace updates, while |
| 2090 | + * systable_recheck_tuple() detects staleness from normal updates. |
| 2091 | + * |
| 2092 | + * While this equalTuple() follows the usual rule of reading with |
| 2093 | + * a pin and no buffer lock, it warrants suspicion since an |
| 2094 | + * inplace update could appear at any moment. It's safe because |
| 2095 | + * the inplace update sends an invalidation that can't reorder |
| 2096 | + * before the inplace heap change. If the heap change reaches |
| 2097 | + * this process just after equalTuple() looks, we've not missed |
| 2098 | + * its inval. |
2066 | 2099 | */
|
2067 |
| - if (!systable_recheck_tuple(scandesc, ntp)) |
| 2100 | + if (need_cmp) |
| 2101 | + { |
| 2102 | + matches = equalTuple(before, ntp); |
| 2103 | + heap_freetuple(before); |
| 2104 | + } |
| 2105 | + if (!matches || !systable_recheck_tuple(scandesc, ntp)) |
2068 | 2106 | {
|
2069 | 2107 | heap_freetuple(dtp);
|
2070 | 2108 | return NULL;
|
|
0 commit comments