Pursuant to my comments at
https://www.postgresql.org/message-id/20161223192245.hx4rbrxbrwtgwj6i@alvherre.pgsql
and because of a stupid bug I found in my indirect indexes patch, I
rewrote (read: removed) HeapSatisfiesHOTAndKey.  The replacement
function HeapDetermineModifiedColumns returns a bitmapset with a bit set
for each modified column, for those columns that are listed as
"interesting" -- currently that set is the ID columns, the "key"
columns, and the indexed columns.  The new code is much simpler, at the
expense of a few bytes of additional memory used during heap_update().

All tests pass.

Both WARM and indirect indexes should be able to use this infrastructure
in a way that better serves them than the current HeapSatisfiesHOTAndKey
(both patches modify that function in a rather ugly way).  I intend to
get this pushed shortly unless objections are raised.

The new coding prevents stopping the check early as soon as the three
result booleans could be determined.  However, both patches were adding
reasons to avoid stopping early anyway, so I don't think this is a
significant loss.

Pavan, please rebase your WARM patch on top of this and let me know how
you like it.  I'll post a new version of indirect indexes later this
week.

Comments welcome.

-- 
Álvaro Herrera                https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index ea579a0..1dbefda 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -95,11 +95,8 @@ static XLogRecPtr log_heap_update(Relation reln, Buffer 
oldbuf,
                                Buffer newbuf, HeapTuple oldtup,
                                HeapTuple newtup, HeapTuple old_key_tup,
                                bool all_visible_cleared, bool 
new_all_visible_cleared);
-static void HeapSatisfiesHOTandKeyUpdate(Relation relation,
-                                                        Bitmapset *hot_attrs,
-                                                        Bitmapset *key_attrs, 
Bitmapset *id_attrs,
-                                                        bool *satisfies_hot, 
bool *satisfies_key,
-                                                        bool *satisfies_id,
+static Bitmapset *HeapDetermineModifiedColumns(Relation relation,
+                                                        Bitmapset 
*interesting_cols,
                                                         HeapTuple oldtup, 
HeapTuple newtup);
 static bool heap_acquire_tuplock(Relation relation, ItemPointer tid,
                                         LockTupleMode mode, LockWaitPolicy 
wait_policy,
@@ -3443,6 +3440,8 @@ heap_update(Relation relation, ItemPointer otid, 
HeapTuple newtup,
        Bitmapset  *hot_attrs;
        Bitmapset  *key_attrs;
        Bitmapset  *id_attrs;
+       Bitmapset  *interesting_attrs;
+       Bitmapset  *modified_attrs;
        ItemId          lp;
        HeapTupleData oldtup;
        HeapTuple       heaptup;
@@ -3460,9 +3459,6 @@ heap_update(Relation relation, ItemPointer otid, 
HeapTuple newtup,
                                pagefree;
        bool            have_tuple_lock = false;
        bool            iscombo;
-       bool            satisfies_hot;
-       bool            satisfies_key;
-       bool            satisfies_id;
        bool            use_hot_update = false;
        bool            key_intact;
        bool            all_visible_cleared = false;
@@ -3504,6 +3500,10 @@ heap_update(Relation relation, ItemPointer otid, 
HeapTuple newtup,
        key_attrs = RelationGetIndexAttrBitmap(relation, INDEX_ATTR_BITMAP_KEY);
        id_attrs = RelationGetIndexAttrBitmap(relation,
                                                                                
  INDEX_ATTR_BITMAP_IDENTITY_KEY);
+       interesting_attrs = bms_add_members(NULL, hot_attrs);
+       interesting_attrs = bms_add_members(interesting_attrs, key_attrs);
+       interesting_attrs = bms_add_members(interesting_attrs, id_attrs);
+
 
        block = ItemPointerGetBlockNumber(otid);
        buffer = ReadBuffer(relation, block);
@@ -3524,7 +3524,7 @@ heap_update(Relation relation, ItemPointer otid, 
HeapTuple newtup,
        Assert(ItemIdIsNormal(lp));
 
        /*
-        * Fill in enough data in oldtup for HeapSatisfiesHOTandKeyUpdate to 
work
+        * Fill in enough data in oldtup for HeapDetermineModifiedColumns to 
work
         * properly.
         */
        oldtup.t_tableOid = RelationGetRelid(relation);
@@ -3551,6 +3551,13 @@ heap_update(Relation relation, ItemPointer otid, 
HeapTuple newtup,
        }
 
        /*
+        * Determine which columns are being modified by the update.
+        */
+
+       modified_attrs = HeapDetermineModifiedColumns(relation, 
interesting_attrs,
+                                                                               
                  &oldtup, newtup);
+
+       /*
         * If we're not updating any "key" column, we can grab a weaker lock 
type.
         * This allows for more concurrency when we are running simultaneously
         * with foreign key checks.
@@ -3561,10 +3568,7 @@ heap_update(Relation relation, ItemPointer otid, 
HeapTuple newtup,
         * is updates that don't manipulate key columns, not those that
         * serendipitiously arrive at the same key values.
         */
-       HeapSatisfiesHOTandKeyUpdate(relation, hot_attrs, key_attrs, id_attrs,
-                                                                
&satisfies_hot, &satisfies_key,
-                                                                &satisfies_id, 
&oldtup, newtup);
-       if (satisfies_key)
+       if (!bms_overlap(modified_attrs, key_attrs))
        {
                *lockmode = LockTupleNoKeyExclusive;
                mxact_status = MultiXactStatusNoKeyUpdate;
@@ -3803,6 +3807,8 @@ l2:
                bms_free(hot_attrs);
                bms_free(key_attrs);
                bms_free(id_attrs);
+               bms_free(modified_attrs);
+               bms_free(interesting_attrs);
                return result;
        }
 
@@ -4107,7 +4113,7 @@ l2:
                 * to do a HOT update.  Check if any of the index columns have 
been
                 * changed.  If not, then HOT update is possible.
                 */
-               if (satisfies_hot)
+               if (!bms_overlap(modified_attrs, hot_attrs))
                        use_hot_update = true;
        }
        else
@@ -4122,7 +4128,9 @@ l2:
         * ExtractReplicaIdentity() will return NULL if nothing needs to be
         * logged.
         */
-       old_key_tuple = ExtractReplicaIdentity(relation, &oldtup, 
!satisfies_id, &old_key_copied);
+       old_key_tuple = ExtractReplicaIdentity(relation, &oldtup,
+                                                                               
   bms_overlap(modified_attrs, id_attrs),
+                                                                               
   &old_key_copied);
 
        /* NO EREPORT(ERROR) from here till changes are logged */
        START_CRIT_SECTION();
@@ -4270,6 +4278,8 @@ l2:
        bms_free(hot_attrs);
        bms_free(key_attrs);
        bms_free(id_attrs);
+       bms_free(modified_attrs);
+       bms_free(interesting_attrs);
 
        return HeapTupleMayBeUpdated;
 }
@@ -4369,100 +4379,24 @@ heap_tuple_attr_equals(TupleDesc tupdesc, int attrnum,
  * modify columns used in the key; id_result is set to TRUE if the update does
  * not modify columns in any index marked as the REPLICA IDENTITY.
  */
-static void
-HeapSatisfiesHOTandKeyUpdate(Relation relation, Bitmapset *hot_attrs,
-                                                        Bitmapset *key_attrs, 
Bitmapset *id_attrs,
-                                                        bool *satisfies_hot, 
bool *satisfies_key,
-                                                        bool *satisfies_id,
+static Bitmapset *
+HeapDetermineModifiedColumns(Relation relation, Bitmapset *interesting_cols,
                                                         HeapTuple oldtup, 
HeapTuple newtup)
 {
-       int                     next_hot_attnum;
-       int                     next_key_attnum;
-       int                     next_id_attnum;
-       bool            hot_result = true;
-       bool            key_result = true;
-       bool            id_result = true;
+       int             attnum;
+       Bitmapset *modified = NULL;
 
-       /* If REPLICA IDENTITY is set to FULL, id_attrs will be empty. */
-       Assert(bms_is_subset(id_attrs, key_attrs));
-       Assert(bms_is_subset(key_attrs, hot_attrs));
-
-       /*
-        * If one of these sets contains no remaining bits, bms_first_member 
will
-        * return -1, and after adding FirstLowInvalidHeapAttributeNumber (which
-        * is negative!)  we'll get an attribute number that can't possibly be
-        * real, and thus won't match any actual attribute number.
-        */
-       next_hot_attnum = bms_first_member(hot_attrs);
-       next_hot_attnum += FirstLowInvalidHeapAttributeNumber;
-       next_key_attnum = bms_first_member(key_attrs);
-       next_key_attnum += FirstLowInvalidHeapAttributeNumber;
-       next_id_attnum = bms_first_member(id_attrs);
-       next_id_attnum += FirstLowInvalidHeapAttributeNumber;
-
-       for (;;)
+       while ((attnum = bms_first_member(interesting_cols)) >= 0)
        {
-               bool            changed;
-               int                     check_now;
+               attnum += FirstLowInvalidHeapAttributeNumber;
 
-               /*
-                * Since the HOT attributes are a superset of the key 
attributes and
-                * the key attributes are a superset of the id attributes, this 
logic
-                * is guaranteed to identify the next column that needs to be 
checked.
-                */
-               if (hot_result && next_hot_attnum > 
FirstLowInvalidHeapAttributeNumber)
-                       check_now = next_hot_attnum;
-               else if (key_result && next_key_attnum > 
FirstLowInvalidHeapAttributeNumber)
-                       check_now = next_key_attnum;
-               else if (id_result && next_id_attnum > 
FirstLowInvalidHeapAttributeNumber)
-                       check_now = next_id_attnum;
-               else
-                       break;
-
-               /* See whether it changed. */
-               changed = !heap_tuple_attr_equals(RelationGetDescr(relation),
-                                                                               
  check_now, oldtup, newtup);
-               if (changed)
-               {
-                       if (check_now == next_hot_attnum)
-                               hot_result = false;
-                       if (check_now == next_key_attnum)
-                               key_result = false;
-                       if (check_now == next_id_attnum)
-                               id_result = false;
-
-                       /* if all are false now, we can stop checking */
-                       if (!hot_result && !key_result && !id_result)
-                               break;
-               }
-
-               /*
-                * Advance the next attribute numbers for the sets that contain 
the
-                * attribute we just checked.  As we work our way through the 
columns,
-                * the next_attnum values will rise; but when each set becomes 
empty,
-                * bms_first_member() will return -1 and the attribute number 
will end
-                * up with a value less than FirstLowInvalidHeapAttributeNumber.
-                */
-               if (hot_result && check_now == next_hot_attnum)
-               {
-                       next_hot_attnum = bms_first_member(hot_attrs);
-                       next_hot_attnum += FirstLowInvalidHeapAttributeNumber;
-               }
-               if (key_result && check_now == next_key_attnum)
-               {
-                       next_key_attnum = bms_first_member(key_attrs);
-                       next_key_attnum += FirstLowInvalidHeapAttributeNumber;
-               }
-               if (id_result && check_now == next_id_attnum)
-               {
-                       next_id_attnum = bms_first_member(id_attrs);
-                       next_id_attnum += FirstLowInvalidHeapAttributeNumber;
-               }
+               if (!heap_tuple_attr_equals(RelationGetDescr(relation),
+                                                                  attnum, 
oldtup, newtup))
+                       modified = bms_add_member(modified,
+                                                                         
attnum - FirstLowInvalidHeapAttributeNumber);
        }
 
-       *satisfies_hot = hot_result;
-       *satisfies_key = key_result;
-       *satisfies_id = id_result;
+       return modified;
 }
 
 /*
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to