From: Daniele Varrazzo Date: Fri, 8 Jan 2021 02:54:36 +0000 (+0100) Subject: Some refcount care in tight loops X-Git-Tag: 3.0.dev0~194 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7708dc9a41008699e09e5cd8e337c8b1bed9f993;p=thirdparty%2Fpsycopg.git Some refcount care in tight loops --- diff --git a/psycopg3_c/psycopg3_c/_psycopg3/copy.pyx b/psycopg3_c/psycopg3_c/_psycopg3/copy.pyx index 059569f91..009e6ea29 100644 --- a/psycopg3_c/psycopg3_c/_psycopg3/copy.pyx +++ b/psycopg3_c/psycopg3_c/_psycopg3/copy.pyx @@ -42,11 +42,12 @@ def format_row_binary( cdef uint32_t besize cdef char *buf cdef int i + fmt = FORMAT_BINARY for i in range(rowlen): item = row[i] if item is not None: - dumper = tx.get_dumper(item, FORMAT_BINARY) + dumper = tx.get_dumper(item, fmt) if isinstance(dumper, CDumper): # A cdumper can resize if necessary and copy in place size = (dumper).cdump(item, out, pos + sizeof(besize)) @@ -56,7 +57,7 @@ def format_row_binary( memcpy(target + pos, &besize, sizeof(besize)) else: # A Python dumper, gotta call it and extract its juices - b = dumper.dump(item) + b = PyObject_CallFunctionObjArgs(dumper.dump, item, NULL) _buffer_as_string_and_size(b, &buf, &size) target = CDumper.ensure_size(out, pos, size + sizeof(besize)) besize = htobe32(size) @@ -98,6 +99,7 @@ def format_row_text( cdef unsigned char *target cdef int nesc = 0 cdef int with_tab + fmt = FORMAT_TEXT for i in range(rowlen): # Include the tab before the data, so it gets included in the resizes @@ -115,14 +117,14 @@ def format_row_text( pos += 2 continue - dumper = tx.get_dumper(item, FORMAT_TEXT) + dumper = tx.get_dumper(item, fmt) if isinstance(dumper, CDumper): # A cdumper can resize if necessary and copy in place size = (dumper).cdump(item, out, pos + with_tab) target = PyByteArray_AS_STRING(out) + pos else: # A Python dumper, gotta call it and extract its juices - b = dumper.dump(item) + b = PyObject_CallFunctionObjArgs(dumper.dump, item, NULL) _buffer_as_string_and_size(b, &buf, &size) target = CDumper.ensure_size(out, pos, size + with_tab) memcpy(target + with_tab, buf, size) diff --git a/psycopg3_c/psycopg3_c/_psycopg3/transform.pyx b/psycopg3_c/psycopg3_c/_psycopg3/transform.pyx index 8d9ea6ff3..1d5c21e32 100644 --- a/psycopg3_c/psycopg3_c/_psycopg3/transform.pyx +++ b/psycopg3_c/psycopg3_c/_psycopg3/transform.pyx @@ -247,18 +247,13 @@ cdef class Transformer: Py_INCREF(record) PyList_SET_ITEM(records, row - row0, record) - cdef RowLoader loader - cdef CLoader cloader - cdef object pyloader + cdef PyObject *loader # borrowed RowLoader cdef PyObject *brecord # borrowed - for col in range(self._nfields): - # TODO: the is some visible python churn around this lookup. - # replace with a C array of borrowed references pointing to - # the cloader.cload function pointer - loader = self._row_loaders[col] - if loader.cloader is not None: - cloader = loader.cloader + row_loaders = self._row_loaders # avoid an incref/decref per item + for col in range(self._nfields): + loader = PyList_GET_ITEM(row_loaders, col) + if (loader).cloader is not None: for row in range(row0, row1): brecord = PyList_GET_ITEM(records, row - row0) attval = &(ires.tuples[row][col]) @@ -267,13 +262,12 @@ cdef class Transformer: PyTuple_SET_ITEM(brecord, col, None) continue - pyval = loader.cloader.cload(attval.value, attval.len) + pyval = (loader).cloader.cload( + attval.value, attval.len) Py_INCREF(pyval) PyTuple_SET_ITEM(brecord, col, pyval) else: - pyloader = loader.pyloader - for row in range(row0, row1): brecord = PyList_GET_ITEM(records, row - row0) attval = &(ires.tuples[row][col]) @@ -285,7 +279,7 @@ cdef class Transformer: # TODO: no copy b = attval.value[:attval.len] pyval = PyObject_CallFunctionObjArgs( - pyloader, b, NULL) + (loader).pyloader, b, NULL) Py_INCREF(pyval) PyTuple_SET_ITEM(brecord, col, pyval) @@ -302,13 +296,15 @@ cdef class Transformer: # cheeky access to the internal PGresult structure cdef pg_result_int *ires = res - cdef RowLoader loader + cdef PyObject *loader # borrowed RowLoader cdef int col cdef PGresAttValue *attval cdef const char *val cdef object record # not 'tuple' as it would check on assignment record = PyTuple_New(self._nfields) + row_loaders = self._row_loaders # avoid an incref/decref per item + for col in range(self._nfields): attval = &(ires.tuples[row][col]) if attval.len == -1: # NULL_LEN @@ -316,18 +312,15 @@ cdef class Transformer: PyTuple_SET_ITEM(record, col, None) continue - # TODO: the is some visible python churn around this lookup. - # replace with a C array of borrowed references pointing to - # the cloader.cload function pointer - loader = self._row_loaders[col] val = attval.value - if loader.cloader is not None: - pyval = loader.cloader.cload(val, attval.len) + loader = PyList_GET_ITEM(row_loaders, col) + if (loader).cloader is not None: + pyval = (loader).cloader.cload(val, attval.len) else: # TODO: no copy b = val[:attval.len] pyval = PyObject_CallFunctionObjArgs( - loader.pyloader, b, NULL) + (loader).pyloader, b, NULL) Py_INCREF(pyval) PyTuple_SET_ITEM(record, col, pyval)