On Wed, 2009-08-26 at 16:51 -0700, WANGRUNGVICHAISRI, SHIVESH wrote: > However, I still insist that potentially the PostgreSQL community might > want to look into why making use of libpq causes the client program's > memory consumption to keep growing. This can be easily observed using > the earlier test program uploaded to here:
I've looked into it ... and concluded I'm an idiot. Your query is: SELECT * FROM tmp WHERE id>615; (where "615" could be any value < 1000) For some reason I'd been thinking all along that the query was grabbing *no* *more* *than* *1000* *rows* ... but of course it's not, it's grabbing all but some lower fraction of the rows. So the result set gets bigger and bigger over time until the program doesn't have enough RAM to hold the result set and it crashes. The attached (adjusted) test program no longer has any issues with growth or runtime. There's no libpq issue here, only a my-brain-is-only-semifunctional issue. So, it seems we've eliminated any issue with leakage in the PostgreSQL server backend, you've isolated your problem to PostGIS, and we've found that the growth of the test program was libpq working as designed. It looks like we're done here. -- Craig Ringer
// Standard C++ headers #include <iostream> #include <sstream> #include <stdexcept> // PostgreSQL libpq headers #include "libpq-fe.h" #include "libpq/libpq-fs.h" // Intel TBB header for threading #include <tbb/tbb_thread.h> #include <tbb/spin_mutex.h> #include <cstdlib> #if defined(_WIN32) # include <windows.h> # define sleep Sleep #else # include <unistd.h> #endif class TestException: public std::exception { std::string m_what; public: TestException(const std::string& what) : m_what(what) { } ~TestException() throw() { } virtual const char* what() const throw() { return "My exception happened"; } }; // Flag used to control thread exit static bool terminate = false; // This class does an insert into the test table struct Inserter { void operator()() { // Establish a connection PGconn* conn = PQconnectdb("user=postgres password=1234"); // Insert data into table indefinitely int i=0; while(!terminate) { // SQL Statement std::stringstream insert; insert << "INSERT INTO tmp (value) VALUES (" << i%250 << ");"; std::string insertStr = insert.str(); const char* c_str = insertStr.c_str(); // Execute query PGresult* res=PQexec(conn,c_str); if (PQresultStatus(res) == PGRES_FATAL_ERROR) { std::cerr << "Error in inserting data:\nError code: " << PQresStatus(PQresultStatus(res)) << "Error Message: " << PQerrorMessage(conn); PQclear(res); PQfinish(conn); throw TestException( "Inserter::PQexec() failed." ); } PQclear(res); // Increment index i++; } PQfinish(conn); } }; struct Queryer { void operator()() { // Establish a connection PGconn* conn = PQconnectdb("user=postgres password=1234"); // Retrieve data from the test table indefinitely int i=1; while (!terminate) { // SQL statement - read the top 1000 values off `tmp' std::stringstream query; query << "SELECT * FROM tmp WHERE id > (SELECT last_value - 1000 FROM tmp_id_seq);"; std::string queryStr = query.str(); const char* c_str = queryStr.c_str(); // Execute query PGresult* res=PQexec(conn, c_str); if (PQresultStatus(res) == PGRES_FATAL_ERROR) { std::cerr << "Error in searching data:\nError code: " << PQresStatus(PQresultStatus(res)) << "Error Message: " << PQerrorMessage(conn); PQclear(res); PQfinish(conn); throw TestException( "Queryer::PQexec() failed." ); } PQclear(res); // Increment index i++; } PQfinish(conn); } }; int main(int argc, char * argv[]) { int sleep_time = 0; if (argc > 1) { sleep_time = atoi(argv[1]); } std::cerr << std::string("Libpq is ") + (PQisthreadsafe() ? "" : "not ") + "threadsafe" << std::endl; // Establish a connection PGconn* conn = PQconnectdb("user=postgres password=1234"); // Create the test table std::cout << "Creating table...\n"; PGresult* res=PQexec(conn,"DROP TABLE IF EXISTS tmp; CREATE TABLE tmp (id SERIAL8 PRIMARY KEY,value INT);"); if (PQresultStatus(res) == PGRES_FATAL_ERROR) { std::cerr << "Error in Creating table:\nError code: " << PQresStatus(PQresultStatus(res)) << "Error Message: " << PQerrorMessage(conn); PQclear(res); PQfinish(conn); return 1; } // Clear and close the current connection PQclear(res); PQfinish(conn); // Launch thread that does INSERT std::cout << "Starting table filling thread...\n"; Inserter inserter; tbb::tbb_thread inserter_thread(inserter); // Launch thread that does SELECT ...This thread causes memory in postgres.exe to slowly go up indefinitely std::cout << "Starting table searching thread...\n"; Queryer selector; tbb::tbb_thread selector_thread(selector); // run for timer if (sleep_time) { sleep( sleep_time ); terminate = true; } inserter_thread.join(); selector_thread.join(); // and terminate return 0; }
SandBox: main.cpp g++ -o SandBox -g3 -I tbb22_20090809oss/include -L tbb22_20090809oss/build/linux_ia32_gcc_cc4.3.3_libc2.9_kernel2.6.28_debug -I /usr/include/postgresql -ltbb_debug -lpq -lpthread main.cpp run: SandBox LD_LIBRARY_PATH=tbb22_20090809oss/build/linux_ia32_gcc_cc4.3.3_libc2.9_kernel2.6.28_debug ./SandBox valgrind: SandBox LD_LIBRARY_PATH=tbb22_20090809oss/build/linux_ia32_gcc_cc4.3.3_libc2.9_kernel2.6.28_debug valgrind --leak-check=full --show-reachable=yes ./SandBox
-- Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-bugs