Browse Source

Improve findHandler API

- Make findHandler non-blocking for read functionality
- Return copy of handlers instead of reference to internal container
Alexey Edelev 4 years ago
parent
commit
8954055baf

+ 20 - 7
src/protobuf/qabstractprotobufserializer.cpp

@@ -27,6 +27,7 @@
 #include <QVariant>
 #include <QMetaObject>
 #include <QMutex>
+#include <QSemaphore>
 
 #include "qabstractprotobufserializer.h"
 
@@ -34,24 +35,35 @@ using namespace QtProtobuf;
 
 namespace  {
 
+const int MaximumSimultaniousThreads = 64;
 /*!
  * \private
  * \brief The HandlersRegistry is container to store mapping between metatype identifier and serialization handlers.
  */
 struct HandlersRegistry {
 
+    HandlersRegistry() : m_readLock(MaximumSimultaniousThreads) {
+
+    }
+
     void registerHandler(int userType, const QtProtobufPrivate::SerializationHandler &handlers) {
-        QMutexLocker locker(&m_lock);
+        QMutexLocker locker(&m_writeLock);
+        QSemaphoreReleaser releaser(m_readLock, MaximumSimultaniousThreads);
+        m_readLock.acquire(MaximumSimultaniousThreads);
         m_registry[userType] = handlers;
     }
 
-    QtProtobufPrivate::SerializationHandler &findHandler(int userType) {
-        QMutexLocker locker(&m_lock);
+    QtProtobufPrivate::SerializationHandler findHandler(int userType) {
+        auto handler = empty;
+        QMutexLocker locker(&m_writeLock);
+        QSemaphoreReleaser releaser(m_readLock, 1);
+        m_readLock.acquire();
+        locker.unlock();
         auto it = m_registry.find(userType);
         if (it != m_registry.end()) {
-            return it->second;
+            handler = it->second;
         }
-        return empty;
+        return handler;
     }
 
     static HandlersRegistry &instance() {
@@ -59,7 +71,8 @@ struct HandlersRegistry {
         return _instance;
     }
 private:
-    QMutex m_lock;
+    QSemaphore m_readLock;
+    QMutex m_writeLock;
     std::unordered_map<int/*metatypeid*/, QtProtobufPrivate::SerializationHandler> m_registry;
     static QtProtobufPrivate::SerializationHandler empty;
 };
@@ -72,7 +85,7 @@ void QtProtobufPrivate::registerHandler(int userType, const QtProtobufPrivate::S
     HandlersRegistry::instance().registerHandler(userType, handlers);
 }
 
-QtProtobufPrivate::SerializationHandler &QtProtobufPrivate::findHandler(int userType)
+QtProtobufPrivate::SerializationHandler QtProtobufPrivate::findHandler(int userType)
 {
     return HandlersRegistry::instance().findHandler(userType);
 }

+ 1 - 1
src/protobuf/qabstractprotobufserializer_p.h

@@ -68,7 +68,7 @@ struct SerializationHandler {
     HandlerType type;/*!< Serialization WireType */
 };
 
-extern Q_PROTOBUF_EXPORT SerializationHandler &findHandler(int userType);
+extern Q_PROTOBUF_EXPORT SerializationHandler findHandler(int userType);
 extern Q_PROTOBUF_EXPORT void registerHandler(int userType, const SerializationHandler &handlers);
 
 /*!

+ 2 - 2
src/protobuf/qprotobufjsonserializer.cpp

@@ -159,7 +159,7 @@ public:
     QByteArray serializeValue(const QVariant &propertyValue, const QProtobufMetaProperty &metaProperty) {
         QByteArray buffer;
         auto userType = propertyValue.userType();
-        auto &value = QtProtobufPrivate::findHandler(userType);
+        auto value = QtProtobufPrivate::findHandler(userType);
         if (value.serializer) {
             value.serializer(qPtr, propertyValue, metaProperty, buffer);
         } else {
@@ -311,7 +311,7 @@ public:
 
     QVariant deserializeValue(int type, const QByteArray &data, microjson::JsonType jsonType, bool &ok) {
         QVariant newValue;
-        auto &handler = QtProtobufPrivate::findHandler(type);
+        auto handler = QtProtobufPrivate::findHandler(type);
         if (handler.deserializer) {
             QtProtobuf::QProtobufSelfcheckIterator it(data);
             QtProtobuf::QProtobufSelfcheckIterator last = it;

+ 3 - 3
src/protobuf/qprotobufserializer.cpp

@@ -272,7 +272,7 @@ QByteArray QProtobufSerializerPrivate::serializeProperty(const QVariant &propert
             result.prepend(QProtobufSerializerPrivate::encodeHeader(metaProperty.protoFieldIndex(), type));
         }
     } else {
-        auto &handler = QtProtobufPrivate::findHandler(userType);
+        auto handler = QtProtobufPrivate::findHandler(userType);
         handler.serializer(q_ptr, propertyValue, QProtobufMetaProperty(metaProperty, metaProperty.protoFieldIndex()), result);
     }
     return result;
@@ -313,7 +313,7 @@ void QProtobufSerializerPrivate::deserializeProperty(QObject *object, const QPro
     if (basicIt != handlers.end()) {
         basicIt->second.deserializer(it, newPropertyValue);
     } else {
-        auto &handler = QtProtobufPrivate::findHandler(userType);
+        auto handler = QtProtobufPrivate::findHandler(userType);
         handler.deserializer(q_ptr, it, newPropertyValue);
     }
 
@@ -341,7 +341,7 @@ void QProtobufSerializerPrivate::deserializeMapPair(QVariant &key, QVariant &val
             if (basicIt != handlers.end()) {
                 basicIt->second.deserializer(it, value);
             } else {
-                auto &handler = QtProtobufPrivate::findHandler(userType);
+                auto handler = QtProtobufPrivate::findHandler(userType);
                 handler.deserializer(q_ptr, it, value);//throws if not implemented
             }
         }