Introduce protobuf-unsafe-registry feature

The feature guards the private code paths that enable or disable
the safe registering of the custom protobuf serializers.
The feature is useful when user want to trade the thread safety for
performance.

From the code perspective feature disables read/write locks when
accessing custom protobuf serializers registered privately.

Change-Id: I07cb622481a798e7aeba9c7afb29593e791e065e
Reviewed-by: Dennis Oberst <dennis.oberst@qt.io>
This commit is contained in:
Alexey Edelev 2025-01-14 18:39:32 +01:00
parent c7b78a5cbd
commit 7986e077c1
3 changed files with 31 additions and 2 deletions

View File

@ -87,11 +87,20 @@ qt_feature("protobufquick" PUBLIC
AUTODETECT TRUE AUTODETECT TRUE
CONDITION TARGET Qt6::Quick CONDITION TARGET Qt6::Quick
) )
qt_feature("protobuf-unsafe-registry" PRIVATE
SECTION "Qt Protobuf"
LABEL "Unsafe registry"
PURPOSE "Allows lock-free registry access for custom serializers"
AUTODETECT FALSE
)
qt_configure_add_summary_section(NAME "Qt Protobuf") qt_configure_add_summary_section(NAME "Qt Protobuf")
qt_configure_add_summary_entry(ARGS "protobuf-qtcoretypes") qt_configure_add_summary_entry(ARGS "protobuf-qtcoretypes")
qt_configure_add_summary_entry(ARGS "protobuf-qtguitypes") qt_configure_add_summary_entry(ARGS "protobuf-qtguitypes")
qt_configure_add_summary_entry(ARGS "protobuf-wellknowntypes") qt_configure_add_summary_entry(ARGS "protobuf-wellknowntypes")
qt_configure_add_summary_entry(ARGS "protobufquick") qt_configure_add_summary_entry(ARGS "protobufquick")
qt_configure_add_summary_entry(ARGS "protobuf-unsafe-registry")
qt_configure_end_summary_section() qt_configure_end_summary_section()
qt_configure_add_summary_section(NAME "Qt Protobuf tools") qt_configure_add_summary_section(NAME "Qt Protobuf tools")
qt_configure_add_summary_entry(ARGS "qtprotobufgen") qt_configure_add_summary_entry(ARGS "qtprotobufgen")

View File

@ -3,6 +3,7 @@
#include <QtProtobuf/qprotobufjsonserializer.h> #include <QtProtobuf/qprotobufjsonserializer.h>
#include <QtProtobuf/private/qtprotobuf-config_p.h>
#include <QtProtobuf/private/protobuffieldpresencechecker_p.h> #include <QtProtobuf/private/protobuffieldpresencechecker_p.h>
#include <QtProtobuf/private/protobufscalarjsonserializers_p.h> #include <QtProtobuf/private/protobufscalarjsonserializers_p.h>
#include <QtProtobuf/private/qprotobufdeserializerbase_p.h> #include <QtProtobuf/private/qprotobufdeserializerbase_p.h>
@ -18,7 +19,9 @@
#include <QtCore/qjsonarray.h> #include <QtCore/qjsonarray.h>
#include <QtCore/qjsondocument.h> #include <QtCore/qjsondocument.h>
#include <QtCore/qjsonobject.h> #include <QtCore/qjsonobject.h>
#include <QtCore/qreadwritelock.h> #if !QT_CONFIG(protobuf_unsafe_registry)
# include <QtCore/qreadwritelock.h>
#endif
#include <QtCore/qtimezone.h> #include <QtCore/qtimezone.h>
#include <QtCore/qvariant.h> #include <QtCore/qvariant.h>
@ -52,13 +55,17 @@ struct JsonHandlerRegistry
void registerHandler(QMetaType metaType, QtProtobufPrivate::CustomJsonSerializer serializer, void registerHandler(QMetaType metaType, QtProtobufPrivate::CustomJsonSerializer serializer,
QtProtobufPrivate::CustomJsonDeserializer deserializer) QtProtobufPrivate::CustomJsonDeserializer deserializer)
{ {
#if !QT_CONFIG(protobuf_unsafe_registry)
QWriteLocker locker(&m_lock); QWriteLocker locker(&m_lock);
#endif
m_registry[metaType] = { serializer, deserializer }; m_registry[metaType] = { serializer, deserializer };
} }
QtProtobufPrivate::CustomJsonSerializer findSerializer(QMetaType metaType) QtProtobufPrivate::CustomJsonSerializer findSerializer(QMetaType metaType)
{ {
#if !QT_CONFIG(protobuf_unsafe_registry)
QReadLocker locker(&m_lock); QReadLocker locker(&m_lock);
#endif
const auto it = m_registry.constFind(metaType); const auto it = m_registry.constFind(metaType);
if (it != m_registry.constEnd()) if (it != m_registry.constEnd())
return it.value().first; return it.value().first;
@ -67,7 +74,9 @@ struct JsonHandlerRegistry
QtProtobufPrivate::CustomJsonDeserializer findDeserializer(QMetaType metaType) QtProtobufPrivate::CustomJsonDeserializer findDeserializer(QMetaType metaType)
{ {
#if !QT_CONFIG(protobuf_unsafe_registry)
QReadLocker locker(&m_lock); QReadLocker locker(&m_lock);
#endif
const auto it = m_registry.constFind(metaType); const auto it = m_registry.constFind(metaType);
if (it != m_registry.constEnd()) if (it != m_registry.constEnd())
return it.value().second; return it.value().second;
@ -77,7 +86,9 @@ struct JsonHandlerRegistry
private: private:
using Handler = std::pair<QtProtobufPrivate::CustomJsonSerializer, using Handler = std::pair<QtProtobufPrivate::CustomJsonSerializer,
QtProtobufPrivate::CustomJsonDeserializer>; QtProtobufPrivate::CustomJsonDeserializer>;
#if !QT_CONFIG(protobuf_unsafe_registry)
QReadWriteLock m_lock; QReadWriteLock m_lock;
#endif
QHash<QMetaType, Handler> m_registry; QHash<QMetaType, Handler> m_registry;
}; };
Q_GLOBAL_STATIC(JsonHandlerRegistry, jsonHandlersRegistry) Q_GLOBAL_STATIC(JsonHandlerRegistry, jsonHandlersRegistry)

View File

@ -3,12 +3,15 @@
#include <QtProtobuf/qprotobufregistration.h> #include <QtProtobuf/qprotobufregistration.h>
#include <QtProtobuf/private/qtprotobuf-config_p.h>
#include <QtProtobuf/private/qprotobufregistration_p.h> #include <QtProtobuf/private/qprotobufregistration_p.h>
#include <QtProtobuf/qtprotobuftypes.h> #include <QtProtobuf/qtprotobuftypes.h>
#include <QtCore/qmutex.h> #include <QtCore/qmutex.h>
#include <QtCore/qmetatype.h> #include <QtCore/qmetatype.h>
#include <QtCore/qreadwritelock.h> #if !QT_CONFIG(protobuf_unsafe_registry)
# include <QtCore/qreadwritelock.h>
#endif
#include <mutex> #include <mutex>
@ -122,13 +125,17 @@ struct HandlersRegistry
void registerHandler(QMetaType type, QtProtobufPrivate::Serializer serializer, void registerHandler(QMetaType type, QtProtobufPrivate::Serializer serializer,
QtProtobufPrivate::Deserializer deserializer) QtProtobufPrivate::Deserializer deserializer)
{ {
#if !QT_CONFIG(protobuf_unsafe_registry)
QWriteLocker locker(&m_lock); QWriteLocker locker(&m_lock);
#endif
m_registry[type] = { serializer, deserializer }; m_registry[type] = { serializer, deserializer };
} }
QtProtobufPrivate::SerializationHandler findHandler(QMetaType type) QtProtobufPrivate::SerializationHandler findHandler(QMetaType type)
{ {
#if !QT_CONFIG(protobuf_unsafe_registry)
QReadLocker locker(&m_lock); QReadLocker locker(&m_lock);
#endif
auto it = m_registry.constFind(type); auto it = m_registry.constFind(type);
if (it != m_registry.constEnd()) if (it != m_registry.constEnd())
return it.value(); return it.value();
@ -136,7 +143,9 @@ struct HandlersRegistry
} }
private: private:
# if !QT_CONFIG(protobuf_unsafe_registry)
QReadWriteLock m_lock; QReadWriteLock m_lock;
# endif
QHash<QMetaType, QtProtobufPrivate::SerializationHandler> m_registry; QHash<QMetaType, QtProtobufPrivate::SerializationHandler> m_registry;
}; };
Q_GLOBAL_STATIC(HandlersRegistry, handlersRegistry) Q_GLOBAL_STATIC(HandlersRegistry, handlersRegistry)