Re: Make tuple deformation faster

Alexander Lakhin <exclusion@gmail.com>

From: Alexander Lakhin <exclusion@gmail.com>
To: David Rowley <dgrowleyml@gmail.com>
Cc: Andres Freund <andres@anarazel.de>, Victor Yegorov <vyegorov@gmail.com>, Matthias van de Meent <boekewurm+postgres@gmail.com>, PostgreSQL Developers <pgsql-hackers@lists.postgresql.org>
Date: 2025-06-07T11:00:01Z
Lists: pgsql-hackers
Hello David,

24.12.2024 03:57, David Rowley wrote:
> On Tue, 24 Dec 2024 at 11:19, David Rowley<dgrowleyml@gmail.com> wrote:
>> The attached adjusts that Assert code so that a fresh CompactAttribute
>> is populated instead of modifying the TupleDesc's one.  I'm not sure
>> if populate_compact_attribute_internal() is exactly the nicest way to
>> do this. I'll think a bit harder about that. Assume the attached is
>> POC grade.
> I've now pushed a fix for this using the same method but with the code
> factored around a little differently. I didn't want to expose the
> populate_compact_attribute_internal() function externally, so I
> invented verify_compact_attribute() to call from
> TupleDescCompactAttr().

I stumbled upon that assertion failure again. It's not reproduced easily,
but maybe you can forgive me the following modification:
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -159,8 +159,11 @@ verify_compact_attribute(TupleDesc tupdesc, int attnum)
      tmp.attcacheoff = cattr->attcacheoff;
      tmp.attnullability = cattr->attnullability;

+for (int i = 0; i < 1000; i++)
+{
      /* Check the freshly populated CompactAttribute matches the TupleDesc's */
      Assert(memcmp(&tmp, cattr, sizeof(CompactAttribute)) == 0);
+}
  #endif
  }

which helps for this script:
for i in {1..50}; do
echo "ITERATION $i"
for c in {1..20}; do
echo "
set parallel_setup_cost = 1;
set min_parallel_table_scan_size = '1kB';
select * from information_schema.role_udt_grants limit 50;
" | psql > psql-$c.log &
done
wait
grep 'was terminated by signal' server.log && break;
done

to fail for me as below:
...
ITERATION 34
WARNING:  terminating connection because of crash of another server process
DETAIL:  The postmaster has commanded this server process to roll back the current transaction and exit, because another 
server process exited abnormally and possibly corrupted shared memory.
HINT:  In a moment you should be able to reconnect to the database and repeat your command.
server closed the connection unexpectedly
         This probably means the server terminated abnormally
         before or while processing the request.
connection to server was lost
2025-06-07 13:01:39.326 EEST [537106] LOG:  background worker "parallel worker" (PID 539473) was terminated by signal 6: 
Aborted

Core was generated by `postgres: parallel worker for PID 539434                                      '.
Program terminated with signal SIGABRT, Aborted.
(gdb) bt
#0  __pthread_kill_implementation (no_tid=0, signo=6, threadid=<optimized out>) at ./nptl/pthread_kill.c:44
#1  __pthread_kill_internal (signo=6, threadid=<optimized out>) at ./nptl/pthread_kill.c:78
#2  __GI___pthread_kill (threadid=<optimized out>, signo=signo@entry=6) at ./nptl/pthread_kill.c:89
#3  0x00007de05ec4526e in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#4  0x00007de05ec288ff in __GI_abort () at ./stdlib/abort.c:79
#5  0x00005dd0a1788377 in ExceptionalCondition (conditionName=0x5dd0a1822ee8 "memcmp(&tmp, cattr, 
sizeof(CompactAttribute)) == 0",
     fileName=0x5dd0a1822ed9 "tupdesc.c", lineNumber=165) at assert.c:66
#6  0x00005dd0a0f85bfd in verify_compact_attribute (tupdesc=0x7de05ef01000, attnum=1) at tupdesc.c:165
#7  0x00005dd0a0f72a25 in TupleDescCompactAttr (tupdesc=0x7de05ef01000, i=1) at ../../../../src/include/access/tupdesc.h:182
#8  0x00005dd0a0f73da6 in nocachegetattr (tup=0x7ffc737cc550, attnum=1, tupleDesc=0x7de05ef01000) at heaptuple.c:581
#9  0x00005dd0a12719c9 in fastgetattr (tup=0x7ffc737cc550, attnum=2, tupleDesc=0x7de05ef01000, isnull=0x5dd0a7b919d5)
     at ../../../src/include/access/htup_details.h:880
#10 0x00005dd0a1271a74 in heap_getattr (tup=0x7ffc737cc550, attnum=2, tupleDesc=0x7de05ef01000, isnull=0x5dd0a7b919d5)
     at ../../../src/include/access/htup_details.h:916
#11 0x00005dd0a127a50d in ExecEvalFieldSelect (state=0x5dd0a7b919d0, op=0x5dd0a7b93258, econtext=0x5dd0a7b86648) at 
execExprInterp.c:3837
#12 0x00005dd0a12759ce in ExecInterpExpr (state=0x5dd0a7b919d0, econtext=0x5dd0a7b86648, isnull=0x0) at 
execExprInterp.c:1698
#13 0x00005dd0a127702f in ExecInterpExprStillValid (state=0x5dd0a7b919d0, econtext=0x5dd0a7b86648, isNull=0x0) at 
execExprInterp.c:2299
#14 0x00005dd0a12db079 in ExecEvalExprNoReturn (state=0x5dd0a7b919d0, econtext=0x5dd0a7b86648) at 
../../../src/include/executor/executor.h:417
#15 0x00005dd0a12db137 in ExecEvalExprNoReturnSwitchContext (state=0x5dd0a7b919d0, econtext=0x5dd0a7b86648) at 
../../../src/include/executor/executor.h:458
#16 0x00005dd0a12db198 in ExecProject (projInfo=0x5dd0a7b919c8) at ../../../src/include/executor/executor.h:490
#17 0x00005dd0a12db3bb in ExecResult (pstate=0x5dd0a7b86538) at nodeResult.c:135
#18 0x00005dd0a1290e47 in ExecProcNodeFirst (node=0x5dd0a7b86538) at execProcnode.c:469
#19 0x00005dd0a12e2823 in ExecProcNode (node=0x5dd0a7b86538) at ../../../src/include/executor/executor.h:313
#20 0x00005dd0a12e2848 in SubqueryNext (node=0x5dd0a7b86318) at nodeSubqueryscan.c:53
#21 0x00005dd0a1295a36 in ExecScanFetch (node=0x5dd0a7b86318, epqstate=0x0, accessMtd=0x5dd0a12e2825 <SubqueryNext>,
...
(gdb) f 6
#6  0x00005dd0a0f85bfd in verify_compact_attribute (tupdesc=0x7de05ef01000, attnum=1) at tupdesc.c:165
165             Assert(memcmp(&tmp, cattr, sizeof(CompactAttribute)) == 0);
(gdb) p i
$1 = 484

(I've compiled postgres with -O0.)

Could you look at this once again, please?

Best regards,
Alexander

Commits

Same data as JSON: GET /api/v1/messages/:b64id/commits the thread's linked commits as JSON, with link sources. API reference →
  1. Fix possible Assert failure in verify_compact_attribute()

  2. Speedup tuple deformation with additional function inlining

  3. Fix race condition in TupleDescCompactAttr assert code

  4. Optimize alignment calculations in tuple form/deform

  5. Remove pg_attribute.attcacheoff column

  6. Introduce CompactAttribute array in TupleDesc, take 2

  7. Introduce CompactAttribute array in TupleDesc

  8. Use TupleDescAttr macro consistently