Thread: Postgres 7.4 : ECPG not Thread-safe

Postgres 7.4 : ECPG not Thread-safe

From
Thierry Missimilly
Date:
Hi,

This is the wrong mailing list but I don't sent it to pgsql-bugs with
success.



============================================================================

                        POSTGRESQL BUG REPORT TEMPLATE
============================================================================



Your name  : Thierry Missimilly
Your email address : Thierry.Missimilly@bull.net


System Configuration
---------------------
  Architecture (example: Intel Pentium)   : Pentium IV 1.8 Ghz

  Operating System (example: Linux 2.0.26 ELF)  : Linux Red Hat 7.3

  PostgreSQL version (example: PostgreSQL-7.3):   PostgreSQL-7.4Beta2 &
Beta4

  Compiler used (example:  gcc 2.95.2)  : gcc 2.96


Please enter a FULL description of your problem:
------------------------------------------------
I think i have a Thread-safe problem. PostgreSQL developpers will find a
test program  to reproduce it on their lab.

I have, already sent this to pgsql-general and pgsql-hacker, but get
back not answers. But neve mind.

I've built Postgresql with the option --enable-thread-safety --with-tcl.

And now run a pgbench like program call pgbch.pgc (attached with this
mail).

The main differences of pgbch.pgc are :
1) Pro*c code
2) Multi-threaded
3) Some specific code for Oracle
4) Some specific dynamic trace for debug


Please describe a way to repeat the problem.   Please try to provide a
concise reproducible example, if at all possible:
----------------------------------------------------------------------

To compile  :
--------------

ecpg -o pgbhc.c pgbch.pgc
cc -g -D_THREAD_SAFE -D_REENTRANT -I /usr/local/pgsql/include -L
/usr/local/pgsql/lib -lpthread
-lecpg -o pgbch pgbch.c

To execute :
-------------

pgbch -i base_s1
pgbch -c3 -t10 base_s1

(you can add -d10 to have debug traces)

Well, the problem is that sometime pgbch hang. Run it 3 or 4 times and
it will hang.
I don't know if it is really link to Postgres and ECPG but if you
modifiy pgbch.pgc in the way that the
transaction is limited to "BEGIN; END; ", it will never hang.

pgbch with 3 clients means 4 processes, but when then hang occurs,
generally, one client has finished
its 10 transactions and there still are 3 processes.

A look at gdb (gdb pgbch <pid>) gives (See the attach file pgbch.gdb) :
1) The main thread is in pthread_join() waitting for the 2 other child
threads.
2) One thread has finished, but is hanged in pqSocketPoll()
3) The last other thread is waitting to start running in
__pthread_manager()

Well, i'm not an expert in Linux multi-thread, but it seems the thread
(2) is waitting from a message
from the postgresql backend which never comes and therefore blocks the
others threads.

I hope this will help to give back Postgres 7.4 more robust.

You will find attached the pgbch.pgc source and pgbch.gdb trace get on
Postgresql-7.4beta2
(they are the same with Postgresql-7.4Beta4)

Thierry Missimilly


/*
 * $Header: /home/projects/pgsql/cvsroot/pgsql/contrib/pgbench/pgbench.c,v 1.8 2001/02/10 02:31:25 tgl Exp $
 *
 * pgbench: a simple TPC-B like benchmark program for PostgreSQL
 * written by Tatsuo Ishii
 *
 * Copyright (c) 2000  Tatsuo Ishii
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose and without fee is hereby
 * granted, provided that the above copyright notice appear in all
 * copies and that both that copyright notice and this permission
 * notice appear in supporting documentation, and that the name of the
 * author not be used in advertising or publicity pertaining to
 * distribution of the software without specific, written prior
 * permission. The author makes no representations about the
 * suitability of this software for any purpose.  It is provided "as
 * is" without express or implied warranty.
 VERSION 3.2 */

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

#ifdef WIN32
#include "win32.h"
#else
#include <sys/time.h>
#include <unistd.h>

#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif

#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif

/* for getrlimit */
#include <sys/resource.h>

#endif   /* WIN32 */

/********************************************************************
 * some configurable parameters */

exec sql include sqlca;

#ifdef ORACLE
#define EXIT_THREAD(a)   return(NULL)
#else
#define EXIT_THREAD(a)   pthread_exit(NULL) //return(NULL)
#endif

#define MAXCLIENTS 1024      /* max number of clients allowed */
#define a_result char
int nclients = 1;/* default number of simulated clients */
int ncli_connected ;/* Connected clients */
int nb_sql_failed ;/* nb SQL failed */
int num_cli = 0;
int nxacts = 10;/* default number of transactions per Clients */

/*
 * scaling factor. for example, tps = 10 will make 1000000 tuples of
 * accounts table.
 */
typedef struct
{
int finish;
char name[32];
}      st_connection;

int      tps = 1;
int      gi_debug = 0;    /* debug flag */
char     *gdbName;
st_connection      gtab_cnx[MAXCLIENTS];
#ifdef NO_USED
int      gi_break = 0;
#endif

#ifdef ORACLE
  sql_context tab_ctx[MAXCLIENTS];
#endif


/*
 * end of configurable parameters
 *********************************************************************/

#define nbranches  1
#define ntellers  10
#define naccounts  100000

typedef struct
{
  int      etat;      /* etat No. */
  int      cnt;      /* xacts count */
  int      aid;      /* account id for this transaction */
  int      bid;      /* branch id for this transaction */
  int      tid;      /* teller id for this transaction */
  int      delta;
  int      abalance;
}      Client_State;
char command[128];

/*===========================*/
#ifndef ORACLE
static void
doBegin(pnum_thread)
int pnum_thread;
/*===========================*/
{
exec sql begin work;
if ( gi_debug > 9 )
  {
    fprintf (stderr, "... Begin work");
    if ( pnum_thread >= 0 )
      fprintf (stderr, " for client %d\n", pnum_thread);
    else
      fprintf (stderr, "\n");
  }
}
#endif

/*===========================*/
static void
  doCommit( pnum_thread )
  int pnum_thread;
/*===========================*/
{
  exec sql commit ;

if ( gi_debug> 9  )
  {
    fprintf (stderr, "... Commited");
    if ( pnum_thread >= 0 )
      fprintf (stderr, " for client %d\n", pnum_thread);
    else
      fprintf (stderr, "\n");
  }
}

/*===========================*/
static int
doDisconnect( cnx_name )
char *cnx_name;
/*===========================*/
{
exec sql begin declare section;
  char pg_cnx_name[32];
exec sql end declare section;

  strcpy(pg_cnx_name,cnx_name);
#ifndef ORACLE
  if (gi_debug> 9 )
    fprintf(stderr, "-> exec sql disconnect %s\n",cnx_name);
  exec sql disconnect :pg_cnx_name;
#endif
}

/*===========================*/
static int
#ifdef ORACLE
  doConnect( cnx_name , ctx )
    char *cnx_name;
    sql_context ctx;
#else
  doConnect( cnx_name )
    char *cnx_name;
#endif
/*===========================*/
{
exec sql begin declare section;
  char connection[32];
  char pg_cnx_name[32];
exec sql end declare section;

  strcpy(connection,gdbName);
  strcpy(pg_cnx_name,cnx_name);
  if (gi_debug> 9 )
    fprintf(stderr, "-> exec sql connect to %s as %s\n",gdbName,cnx_name);

#ifdef ORACLE
/*-->    exec sql context use :ctx; <--*/
   strcpy (connection,"scott/tiger");
   EXEC SQL CONNECT :connection;
#else
  exec sql connect to :connection as :pg_cnx_name;
#endif
  if ( sqlca.sqlcode < 0 )
  {
    if (gi_debug> 9 )
      fprintf(stderr, "*** pgbch:Connection to '%s' failed.\n", gdbName);
    return ( sqlca.sqlcode );
  }
  return(0); /* connection successful */
}

#ifdef NO_USED
/*===========================*/
static void printerr(sqlcb)
struct sqlca sqlcb;
/*===========================*/
{
  if ( sqlcb.sqlcode < 0 )
  {
    nb_sql_failed++;
#ifdef NO_USED
    gi_break=2;
#endif
    fprintf(stderr, "*** Exec SQL failed. ***\n");
  }
}
#endif


/*===========================*/
#ifndef ORACLE
static void printwarn(void)
/*===========================*/
{
   if (sqlca.sqlwarn[0]) printf("sqlca.sqlwarn: %c",sqlca.sqlwarn[0]);
   else return;

   if (sqlca.sqlwarn[1]) putchar('1');
   if (sqlca.sqlwarn[2]) putchar('2');

   putchar('\n');
}
#endif

/*===========================*/
static void
usage()
/*===========================*/
{
  fprintf(stderr, "usage: pgbench [-h hostname][-p port][-c nclients][-t ntransactions][-s
scaling_factor][-n][-v][-S][-d][dbname]\n");
  fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor][-d][dbname]\n");
}

/*===========================*/
/* random number generator */
static int
getrand(int min, int max)
/*===========================*/
{
  return (min + (int) (max * 1.0 * rand() / (RAND_MAX + 1.0)));
}


/*===========================*/
/* process a transaction */
static void *
doOne( void * arg )
/*===========================*/
{
  Client_State  st;
  char    sql[256];
  int iret=0;
  int i_am_done=0;

  int numero_thread=(int) arg;
exec sql begin declare section;
  char text[16];
  char text1[16];
  char text2[16];
  char text3[16];
exec sql end declare section;

  if (gi_debug> 9 )
    fprintf(stderr, "### client %d connecting to %s\n", numero_thread, gdbName);
    fflush(stderr);
  sprintf(gtab_cnx[numero_thread].name,"CNX_%d", numero_thread);

#ifdef ORACLE
/*-->   exec sql context allocate :tab_ctx[numero_thread]; <--*/
  if ( gi_debug > 9 )
     fprintf (stderr,"allocate ctx %d\n", numero_thread);
  iret=doConnect (gtab_cnx[numero_thread].name, tab_ctx[numero_thread]);
#else
  iret=doConnect (gtab_cnx[numero_thread].name);
#endif
  if ( iret )
  {
    ncli_connected--;
    fprintf(stderr, "*** FATAL CLIENT %d CAN NOT CONNECT TO DB=%s\n",
                      numero_thread, gdbName);
    fflush(stderr);
    gtab_cnx[numero_thread].finish=0;
#ifdef NO_USED
    gi_break=1;
#endif
    EXIT_THREAD(arg);
  }

#ifdef NO_USED
sleep(1);
#endif

  if ( gi_debug > 0 )
    fprintf(stderr, "    CLIENT %d CONNECTED TO DB=%s\n",
                      numero_thread, gdbName);
#ifdef ORACLE
/*-->   exec sql context use :tab_ctx[numero_thread]; <--*/
#endif
  for(;;)
  {
  switch (st.etat)
  {
    case 0:      /* about to start */
      strcpy(sql, "begin");
      st.aid = getrand(1, naccounts * tps);
      st.bid = getrand(1, nbranches * tps);
      st.tid = getrand(1, ntellers * tps);
      st.delta = getrand(1, 1000);
#ifndef ORACLE
      doBegin(numero_thread);
#endif
      break;
    case 1:
      sprintf(sql, "update accounts set abalance = abalance + %d where aid = %d\n", st.delta, st.aid);
      sprintf(text,"%d",st.delta);
      sprintf(text1,"%d",st.aid);
      exec sql update accounts set abalance = abalance + :text where aid = :text1;
      break;

    case 2:
      sprintf(sql, "select abalance from accounts where aid = %d", st.aid);
      sprintf(text,"%d", st.aid);
      exec sql select abalance from accounts where aid = :text;
      break;
    case 3:
      sprintf(sql, "update tellers set tbalance = tbalance + %d where tid = %d\n",
          st.delta, st.tid);
      sprintf (text,"%d",st.delta);
      sprintf (text1,"%d",st.tid);
      exec sql update tellers set tbalance = tbalance + :text where tid = :text1;
      break;
    case 4:
      sprintf(sql, "update branches set bbalance = bbalance + %d where bid = %d", st.delta, st.bid);
      sprintf (text,"%d",st.delta);
      sprintf (text1,"%d",st.bid);
      exec sql update branches set bbalance = bbalance + :text where bid = :text1;
      break;
    case 5:
      sprintf(sql, "insert into history(tid,bid,aid,delta,mtime) values(%d,%d,%d,%d,'now')",
          st.tid, st.bid, st.aid, st.delta);
      sprintf (text,"%d",st.tid);
      sprintf (text1,"%d",st.bid);
      sprintf (text2,"%d",st.aid);
      sprintf (text3,"%d",st.delta);
      exec sql insert into history(tid,bid,aid,delta,mtime)
               values(:text, :text1, :text2, :text3,'now');
      break;

    case 6:
      strcpy(sql, "end");
      doCommit(numero_thread);

      if (++st.cnt >= nxacts)
      {
        /* I've done */
        gtab_cnx[numero_thread].finish=0;

        if (gi_debug > 0)
        {
          fprintf(stderr, "           CLIENT %d ENDED\n", numero_thread);
          fflush(stderr);
        }
        EXIT_THREAD(arg);
      }
      break;
  }
#ifdef DO_IT
+ifdef NO_USED
sleep(1);
#endif

  if (gi_debug > 9)
    fprintf(stderr, "client %d sending %s\n", numero_thread, sql);
  /* increment etat counter */
  st.etat++;
  if (st.etat > 6)
    st.etat = 0;
  }

} /* End of doOne */

/*===========================*/
static void
#ifdef ORACLE
  init(ctx)
  sql_context ctx;
#else
  init()
#endif
/*===========================*/
{
exec sql begin declare section;
  int      i;
  char text[16];
  char text1[16];
exec sql end declare section;

char cnx_name[32];
int iret = -1;

  strcpy(cnx_name, "cnx_init");

#ifdef ORACLE
/*-->   exec sql context use :ctx; <--*/
  iret = doConnect (cnx_name, ctx);
#else
  iret = doConnect (cnx_name);
#endif
  if ( iret )
  {
    fprintf(stderr, "*** FATAL init can not connect to DB=%s\n", gdbName);
    fflush(stderr);
    return;
  }
  fprintf(stderr, "-> Begin creating ...\n");
  exec sql drop table branches;
  exec sql create table branches (
    "bid" int primary key,
    "bbalance" int,
    "filler" char(88));
  fprintf(stderr, "tables branches created ...\n");

  exec sql drop table tellers;
  exec sql create table tellers(
    tid int primary key,
    bid int,
    tbalance int,
    filler char(84));
  fprintf(stderr, "tables tellers created...\n");

  exec sql drop table accounts;
  exec sql create table accounts(
    aid int primary key,
    bid int,
    abalance int,
    filler char(84));
  fprintf(stderr, "tables accounts created ...\n");

  exec sql drop table history;
  exec sql create table history(
    tid int,
    bid int,
    aid int,
    delta int,
    mtime timestamp,
    filler char(22));
  fprintf(stderr, "tables history created  ...\n");

  fprintf(stderr, "-> Create Tables done  ...\n");

  for (i = 0; i < nbranches * tps; i++)
  {
    sprintf(command, "insert into branches (bid,bbalance) values(%d,0)", i+1);
    sprintf( text, "%d", i+1);
    exec sql insert into branches(bid,bbalance) values(:text,0);
  }

  for (i = 0; i < ntellers * tps; i++)
  {
    sprintf(command, "insert into tellers(tid,bid,tbalance) values (%d,%d,0)" ,i + 1, i / ntellers + 1);
    sprintf(text,"%d",i+1);
    sprintf(text1,"%d",i-1/ntellers+1);
    i+1;
    exec sql insert into tellers(tid,bid,tbalance) values(:text,:text1,0);
  }

  for (i = 0; i < naccounts * tps; i++)
  {
     int                     j = i + 1;
     sprintf (text,"%d", j);
     sprintf (text1,"%d", j/ naccounts);
     exec sql insert into accounts(aid,bid,abalance) values(:text,:text1,0);
     if (j % 10000 == 0)
     {
      /*
       * every 10000 tuples, we commit the copy command. this should
       * avoid generating too much WAL logs
       */
       fprintf(stderr, "%d tuples done.\n", j);
     }
  }
  doCommit(-1);
  doDisconnect ( cnx_name );

#ifdef ORACLE
/*-->   exec sql context free :tab_ctx[0]; <--*/
#endif

  fprintf(stderr, "done init !");
} /* Fin init */

/*===========================*/
/* print out results */
static void
printResults(
       int ttype, Client_State * process,
       struct timeval * tv1, struct timeval * tv2,
       struct timeval * tv3)
/*===========================*/
{
  double    t1,
        t2;
  int      i;
  int      normal_xacts = 0;

  normal_xacts = nclients*nxacts ;
  t1 = (tv3->tv_sec - tv1->tv_sec) * 1000000.0 + (tv3->tv_usec - tv1->tv_usec);
  t1 = nxacts*ncli_connected * 1000000.0 / t1;

  t2 = (tv3->tv_sec - tv2->tv_sec) * 1000000.0 + (tv3->tv_usec - tv2->tv_usec);
  t2 = nxacts*ncli_connected * 1000000.0 / t2;

  printf("****************************************************************\n");
  printf("transaction type: %s\n", ttype == 0 ? "TPC-B (sort of)" : "SELECT only");
  printf("scaling factor: %d\n", tps);
  printf("number of clients: %d\n", nclients);
  printf("number of clients connected: %d\n", ncli_connected);
  printf("number of transactions per client: %d\n", nxacts);
  printf("number of transactions actually processed: %d/%d\n", nxacts*ncli_connected - nb_sql_failed, normal_xacts);
  printf("tps = %f(including connections establishing)\n", t1);
  printf("tps = %f(excluding connections establishing)\n", t2);
  printf("****************************************************************\n");
} /* Fin print_resu */

/*===========================*/
int
main(int argc, char **argv)
/*===========================*/
{
  extern char *optarg;
  extern int  optind,
        opterr,
        optopt;
  int      c;
  char     *pghost = NULL;
  char     *pgport = NULL;
  int      is_init_mode = 0;    /* initialize mode? */
  int      is_no_vacuum = 0;    /* no vacuum at all before */
  int      is_drop = 0;    /* no drop before */
  int      is_full_vacuum = 0;    /* do full vacuum before testing? */
  int      ttype = 0;    /* transaction type. 0: TPC-B, 1: SELECT
                 * only */

  static Client_State process[MAXCLIENTS];  /* clients status */

  struct timeval tv1;      /* start up time */
  struct timeval tv2;      /* after establishing all connections to
                 * the backend */
  struct timeval tv3;      /* end time */

  int      i;
  int      i_fois=0;
  int      i_encours=0;
  int      iret;
  pthread_t  thread[MAXCLIENTS];
  pthread_attr_t thread_attr;


#ifdef NO_USED
exec sql whenever sqlerror do printerr(sqlca);
#endif
exec sql whenever sqlerror do printwarn();
#ifndef ORACLE
exec sql whenever not found sqlprint;

exec sql whenever sqlwarning do printwarn();
#endif

#ifdef ORACLE
/*-->    exec sql enable threads; <--*/
#endif

  while ((c = getopt(argc, argv, "ih:nNvp:d:c:C:t:s:S")) != EOF)
  {
    switch (c)
    {
      case 'i':
        is_init_mode++;
        break;
      case 'h':
        pghost = optarg;
        break;
      case 'N':
        is_drop++;
        break;
      case 'n':
        is_no_vacuum++;
        break;
      case 'v':
        is_full_vacuum++;
        break;
      case 'p':
        pgport = optarg;
        break;
      case 'd':
        gi_debug = atoi(optarg);
        break;
      case 'S':
        ttype = 1;
        break;

      case 'C':
        num_cli = atoi(optarg);
        break;

      case 'c':
        nclients = atoi(optarg);
        ncli_connected = nclients;
        if (nclients <= 0 || nclients > MAXCLIENTS)
        {
          fprintf(stderr, "wrong number of clients: %d\n", nclients);
          exit(1);
        }
        break;
      case 's':
        tps = atoi(optarg);
        if (tps <= 0)
        {
          fprintf(stderr, "wrong scaling factor: %d\n", tps);
          exit(1);
        }
        break;
      case 't':
        nxacts = atoi(optarg);
        if (nxacts <= 0)
        {
          fprintf(stderr, "wrong number of transactions: %d\n", nxacts);
          exit(1);
        }
        break;
      default:
        usage();
        exit(1);
        break;
    } /* switch */
  } /* Fin du traitement */

  if (argc > optind)
    gdbName = argv[optind];
  else
  {
    gdbName = getenv("USER");
    if (gdbName == NULL)
      gdbName = "";
  }

  if (is_init_mode)
  {
#ifdef ORACLE
/*-->     exec sql context allocate :tab_ctx[0]; <--*/
    init(tab_ctx[0]);
#else
    init();
#endif
    exit(0);
  }

  if (gi_debug > 9)
  {
    printf("pghost: %s pgport: %s nclients: %d nxacts: %d dbName: %s\n",
         pghost, pgport, nclients, nxacts, gdbName);
  }
  /*
   * get the scaling factor that should be same as count(*) from
   * branches...
   */

  if (is_drop)
  {
#ifdef ORACLE

/*-->    exec sql context allocate :tab_ctx[0]; <--*/
/*-->    exec sql context use :tab_ctx[0]; <--*/
#endif
    fprintf(stderr, "starting drop...");
    exec sql drop table branches;
    exec sql drop table tellers;
    exec sql drop table accounts;
    exec sql drop table history;
    exec sql commit;
  } /* Fin du traitement si pas d option -n */

   for (i = 0; i < nclients ; i++)
     gtab_cnx[i].finish=1;

  /* set random seed */
  gettimeofday(&tv1, 0);
  srand((uint) tv1.tv_usec);

  /*====== CREATE THE THREADS ============================*/
  /* get start up time */
   gettimeofday(&tv1, 0);

   if ( pthread_attr_init(&thread_attr) )
     perror ("pthread_attr_init: ");

   if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE))
     perror("pthread_attr_setdetachstate :");

  /* time after connections set up */
  gettimeofday(&tv2, 0);

   for (i = 0; i < nclients ; i++)
     pthread_create (&thread[i], &thread_attr, doOne, (void *) i);

  /*====== WAITING THE END OF THREADS ===================*/
   for (i = 0; i < nclients ; i++)
   {
     if (pthread_join (thread[i], NULL))
       perror("pthread_join failed by : ");
     else
       if ( gi_debug > 0)
         printf("- thread %d stopped\n", i);

   }
  /* time after the end of transaction */
   gettimeofday(&tv3, 0);

#ifdef ORACLE
  /*====== ORACLE: FREE CONTEXT ==========================*/
   for (i = 0; i < nclients ; i++)
   {
     if ( pthread_detach(thread[i]) )
     {
     if ( gi_debug > 0)
       printf(" -> detached thread %d ...", i );
     }
     else
     {
     if ( gi_debug > 0)
       printf(" -> detached thread %d OK", i );
     }
/*-->      exec sql context use :tab_ctx[i]; <--*/
     exec sql commit work release;
/*-->      exec sql context free :tab_ctx[i]; <--*/
     if ( gi_debug > 0)
       fprintf (stderr," free %d \n", i );
   }
#endif /* ORACLE */

  /*====== PRINTING OF RESULTS ==========================*/
   printResults(ttype, process, &tv1, &tv2, &tv3);

}
[postgres@tux3 bao.d]$ gdb pgbch 14728
GNU gdb Red Hat Linux (5.1.90CVS-5)
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux"...
Attaching to program: /home/postgres/bao.d/pgbch, process 14728
Reading symbols from /lib/i686/libpthread.so.0...done.
[New Thread 1024 (LWP 14728)]
[New Thread 2049 (LWP 14729)]
[New Thread 2051 (LWP 14732)]
Loaded symbols for /lib/i686/libpthread.so.0
Reading symbols from /usr/local/pgsql/lib/libecpg.so.4...done.
Loaded symbols for /usr/local/pgsql/lib/libecpg.so.4
Reading symbols from /lib/i686/libc.so.6...done.
Loaded symbols for /lib/i686/libc.so.6
Reading symbols from /usr/local/pgsql/lib/libpgtypes.so.1...done.
Loaded symbols for /usr/local/pgsql/lib/libpgtypes.so.1
Reading symbols from /usr/local/pgsql/lib/libpq.so.3...done.
Loaded symbols for /usr/local/pgsql/lib/libpq.so.3
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
Reading symbols from /lib/i686/libm.so.6...done.
Loaded symbols for /lib/i686/libm.so.6
Reading symbols from /lib/libcrypt.so.1...done.
Loaded symbols for /lib/libcrypt.so.1
Reading symbols from /lib/libresolv.so.2...done.
Loaded symbols for /lib/libresolv.so.2
Reading symbols from /lib/libnsl.so.1...done.
Loaded symbols for /lib/libnsl.so.1
Reading symbols from /lib/libnss_files.so.2...done.
Loaded symbols for /lib/libnss_files.so.2
0x420292e5 in sigsuspend () from /lib/i686/libc.so.6

(gdb) thread 1
[Switching to thread 1 (Thread 1024 (LWP 14728))]#0  0x420292e5 in sigsuspend ()
   from /lib/i686/libc.so.6
(gdb) where
#0  0x420292e5 in sigsuspend () from /lib/i686/libc.so.6
#1  0x40031679 in __pthread_wait_for_restart_signal () from /lib/i686/libpthread.so.0
#2  0x4002e85a in pthread_join () from /lib/i686/libpthread.so.0
#3  0x0804a065 in main (argc=9, argv=0xbffff924) at pgbch.pgc:718
#4  0x42017499 in __libc_start_main () from /lib/i686/libc.so.6
(gdb) thread 2
[Switching to thread 2 (Thread 2049 (LWP 14729))]#0  0x420e0037 in poll ()
   from /lib/i686/libc.so.6
(gdb) where
#0  0x420e0037 in poll () from /lib/i686/libc.so.6
#1  0x4002ec70 in __pthread_manager () from /lib/i686/libpthread.so.0
(gdb) thread 3
[Switching to thread 3 (Thread 2051 (LWP 14732))]#0  0x420e0037 in poll ()
   from /lib/i686/libc.so.6
(gdb) where
#0  0x420e0037 in poll () from /lib/i686/libc.so.6
#1  0x40063b64 in pqSocketPoll () from /usr/local/pgsql/lib/libpq.so.3
#2  0x40063a85 in pqSocketCheck () from /usr/local/pgsql/lib/libpq.so.3
#3  0x400639b7 in pqWaitTimed () from /usr/local/pgsql/lib/libpq.so.3
#4  0x4006398d in pqWait () from /usr/local/pgsql/lib/libpq.so.3
#5  0x400618f2 in PQgetResult () from /usr/local/pgsql/lib/libpq.so.3
#6  0x40061c4b in PQexecFinish () from /usr/local/pgsql/lib/libpq.so.3
#7  0x4004447d in ECPGexecute () from /usr/local/pgsql/lib/libecpg.so.4
#8  0x400449d8 in ECPGdo () from /usr/local/pgsql/lib/libecpg.so.4
#9  0x080490d8 in doOne (arg=0x1) at pgbch.pgc:326
#10 0x4002efef in pthread_start_thread () from /lib/i686/libpthread.so.0


Attachment

Re: Postgres 7.4 : ECPG not Thread-safe

From
Michael Meskes
Date:
On Thu, Oct 09, 2003 at 04:42:18PM +0200, Thierry Missimilly wrote:
> I don't know if it is really link to Postgres and ECPG but if you
> modifiy pgbch.pgc in the way that the
> transaction is limited to "BEGIN; END; ", it will never hang.

Do you mean it only hangs if you do automatic transaction starting? I
mean if you use PGSQL implicit transactions and explicit BEGIN...END
blocks it works well, but if you let libecpg start the transaction and
just do a COMMIT every once in a while it is not?

> Well, i'm not an expert in Linux multi-thread, but it seems the thread

Neither am I, so I have no idea where to look.

Michael
--
Michael Meskes
Email: Michael at Fam-Meskes dot De
ICQ: 179140304, AIM/Yahoo: michaelmeskes, Jabber: meskes@jabber.org
Go SF 49ers! Go Rhein Fire! Use Debian GNU/Linux! Use PostgreSQL!

Re: Postgres 7.4 : ECPG not Thread-safe

From
Bruce Momjian
Date:
I am going to see if I can reproduce the hang.

---------------------------------------------------------------------------

Michael Meskes wrote:
> On Thu, Oct 09, 2003 at 04:42:18PM +0200, Thierry Missimilly wrote:
> > I don't know if it is really link to Postgres and ECPG but if you
> > modifiy pgbch.pgc in the way that the
> > transaction is limited to "BEGIN; END; ", it will never hang.
>
> Do you mean it only hangs if you do automatic transaction starting? I
> mean if you use PGSQL implicit transactions and explicit BEGIN...END
> blocks it works well, but if you let libecpg start the transaction and
> just do a COMMIT every once in a while it is not?
>
> > Well, i'm not an expert in Linux multi-thread, but it seems the thread
>
> Neither am I, so I have no idea where to look.
>
> Michael
> --
> Michael Meskes
> Email: Michael at Fam-Meskes dot De
> ICQ: 179140304, AIM/Yahoo: michaelmeskes, Jabber: meskes@jabber.org
> Go SF 49ers! Go Rhein Fire! Use Debian GNU/Linux! Use PostgreSQL!
>
> ---------------------------(end of broadcast)---------------------------
> TIP 4: Don't 'kill -9' the postmaster
>

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

Re: Postgres 7.4 : ECPG not Thread-safe

From
Thierry Missimilly
Date:

Michael Meskes wrote:

> On Thu, Oct 09, 2003 at 04:42:18PM +0200, Thierry Missimilly wrote:
> > I don't know if it is really link to Postgres and ECPG but if you
> > modifiy pgbch.pgc in the way that the
> > transaction is limited to "BEGIN; END; ", it will never hang.
>
> Do you mean it only hangs if you do automatic transaction starting? I
> mean if you use PGSQL implicit transactions and explicit BEGIN...END
> blocks it works well, but if you let libecpg start the transaction and
> just do a COMMIT every once in a while it is not?
>

Well, i'm wrong.
A pgbch (pgbench) transcation limited to :
BEGIN;
END;
Will hang too (with the same gdb stack trace), but i need to increase the
number of client to see it.

But, when the doOne() function is just doing :
    for (j = 0; j < 1000000; j++) { }
pgbch never hang.
In that case, except doConnect() the lib ecpg is not used at all by the
threads.


>
> > Well, i'm not an expert in Linux multi-thread, but it seems the thread
>
> Neither am I, so I have no idea where to look.
>
> Michael
> --
> Michael Meskes
> Email: Michael at Fam-Meskes dot De
> ICQ: 179140304, AIM/Yahoo: michaelmeskes, Jabber: meskes@jabber.org
> Go SF 49ers! Go Rhein Fire! Use Debian GNU/Linux! Use PostgreSQL!

Attachment

Re: Postgres 7.4 : ECPG not Thread-safe

From
Bruce Momjian
Date:
Thierry Missimilly wrote:
> Please enter a FULL description of your problem:
> ------------------------------------------------
> I think i have a Thread-safe problem. PostgreSQL developpers will find a
> test program  to reproduce it on their lab.
>
> I have, already sent this to pgsql-general and pgsql-hacker, but get
> back not answers. But neve mind.
>
> I've built Postgresql with the option --enable-thread-safety --with-tcl.
>
> And now run a pgbench like program call pgbch.pgc (attached with this
> mail).
>
> The main differences of pgbch.pgc are :
> 1) Pro*c code
> 2) Multi-threaded
> 3) Some specific code for Oracle
> 4) Some specific dynamic trace for debug
>

I have worked with this user and found they were using EXEC SQL from
different threads, but were not using the "AT" clause to force the
threads to use their own private connection, so there was no threading
bug in our code.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073