Re: libpq++
От | Justin Banks |
---|---|
Тема | Re: libpq++ |
Дата | |
Msg-id | 15084.54539.44529.709222@dervish.mr-boo.com обсуждение исходный текст |
Ответ на | Re: libpq++ (Bruce Momjian <pgman@candle.pha.pa.us>) |
Список | pgsql-interfaces |
>>>>> "Bruce" == Bruce Momjian <pgman@candle.pha.pa.us> writes: Bruce> I am not so much the libpq++ maintainer as the one who applies Bruce> people's patches. There is an interfaces listthat would love to Bruce> hear about your work. I am CC'ing them on this. We certainly need Bruce> libpq++ improvements. If you would prefer not to deal with the Bruce> interfaces list, send something to me and I will send it overthere. Here's what I've done. The following code will create a number of different connections to the B.E., even though there's no reason to have more than one. This prevents one from inheriting PgDatabase, and then creating an array of 100 or so of those objects. #include <iostream.h> #include <stdlib.h> #include <libpq++.h> class base : public PgDatabase { public: base() { cout << "base class instantiating" << endl; Connect("host=dbdbname=golem user=golemadmin password=bleen"); } virtual ~base() { cout << "Base class destructing"<< endl; } }; class derived : public base { public: derived() { cout << "derived class instantiating" << endl; } ~derived() { cout << "derived class destructing" << endl; } }; int main(int argc, char* argv[]) { int cnt, tuples; derived* classes, *ptr; derived single; if(argc > 1) cnt = atoi(argv[1]); else cnt = 5; cout << "getting array of " << cnt << " objects" << endl; classes = new derived[cnt]; cout << "array allocated, sleeping for validation" << endl; sleep(5); for(int i = 0; i < cnt; i++) { cout << "testingobject " << i << endl; ptr = &(classes[i]); ptr->Exec("select * from defaults"); tuples = ptr->Tuples(); cout << "got " << tuples << " tuples" << endl; for(int j = 0; j < tuples; j++) { cout << "4th field is " << ptr->GetValue(j,4) << endl; } } delete[] classes; cout << "aggregates deleted" << endl; single.Exec("select table_name from tables limit 1"); cout << "exec of single finished"<< endl; cout << "value is " << single.GetValue(0, 0) << endl; exit(0); } What I'd like to have happen is for a total of one connection to the database to be made, and have all these objects share that connection transparently. I made this happen by using a shared memory segment to store the connection pointer. Here's the diff. It doesn't seem to break anything, but then again, my coverage is rather limited at this point. Diff follows : --- pgconnection.cc.orig Sun Apr 29 16:09:02 2001 +++ pgconnection.cc Sun Apr 29 21:35:36 2001 @@ -17,7 +17,6 @@#include "pgconnection.h" -// ****************************************************************//// PgConnection Implementation @@ -54,7 +53,15 @@// close down the connection if there is onevoid PgConnection::CloseConnection() { - // if the connection is open, close it first +#if USING_SYSV_IPC == 1 + struct shmid_ds shminfo; + + shmctl(shmid, IPC_STAT, &shminfo); + // + // if we're the only one left ... + // + if(shminfo.shm_nattch == 1) { +#endif if ( pgCloseConnection ) { if(pgResult) PQclear(pgResult); pgResult=NULL; @@ -62,6 +69,10 @@ pgConn=NULL; pgCloseConnection=0; } +#if USING_SYSV_IPC == 1 + } + shmdt(addr); +#endif} @@ -69,11 +80,60 @@// establish a connection to a backendConnStatusType PgConnection::Connect(const char* conninfo){ +#if USING_SYSV_IPC == 1 + int key = (int)getpid(); + struct shmid_ds shminfo; +#endif + // if the connection is open, close it first CloseConnection(); // Connect to the database +#if USING_SYSV_IPC == 1 + if((shmid = shmget(key, sizeof(addr), IPC_CREAT|SHM_W|SHM_R)) >= 0) { + if((addr = (int*)shmat(shmid, 0, 0)) > 0) { + // + // now, we have our segment. If we're the first attacher, then we need + // to do the connect. If we're not the first attacher, then the + // connection is already made, we just need to check and make sure + // it's okay, connecting again if we have to. + // + if(shmctl(shmid, IPC_STAT, &shminfo) == 0) { + if(shminfo.shm_nattch == 1) { + pgConn = PQconnectdb(conninfo); + *addr = (int)pgConn; + } + else { + pgConn = (PGconn*)*addr; + if(Status() == CONNECTION_BAD) { + pgConn = PQconnectdb(conninfo); + *addr = (int)pgConn; + } + } + } + else { + // + // fallback to safe connection + // + pgConn = PQconnectdb(conninfo); + } + } + else { + // + // fallback to safe connection + // + pgConn = PQconnectdb(conninfo); + } + } + else { + // + // fallback to safe connection + // + pgConn = PQconnectdb(conninfo); + } +#else pgConn = PQconnectdb(conninfo); +#endif // Now we have a connection we must close (even if it's bad!) pgCloseConnection = 1; --- pgconnection.h.orig Sun Apr 29 16:09:54 2001 +++ pgconnection.h Sun Apr 29 17:07:57 2001 @@ -46,6 +46,15 @@using namespace std;#endif +#if HAVE_SYS_SHM_H == 1 && HAVE_SYS_IPC_H == 1 + #include <sys/types.h> + #include <sys/ipc.h> + #include <sys/shm.h> + #include <unistd.h> + #define USING_SYSV_IPC 1 +#else + #define USING_SYSV_IPC 0 +#endif// ****************************************************************// @@ -91,6 +100,9 @@// so make copy constructor and assignment op private. PgConnection(const PgConnection&); PgConnection&operator= (const PgConnection&); +#if USING_SYSV_IPC == 1 + int shmid, *addr; +#endif};#endif // PGCONNECTION_H I think that's it. I've got more at work, so I may have missed something, but I don't think so. -justinb -- Justin Banks @ home Distrust any enterprise that requires new clothes. -Thoreau
В списке pgsql-interfaces по дате отправления: