comparison Framework/Plugins/DatabaseBackendAdapterV3.cpp @ 374:4a3985088723 db-protobuf

moved class IndexConnectionsPool out of DatabaseBackendAdapterV3
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 28 Mar 2023 14:51:17 +0200
parents be7de633695c
children 9db9e0275ec0
comparison
equal deleted inserted replaced
373:be7de633695c 374:4a3985088723
23 #include "DatabaseBackendAdapterV3.h" 23 #include "DatabaseBackendAdapterV3.h"
24 24
25 #if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in Orthanc 1.3.1 25 #if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in Orthanc 1.3.1
26 # if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 9, 2) 26 # if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 9, 2)
27 27
28 #include "IndexConnectionsPool.h"
29
28 #include <Logging.h> 30 #include <Logging.h>
29 #include <MultiThreading/SharedMessageQueue.h>
30 #include <OrthancException.h> 31 #include <OrthancException.h>
31 32
32 #include <stdexcept> 33 #include <stdexcept>
33 #include <list> 34 #include <list>
34 #include <string> 35 #include <string>
80 target.push_back(*it); 81 target.push_back(*it);
81 } 82 }
82 } 83 }
83 84
84 85
85 class DatabaseBackendAdapterV3::Adapter : public boost::noncopyable
86 {
87 private:
88 class ManagerReference : public Orthanc::IDynamicObject
89 {
90 private:
91 DatabaseManager* manager_;
92
93 public:
94 ManagerReference(DatabaseManager& manager) :
95 manager_(&manager)
96 {
97 }
98
99 DatabaseManager& GetManager()
100 {
101 assert(manager_ != NULL);
102 return *manager_;
103 }
104 };
105
106 std::unique_ptr<IndexBackend> backend_;
107 OrthancPluginContext* context_;
108 boost::shared_mutex connectionsMutex_;
109 size_t countConnections_;
110 std::list<DatabaseManager*> connections_;
111 Orthanc::SharedMessageQueue availableConnections_;
112
113 public:
114 Adapter(IndexBackend* backend,
115 size_t countConnections) :
116 backend_(backend),
117 countConnections_(countConnections)
118 {
119 if (countConnections == 0)
120 {
121 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange,
122 "There must be a non-zero number of connections to the database");
123 }
124 else if (backend == NULL)
125 {
126 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
127 }
128 else
129 {
130 context_ = backend_->GetContext();
131 }
132 }
133
134 ~Adapter()
135 {
136 for (std::list<DatabaseManager*>::iterator
137 it = connections_.begin(); it != connections_.end(); ++it)
138 {
139 assert(*it != NULL);
140 delete *it;
141 }
142 }
143
144 OrthancPluginContext* GetContext() const
145 {
146 return context_;
147 }
148
149 void OpenConnections()
150 {
151 boost::unique_lock<boost::shared_mutex> lock(connectionsMutex_);
152
153 if (connections_.size() == 0)
154 {
155 assert(backend_.get() != NULL);
156
157 {
158 std::unique_ptr<DatabaseManager> manager(new DatabaseManager(backend_->CreateDatabaseFactory()));
159 manager->GetDatabase(); // Make sure to open the database connection
160
161 backend_->ConfigureDatabase(*manager);
162 connections_.push_back(manager.release());
163 }
164
165 for (size_t i = 1; i < countConnections_; i++)
166 {
167 connections_.push_back(new DatabaseManager(backend_->CreateDatabaseFactory()));
168 connections_.back()->GetDatabase(); // Make sure to open the database connection
169 }
170
171 for (std::list<DatabaseManager*>::iterator
172 it = connections_.begin(); it != connections_.end(); ++it)
173 {
174 assert(*it != NULL);
175 availableConnections_.Enqueue(new ManagerReference(**it));
176 }
177 }
178 else
179 {
180 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
181 }
182 }
183
184 void CloseConnections()
185 {
186 boost::unique_lock<boost::shared_mutex> lock(connectionsMutex_);
187
188 if (connections_.size() != countConnections_)
189 {
190 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
191 }
192 else if (availableConnections_.GetSize() != countConnections_)
193 {
194 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database, "Some connections are still in use, bug in the Orthanc core");
195 }
196 else
197 {
198 for (std::list<DatabaseManager*>::iterator
199 it = connections_.begin(); it != connections_.end(); ++it)
200 {
201 assert(*it != NULL);
202 (*it)->Close();
203 }
204 }
205 }
206
207 class DatabaseAccessor : public boost::noncopyable
208 {
209 private:
210 boost::shared_lock<boost::shared_mutex> lock_;
211 Adapter& adapter_;
212 DatabaseManager* manager_;
213
214 public:
215 DatabaseAccessor(Adapter& adapter) :
216 lock_(adapter.connectionsMutex_),
217 adapter_(adapter),
218 manager_(NULL)
219 {
220 for (;;)
221 {
222 std::unique_ptr<Orthanc::IDynamicObject> manager(adapter.availableConnections_.Dequeue(100));
223 if (manager.get() != NULL)
224 {
225 manager_ = &dynamic_cast<ManagerReference&>(*manager).GetManager();
226 return;
227 }
228 }
229 }
230
231 ~DatabaseAccessor()
232 {
233 assert(manager_ != NULL);
234 adapter_.availableConnections_.Enqueue(new ManagerReference(*manager_));
235 }
236
237 IndexBackend& GetBackend() const
238 {
239 return *adapter_.backend_;
240 }
241
242 DatabaseManager& GetManager() const
243 {
244 assert(manager_ != NULL);
245 return *manager_;
246 }
247 };
248 };
249
250
251 class DatabaseBackendAdapterV3::Output : public IDatabaseBackendOutput 86 class DatabaseBackendAdapterV3::Output : public IDatabaseBackendOutput
252 { 87 {
253 private: 88 private:
254 struct Metadata 89 struct Metadata
255 { 90 {
800 635
801 636
802 class DatabaseBackendAdapterV3::Transaction : public boost::noncopyable 637 class DatabaseBackendAdapterV3::Transaction : public boost::noncopyable
803 { 638 {
804 private: 639 private:
805 Adapter& adapter_; 640 IndexConnectionsPool& pool_;
806 std::unique_ptr<Adapter::DatabaseAccessor> accessor_; 641 std::unique_ptr<IndexConnectionsPool::Accessor> accessor_;
807 std::unique_ptr<Output> output_; 642 std::unique_ptr<Output> output_;
808 643
809 public: 644 public:
810 Transaction(Adapter& adapter) : 645 Transaction(IndexConnectionsPool& pool) :
811 adapter_(adapter), 646 pool_(pool),
812 accessor_(new Adapter::DatabaseAccessor(adapter)), 647 accessor_(new IndexConnectionsPool::Accessor(pool)),
813 output_(new Output) 648 output_(new Output)
814 { 649 {
815 } 650 }
816 651
817 ~Transaction() 652 ~Transaction()
959 } 794 }
960 795
961 796
962 static OrthancPluginErrorCode Open(void* database) 797 static OrthancPluginErrorCode Open(void* database)
963 { 798 {
964 DatabaseBackendAdapterV3::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV3::Adapter*>(database); 799 IndexConnectionsPool* pool = reinterpret_cast<IndexConnectionsPool*>(database);
965 800
966 try 801 try
967 { 802 {
968 adapter->OpenConnections(); 803 pool->OpenConnections();
969 return OrthancPluginErrorCode_Success; 804 return OrthancPluginErrorCode_Success;
970 } 805 }
971 ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext()); 806 ORTHANC_PLUGINS_DATABASE_CATCH(pool->GetContext());
972 } 807 }
973 808
974 809
975 static OrthancPluginErrorCode Close(void* database) 810 static OrthancPluginErrorCode Close(void* database)
976 { 811 {
977 DatabaseBackendAdapterV3::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV3::Adapter*>(database); 812 IndexConnectionsPool* pool = reinterpret_cast<IndexConnectionsPool*>(database);
978 813
979 try 814 try
980 { 815 {
981 adapter->CloseConnections(); 816 pool->CloseConnections();
982 return OrthancPluginErrorCode_Success; 817 return OrthancPluginErrorCode_Success;
983 } 818 }
984 ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext()); 819 ORTHANC_PLUGINS_DATABASE_CATCH(pool->GetContext());
985 } 820 }
986 821
987 822
988 static OrthancPluginErrorCode DestructDatabase(void* database) 823 static OrthancPluginErrorCode DestructDatabase(void* database)
989 { 824 {
990 DatabaseBackendAdapterV3::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV3::Adapter*>(database); 825 IndexConnectionsPool* pool = reinterpret_cast<IndexConnectionsPool*>(database);
991 826
992 if (adapter == NULL) 827 if (pool == NULL)
993 { 828 {
994 return OrthancPluginErrorCode_InternalError; 829 return OrthancPluginErrorCode_InternalError;
995 } 830 }
996 else 831 else
997 { 832 {
999 { 834 {
1000 isBackendInUse_ = false; 835 isBackendInUse_ = false;
1001 } 836 }
1002 else 837 else
1003 { 838 {
1004 OrthancPluginLogError(adapter->GetContext(), "More than one index backend was registered, internal error"); 839 OrthancPluginLogError(pool->GetContext(), "More than one index backend was registered, internal error");
1005 } 840 }
1006 841
1007 delete adapter; 842 delete pool;
1008 843
1009 return OrthancPluginErrorCode_Success; 844 return OrthancPluginErrorCode_Success;
1010 } 845 }
1011 } 846 }
1012 847
1013 848
1014 static OrthancPluginErrorCode GetDatabaseVersion(void* database, 849 static OrthancPluginErrorCode GetDatabaseVersion(void* database,
1015 uint32_t* version) 850 uint32_t* version)
1016 { 851 {
1017 DatabaseBackendAdapterV3::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV3::Adapter*>(database); 852 IndexConnectionsPool* pool = reinterpret_cast<IndexConnectionsPool*>(database);
1018 853
1019 try 854 try
1020 { 855 {
1021 DatabaseBackendAdapterV3::Adapter::DatabaseAccessor accessor(*adapter); 856 IndexConnectionsPool::Accessor accessor(*pool);
1022 *version = accessor.GetBackend().GetDatabaseVersion(accessor.GetManager()); 857 *version = accessor.GetBackend().GetDatabaseVersion(accessor.GetManager());
1023 return OrthancPluginErrorCode_Success; 858 return OrthancPluginErrorCode_Success;
1024 } 859 }
1025 ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext()); 860 ORTHANC_PLUGINS_DATABASE_CATCH(pool->GetContext());
1026 } 861 }
1027 862
1028 863
1029 static OrthancPluginErrorCode UpgradeDatabase(void* database, 864 static OrthancPluginErrorCode UpgradeDatabase(void* database,
1030 OrthancPluginStorageArea* storageArea, 865 OrthancPluginStorageArea* storageArea,
1031 uint32_t targetVersion) 866 uint32_t targetVersion)
1032 { 867 {
1033 DatabaseBackendAdapterV3::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV3::Adapter*>(database); 868 IndexConnectionsPool* pool = reinterpret_cast<IndexConnectionsPool*>(database);
1034 869
1035 try 870 try
1036 { 871 {
1037 DatabaseBackendAdapterV3::Adapter::DatabaseAccessor accessor(*adapter); 872 IndexConnectionsPool::Accessor accessor(*pool);
1038 accessor.GetBackend().UpgradeDatabase(accessor.GetManager(), targetVersion, storageArea); 873 accessor.GetBackend().UpgradeDatabase(accessor.GetManager(), targetVersion, storageArea);
1039 return OrthancPluginErrorCode_Success; 874 return OrthancPluginErrorCode_Success;
1040 } 875 }
1041 ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext()); 876 ORTHANC_PLUGINS_DATABASE_CATCH(pool->GetContext());
1042 } 877 }
1043 878
1044 879
1045 static OrthancPluginErrorCode HasRevisionsSupport(void* database, 880 static OrthancPluginErrorCode HasRevisionsSupport(void* database,
1046 uint8_t* target) 881 uint8_t* target)
1047 { 882 {
1048 DatabaseBackendAdapterV3::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV3::Adapter*>(database); 883 IndexConnectionsPool* pool = reinterpret_cast<IndexConnectionsPool*>(database);
1049 884
1050 try 885 try
1051 { 886 {
1052 DatabaseBackendAdapterV3::Adapter::DatabaseAccessor accessor(*adapter); 887 IndexConnectionsPool::Accessor accessor(*pool);
1053 *target = (accessor.GetBackend().HasRevisionsSupport() ? 1 : 0); 888 *target = (accessor.GetBackend().HasRevisionsSupport() ? 1 : 0);
1054 return OrthancPluginErrorCode_Success; 889 return OrthancPluginErrorCode_Success;
1055 } 890 }
1056 ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext()); 891 ORTHANC_PLUGINS_DATABASE_CATCH(pool->GetContext());
1057 } 892 }
1058 893
1059 894
1060 static OrthancPluginErrorCode StartTransaction(void* database, 895 static OrthancPluginErrorCode StartTransaction(void* database,
1061 OrthancPluginDatabaseTransaction** target /* out */, 896 OrthancPluginDatabaseTransaction** target /* out */,
1062 OrthancPluginDatabaseTransactionType type) 897 OrthancPluginDatabaseTransactionType type)
1063 { 898 {
1064 DatabaseBackendAdapterV3::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV3::Adapter*>(database); 899 IndexConnectionsPool* pool = reinterpret_cast<IndexConnectionsPool*>(database);
1065 900
1066 try 901 try
1067 { 902 {
1068 std::unique_ptr<DatabaseBackendAdapterV3::Transaction> transaction(new DatabaseBackendAdapterV3::Transaction(*adapter)); 903 std::unique_ptr<DatabaseBackendAdapterV3::Transaction> transaction(new DatabaseBackendAdapterV3::Transaction(*pool));
1069 904
1070 switch (type) 905 switch (type)
1071 { 906 {
1072 case OrthancPluginDatabaseTransactionType_ReadOnly: 907 case OrthancPluginDatabaseTransactionType_ReadOnly:
1073 transaction->GetManager().StartTransaction(TransactionType_ReadOnly); 908 transaction->GetManager().StartTransaction(TransactionType_ReadOnly);
1083 918
1084 *target = reinterpret_cast<OrthancPluginDatabaseTransaction*>(transaction.release()); 919 *target = reinterpret_cast<OrthancPluginDatabaseTransaction*>(transaction.release());
1085 920
1086 return OrthancPluginErrorCode_Success; 921 return OrthancPluginErrorCode_Success;
1087 } 922 }
1088 ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext()); 923 ORTHANC_PLUGINS_DATABASE_CATCH(pool->GetContext());
1089 } 924 }
1090 925
1091 926
1092 static OrthancPluginErrorCode DestructTransaction(OrthancPluginDatabaseTransaction* transaction) 927 static OrthancPluginErrorCode DestructTransaction(OrthancPluginDatabaseTransaction* transaction)
1093 { 928 {
2075 1910
2076 OrthancPluginContext* context = protection->GetContext(); 1911 OrthancPluginContext* context = protection->GetContext();
2077 1912
2078 if (OrthancPluginRegisterDatabaseBackendV3( 1913 if (OrthancPluginRegisterDatabaseBackendV3(
2079 context, &params, sizeof(params), maxDatabaseRetries, 1914 context, &params, sizeof(params), maxDatabaseRetries,
2080 new Adapter(protection.release(), countConnections)) != OrthancPluginErrorCode_Success) 1915 new IndexConnectionsPool(protection.release(), countConnections)) != OrthancPluginErrorCode_Success)
2081 { 1916 {
2082 delete backend; 1917 delete backend;
2083 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Unable to register the database backend"); 1918 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Unable to register the database backend");
2084 } 1919 }
2085 1920