mirror of
https://github.com/postgres/postgres.git
synced 2025-06-04 00:02:37 -04:00
Add PQresultMemorySize function to report allocated size of a PGresult.
This number can be useful for application memory management, and the overhead to track it seems pretty trivial. Lars Kanis, reviewed by Pavel Stehule, some mods by me Discussion: https://postgr.es/m/fa16a288-9685-14f2-97c8-b8ac84365a4f@greiz-reinsdorf.de
This commit is contained in:
parent
e7a2217978
commit
2970afa6cf
@ -6387,6 +6387,32 @@ void *PQresultAlloc(PGresult *res, size_t nBytes);
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="libpq-pqresultmemorysize">
|
||||||
|
<term>
|
||||||
|
<function>PQresultMemorySize</function>
|
||||||
|
<indexterm>
|
||||||
|
<primary>PQresultMemorySize</primary>
|
||||||
|
</indexterm>
|
||||||
|
</term>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Retrieves the number of bytes allocated for
|
||||||
|
a <structname>PGresult</structname> object.
|
||||||
|
<synopsis>
|
||||||
|
size_t PQresultMemorySize(const PGresult *res);
|
||||||
|
</synopsis>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This value is the sum of all <function>malloc</function> requests
|
||||||
|
associated with the <structname>PGresult</structname> object, that is,
|
||||||
|
all the space that will be freed by <function>PQclear</function>.
|
||||||
|
This information can be useful for managing memory consumption.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="libpq-pqlibversion">
|
<varlistentry id="libpq-pqlibversion">
|
||||||
<term>
|
<term>
|
||||||
<function>PQlibVersion</function>
|
<function>PQlibVersion</function>
|
||||||
@ -6960,6 +6986,14 @@ void *PQinstanceData(const PGconn *conn, PGEventProc proc);
|
|||||||
int PQresultSetInstanceData(PGresult *res, PGEventProc proc, void *data);
|
int PQresultSetInstanceData(PGresult *res, PGEventProc proc, void *data);
|
||||||
</synopsis>
|
</synopsis>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Beware that any storage represented by <parameter>data</parameter>
|
||||||
|
will not be accounted for by <function>PQresultMemorySize</function>,
|
||||||
|
unless it is allocated using <function>PQresultAlloc</function>.
|
||||||
|
(Doing so is recommendable because it eliminates the need to free
|
||||||
|
such storage explicitly when the result is destroyed.)
|
||||||
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
@ -172,3 +172,4 @@ PQsslAttribute 169
|
|||||||
PQsetErrorContextVisibility 170
|
PQsetErrorContextVisibility 170
|
||||||
PQresultVerboseErrorMessage 171
|
PQresultVerboseErrorMessage 171
|
||||||
PQencryptPasswordConn 172
|
PQencryptPasswordConn 172
|
||||||
|
PQresultMemorySize 173
|
||||||
|
@ -51,7 +51,7 @@ static int static_client_encoding = PG_SQL_ASCII;
|
|||||||
static bool static_std_strings = false;
|
static bool static_std_strings = false;
|
||||||
|
|
||||||
|
|
||||||
static PGEvent *dupEvents(PGEvent *events, int count);
|
static PGEvent *dupEvents(PGEvent *events, int count, size_t *memSize);
|
||||||
static bool pqAddTuple(PGresult *res, PGresAttValue *tup,
|
static bool pqAddTuple(PGresult *res, PGresAttValue *tup,
|
||||||
const char **errmsgp);
|
const char **errmsgp);
|
||||||
static bool PQsendQueryStart(PGconn *conn);
|
static bool PQsendQueryStart(PGconn *conn);
|
||||||
@ -166,6 +166,7 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
|
|||||||
result->curBlock = NULL;
|
result->curBlock = NULL;
|
||||||
result->curOffset = 0;
|
result->curOffset = 0;
|
||||||
result->spaceLeft = 0;
|
result->spaceLeft = 0;
|
||||||
|
result->memorySize = sizeof(PGresult);
|
||||||
|
|
||||||
if (conn)
|
if (conn)
|
||||||
{
|
{
|
||||||
@ -193,7 +194,8 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
|
|||||||
/* copy events last; result must be valid if we need to PQclear */
|
/* copy events last; result must be valid if we need to PQclear */
|
||||||
if (conn->nEvents > 0)
|
if (conn->nEvents > 0)
|
||||||
{
|
{
|
||||||
result->events = dupEvents(conn->events, conn->nEvents);
|
result->events = dupEvents(conn->events, conn->nEvents,
|
||||||
|
&result->memorySize);
|
||||||
if (!result->events)
|
if (!result->events)
|
||||||
{
|
{
|
||||||
PQclear(result);
|
PQclear(result);
|
||||||
@ -344,7 +346,8 @@ PQcopyResult(const PGresult *src, int flags)
|
|||||||
/* Wants to copy PGEvents? */
|
/* Wants to copy PGEvents? */
|
||||||
if ((flags & PG_COPYRES_EVENTS) && src->nEvents > 0)
|
if ((flags & PG_COPYRES_EVENTS) && src->nEvents > 0)
|
||||||
{
|
{
|
||||||
dest->events = dupEvents(src->events, src->nEvents);
|
dest->events = dupEvents(src->events, src->nEvents,
|
||||||
|
&dest->memorySize);
|
||||||
if (!dest->events)
|
if (!dest->events)
|
||||||
{
|
{
|
||||||
PQclear(dest);
|
PQclear(dest);
|
||||||
@ -379,17 +382,20 @@ PQcopyResult(const PGresult *src, int flags)
|
|||||||
* Copy an array of PGEvents (with no extra space for more).
|
* Copy an array of PGEvents (with no extra space for more).
|
||||||
* Does not duplicate the event instance data, sets this to NULL.
|
* Does not duplicate the event instance data, sets this to NULL.
|
||||||
* Also, the resultInitialized flags are all cleared.
|
* Also, the resultInitialized flags are all cleared.
|
||||||
|
* The total space allocated is added to *memSize.
|
||||||
*/
|
*/
|
||||||
static PGEvent *
|
static PGEvent *
|
||||||
dupEvents(PGEvent *events, int count)
|
dupEvents(PGEvent *events, int count, size_t *memSize)
|
||||||
{
|
{
|
||||||
PGEvent *newEvents;
|
PGEvent *newEvents;
|
||||||
|
size_t msize;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!events || count <= 0)
|
if (!events || count <= 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
newEvents = (PGEvent *) malloc(count * sizeof(PGEvent));
|
msize = count * sizeof(PGEvent);
|
||||||
|
newEvents = (PGEvent *) malloc(msize);
|
||||||
if (!newEvents)
|
if (!newEvents)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -407,8 +413,10 @@ dupEvents(PGEvent *events, int count)
|
|||||||
free(newEvents);
|
free(newEvents);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
msize += strlen(events[i].name) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*memSize += msize;
|
||||||
return newEvents;
|
return newEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,9 +575,12 @@ pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary)
|
|||||||
*/
|
*/
|
||||||
if (nBytes >= PGRESULT_SEP_ALLOC_THRESHOLD)
|
if (nBytes >= PGRESULT_SEP_ALLOC_THRESHOLD)
|
||||||
{
|
{
|
||||||
block = (PGresult_data *) malloc(nBytes + PGRESULT_BLOCK_OVERHEAD);
|
size_t alloc_size = nBytes + PGRESULT_BLOCK_OVERHEAD;
|
||||||
|
|
||||||
|
block = (PGresult_data *) malloc(alloc_size);
|
||||||
if (!block)
|
if (!block)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
res->memorySize += alloc_size;
|
||||||
space = block->space + PGRESULT_BLOCK_OVERHEAD;
|
space = block->space + PGRESULT_BLOCK_OVERHEAD;
|
||||||
if (res->curBlock)
|
if (res->curBlock)
|
||||||
{
|
{
|
||||||
@ -594,6 +605,7 @@ pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary)
|
|||||||
block = (PGresult_data *) malloc(PGRESULT_DATA_BLOCKSIZE);
|
block = (PGresult_data *) malloc(PGRESULT_DATA_BLOCKSIZE);
|
||||||
if (!block)
|
if (!block)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
res->memorySize += PGRESULT_DATA_BLOCKSIZE;
|
||||||
block->next = res->curBlock;
|
block->next = res->curBlock;
|
||||||
res->curBlock = block;
|
res->curBlock = block;
|
||||||
if (isBinary)
|
if (isBinary)
|
||||||
@ -615,6 +627,18 @@ pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary)
|
|||||||
return space;
|
return space;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PQresultMemorySize -
|
||||||
|
* Returns total space allocated for the PGresult.
|
||||||
|
*/
|
||||||
|
size_t
|
||||||
|
PQresultMemorySize(const PGresult *res)
|
||||||
|
{
|
||||||
|
if (!res)
|
||||||
|
return 0;
|
||||||
|
return res->memorySize;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pqResultStrdup -
|
* pqResultStrdup -
|
||||||
* Like strdup, but the space is subsidiary PGresult space.
|
* Like strdup, but the space is subsidiary PGresult space.
|
||||||
@ -927,6 +951,8 @@ pqAddTuple(PGresult *res, PGresAttValue *tup, const char **errmsgp)
|
|||||||
realloc(res->tuples, newSize * sizeof(PGresAttValue *));
|
realloc(res->tuples, newSize * sizeof(PGresAttValue *));
|
||||||
if (!newTuples)
|
if (!newTuples)
|
||||||
return false; /* malloc or realloc failed */
|
return false; /* malloc or realloc failed */
|
||||||
|
res->memorySize +=
|
||||||
|
(newSize - res->tupArrSize) * sizeof(PGresAttValue *);
|
||||||
res->tupArrSize = newSize;
|
res->tupArrSize = newSize;
|
||||||
res->tuples = newTuples;
|
res->tuples = newTuples;
|
||||||
}
|
}
|
||||||
|
@ -516,6 +516,7 @@ extern PGresult *PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
|
|||||||
extern PGresult *PQcopyResult(const PGresult *src, int flags);
|
extern PGresult *PQcopyResult(const PGresult *src, int flags);
|
||||||
extern int PQsetResultAttrs(PGresult *res, int numAttributes, PGresAttDesc *attDescs);
|
extern int PQsetResultAttrs(PGresult *res, int numAttributes, PGresAttDesc *attDescs);
|
||||||
extern void *PQresultAlloc(PGresult *res, size_t nBytes);
|
extern void *PQresultAlloc(PGresult *res, size_t nBytes);
|
||||||
|
extern size_t PQresultMemorySize(const PGresult *res);
|
||||||
extern int PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len);
|
extern int PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len);
|
||||||
|
|
||||||
/* Quoting strings before inclusion in queries. */
|
/* Quoting strings before inclusion in queries. */
|
||||||
|
@ -208,6 +208,8 @@ struct pg_result
|
|||||||
PGresult_data *curBlock; /* most recently allocated block */
|
PGresult_data *curBlock; /* most recently allocated block */
|
||||||
int curOffset; /* start offset of free space in block */
|
int curOffset; /* start offset of free space in block */
|
||||||
int spaceLeft; /* number of free bytes remaining in block */
|
int spaceLeft; /* number of free bytes remaining in block */
|
||||||
|
|
||||||
|
size_t memorySize; /* total space allocated for this PGresult */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* PGAsyncStatusType defines the state of the query-execution state machine */
|
/* PGAsyncStatusType defines the state of the query-execution state machine */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user