Обсуждение: Bug #933: Too many inserts crash server

Поиск
Список
Период
Сортировка

Bug #933: Too many inserts crash server

От
pgsql-bugs@postgresql.org
Дата:
Mark Pether (mutex@redsheriff.com) reports a bug with a severity of 2
The lower the number the more severe it is.

Short Description
Too many inserts crash server

Long Description
If I create an external C function consisting of a
simple loop that inserts 250000 records into a table
the server process eventually crashes.

Actually the number of inserts appears to be dependant
upon memory consumption by SPI manager. (so your milage
may vary)

The workaround I found involves periodically calling
SPI_finish + SPI_connect to bounce the manager.

I have included code to illustrate the problem and my workaround.

My platform is:
Intel P3
Mandrake 8.2
512mb RAM
Postgres 7.3
plenty of disk free.

Sample Code
postgres initialisation:

create table triple (a int, b int, c int);
create or replace function crashme() returns void as 'pgtest.so' language 'c';
create or replace function dontcrashme() returns void as 'pgtest.so' language 'c';

the code:

#include <string.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include "avl.h"
#include "postgres.h"
#include "fmgr.h"
#include "executor/spi.h"
#include "utils/date.h"
#include "utils/datetime.h"

Datum crashme(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(crashme);
Datum crashme(PG_FUNCTION_ARGS)
{
    const char *DEBUG_NAME = "crashme(): ";

    char *query = "insert into triple values (100, 200, 300)";

    if (SPI_connect() == SPI_OK_CONNECT)
    {
        int i;
        int exec_result;

        for (i=0; i<250000; i++)
        {
            if (!(i%16384))
            {
                elog(INFO, "%sstill alive", DEBUG_NAME);
            }

            if ((exec_result = SPI_exec(query, 0)) != SPI_OK_INSERT)
            {
                elog(ERROR, "%sinsert failed (%d)", DEBUG_NAME, exec_result);
                break;
            }
        }

        SPI_finish();
    }
    else
    {
        elog(ERROR, "%scould not connect", DEBUG_NAME);
    }

    PG_RETURN_NULL();
}

Datum dontcrashme(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(dontcrashme);
Datum dontcrashme(PG_FUNCTION_ARGS)
{
    const char *DEBUG_NAME = "dontcrashme(): ";

    char *query = "insert into triple values (100, 200, 300)";

    if (SPI_connect() == SPI_OK_CONNECT)
    {
        int i;
        int exec_result;

        for (i=0; i<250000; i++)
        {
            if (!(i%16384))
            {
                elog(INFO, "%sbouncing SPI manager", DEBUG_NAME);
                elog(INFO, "%sSPI_finish (%s)",
                        DEBUG_NAME, (SPI_finish() == SPI_OK_FINISH) ? "good" : "bad");
                elog(INFO, "%sSPI_connect (%s)",
                        DEBUG_NAME, (SPI_connect() == SPI_OK_CONNECT) ? "good" : "bad");
            }

            if ((exec_result = SPI_exec(query, 0)) != SPI_OK_INSERT)
            {
                elog(ERROR, "%sinsert failed (%d)", DEBUG_NAME, exec_result);
                break;
            }
        }

        SPI_finish();
    }
    else
    {
        elog(ERROR, "%scould not connect", DEBUG_NAME);
    }

    PG_RETURN_NULL();
}

No file was uploaded with this report

Re: Bug #933: Too many inserts crash server

От
Tom Lane
Дата:
pgsql-bugs@postgresql.org writes:
> If I create an external C function consisting of a
> simple loop that inserts 250000 records into a table
> the server process eventually crashes.

The memory leak goes away if you add

    SPI_freetuptable(SPI_tuptable);

after the SPI_exec() call.

I am not sure whether to consider this an SPI bug or not.  It's possibly
surprising that a non-SELECT query generates an empty tuple table; but
on the other hand, it's hard to say that no non-SELECT query can ever
generate a tuple table.  (EXPLAIN is a counterexample, for instance.)

It may be better to document that you should always do
SPI_freetuptable() no matter what kind of query you executed.

            regards, tom lane

Re: Bug #933: Too many inserts crash server

От
Mark Pether
Дата:
Ok,

Thanks for advice I'll add SPI_freetuple() to my program.

I must say I had a difficult time trying to work around this problem
(couldn't find any docs),
so you may want to add note into Postgres 7.3 Server Programming docs.

By the way, my workaround successfully used was:

 SPI_push();
 SPI_connect();

do loop
    if loop % 16834 == 0
       SPI_finish()
       SPI_connect()
    end if
end loop;

SPI_finish()
SPI_pop();

This also freed memory, but doesn't look nice and uses the undoc'd push
and pop calls.

Regards,
Mark Pether.



Tom Lane wrote:

>pgsql-bugs@postgresql.org writes:
>
>
>>If I create an external C function consisting of a
>>simple loop that inserts 250000 records into a table
>>the server process eventually crashes.
>>
>>
>
>The memory leak goes away if you add
>
>    SPI_freetuptable(SPI_tuptable);
>
>after the SPI_exec() call.
>
>I am not sure whether to consider this an SPI bug or not.  It's possibly
>surprising that a non-SELECT query generates an empty tuple table; but
>on the other hand, it's hard to say that no non-SELECT query can ever
>generate a tuple table.  (EXPLAIN is a counterexample, for instance.)
>
>It may be better to document that you should always do
>SPI_freetuptable() no matter what kind of query you executed.
>
>            regards, tom lane
>
>
>
>

Re: Bug #933: Too many inserts crash server

От
Mark Pether
Дата:
I meant SPI_freetuptable() by the way  :-)

Regards,
Mark.