From 0b5bdccf3ae1233a032c525bc809c84eed3520d1 Mon Sep 17 00:00:00 2001 From: Iris <58442094+sleepyStick@users.noreply.github.com> Date: Mon, 3 Jul 2023 09:15:04 -0700 Subject: [PATCH] PYTHON-3729 use PyObject_GetAddr instead of PyObject_GetAddrString (#1281) --- bson/_cbsonmodule.c | 117 +++++++++++++++++++++++++++++--------- pymongo/_cmessagemodule.c | 34 ++++++++--- 2 files changed, 116 insertions(+), 35 deletions(-) diff --git a/bson/_cbsonmodule.c b/bson/_cbsonmodule.c index 68ea6b63c..c26ad252c 100644 --- a/bson/_cbsonmodule.c +++ b/bson/_cbsonmodule.c @@ -56,6 +56,20 @@ struct module_state { PyObject* _min_datetime_ms; PyObject* _max_datetime_ms; PyObject* _type_marker_str; + PyObject* _flags_str; + PyObject* _pattern_str; + PyObject* _encoder_map_str; + PyObject* _decoder_map_str; + PyObject* _fallback_encoder_str; + PyObject* _raw_str; + PyObject* _subtype_str; + PyObject* _binary_str; + PyObject* _scope_str; + PyObject* _inc_str; + PyObject* _time_str; + PyObject* _bid_str; + PyObject* _replace_str; + PyObject* _astimezone_str; }; #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) @@ -219,7 +233,7 @@ static int _write_element_to_buffer(PyObject* self, buffer_t buffer, /* Write a RawBSONDocument to the buffer. * Returns the number of bytes written or 0 on failure. */ -static int write_raw_doc(buffer_t buffer, PyObject* raw); +static int write_raw_doc(buffer_t buffer, PyObject* raw, PyObject* _raw); /* Date stuff */ static PyObject* datetime_from_millis(long long millis) { @@ -468,8 +482,24 @@ static int _load_python_objects(PyObject* module) { PyObject* compiled = NULL; struct module_state *state = GETSTATE(module); - /* Python str for faster _type_marker check */ - state->_type_marker_str = PyUnicode_FromString("_type_marker"); + /* Cache commonly used attribute names to improve performance. */ + if (!((state->_type_marker_str = PyUnicode_FromString("_type_marker")) && + (state->_flags_str = PyUnicode_FromString("flags")) && + (state->_pattern_str = PyUnicode_FromString("pattern")) && + (state->_encoder_map_str = PyUnicode_FromString("_encoder_map")) && + (state->_decoder_map_str = PyUnicode_FromString("_decoder_map")) && + (state->_fallback_encoder_str = PyUnicode_FromString("_fallback_encoder")) && + (state->_raw_str = PyUnicode_FromString("raw")) && + (state->_subtype_str = PyUnicode_FromString("subtype")) && + (state->_binary_str = PyUnicode_FromString("binary")) && + (state->_scope_str = PyUnicode_FromString("scope")) && + (state->_inc_str = PyUnicode_FromString("inc")) && + (state->_time_str = PyUnicode_FromString("time")) && + (state->_bid_str = PyUnicode_FromString("bid")) && + (state->_replace_str = PyUnicode_FromString("replace")) && + (state->_astimezone_str = PyUnicode_FromString("astimezone")))) { + return 1; + } if (_load_object(&state->Binary, "bson.binary", "Binary") || _load_object(&state->Code, "bson.code", "Code") || @@ -555,25 +585,25 @@ static long _type_marker(PyObject* object, PyObject* _type_marker_str) { * Return 1 on success. options->document_class is a new reference. * Return 0 on failure. */ -int cbson_convert_type_registry(PyObject* registry_obj, type_registry_t* registry) { +int cbson_convert_type_registry(PyObject* registry_obj, type_registry_t* registry, PyObject* _encoder_map_str, PyObject* _decoder_map_str, PyObject* _fallback_encoder_str) { registry->encoder_map = NULL; registry->decoder_map = NULL; registry->fallback_encoder = NULL; registry->registry_obj = NULL; - registry->encoder_map = PyObject_GetAttrString(registry_obj, "_encoder_map"); + registry->encoder_map = PyObject_GetAttr(registry_obj, _encoder_map_str); if (registry->encoder_map == NULL) { goto fail; } registry->is_encoder_empty = (PyDict_Size(registry->encoder_map) == 0); - registry->decoder_map = PyObject_GetAttrString(registry_obj, "_decoder_map"); + registry->decoder_map = PyObject_GetAttr(registry_obj, _decoder_map_str); if (registry->decoder_map == NULL) { goto fail; } registry->is_decoder_empty = (PyDict_Size(registry->decoder_map) == 0); - registry->fallback_encoder = PyObject_GetAttrString(registry_obj, "_fallback_encoder"); + registry->fallback_encoder = PyObject_GetAttr(registry_obj, _fallback_encoder_str); if (registry->fallback_encoder == NULL) { goto fail; } @@ -597,6 +627,7 @@ fail: */ int convert_codec_options(PyObject* self, PyObject* options_obj, codec_options_t* options) { PyObject* type_registry_obj = NULL; + struct module_state *state = GETSTATE(self); long type_marker; options->unicode_decode_error_handler = NULL; @@ -613,13 +644,13 @@ int convert_codec_options(PyObject* self, PyObject* options_obj, codec_options_t } type_marker = _type_marker(options->document_class, - GETSTATE(self)->_type_marker_str); + state->_type_marker_str); if (type_marker < 0) { return 0; } if (!cbson_convert_type_registry(type_registry_obj, - &options->type_registry)) { + &options->type_registry, state->_encoder_map_str, state->_decoder_map_str, state->_fallback_encoder_str)) { return 0; } @@ -692,7 +723,7 @@ error: * Sets exception and returns 0 on failure. */ static int _write_regex_to_buffer( - buffer_t buffer, int type_byte, PyObject* value) { + buffer_t buffer, int type_byte, PyObject* value, PyObject* _flags_str, PyObject* _pattern_str) { PyObject* py_flags; PyObject* py_pattern; @@ -708,7 +739,7 @@ static int _write_regex_to_buffer( * Both the builtin re type and our Regex class have attributes * "flags" and "pattern". */ - py_flags = PyObject_GetAttrString(value, "flags"); + py_flags = PyObject_GetAttr(value, _flags_str); if (!py_flags) { return 0; } @@ -717,7 +748,7 @@ static int _write_regex_to_buffer( if (int_flags == -1 && PyErr_Occurred()) { return 0; } - py_pattern = PyObject_GetAttrString(value, "pattern"); + py_pattern = PyObject_GetAttr(value, _pattern_str); if (!py_pattern) { return 0; } @@ -838,7 +869,7 @@ static int _write_element_to_buffer(PyObject* self, buffer_t buffer, int size; *(pymongo_buffer_get_buffer(buffer) + type_byte) = 0x05; - subtype_object = PyObject_GetAttrString(value, "subtype"); + subtype_object = PyObject_GetAttr(value, state->_subtype_str); if (!subtype_object) { return 0; } @@ -886,7 +917,7 @@ static int _write_element_to_buffer(PyObject* self, buffer_t buffer, { /* ObjectId */ const char* data; - PyObject* pystring = PyObject_GetAttrString(value, "binary"); + PyObject* pystring = PyObject_GetAttr(value, state->_binary_str); if (!pystring) { return 0; } @@ -906,7 +937,7 @@ static int _write_element_to_buffer(PyObject* self, buffer_t buffer, case 11: { /* Regex */ - return _write_regex_to_buffer(buffer, type_byte, value); + return _write_regex_to_buffer(buffer, type_byte, value, state->_flags_str, state->_pattern_str); } case 13: { @@ -915,7 +946,7 @@ static int _write_element_to_buffer(PyObject* self, buffer_t buffer, length_location, length; - PyObject* scope = PyObject_GetAttrString(value, "scope"); + PyObject* scope = PyObject_GetAttr(value, state->_scope_str); if (!scope) { return 0; } @@ -958,7 +989,7 @@ static int _write_element_to_buffer(PyObject* self, buffer_t buffer, PyObject* obj; unsigned long i; - obj = PyObject_GetAttrString(value, "inc"); + obj = PyObject_GetAttr(value, state->_inc_str); if (!obj) { return 0; } @@ -971,7 +1002,7 @@ static int _write_element_to_buffer(PyObject* self, buffer_t buffer, return 0; } - obj = PyObject_GetAttrString(value, "time"); + obj = PyObject_GetAttr(value, state->_time_str); if (!obj) { return 0; } @@ -1006,7 +1037,7 @@ static int _write_element_to_buffer(PyObject* self, buffer_t buffer, { /* Decimal128 */ const char* data; - PyObject* pystring = PyObject_GetAttrString(value, "bid"); + PyObject* pystring = PyObject_GetAttr(value, state->_bid_str); if (!pystring) { return 0; } @@ -1041,7 +1072,7 @@ static int _write_element_to_buffer(PyObject* self, buffer_t buffer, case 101: { /* RawBSONDocument */ - if (!write_raw_doc(buffer, value)) { + if (!write_raw_doc(buffer, value, state->_raw_str)) { return 0; } *(pymongo_buffer_get_buffer(buffer) + type_byte) = 0x03; @@ -1206,7 +1237,7 @@ static int _write_element_to_buffer(PyObject* self, buffer_t buffer, *(pymongo_buffer_get_buffer(buffer) + type_byte) = 0x09; return buffer_write_int64(buffer, (int64_t)millis); } else if (PyObject_TypeCheck(value, state->REType)) { - return _write_regex_to_buffer(buffer, type_byte, value); + return _write_regex_to_buffer(buffer, type_byte, value, state->_flags_str, state->_pattern_str); } /* @@ -1437,14 +1468,14 @@ int decode_and_write_pair(PyObject* self, buffer_t buffer, /* Write a RawBSONDocument to the buffer. * Returns the number of bytes written or 0 on failure. */ -static int write_raw_doc(buffer_t buffer, PyObject* raw) { +static int write_raw_doc(buffer_t buffer, PyObject* raw, PyObject* _raw_str) { char* bytes; Py_ssize_t len; int len_int; int bytes_written = 0; PyObject* bytes_obj = NULL; - bytes_obj = PyObject_GetAttrString(raw, "raw"); + bytes_obj = PyObject_GetAttr(raw, _raw_str); if (!bytes_obj) { goto fail; } @@ -1485,7 +1516,7 @@ int write_dict(PyObject* self, buffer_t buffer, } if (101 == type_marker) { - return write_raw_doc(buffer, dict); + return write_raw_doc(buffer, dict, state->_raw_str); } mapping_type = _get_object(state->Mapping, "collections.abc", "Mapping"); @@ -1606,6 +1637,7 @@ static PyObject* _cbson_dict_to_bson(PyObject* self, PyObject* args) { buffer_t buffer; PyObject* raw_bson_document_bytes_obj; long type_marker; + struct module_state *state = GETSTATE(self); if (!(PyArg_ParseTuple(args, "ObO|b", &dict, &check_keys, &options_obj, &top_level) && @@ -1614,13 +1646,13 @@ static PyObject* _cbson_dict_to_bson(PyObject* self, PyObject* args) { } /* check for RawBSONDocument */ - type_marker = _type_marker(dict, GETSTATE(self)->_type_marker_str); + type_marker = _type_marker(dict, state->_type_marker_str); if (type_marker < 0) { destroy_codec_options(&options); return NULL; } else if (101 == type_marker) { destroy_codec_options(&options); - raw_bson_document_bytes_obj = PyObject_GetAttrString(dict, "raw"); + raw_bson_document_bytes_obj = PyObject_GetAttr(dict, state->_raw_str); if (NULL == raw_bson_document_bytes_obj) { return NULL; } @@ -2102,7 +2134,7 @@ static PyObject* get_value(PyObject* self, PyObject* name, const char* buffer, if (!naive) { goto invalid; } - replace = PyObject_GetAttrString(naive, "replace"); + replace = PyObject_GetAttr(naive, state->_replace_str); Py_DECREF(naive); if (!replace) { goto invalid; @@ -2137,7 +2169,7 @@ static PyObject* get_value(PyObject* self, PyObject* name, const char* buffer, /* convert to local time */ if (options->tzinfo != Py_None) { - astimezone = PyObject_GetAttrString(value, "astimezone"); + astimezone = PyObject_GetAttr(value, state->_astimezone_str); Py_DECREF(value); if (!astimezone) { Py_DECREF(replace); @@ -3051,6 +3083,21 @@ static int _cbson_traverse(PyObject *m, visitproc visit, void *arg) { Py_VISIT(GETSTATE(m)->MaxKey); Py_VISIT(GETSTATE(m)->UTC); Py_VISIT(GETSTATE(m)->REType); + Py_VISIT(GETSTATE(m)->_type_marker_str); + Py_VISIT(GETSTATE(m)->_flags_str); + Py_VISIT(GETSTATE(m)->_pattern_str); + Py_VISIT(GETSTATE(m)->_encoder_map_str); + Py_VISIT(GETSTATE(m)->_decoder_map_str); + Py_VISIT(GETSTATE(m)->_fallback_encoder_str); + Py_VISIT(GETSTATE(m)->_raw_str); + Py_VISIT(GETSTATE(m)->_subtype_str); + Py_VISIT(GETSTATE(m)->_binary_str); + Py_VISIT(GETSTATE(m)->_scope_str); + Py_VISIT(GETSTATE(m)->_inc_str); + Py_VISIT(GETSTATE(m)->_time_str); + Py_VISIT(GETSTATE(m)->_bid_str); + Py_VISIT(GETSTATE(m)->_replace_str); + Py_VISIT(GETSTATE(m)->_astimezone_str); return 0; } @@ -3067,6 +3114,20 @@ static int _cbson_clear(PyObject *m) { Py_CLEAR(GETSTATE(m)->UTC); Py_CLEAR(GETSTATE(m)->REType); Py_CLEAR(GETSTATE(m)->_type_marker_str); + Py_CLEAR(GETSTATE(m)->_flags_str); + Py_CLEAR(GETSTATE(m)->_pattern_str); + Py_CLEAR(GETSTATE(m)->_encoder_map_str); + Py_CLEAR(GETSTATE(m)->_decoder_map_str); + Py_CLEAR(GETSTATE(m)->_fallback_encoder_str); + Py_CLEAR(GETSTATE(m)->_raw_str); + Py_CLEAR(GETSTATE(m)->_subtype_str); + Py_CLEAR(GETSTATE(m)->_binary_str); + Py_CLEAR(GETSTATE(m)->_scope_str); + Py_CLEAR(GETSTATE(m)->_inc_str); + Py_CLEAR(GETSTATE(m)->_time_str); + Py_CLEAR(GETSTATE(m)->_bid_str); + Py_CLEAR(GETSTATE(m)->_replace_str); + Py_CLEAR(GETSTATE(m)->_astimezone_str); return 0; } diff --git a/pymongo/_cmessagemodule.c b/pymongo/_cmessagemodule.c index ee7623d83..7ac66a1e4 100644 --- a/pymongo/_cmessagemodule.c +++ b/pymongo/_cmessagemodule.c @@ -28,6 +28,10 @@ struct module_state { PyObject* _cbson; + PyObject* _max_bson_size_str; + PyObject* _max_message_size_str; + PyObject* _max_write_batch_size_str; + PyObject* _max_split_size_str; }; /* See comments about module initialization in _cbsonmodule.c */ @@ -366,21 +370,21 @@ _batched_op_msg( PyObject* iterator = NULL; char* flags = ack ? "\x00\x00\x00\x00" : "\x02\x00\x00\x00"; - max_bson_size_obj = PyObject_GetAttrString(ctx, "max_bson_size"); + max_bson_size_obj = PyObject_GetAttr(ctx, state->_max_bson_size_str); max_bson_size = PyLong_AsLong(max_bson_size_obj); Py_XDECREF(max_bson_size_obj); if (max_bson_size == -1) { return 0; } - max_write_batch_size_obj = PyObject_GetAttrString(ctx, "max_write_batch_size"); + max_write_batch_size_obj = PyObject_GetAttr(ctx, state->_max_write_batch_size_str); max_write_batch_size = PyLong_AsLong(max_write_batch_size_obj); Py_XDECREF(max_write_batch_size_obj); if (max_write_batch_size == -1) { return 0; } - max_message_size_obj = PyObject_GetAttrString(ctx, "max_message_size"); + max_message_size_obj = PyObject_GetAttr(ctx, state->_max_message_size_str); max_message_size = PyLong_AsLong(max_message_size_obj); Py_XDECREF(max_message_size_obj); if (max_message_size == -1) { @@ -667,7 +671,7 @@ _batched_write_command( PyObject* doc = NULL; PyObject* iterator = NULL; - max_bson_size_obj = PyObject_GetAttrString(ctx, "max_bson_size"); + max_bson_size_obj = PyObject_GetAttr(ctx, state->_max_bson_size_str); max_bson_size = PyLong_AsLong(max_bson_size_obj); Py_XDECREF(max_bson_size_obj); if (max_bson_size == -1) { @@ -679,7 +683,7 @@ _batched_write_command( */ max_cmd_size = max_bson_size + 16382; - max_write_batch_size_obj = PyObject_GetAttrString(ctx, "max_write_batch_size"); + max_write_batch_size_obj = PyObject_GetAttr(ctx, state->_max_write_batch_size_str); max_write_batch_size = PyLong_AsLong(max_write_batch_size_obj); Py_XDECREF(max_write_batch_size_obj); if (max_write_batch_size == -1) { @@ -689,7 +693,7 @@ _batched_write_command( // max_split_size is the size at which to perform a batch split. // Normally this this value is equal to max_bson_size (16MiB). However, // when auto encryption is enabled max_split_size is reduced to 2MiB. - max_split_size_obj = PyObject_GetAttrString(ctx, "max_split_size"); + max_split_size_obj = PyObject_GetAttr(ctx, state->_max_split_size_str); max_split_size = PyLong_AsLong(max_split_size_obj); Py_XDECREF(max_split_size_obj); if (max_split_size == -1) { @@ -924,11 +928,19 @@ static PyMethodDef _CMessageMethods[] = { #define INITERROR return NULL static int _cmessage_traverse(PyObject *m, visitproc visit, void *arg) { Py_VISIT(GETSTATE(m)->_cbson); + Py_VISIT(GETSTATE(m)->_max_bson_size_str); + Py_VISIT(GETSTATE(m)->_max_message_size_str); + Py_VISIT(GETSTATE(m)->_max_split_size_str); + Py_VISIT(GETSTATE(m)->_max_write_batch_size_str); return 0; } static int _cmessage_clear(PyObject *m) { Py_CLEAR(GETSTATE(m)->_cbson); + Py_CLEAR(GETSTATE(m)->_max_bson_size_str); + Py_CLEAR(GETSTATE(m)->_max_message_size_str); + Py_CLEAR(GETSTATE(m)->_max_split_size_str); + Py_CLEAR(GETSTATE(m)->_max_write_batch_size_str); return 0; } @@ -950,6 +962,7 @@ PyInit__cmessage(void) PyObject *_cbson = NULL; PyObject *c_api_object = NULL; PyObject *m = NULL; + struct module_state* state = NULL; /* Store a reference to the _cbson module since it's needed to call some * of its functions @@ -977,7 +990,14 @@ PyInit__cmessage(void) goto fail; } - GETSTATE(m)->_cbson = _cbson; + state = GETSTATE(m); + state->_cbson = _cbson; + if (!((state->_max_bson_size_str = PyUnicode_FromString("max_bson_size")) && + (state->_max_message_size_str = PyUnicode_FromString("max_message_size")) && + (state->_max_write_batch_size_str = PyUnicode_FromString("max_write_batch_size")) && + (state->_max_split_size_str = PyUnicode_FromString("max_split_size")))) { + goto fail; + } Py_DECREF(c_api_object);