PYTHON-3729 use PyObject_GetAddr instead of PyObject_GetAddrString (#1281)

This commit is contained in:
Iris 2023-07-03 09:15:04 -07:00 committed by GitHub
parent a3940ac278
commit 0b5bdccf3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 116 additions and 35 deletions

View File

@ -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;
}

View File

@ -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);