diff --git a/docs/FeatureToggles.md b/docs/FeatureToggles.md new file mode 100644 index 00000000..5f1187cf --- /dev/null +++ b/docs/FeatureToggles.md @@ -0,0 +1,21 @@ +# Introducing Feature Toggles + +Starting from release v1.2.0.1 we have added support for feature toggles. This allows you to enable or disable certain features in the application without the need to redeploy the application. + +## How to use feature toggles + +Feature toggles are managed through the `feature_config.ini` file (located next to _labview_grpc_server_ library). You can find the `data` section in the file. Here is an example of how to use feature toggles: + +```ini +[data] +EfficientMessageCopy = TRUE +useOccurrence = TRUE +``` + +In the example above, the `EfficientMessageCopy` and `useOccurrence` features are enabled by default. If you want to disable a feature, you can set the value to `FALSE`. + +### More about the flags + +1. `EfficientMessageCopy` - This feature is used to enable or disable the efficient message copy feature. When enabled, the client will use efficient message copy to have throughput. When disabled, the client will use the default message copy. + +2. `useOccurrence` - This feature is used to enable or disable the occurrence feature. When enabled, the client will use occurrence to manage synchroniation between LabVIEW execution threads. When disabled, the client will use not use LabVIEW occurrences. \ No newline at end of file diff --git a/docs/QuickStart.md b/docs/QuickStart.md index 2aeb1c6f..34464966 100644 --- a/docs/QuickStart.md +++ b/docs/QuickStart.md @@ -169,6 +169,11 @@ From the same project, ![Say Hello Again Client Code implementation](images/HelloAgain-Client-Code.png "Say Hello Again Client Code implementation") + +### [Optional] Configure feature toggles + +[Feature Toggle documentation](./FeatureToggles.md) + ### Run! Just like we did before, from the `examples/helloworld` directory: diff --git a/labview source/Client Server Support New/build spec/gRPC Server and Client Template [2].vipb b/labview source/Client Server Support New/build spec/gRPC Server and Client Template [2].vipb index 9ead8c35..dce42dc4 100644 --- a/labview source/Client Server Support New/build spec/gRPC Server and Client Template [2].vipb +++ b/labview source/Client Server Support New/build spec/gRPC Server and Client Template [2].vipb @@ -1,7 +1,7 @@ - + NI_lib_gRPC_Server_and_Client_Template[2] - 1.2.0.1 + 1.2.1.1 false .. ..\..\Builds @@ -17,8 +17,8 @@ - ni_lib_labview_grpc_library >=1.0.0.5 - ni_lib_labview_grpc_servicer >=1.0.0.5 + ni_lib_labview_grpc_library >=1.2.1.1 + ni_lib_labview_grpc_servicer >=1.2.1.1 diff --git a/labview source/gRPC lv Servicer/build spec/LabVIEW gRPC Servicer.vipb b/labview source/gRPC lv Servicer/build spec/LabVIEW gRPC Servicer.vipb index 2d932439..7a072dc6 100644 --- a/labview source/gRPC lv Servicer/build spec/LabVIEW gRPC Servicer.vipb +++ b/labview source/gRPC lv Servicer/build spec/LabVIEW gRPC Servicer.vipb @@ -1,7 +1,7 @@ - + NI_lib_LabVIEW_gRPC_Servicer - 1.2.0.1 + 1.2.1.1 false .. ..\..\Builds @@ -17,7 +17,7 @@ - ni_lib_labview_grpc_library >=1.0.0.5 + ni_lib_labview_grpc_library >=1.2.1.1 @@ -241,7 +241,7 @@ ..\Servicer - EF4D1AC5CAC7F902A7CF8FF5793A28D2 + 2853EF4A6A207E56900A7E4A3B89B820 0 @@ -290,7 +290,7 @@ ..\iService\Server API - 4D9DD7F1C4F365611E7BC9C68C3D0746 + 56DEEC61A2B33CDA6209D66F1823D416 0 @@ -353,7 +353,7 @@ ..\Servicer\Run Servicer.vi - 01211C985534A0A64931AEB80B781E5B + 37CAC1E328AC86A39F584A6C543A8B47 1 @@ -402,7 +402,7 @@ ..\ServiceBase\Accessors\Read Server Stop.vi - 0DAEFFEC54821C1C8A04748AE22F62E7 + 0B31FB6D6BADFFD57F13DDC174FFF2DC 1 @@ -507,7 +507,7 @@ ..\ServiceBase\Server API\Start.vi - 868D92BE0C2CC5C8CEC7B97978B5B57B + A61CAED75DFB09FF807B585DB6A2E329 2 @@ -598,7 +598,7 @@ ..\Servicer\Accessors\Server State - EB0CABE3504FCDCD16AB2CCE0426666E + AB736E3BFE2F16DC39CAD22AED3B9A42 2 @@ -675,7 +675,7 @@ ..\Servicer\Server API\Stop Server.vi - D190312A2A9E027E772830E427BDC409 + 792C56BDAF2F7B6C8C400BA54A35FF4C 5 @@ -724,7 +724,7 @@ ..\Servicer\Accessors\gRPC ID\Set gRPC ID.vi - 9D246540CD96A150DF328248B0FBB69D + 7930AED5671BE270A8A44DD524E1FF6B 5 @@ -773,7 +773,7 @@ ..\Servicer\Accessors\Server Address\Set Server Address.vi - A9D1C08BDED898EA77A18DF0558BFF54 + EBF3BC054A4624C356F6D016BCC226AB 5 @@ -822,7 +822,7 @@ ..\Servicer\Accessors\Server Certificate File\Set Server Certificate File.vi - ABBDD30E4FA250571B687C540BBEF65F + 80EC661840B290568D6B374E3ED4929B 5 @@ -871,7 +871,7 @@ ..\Servicer\Accessors\Server Key File\Set Server Key File.vi - D009C94F8A0CE4085DB46DB08D81EB34 + 91B118288976929E18942FC5B9EC14ED 5 @@ -948,7 +948,7 @@ ..\Servicer\Accessors\Server State\Set Server State.vi - 0339BCF065B73EB2CFA62B59E69A63B4 + 8B469662DF05DD5A2C74E2EB7AF68AD4 11 @@ -997,7 +997,7 @@ ..\Servicer\Accessors\Server State\State Ref\Set Server State Ref.vi - 4989E0323BB114A6D1EB7502BBA40157 + 89F1B5F7BDA2A86F19F601292A18CD1F 11 @@ -1046,7 +1046,7 @@ ..\Servicer\Accessors\Server State\State UE\Set Server State UE.vi - F9328007F4D8CCC6D9AF239EE1D0C1BF + CF4FCC3F6AB2C9C175844260ABFCED8F \ No newline at end of file diff --git a/labview source/gRPC lv Support/Client API/Client Complete Client Streaming Call.vim b/labview source/gRPC lv Support/Client API/Client Complete Client Streaming Call.vim index a4435df4..9b40c3bf 100644 Binary files a/labview source/gRPC lv Support/Client API/Client Complete Client Streaming Call.vim and b/labview source/gRPC lv Support/Client API/Client Complete Client Streaming Call.vim differ diff --git a/labview source/gRPC lv Support/Client API/Client Read From Stream.vim b/labview source/gRPC lv Support/Client API/Client Read From Stream.vim index 3722bd98..fae00c9f 100644 Binary files a/labview source/gRPC lv Support/Client API/Client Read From Stream.vim and b/labview source/gRPC lv Support/Client API/Client Read From Stream.vim differ diff --git a/labview source/gRPC lv Support/Client API/Client Unary Call.vim b/labview source/gRPC lv Support/Client API/Client Unary Call.vim index 68281da9..ef87586e 100644 Binary files a/labview source/gRPC lv Support/Client API/Client Unary Call.vim and b/labview source/gRPC lv Support/Client API/Client Unary Call.vim differ diff --git a/labview source/gRPC lv Support/Server API/Server/Get Server DLL Path.vi b/labview source/gRPC lv Support/Server API/Server/Get Server DLL Path.vi index adc89bf5..729124a1 100644 Binary files a/labview source/gRPC lv Support/Server API/Server/Get Server DLL Path.vi and b/labview source/gRPC lv Support/Server API/Server/Get Server DLL Path.vi differ diff --git a/labview source/gRPC lv Support/Shared/Wait On Occurrence Wrapper.vi b/labview source/gRPC lv Support/Shared/Wait On Occurrence Wrapper.vi new file mode 100644 index 00000000..ef44006e Binary files /dev/null and b/labview source/gRPC lv Support/Shared/Wait On Occurrence Wrapper.vi differ diff --git a/labview source/gRPC lv Support/build spec/LabVIEW gRPC Library.vipb b/labview source/gRPC lv Support/build spec/LabVIEW gRPC Library.vipb index 01038b7e..05015ff3 100644 --- a/labview source/gRPC lv Support/build spec/LabVIEW gRPC Library.vipb +++ b/labview source/gRPC lv Support/build spec/LabVIEW gRPC Library.vipb @@ -1,7 +1,7 @@ - + NI_lib_LabVIEW_gRPC_Library - 1.2.0.1 + 1.2.1.1 false .. ..\..\Builds @@ -252,7 +252,7 @@ https://github.com/ni/grpc-labview ..\Server API - F627CB60D44A5C4716C7A488480A4D48 + BEFED5DB5E2108370610EE39BBEEFB14 0 @@ -371,7 +371,7 @@ https://github.com/ni/grpc-labview ..\Client API\Client Cancel Call.vi - 64CFAF9B687AE3AFE8B3616E673536CC + DB38FE0CA2B16A33371A9E33EC3FB024 0 @@ -490,7 +490,7 @@ https://github.com/ni/grpc-labview ..\Server API\UnpackFromBuffer.vim - 73B249E2631224E8EA80A91855771A7A + A301642648F8716CD2A20F4C93FC59CB 2 @@ -721,7 +721,7 @@ https://github.com/ni/grpc-labview ..\Server API\Message Requests\Write Call Response.vim - C6F6FDFB6E222C0392DBF68D544AD686 + 09E45FBB1C71CA79F5165A0D0744C58A 2 @@ -840,7 +840,7 @@ https://github.com/ni/grpc-labview ..\Server API\Server\Stop Server.vi - A93825BB3476291241D9E34DA3CF83DA + FDA001872E863E8C254CF53A4876F2C6 \ No newline at end of file diff --git a/labview source/gRPC lv Support/grpc-lvsupport.lvlib b/labview source/gRPC lv Support/grpc-lvsupport.lvlib index a2db545b..36b0c1f0 100644 --- a/labview source/gRPC lv Support/grpc-lvsupport.lvlib +++ b/labview source/gRPC lv Support/grpc-lvsupport.lvlib @@ -108,5 +108,6 @@ + diff --git a/src/feature_toggles.cc b/src/feature_toggles.cc index 1bb8f85c..4dd58c03 100644 --- a/src/feature_toggles.cc +++ b/src/feature_toggles.cc @@ -3,6 +3,7 @@ #include #include #include +#include namespace grpc_labview { // Function to read feature configurations from an INI file @@ -35,7 +36,10 @@ namespace grpc_labview { std::string key, value; if (std::getline(iss, key, '=') && std::getline(iss, value)) { // Append section name to key for uniqueness + key.erase(std::remove_if(key.begin(), key.end(), ::isspace),key.end()); + value.erase(std::remove_if(value.begin(), value.end(), ::isspace),value.end()); std::string fullKey = currentSection.empty() ? key : currentSection + "_" + key; + std::transform(value.begin(), value.end(), value.begin(), ::tolower); featureFlags[fullKey] = (value == "true"); } } diff --git a/src/feature_toggles.h b/src/feature_toggles.h index e23ad679..62a20068 100644 --- a/src/feature_toggles.h +++ b/src/feature_toggles.h @@ -1,17 +1,18 @@ #include #include #include -#include +#include namespace grpc_labview { class FeatureConfig { private: - std::map featureFlags; + std::unordered_map featureFlags; // Constructor to initialize with default values FeatureConfig() { featureFlags["gRPC"] = true; // Enable gRPC by default as an example, this will never be overridden by config file - featureFlags["EfficientMessageCopy"] = true; + featureFlags["data_EfficientMessageCopy"] = true; + featureFlags["data_useOccurrence"] = true; } public: @@ -27,4 +28,5 @@ namespace grpc_labview { // Function to check if a feature is enabled bool isFeatureEnabled(const std::string& featureName) const; }; + } \ No newline at end of file diff --git a/src/grpc_client.cc b/src/grpc_client.cc index 28bd5ee6..90c4ee56 100644 --- a/src/grpc_client.cc +++ b/src/grpc_client.cc @@ -18,19 +18,19 @@ namespace grpc_labview //--------------------------------------------------------------------- //--------------------------------------------------------------------- LabVIEWgRPCClient::LabVIEWgRPCClient() - { + { } //--------------------------------------------------------------------- //--------------------------------------------------------------------- - void LabVIEWgRPCClient::Connect(const char* address, const std::string& certificatePath) - { + void LabVIEWgRPCClient::Connect(const char *address, const std::string &certificatePath) + { std::shared_ptr creds; if (!certificatePath.empty()) { std::string cacert = read_keycert(certificatePath); grpc::SslCredentialsOptions ssl_opts; - ssl_opts.pem_root_certs=cacert; + ssl_opts.pem_root_certs = cacert; creds = grpc::SslCredentials(ssl_opts); } else @@ -46,13 +46,13 @@ namespace grpc_labview //--------------------------------------------------------------------- //--------------------------------------------------------------------- ClientCall::~ClientCall() - { + { } //--------------------------------------------------------------------- //--------------------------------------------------------------------- void ClientCall::Finish() - { + { } //--------------------------------------------------------------------- @@ -77,7 +77,7 @@ namespace grpc_labview //--------------------------------------------------------------------- //--------------------------------------------------------------------- - bool ServerStreamingClientCall::Read(LVMessage* message) + bool ServerStreamingClientCall::Read(LVMessage *message) { bool result = _reader->Read(message); return result; @@ -104,15 +104,15 @@ namespace grpc_labview if (!_writesComplete) { _writesComplete = true; - _writer->WritesDone(); + _writer->WritesDone(); } } - + //--------------------------------------------------------------------- //--------------------------------------------------------------------- - bool ClientStreamingClientCall::Write(LVMessage* message) + bool ClientStreamingClientCall::Write(LVMessage *message) { - return _writer->Write(*message); + return _writer->Write(*message); } //--------------------------------------------------------------------- @@ -136,20 +136,20 @@ namespace grpc_labview if (!_writesComplete) { _writesComplete = true; - _readerWriter->WritesDone(); + _readerWriter->WritesDone(); } } - + //--------------------------------------------------------------------- //--------------------------------------------------------------------- - bool BidiStreamingClientCall::Read(LVMessage* message) + bool BidiStreamingClientCall::Read(LVMessage *message) { return _readerWriter->Read(message); } //--------------------------------------------------------------------- //--------------------------------------------------------------------- - bool BidiStreamingClientCall::Write(LVMessage* message) + bool BidiStreamingClientCall::Write(LVMessage *message) { return _readerWriter->Write(*message); } @@ -166,12 +166,12 @@ namespace grpc_labview } } -int32_t ClientCleanUpProc(grpc_labview::gRPCid* clientId); -void CheckActiveAndSignalOccurenceForClientCall(grpc_labview::ClientCall* clientCall); +int32_t ClientCleanUpProc(grpc_labview::gRPCid *clientId); +void CheckActiveAndSignalOccurenceForClientCall(grpc_labview::ClientCall *clientCall); //--------------------------------------------------------------------- //--------------------------------------------------------------------- -LIBRARY_EXPORT int32_t CreateClient(const char* address, const char* certificatePath, grpc_labview::gRPCid** clientId) +LIBRARY_EXPORT int32_t CreateClient(const char *address, const char *certificatePath, grpc_labview::gRPCid **clientId) { grpc_labview::InitCallbacks(); @@ -184,7 +184,7 @@ LIBRARY_EXPORT int32_t CreateClient(const char* address, const char* certificate //--------------------------------------------------------------------- //--------------------------------------------------------------------- -int32_t CloseClient(grpc_labview::LabVIEWgRPCClient* client) +int32_t CloseClient(grpc_labview::LabVIEWgRPCClient *client) { if (!client) { @@ -196,22 +196,20 @@ int32_t CloseClient(grpc_labview::LabVIEWgRPCClient* client) } // Signal a lv occurence for an active client call from async c++ thread -void CheckActiveAndSignalOccurenceForClientCall(grpc_labview::ClientCall* clientCall) +void CheckActiveAndSignalOccurenceForClientCall(grpc_labview::ClientCall *clientCall) { if (clientCall == nullptr) { return; } - std::lock_guard lock(clientCall->_client->clientLock); - std::list::iterator it; - it = std::find(clientCall->_client->ActiveClientCalls.begin(), clientCall->_client->ActiveClientCalls.end(), clientCall); - if (it != clientCall->_client->ActiveClientCalls.end()) + std::unique_lock lock(clientCall->_client->clientLock); + if (clientCall->_client->ActiveClientCalls.find(clientCall) != clientCall->_client->ActiveClientCalls.end()) { grpc_labview::SignalOccurrence(clientCall->_occurrence); } } -LIBRARY_EXPORT int32_t CloseClient(grpc_labview::gRPCid* clientId) +LIBRARY_EXPORT int32_t CloseClient(grpc_labview::gRPCid *clientId) { auto client = clientId->CastTo(); if (!client) @@ -224,28 +222,26 @@ LIBRARY_EXPORT int32_t CloseClient(grpc_labview::gRPCid* clientId) return 0; } -int32_t ClientCleanUpProc(grpc_labview::gRPCid* clientId) +int32_t ClientCleanUpProc(grpc_labview::gRPCid *clientId) { auto client = clientId->CastTo(); if (!client) { return -1; } + std::unique_lock lock(client->clientLock); + for (auto activeClientCall = client->ActiveClientCalls.begin(); activeClientCall != client->ActiveClientCalls.end(); activeClientCall++) { - std::lock_guard lock(client->clientLock); - for (auto activeClientCall = client->ActiveClientCalls.begin(); activeClientCall != client->ActiveClientCalls.end(); activeClientCall++) - { - (*activeClientCall)->Cancel(); - } - - client->ActiveClientCalls.clear(); + activeClientCall->first->Cancel(); } + client->ActiveClientCalls.clear(); + lock.unlock(); return CloseClient(client.get()); } //--------------------------------------------------------------------- //--------------------------------------------------------------------- -LIBRARY_EXPORT int32_t CreateClientContext(grpc_labview::gRPCid** contextId) +LIBRARY_EXPORT int32_t CreateClientContext(grpc_labview::gRPCid **contextId) { auto clientContext = std::make_shared(); *contextId = grpc_labview::gPointerManager.RegisterPointer(clientContext); @@ -254,7 +250,7 @@ LIBRARY_EXPORT int32_t CreateClientContext(grpc_labview::gRPCid** contextId) //--------------------------------------------------------------------- //--------------------------------------------------------------------- -LIBRARY_EXPORT int32_t CloseClientContext(grpc_labview::gRPCid* contextId) +LIBRARY_EXPORT int32_t CloseClientContext(grpc_labview::gRPCid *contextId) { auto context = contextId->CastTo(); if (!context) @@ -265,20 +261,19 @@ LIBRARY_EXPORT int32_t CloseClientContext(grpc_labview::gRPCid* contextId) return 0; } - //--------------------------------------------------------------------- //--------------------------------------------------------------------- LIBRARY_EXPORT int32_t ClientUnaryCall2( - grpc_labview::gRPCid* clientId, - grpc_labview::MagicCookie* occurrence, - const char* methodName, - const char* requestMessageName, - const char* responseMessageName, - int8_t* requestCluster, - grpc_labview::gRPCid** callId, + grpc_labview::gRPCid *clientId, + grpc_labview::MagicCookie *occurrence, + const char *methodName, + const char *requestMessageName, + const char *responseMessageName, + int8_t *requestCluster, + grpc_labview::gRPCid **callId, int32_t timeoutMs, - grpc_labview::gRPCid* contextId, - int8_t* responseCluster) + grpc_labview::gRPCid *contextId, + int8_t *responseCluster) { auto client = clientId->CastTo(); if (!client) @@ -306,66 +301,79 @@ LIBRARY_EXPORT int32_t ClientUnaryCall2( clientContext->set_deadline(timeoutMs); } + auto featureConfig = grpc_labview::FeatureConfig::getInstance(); + auto clientCall = new grpc_labview::ClientCall(); + std::unique_lock lock(client->clientLock); + client->ActiveClientCalls[clientCall] = true; + lock.unlock(); *callId = grpc_labview::gPointerManager.RegisterPointer(clientCall); clientCall->_client = client; clientCall->_methodName = methodName; - clientCall->_occurrence = *occurrence; + + if(featureConfig.isFeatureEnabled("data_useOccurrence")) + { + clientCall->_occurrence = *occurrence; + } + else{ + clientCall->_occurrence = 0; + } clientCall->_context = clientContext; - auto featureConfig = grpc_labview::FeatureConfig::getInstance(); - if (featureConfig.isFeatureEnabled("EfficientMessageCopy") && responseCluster != nullptr){ + if (featureConfig.isFeatureEnabled("data_EfficientMessageCopy") && responseCluster != nullptr) + { clientCall->_useLVEfficientMessage = true; } - if (clientCall->_useLVEfficientMessage){ + if (clientCall->_useLVEfficientMessage) + { clientCall->_request = std::make_shared(requestMetadata); clientCall->_response = std::make_shared(responseMetadata); clientCall->_request->SetLVClusterHandle(reinterpret_cast(requestCluster)); clientCall->_response->SetLVClusterHandle(reinterpret_cast(responseCluster)); } - else { + else + { clientCall->_request = std::make_shared(requestMetadata); - clientCall->_response = std::make_shared(responseMetadata); + clientCall->_response = std::make_shared(responseMetadata); } try { grpc_labview::ClusterDataCopier::CopyFromCluster(*clientCall->_request.get(), requestCluster); } - catch (grpc_labview::InvalidEnumValueException& e) + catch (grpc_labview::InvalidEnumValueException &e) { return e.code; } clientCall->_runFuture = std::async( - std::launch::async, - [clientCall]() + std::launch::async, + [clientCall]() { grpc::internal::RpcMethod method(clientCall->_methodName.c_str(), grpc::internal::RpcMethod::NORMAL_RPC); - clientCall->_status = grpc::internal::BlockingUnaryCall(clientCall->_client->Channel.get(), method, &(clientCall->_context.get()->gRPCClientContext) , *clientCall->_request.get(), clientCall->_response.get()); - CheckActiveAndSignalOccurenceForClientCall(clientCall); + clientCall->_status = grpc::internal::BlockingUnaryCall(clientCall->_client->Channel.get(), method, &(clientCall->_context.get()->gRPCClientContext), *clientCall->_request.get(), clientCall->_response.get()); + if(clientCall->_occurrence != 0) + { + CheckActiveAndSignalOccurenceForClientCall(clientCall); + } return 0; }); - - std::lock_guard lock(client->clientLock); - client->ActiveClientCalls.push_back(clientCall); return 0; } - //--------------------------------------------------------------------- //--------------------------------------------------------------------- LIBRARY_EXPORT int32_t ClientUnaryCall( - grpc_labview::gRPCid* clientId, - grpc_labview::MagicCookie* occurrence, - const char* methodName, - const char* requestMessageName, - const char* responseMessageName, - int8_t* requestCluster, - grpc_labview::gRPCid** callId, + grpc_labview::gRPCid *clientId, + grpc_labview::MagicCookie *occurrence, + const char *methodName, + const char *requestMessageName, + const char *responseMessageName, + int8_t *requestCluster, + grpc_labview::gRPCid **callId, int32_t timeoutMs, - grpc_labview::gRPCid* contextId) + grpc_labview::gRPCid *contextId) { return ClientUnaryCall2(clientId, occurrence, methodName, requestMessageName, responseMessageName, requestCluster, callId, timeoutMs, contextId, nullptr); } @@ -374,10 +382,10 @@ LIBRARY_EXPORT int32_t ClientUnaryCall( //--------------------------------------------------------------------- //--------------------------------------------------------------------- LIBRARY_EXPORT int32_t CompleteClientUnaryCall2( - grpc_labview::gRPCid* callId, - int8_t* responseCluster, - grpc_labview::LStrHandle* errorMessage, - grpc_labview::AnyCluster* errorDetailsCluster) + grpc_labview::gRPCid *callId, + int8_t *responseCluster, + grpc_labview::LStrHandle *errorMessage, + grpc_labview::AnyCluster *errorDetailsCluster) { auto clientCall = callId->CastTo(); if (!clientCall) @@ -385,17 +393,20 @@ LIBRARY_EXPORT int32_t CompleteClientUnaryCall2( return -1; } + grpc_labview::gPointerManager.UnregisterPointer(callId); int32_t result = 0; if (clientCall->_status.ok()) { - if (!clientCall->_useLVEfficientMessage) { + clientCall->_runFuture.wait(); + if (!clientCall->_useLVEfficientMessage) + { try { grpc_labview::ClusterDataCopier::CopyToCluster(*clientCall->_response.get(), responseCluster); } - catch (grpc_labview::InvalidEnumValueException& e) + catch (grpc_labview::InvalidEnumValueException &e) { if (errorMessage != nullptr) { @@ -416,14 +427,19 @@ LIBRARY_EXPORT int32_t CompleteClientUnaryCall2( { } } - std::lock_guard lock(clientCall->_client->clientLock); - clientCall->_client->ActiveClientCalls.remove(clientCall.get()); + std::unique_lock lock(clientCall->_client->clientLock); + auto call = clientCall->_client->ActiveClientCalls.find(clientCall.get()); + if (call != clientCall->_client->ActiveClientCalls.end()) + { + clientCall->_client->ActiveClientCalls.erase(call); + } + lock.unlock(); return result; } //--------------------------------------------------------------------- //--------------------------------------------------------------------- -LIBRARY_EXPORT int32_t CompleteClientUnaryCall(grpc_labview::gRPCid* callId, int8_t* responseCluster) +LIBRARY_EXPORT int32_t CompleteClientUnaryCall(grpc_labview::gRPCid *callId, int8_t *responseCluster) { return CompleteClientUnaryCall2(callId, responseCluster, nullptr, nullptr); } @@ -431,13 +447,13 @@ LIBRARY_EXPORT int32_t CompleteClientUnaryCall(grpc_labview::gRPCid* callId, int //--------------------------------------------------------------------- //--------------------------------------------------------------------- LIBRARY_EXPORT int32_t ClientBeginClientStreamingCall( - grpc_labview::gRPCid* clientId, - const char* methodName, - const char* requestMessageName, - const char* responseMessageName, - grpc_labview::gRPCid** callId, + grpc_labview::gRPCid *clientId, + const char *methodName, + const char *requestMessageName, + const char *responseMessageName, + grpc_labview::gRPCid **callId, int32_t timeoutMs, - grpc_labview::gRPCid* contextId) + grpc_labview::gRPCid *contextId) { auto client = clientId->CastTo(); if (!client) @@ -466,6 +482,9 @@ LIBRARY_EXPORT int32_t ClientBeginClientStreamingCall( } auto clientCall = new grpc_labview::ClientStreamingClientCall(); + std::unique_lock lock(client->clientLock); + client->ActiveClientCalls[clientCall] = true; + lock.unlock(); *callId = grpc_labview::gPointerManager.RegisterPointer(clientCall); clientCall->_client = client; clientCall->_request = std::make_shared(requestMetadata); @@ -476,23 +495,21 @@ LIBRARY_EXPORT int32_t ClientBeginClientStreamingCall( auto writer = grpc::internal::ClientWriterFactory::Create(client->Channel.get(), method, &(clientCall->_context.get()->gRPCClientContext), clientCall->_response.get()); clientCall->_writer = std::shared_ptr>(writer); - std::lock_guard lock(client->clientLock); - client->ActiveClientCalls.push_back(clientCall); - return 0; + return 0; } //--------------------------------------------------------------------- //--------------------------------------------------------------------- LIBRARY_EXPORT int32_t ClientBeginServerStreamingCall( - grpc_labview::gRPCid* clientId, - const char* methodName, - const char* requestMessageName, - const char* responseMessageName, - int8_t* requestCluster, - grpc_labview::gRPCid** callId, + grpc_labview::gRPCid *clientId, + const char *methodName, + const char *requestMessageName, + const char *responseMessageName, + int8_t *requestCluster, + grpc_labview::gRPCid **callId, int32_t timeoutMs, - grpc_labview::gRPCid* contextId) -{ + grpc_labview::gRPCid *contextId) +{ auto client = clientId->CastTo(); if (!client) { @@ -520,6 +537,9 @@ LIBRARY_EXPORT int32_t ClientBeginServerStreamingCall( } auto clientCall = new grpc_labview::ServerStreamingClientCall(); + std::unique_lock lock(client->clientLock); + client->ActiveClientCalls[clientCall] = true; + lock.unlock(); *callId = grpc_labview::gPointerManager.RegisterPointer(clientCall); clientCall->_client = client; clientCall->_request = std::make_shared(requestMetadata); @@ -530,7 +550,7 @@ LIBRARY_EXPORT int32_t ClientBeginServerStreamingCall( { grpc_labview::ClusterDataCopier::CopyFromCluster(*clientCall->_request.get(), requestCluster); } - catch (grpc_labview::InvalidEnumValueException& e) + catch (grpc_labview::InvalidEnumValueException &e) { return e.code; } @@ -539,21 +559,19 @@ LIBRARY_EXPORT int32_t ClientBeginServerStreamingCall( auto reader = grpc::internal::ClientReaderFactory::Create(client->Channel.get(), method, &(clientCall->_context.get()->gRPCClientContext), *clientCall->_request.get()); clientCall->_reader = std::shared_ptr>(reader); - std::lock_guard lock(client->clientLock); - client->ActiveClientCalls.push_back(clientCall); return 0; } //--------------------------------------------------------------------- //--------------------------------------------------------------------- LIBRARY_EXPORT int32_t ClientBeginBidiStreamingCall( - grpc_labview::gRPCid* clientId, - const char* methodName, - const char* requestMessageName, - const char* responseMessageName, - grpc_labview::gRPCid** callId, + grpc_labview::gRPCid *clientId, + const char *methodName, + const char *requestMessageName, + const char *responseMessageName, + grpc_labview::gRPCid **callId, int32_t timeoutMs, - grpc_labview::gRPCid* contextId) + grpc_labview::gRPCid *contextId) { auto client = clientId->CastTo(); if (!client) @@ -582,6 +600,9 @@ LIBRARY_EXPORT int32_t ClientBeginBidiStreamingCall( } auto clientCall = new grpc_labview::BidiStreamingClientCall(); + std::unique_lock lock(client->clientLock); + client->ActiveClientCalls[clientCall] = true; + lock.unlock(); *callId = grpc_labview::gPointerManager.RegisterPointer(clientCall); clientCall->_client = client; clientCall->_request = std::make_shared(requestMetadata); @@ -592,34 +613,42 @@ LIBRARY_EXPORT int32_t ClientBeginBidiStreamingCall( auto readerWriter = grpc::internal::ClientReaderWriterFactory::Create(client->Channel.get(), method, &(clientCall->_context.get()->gRPCClientContext)); clientCall->_readerWriter = std::shared_ptr>(readerWriter); - std::lock_guard lock(client->clientLock); - client->ActiveClientCalls.push_back(clientCall); return 0; } //--------------------------------------------------------------------- //--------------------------------------------------------------------- -LIBRARY_EXPORT int32_t ClientBeginReadFromStream(grpc_labview::gRPCid* callId, grpc_labview::MagicCookie* occurrencePtr) +LIBRARY_EXPORT int32_t ClientBeginReadFromStream(grpc_labview::gRPCid *callId, grpc_labview::MagicCookie *occurrencePtr) { auto reader = callId->CastTo(); auto call = callId->CastTo(); - auto occurrence = *occurrencePtr; + auto featureConfig = grpc_labview::FeatureConfig::getInstance(); + + grpc_labview::MagicCookie occurrence = 0; + if (featureConfig.isFeatureEnabled("data_useOccurrence")) + { + occurrence = *occurrencePtr; + } if (!reader || !call) { - grpc_labview::SignalOccurrence(occurrence); + if (occurrence != 0){ + grpc_labview::SignalOccurrence(occurrence); + } return -1; } call->_occurrence = occurrence; reader->_readFuture = std::async( - std::launch::async, - [call, reader]() + std::launch::async, + [call, reader]() { call->_response->Clear(); auto result = reader->Read(call->_response.get()); - CheckActiveAndSignalOccurenceForClientCall(call.get()); + if (call->_occurrence != 0){ + CheckActiveAndSignalOccurenceForClientCall(call.get()); + } return result; }); @@ -628,7 +657,7 @@ LIBRARY_EXPORT int32_t ClientBeginReadFromStream(grpc_labview::gRPCid* callId, g //--------------------------------------------------------------------- //--------------------------------------------------------------------- -LIBRARY_EXPORT int32_t ClientCompleteReadFromStream(grpc_labview::gRPCid* callId, int* success, int8_t* responseCluster) +LIBRARY_EXPORT int32_t ClientCompleteReadFromStream(grpc_labview::gRPCid *callId, int *success, int8_t *responseCluster) { auto reader = callId->CastTo(); auto call = callId->CastTo(); @@ -644,7 +673,7 @@ LIBRARY_EXPORT int32_t ClientCompleteReadFromStream(grpc_labview::gRPCid* callId { grpc_labview::ClusterDataCopier::CopyToCluster(*call->_response.get(), responseCluster); } - catch (grpc_labview::InvalidEnumValueException& e) + catch (grpc_labview::InvalidEnumValueException &e) { return e.code; } @@ -654,7 +683,7 @@ LIBRARY_EXPORT int32_t ClientCompleteReadFromStream(grpc_labview::gRPCid* callId //--------------------------------------------------------------------- //--------------------------------------------------------------------- -LIBRARY_EXPORT int32_t ClientWriteToStream(grpc_labview::gRPCid* callId, int8_t* requestCluster, int* success) +LIBRARY_EXPORT int32_t ClientWriteToStream(grpc_labview::gRPCid *callId, int8_t *requestCluster, int *success) { auto writer = callId->CastTo(); if (!writer) @@ -670,7 +699,7 @@ LIBRARY_EXPORT int32_t ClientWriteToStream(grpc_labview::gRPCid* callId, int8_t* { grpc_labview::ClusterDataCopier::CopyFromCluster(*clientCall->_request.get(), requestCluster); } - catch (grpc_labview::InvalidEnumValueException& e) + catch (grpc_labview::InvalidEnumValueException &e) { return e.code; } @@ -680,7 +709,7 @@ LIBRARY_EXPORT int32_t ClientWriteToStream(grpc_labview::gRPCid* callId, int8_t* //--------------------------------------------------------------------- //--------------------------------------------------------------------- -LIBRARY_EXPORT int32_t ClientWritesComplete(grpc_labview::gRPCid* callId) +LIBRARY_EXPORT int32_t ClientWritesComplete(grpc_labview::gRPCid *callId) { auto writer = callId->CastTo(); if (!writer) @@ -694,11 +723,11 @@ LIBRARY_EXPORT int32_t ClientWritesComplete(grpc_labview::gRPCid* callId) //--------------------------------------------------------------------- //--------------------------------------------------------------------- LIBRARY_EXPORT int32_t FinishClientCompleteClientStreamingCall( - grpc_labview::gRPCid* callId, - int8_t* responseCluster, - grpc_labview::LStrHandle* errorMessage, - grpc_labview::AnyCluster* errorDetailsCluster) -{ + grpc_labview::gRPCid *callId, + int8_t *responseCluster, + grpc_labview::LStrHandle *errorMessage, + grpc_labview::AnyCluster *errorDetailsCluster) +{ auto call = callId->CastTo(); if (!call) { @@ -707,11 +736,12 @@ LIBRARY_EXPORT int32_t FinishClientCompleteClientStreamingCall( int32_t result = 0; if (call->_status.ok()) { + call->_runFuture.wait(); try { grpc_labview::ClusterDataCopier::CopyToCluster(*call->_response.get(), responseCluster); } - catch (grpc_labview::InvalidEnumValueException& e) + catch (grpc_labview::InvalidEnumValueException &e) { result = e.code; if (errorMessage != nullptr) @@ -731,30 +761,42 @@ LIBRARY_EXPORT int32_t FinishClientCompleteClientStreamingCall( { } } + std::unique_lock lock(call->_client->clientLock); + auto client_call = call->_client->ActiveClientCalls.find(call.get()); + if (client_call != call->_client->ActiveClientCalls.end()) { - std::lock_guard lock(call->_client->clientLock); - call->_client->ActiveClientCalls.remove(call.get()); + call->_client->ActiveClientCalls.erase(client_call); } + lock.unlock(); grpc_labview::gPointerManager.UnregisterPointer(callId); return result; } //--------------------------------------------------------------------- //--------------------------------------------------------------------- -LIBRARY_EXPORT int32_t ClientCompleteClientStreamingCall(grpc_labview::gRPCid* callId, grpc_labview::MagicCookie* occurrencePtr) +LIBRARY_EXPORT int32_t ClientCompleteClientStreamingCall(grpc_labview::gRPCid *callId, grpc_labview::MagicCookie *occurrencePtr) { auto call = callId->CastTo(); if (!call) { return -1; } - call->_occurrence = *occurrencePtr; + auto featureConfig = grpc_labview::FeatureConfig::getInstance(); + + if(featureConfig.isFeatureEnabled("data_useOccurrence")){ + call->_occurrence = *occurrencePtr; + } + else{ + call->_occurrence = 0; + } call->_runFuture = std::async( std::launch::async, [call]() { call->Finish(); - CheckActiveAndSignalOccurenceForClientCall(call.get()); + if(call->_occurrence != 0){ + CheckActiveAndSignalOccurenceForClientCall(call.get()); + } return 0; }); return 0; @@ -763,9 +805,9 @@ LIBRARY_EXPORT int32_t ClientCompleteClientStreamingCall(grpc_labview::gRPCid* c //--------------------------------------------------------------------- //--------------------------------------------------------------------- LIBRARY_EXPORT int32_t ClientCompleteStreamingCall( - grpc_labview::gRPCid* callId, - grpc_labview::LStrHandle* errorMessage, - grpc_labview::AnyCluster* errorDetailsCluster) + grpc_labview::gRPCid *callId, + grpc_labview::LStrHandle *errorMessage, + grpc_labview::AnyCluster *errorDetailsCluster) { auto call = callId->CastTo(); if (!call) @@ -778,7 +820,7 @@ LIBRARY_EXPORT int32_t ClientCompleteStreamingCall( grpc_labview::gPointerManager.UnregisterPointer(callId); call->Finish(); - int32_t result = 0; + int32_t result = 0; if (!call->_status.ok()) { result = -(1000 + call->_status.error_code()); @@ -790,15 +832,20 @@ LIBRARY_EXPORT int32_t ClientCompleteStreamingCall( { } } - std::lock_guard lock(call->_client->clientLock); - call->_client->ActiveClientCalls.remove(call.get()); + std::unique_lock lock(call->_client->clientLock); + auto client_call = call->_client->ActiveClientCalls.find(call.get()); + if (client_call != call->_client->ActiveClientCalls.end()) + { + call->_client->ActiveClientCalls.erase(client_call); + } + lock.unlock(); return result; } //--------------------------------------------------------------------- //--------------------------------------------------------------------- LIBRARY_EXPORT int32_t ClientCancelCallContext( - grpc_labview::gRPCid* contextId) + grpc_labview::gRPCid *contextId) { auto context = contextId->CastTo(); if (!context) @@ -813,9 +860,9 @@ LIBRARY_EXPORT int32_t ClientCancelCallContext( //--------------------------------------------------------------------- //--------------------------------------------------------------------- LIBRARY_EXPORT int32_t ClientCancelCall( - grpc_labview::gRPCid* callId, - grpc_labview::LStrHandle* errorMessage, - grpc_labview::AnyCluster* errorDetailsCluster) + grpc_labview::gRPCid *callId, + grpc_labview::LStrHandle *errorMessage, + grpc_labview::AnyCluster *errorDetailsCluster) { auto call = callId->CastTo(); if (!call) @@ -840,7 +887,12 @@ LIBRARY_EXPORT int32_t ClientCancelCall( { } } - std::lock_guard lock(call->_client->clientLock); - call->_client->ActiveClientCalls.remove(call.get()); + std::unique_lock lock(call->_client->clientLock); + auto client_call = call->_client->ActiveClientCalls.find(call.get()); + if (client_call != call->_client->ActiveClientCalls.end()) + { + call->_client->ActiveClientCalls.erase(client_call); + } + lock.unlock(); return result; } \ No newline at end of file diff --git a/src/grpc_client.h b/src/grpc_client.h index c0a62384..b1f953a5 100644 --- a/src/grpc_client.h +++ b/src/grpc_client.h @@ -10,9 +10,9 @@ #include #include #include -#include +#include -namespace grpc_labview +namespace grpc_labview { //--------------------------------------------------------------------- //--------------------------------------------------------------------- @@ -25,11 +25,11 @@ namespace grpc_labview { public: LabVIEWgRPCClient(); - void Connect(const char* address, const std::string& certificatePath); + void Connect(const char *address, const std::string &certificatePath); public: std::shared_ptr Channel; - std::list ActiveClientCalls; + std::unordered_map ActiveClientCalls; std::mutex clientLock; }; @@ -51,7 +51,7 @@ namespace grpc_labview virtual ~ClientCall(); virtual void Finish(); void Cancel(); - + public: std::shared_ptr _client; std::string _methodName; @@ -69,7 +69,7 @@ namespace grpc_labview class StreamWriter { public: - virtual bool Write(LVMessage* message) = 0; + virtual bool Write(LVMessage *message) = 0; virtual void WritesComplete() = 0; }; @@ -81,17 +81,18 @@ namespace grpc_labview std::future _readFuture; public: - virtual bool Read(LVMessage* message) = 0; + virtual bool Read(LVMessage *message) = 0; }; //--------------------------------------------------------------------- //--------------------------------------------------------------------- class ServerStreamingClientCall : public ClientCall, public StreamReader - { + { public: ~ServerStreamingClientCall() override; - bool Read(LVMessage* message) override; + bool Read(LVMessage *message) override; void Finish() override; + public: std::shared_ptr> _reader; }; @@ -99,16 +100,17 @@ namespace grpc_labview //--------------------------------------------------------------------- //--------------------------------------------------------------------- class ClientStreamingClientCall : public ClientCall, public StreamWriter - { + { public: ClientStreamingClientCall() { _writesComplete = false; } ~ClientStreamingClientCall(); void Finish() override; - bool Write(LVMessage* message) override; + bool Write(LVMessage *message) override; void WritesComplete() override; public: std::shared_ptr> _writer; + private: bool _writesComplete; }; @@ -116,17 +118,18 @@ namespace grpc_labview //--------------------------------------------------------------------- //--------------------------------------------------------------------- class BidiStreamingClientCall : public ClientCall, public StreamReader, public StreamWriter - { + { public: BidiStreamingClientCall() { _writesComplete = false; } ~BidiStreamingClientCall(); void Finish() override; void WritesComplete() override; - bool Read(LVMessage* message) override; - bool Write(LVMessage* message) override; + bool Read(LVMessage *message) override; + bool Write(LVMessage *message) override; public: std::shared_ptr> _readerWriter; + private: bool _writesComplete; }; diff --git a/src/grpc_interop.cc b/src/grpc_interop.cc index 50bde0ad..24e4bfcf 100644 --- a/src/grpc_interop.cc +++ b/src/grpc_interop.cc @@ -10,6 +10,7 @@ #include #include #include +#include namespace grpc_labview { @@ -187,6 +188,13 @@ namespace grpc_labview int32_t ServerCleanupProc(grpc_labview::gRPCid* serverId); +//--------------------------------------------------------------------- +//--------------------------------------------------------------------- +LIBRARY_EXPORT void readIniFile(const char* filePath) +{ + grpc_labview::FeatureConfig::getInstance().readConfigFromFile(filePath); +} + //--------------------------------------------------------------------- //--------------------------------------------------------------------- LIBRARY_EXPORT int32_t LVCreateServer(grpc_labview::gRPCid** id) diff --git a/src/lv_interop.cc b/src/lv_interop.cc index 51f9371b..5c362441 100644 --- a/src/lv_interop.cc +++ b/src/lv_interop.cc @@ -60,7 +60,7 @@ namespace grpc_labview void InitCallbacks() { // Instantiating the feature toggles singleton that will read the feature configuration file - FeatureConfig::getInstance().readConfigFromFile("feature_config.ini"); + // FeatureConfig::getInstance().readConfigFromFile("feature_config.ini"); if (NumericArrayResizeImp != nullptr) {