From 1cf1eac4cc387b886b246e71d0dfd8d55f1fcdad Mon Sep 17 00:00:00 2001 From: Claudio Bisegni <Claudio.Bisegni@lnf.infn.it> Date: Tue, 10 Jul 2018 15:51:12 +0200 Subject: [PATCH] Squashed commit of the following: - use pointer instenad struct for CMultiTypeDataArrayWrapper internal bson data because force an unwanted alignement for class, as reported by asan library. - remove warning in compilation due to use of wrong bson typed struct. - fix memory leaks CMultiTypeDataArrayWrapper dow to pointer usage. - remove performance tester from xcode project, need to be reimplemented, code is not deleted for try to recode. - fixed the bug that prevent the io driver to be deinitilized when a cu controller is removed. - UIToolkit is now removed. - implemented the burst management within KeyDataStorage driver - defined the structured data type for Burst execution (chaos/common/da- ta/structured/Dataset.h) and an RPC action for control unit to add a burst request to the driver queue. The driver KeyDataStorage have a queue that need to be used to check a a burst request is pendig. - storage type constant internally to class KeyDataStorage are used as bitfield to simplify the burst storage feature - RPC now don't use SerializationBuffer that in future will be depreca- ted and has been added the RPC echo test for MDS message channel - Storage Agein now check that tags vector is not defined or empty to permit the erase of the stored dataset - implemented api on mds (server/client) for the submition of burst information --- CHAOSFramework.xcodeproj/project.pbxproj | 285 +---- .../project.pbxproj | 2 - .../cache/EmbeddedLFCacheTest.cpp | 4 +- .../FrameworkTest/data/TestCDataWrapper.cpp | 7 +- .../DirectIODeviceServerChannelTest.cpp | 27 +- .../contents.xcworkspacedata | 6 - CMakeLists.txt | 21 +- ChaosDataExport/CMakeLists.txt | 2 +- .../ChaosDataExport.xcodeproj/project.pbxproj | 14 +- .../TestDatasetIO/ChaosDatasetIO.cpp | 21 +- ChaosDataExport/cde.cpp | 63 +- ChaosMetadataService/CMakeLists.txt | 3 +- ChaosMetadataService/QueryDataConsumer.cpp | 74 +- ChaosMetadataService/QueryDataConsumer.h | 19 +- .../api/control_unit/ControlUnitGroup.cpp | 4 +- .../api/control_unit/SendStorageBurst.cpp | 102 ++ .../api/control_unit/SendStorageBurst.h | 45 + .../abstraction/ObjectStorageDataAccess.h | 2 + .../MongoDBObjectStorageDataAccess.cpp | 40 +- .../mongodb/MongoDBObjectStorageDataAccess.h | 6 +- .../mongodb/MongoDBControlUnitDataAccess.cpp | 4 +- .../worker/DeviceSharedDataWorker.cpp | 1 + .../worker/DeviceSharedDataWorker.h | 4 +- .../DeviceSharedDataWorkerMetricCollector.cpp | 4 +- ccs/ccs.pro | 9 +- .../control_unit/ControUnitInstanceEditor.ui | 12 +- ccs/node/control_unit/ControlUnitEditor.ui | 4 +- ccs/widget/ChaosStorageTypeWidget.cpp | 12 + ccs/widget/ChaosStorageTypeWidget.h | 2 + ccs/widget/ChaosStorageTypeWidget.ui | 22 +- ccs/widget/StorageBurst.cpp | 53 + ccs/widget/StorageBurst.h | 32 + ccs/widget/StorageBurst.ui | 168 +++ chaos/common/chaos_constants.h | 44 +- chaos/common/chaos_types.h | 13 +- chaos/common/data/CDataBuffer.cpp | 50 +- chaos/common/data/CDataBuffer.h | 26 +- chaos/common/data/CDataVariant.cpp | 23 +- chaos/common/data/CDataVariant.h | 2 +- chaos/common/data/CDataWrapper.cpp | 442 +++---- chaos/common/data/CDataWrapper.h | 44 +- chaos/common/data/structured/Dataset.cpp | 16 + chaos/common/data/structured/Dataset.h | 33 + chaos/common/direct_io/DirectIODispatcher.cpp | 3 +- .../channel/DirectIODeviceChannelGlobal.h | 12 +- .../channel/DirectIODeviceClientChannel.cpp | 70 +- .../channel/DirectIODeviceClientChannel.h | 9 +- .../channel/DirectIODeviceServerChannel.cpp | 79 +- .../channel/DirectIODeviceServerChannel.h | 34 +- .../direct_io/impl/ZMQDirectIOClient.cpp | 2 - .../http_adapter/HTTPBaseAdapter.h | 2 +- .../http_adapter/HTTPClientAdapter.cpp | 3 +- .../ExternalBSONExtJsonSerialization.cpp | 2 +- .../ExternalBSONJsonSerialization.cpp | 2 +- chaos/common/healt_system/HealtManager.cpp | 56 +- chaos/common/healt_system/HealtManager.h | 10 +- chaos/common/healt_system/HealtMetric.cpp | 2 +- chaos/common/io/IODataDriver.cpp | 17 - chaos/common/io/IODataDriver.h | 36 +- chaos/common/io/IODirectIODriver.cpp | 58 +- chaos/common/io/IODirectIODriver.h | 24 +- chaos/common/io/QueryCursor.cpp | 7 +- chaos/common/io/QueryCursor.h | 5 +- chaos/common/message/MDSMessageChannel.cpp | 21 +- chaos/common/message/MDSMessageChannel.h | 3 + chaos/common/rpc/zmq/ZMQClient.cpp | 12 +- chaos/common/rpc/zmq/ZMQServer.cpp | 19 +- .../rpc/zmq/ZmqMemoryManagement.h} | 19 +- chaos/common/state_flag/StateFlagCatalog.cpp | 12 +- chaos/common/state_flag/StateFlagCatalog.h | 4 +- chaos/common/utility/DataBuffer.h | 30 +- .../control_manager/AbstractControlUnit.cpp | 173 +-- .../control_manager/AbstractControlUnit.h | 17 +- .../control_manager/AbstractExecutionUnit.cpp | 4 +- .../control_manager/AbstractExecutionUnit.h | 1 + .../control_manager/script/api/EUSearch.cpp | 3 + .../script/api/plugin/EUPluginApiWrapper.cpp | 2 +- chaos/cu_toolkit/data_manager/DataManager.cpp | 6 +- chaos/cu_toolkit/data_manager/DataManager.h | 4 +- .../data_manager/KeyDataStorage.cpp | 208 ++-- .../cu_toolkit/data_manager/KeyDataStorage.h | 85 +- chaos/ui_toolkit/CMakeLists.txt | 41 - chaos/ui_toolkit/ChaosUIToolkit.cpp | 101 -- chaos/ui_toolkit/ChaosUIToolkit.h | 88 -- chaos/ui_toolkit/ChaosUIToolkitCWrapper.cc | 512 -------- chaos/ui_toolkit/ChaosUIToolkitCWrapper.h | 244 ---- .../HighLevelApi/DeviceController.cpp | 1065 ----------------- .../HighLevelApi/DeviceController.h | 470 -------- chaos/ui_toolkit/HighLevelApi/HLDataApi.cpp | 97 -- chaos/ui_toolkit/HighLevelApi/HLDataApi.h | 69 -- .../HighLevelApi/HLInfrastructureApi.cpp | 38 - .../HighLevelApi/HLInfrastructureApi.h | 43 - chaos/ui_toolkit/Labview/LV12/CUinfo.ctl | Bin 4775 -> 0 bytes .../Labview/LV12/ChaosPowerSupply.vi | Bin 27532 -> 0 bytes .../Labview/LV12/InitialiseChaosCUs.vi | Bin 13566 -> 0 bytes chaos/ui_toolkit/LowLevelApi/LLDataApi.h | 47 - chaos/ui_toolkit/LowLevelApi/LLRpcApi.cpp | 172 --- chaos/ui_toolkit/LowLevelApi/LLRpcApi.h | 152 --- chaos/ui_toolkit/caching/LiveDataFetcher.cpp | 65 - chaos/ui_toolkit/caching/LiveDataFetcher.h | 74 -- chaos_metadata_service_client/CMakeLists.txt | 13 +- .../api_proxy/control_unit/Delete.h | 2 - .../control_unit/SendStorageBurst.cpp | 54 + .../api_proxy/control_unit/SendStorageBurst.h | 64 + .../api_proxy/control_unit/control_unit.h | 2 +- .../node_controller/CUController.cpp | 95 +- .../node_controller/CUController.h | 46 +- config/CMakeMacroUtils.txt | 6 + example/ChaosCLI/CMakeLists.txt | 16 - example/ChaosCLI/ChaosCLI | Bin 553004 -> 0 bytes .../ChaosCLI.xcodeproj/project.pbxproj | 261 ---- .../contents.xcworkspacedata | 7 - example/ChaosCLI/main.cpp | 518 -------- example/ChaosPerformanceTester/main.cpp | 4 - 114 files changed, 1909 insertions(+), 5280 deletions(-) create mode 100644 ChaosMetadataService/api/control_unit/SendStorageBurst.cpp create mode 100644 ChaosMetadataService/api/control_unit/SendStorageBurst.h create mode 100644 ccs/widget/StorageBurst.cpp create mode 100644 ccs/widget/StorageBurst.h create mode 100644 ccs/widget/StorageBurst.ui rename chaos/{ui_toolkit/LowLevelApi/LLDataApi.cpp => common/rpc/zmq/ZmqMemoryManagement.h} (61%) delete mode 100644 chaos/ui_toolkit/CMakeLists.txt delete mode 100644 chaos/ui_toolkit/ChaosUIToolkit.cpp delete mode 100644 chaos/ui_toolkit/ChaosUIToolkit.h delete mode 100644 chaos/ui_toolkit/ChaosUIToolkitCWrapper.cc delete mode 100644 chaos/ui_toolkit/ChaosUIToolkitCWrapper.h delete mode 100644 chaos/ui_toolkit/HighLevelApi/DeviceController.cpp delete mode 100644 chaos/ui_toolkit/HighLevelApi/DeviceController.h delete mode 100644 chaos/ui_toolkit/HighLevelApi/HLDataApi.cpp delete mode 100644 chaos/ui_toolkit/HighLevelApi/HLDataApi.h delete mode 100644 chaos/ui_toolkit/HighLevelApi/HLInfrastructureApi.cpp delete mode 100644 chaos/ui_toolkit/HighLevelApi/HLInfrastructureApi.h delete mode 100644 chaos/ui_toolkit/Labview/LV12/CUinfo.ctl delete mode 100644 chaos/ui_toolkit/Labview/LV12/ChaosPowerSupply.vi delete mode 100644 chaos/ui_toolkit/Labview/LV12/InitialiseChaosCUs.vi delete mode 100644 chaos/ui_toolkit/LowLevelApi/LLDataApi.h delete mode 100644 chaos/ui_toolkit/LowLevelApi/LLRpcApi.cpp delete mode 100644 chaos/ui_toolkit/LowLevelApi/LLRpcApi.h delete mode 100644 chaos/ui_toolkit/caching/LiveDataFetcher.cpp delete mode 100644 chaos/ui_toolkit/caching/LiveDataFetcher.h create mode 100644 chaos_metadata_service_client/api_proxy/control_unit/SendStorageBurst.cpp create mode 100644 chaos_metadata_service_client/api_proxy/control_unit/SendStorageBurst.h delete mode 100644 example/ChaosCLI/CMakeLists.txt delete mode 100755 example/ChaosCLI/ChaosCLI delete mode 100644 example/ChaosCLI/ChaosCLI.xcodeproj/project.pbxproj delete mode 100644 example/ChaosCLI/ChaosCLI.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 example/ChaosCLI/main.cpp diff --git a/CHAOSFramework.xcodeproj/project.pbxproj b/CHAOSFramework.xcodeproj/project.pbxproj index 79cecbc8c..7df219ddc 100644 --- a/CHAOSFramework.xcodeproj/project.pbxproj +++ b/CHAOSFramework.xcodeproj/project.pbxproj @@ -15,7 +15,6 @@ dependencies = ( 3211C6781C146252003B38BF /* PBXTargetDependency */, 3211C67A1C146252003B38BF /* PBXTargetDependency */, - 3211C67C1C146252003B38BF /* PBXTargetDependency */, 3211C67E1C146252003B38BF /* PBXTargetDependency */, 3211C6801C146252003B38BF /* PBXTargetDependency */, 3211C6821C146252003B38BF /* PBXTargetDependency */, @@ -99,8 +98,6 @@ 320CA9511C29D16D00894AAA /* DeleteUS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 320CA94F1C29D16D00894AAA /* DeleteUS.cpp */; }; 320CA9541C29D71A00894AAA /* DeleteUS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 320CA9521C29D71A00894AAA /* DeleteUS.cpp */; }; 320CA9551C29D71A00894AAA /* DeleteUS.h in Headers */ = {isa = PBXBuildFile; fileRef = 320CA9531C29D71A00894AAA /* DeleteUS.h */; }; - 320DF98D14E17E2700251621 /* DeviceController.h in Headers */ = {isa = PBXBuildFile; fileRef = 320DF98C14E17E2700251621 /* DeviceController.h */; }; - 320DF99114E190BB00251621 /* DeviceController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 320DF98F14E17E3D00251621 /* DeviceController.cpp */; }; 320E2FBF1D7EB9CB0077E8FE /* QueryCursor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 320E2FBD1D7EB9CB0077E8FE /* QueryCursor.cpp */; }; 320E2FC01D7EB9CB0077E8FE /* QueryCursor.h in Headers */ = {isa = PBXBuildFile; fileRef = 320E2FBE1D7EB9CB0077E8FE /* QueryCursor.h */; }; 320E773E1A7FBD84001FB8BC /* UnitServerAckBatchCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 320E773C1A7FBD84001FB8BC /* UnitServerAckBatchCommand.cpp */; }; @@ -117,8 +114,6 @@ 3211CCDA1B021B8D00F9B80E /* GetBestEndpoints.h in Headers */ = {isa = PBXBuildFile; fileRef = 3211CCD81B021B8D00F9B80E /* GetBestEndpoints.h */; }; 3211CCDD1B03402800F9B80E /* QuantumKeyConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3211CCDB1B03402800F9B80E /* QuantumKeyConsumer.cpp */; }; 3211CCDE1B03402800F9B80E /* QuantumKeyConsumer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3211CCDC1B03402800F9B80E /* QuantumKeyConsumer.h */; }; - 3211FD1D1698699D00424A3C /* LiveDataFetcher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3211FD1B1698699D00424A3C /* LiveDataFetcher.cpp */; }; - 3211FD1E1698699D00424A3C /* LiveDataFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 3211FD1C1698699D00424A3C /* LiveDataFetcher.h */; }; 3214E7401DC1081100A67414 /* AlarmDescription.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3214E73E1DC1081100A67414 /* AlarmDescription.cpp */; }; 3214E7411DC1081100A67414 /* AlarmDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 3214E73F1DC1081100A67414 /* AlarmDescription.h */; }; 3214E7441DC10B9500A67414 /* MultiSeverityAlarm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3214E7421DC10B9500A67414 /* MultiSeverityAlarm.cpp */; }; @@ -421,8 +416,6 @@ 32655AD71E9CE0FA00829266 /* RemoveScript.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 32655AD51E9CE0FA00829266 /* RemoveScript.cpp */; }; 32655ADA1E9CE1E700829266 /* RemoveScript.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 32655AD81E9CE1E700829266 /* RemoveScript.cpp */; }; 32655ADB1E9CE1E700829266 /* RemoveScript.h in Headers */ = {isa = PBXBuildFile; fileRef = 32655AD91E9CE1E700829266 /* RemoveScript.h */; }; - 3265BF4615D1A9CA00C3CAC6 /* ChaosUIToolkitCWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 3265BF4515D1A9CA00C3CAC6 /* ChaosUIToolkitCWrapper.h */; }; - 3265BF4915D1AA9F00C3CAC6 /* ChaosUIToolkitCWrapper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3265BF4815D1AA9F00C3CAC6 /* ChaosUIToolkitCWrapper.cc */; }; 3265F332197E626900F22FBC /* WorkUnitManagement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 32D72CA8197D196D00512B89 /* WorkUnitManagement.cpp */; }; 3265F94B1FB899D400FEA246 /* DataPack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3265F9491FB899D300FEA246 /* DataPack.cpp */; }; 3265F94C1FB89F6B00FEA246 /* bson-context.c in Sources */ = {isa = PBXBuildFile; fileRef = 3265F9111FB8997300FEA246 /* bson-context.c */; }; @@ -536,16 +529,6 @@ 326DB4CA14B3A3E50018A8D0 /* DataManagerException.h in Headers */ = {isa = PBXBuildFile; fileRef = 326DB4B214B3A3E50018A8D0 /* DataManagerException.h */; }; 326DB4CB14B3A3E50018A8D0 /* KeyDataStorage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 326DB4B314B3A3E50018A8D0 /* KeyDataStorage.cpp */; }; 326DB4CC14B3A3E50018A8D0 /* KeyDataStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 326DB4B414B3A3E50018A8D0 /* KeyDataStorage.h */; }; - 326DB4EB14B3B0070018A8D0 /* ChaosUIToolkit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 326DB4D714B3B0070018A8D0 /* ChaosUIToolkit.cpp */; }; - 326DB4EC14B3B0070018A8D0 /* ChaosUIToolkit.h in Headers */ = {isa = PBXBuildFile; fileRef = 326DB4D814B3B0070018A8D0 /* ChaosUIToolkit.h */; }; - 326DB4ED14B3B0070018A8D0 /* HLDataApi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 326DB4DA14B3B0070018A8D0 /* HLDataApi.cpp */; }; - 326DB4EE14B3B0070018A8D0 /* HLDataApi.h in Headers */ = {isa = PBXBuildFile; fileRef = 326DB4DB14B3B0070018A8D0 /* HLDataApi.h */; }; - 326DB4EF14B3B0070018A8D0 /* HLInfrastructureApi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 326DB4DC14B3B0070018A8D0 /* HLInfrastructureApi.cpp */; }; - 326DB4F014B3B0070018A8D0 /* HLInfrastructureApi.h in Headers */ = {isa = PBXBuildFile; fileRef = 326DB4DD14B3B0070018A8D0 /* HLInfrastructureApi.h */; }; - 326DB4F314B3B0070018A8D0 /* LLDataApi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 326DB4E114B3B0070018A8D0 /* LLDataApi.cpp */; }; - 326DB4F414B3B0070018A8D0 /* LLDataApi.h in Headers */ = {isa = PBXBuildFile; fileRef = 326DB4E214B3B0070018A8D0 /* LLDataApi.h */; }; - 326DB4F514B3B0070018A8D0 /* LLRpcApi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 326DB4E314B3B0070018A8D0 /* LLRpcApi.cpp */; }; - 326DB4F614B3B0070018A8D0 /* LLRpcApi.h in Headers */ = {isa = PBXBuildFile; fileRef = 326DB4E414B3B0070018A8D0 /* LLRpcApi.h */; }; 326EA57814D2D8EE00D4962A /* MultiKeyObjectWaitSemaphore.h in Headers */ = {isa = PBXBuildFile; fileRef = 326EA57714D2D8EE00D4962A /* MultiKeyObjectWaitSemaphore.h */; }; 3270D5E81CCFAC4F0072017B /* AbstractExecutionUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3270D5E61CCFAC4F0072017B /* AbstractExecutionUnit.cpp */; }; 3270D5E91CCFAC4F0072017B /* AbstractExecutionUnit.h in Headers */ = {isa = PBXBuildFile; fileRef = 3270D5E71CCFAC4F0072017B /* AbstractExecutionUnit.h */; }; @@ -579,6 +562,9 @@ 3277A22F20973A0100FD7307 /* CPPScriptVM.h in Headers */ = {isa = PBXBuildFile; fileRef = 3277A22D20973A0100FD7307 /* CPPScriptVM.h */; }; 3277A235209C4AFD00FD7307 /* ClingRootInterpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3277A233209C4AFD00FD7307 /* ClingRootInterpreter.cpp */; }; 3277A236209C4AFD00FD7307 /* ClingRootInterpreter.h in Headers */ = {isa = PBXBuildFile; fileRef = 3277A234209C4AFD00FD7307 /* ClingRootInterpreter.h */; }; + 3278855620EB91CE004D1A34 /* SendStorageBurst.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3278855520EB91CE004D1A34 /* SendStorageBurst.cpp */; }; + 3278855920EB97BC004D1A34 /* SendStorageBurst.h in Headers */ = {isa = PBXBuildFile; fileRef = 3278855720EB97BC004D1A34 /* SendStorageBurst.h */; }; + 3278855A20EB97BC004D1A34 /* SendStorageBurst.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3278855820EB97BC004D1A34 /* SendStorageBurst.cpp */; }; 32788D7F1F277207009BBB1E /* OpcodeDriverWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32788D7D1F277207009BBB1E /* OpcodeDriverWrapper.h */; }; 32788D831F27766A009BBB1E /* OpcodeExternalCommandMapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 32788D811F27766A009BBB1E /* OpcodeExternalCommandMapper.h */; }; 327967B515DF99FB0003C6DA /* RpcClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 327967B415DF99FB0003C6DA /* RpcClient.cpp */; }; @@ -1213,13 +1199,6 @@ remoteGlobalIDString = 3260276514B3068100C906CE; remoteInfo = chaos_cutoolkit; }; - 3211C67B1C146252003B38BF /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 3260260D14B300FE00C906CE /* Project object */; - proxyType = 1; - remoteGlobalIDString = 3260278614B307DA00C906CE; - remoteInfo = chaos_uitoolkit; - }; 3211C67D1C146252003B38BF /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 3260260D14B300FE00C906CE /* Project object */; @@ -1345,8 +1324,6 @@ 320CA9521C29D71A00894AAA /* DeleteUS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeleteUS.cpp; sourceTree = "<group>"; }; 320CA9531C29D71A00894AAA /* DeleteUS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeleteUS.h; sourceTree = "<group>"; }; 320DEA6319CC77F200ED66AB /* ThreadSemaphore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ThreadSemaphore.h; sourceTree = "<group>"; }; - 320DF98C14E17E2700251621 /* DeviceController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeviceController.h; sourceTree = "<group>"; }; - 320DF98F14E17E3D00251621 /* DeviceController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeviceController.cpp; sourceTree = "<group>"; }; 320E2FBD1D7EB9CB0077E8FE /* QueryCursor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = QueryCursor.cpp; sourceTree = "<group>"; }; 320E2FBE1D7EB9CB0077E8FE /* QueryCursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QueryCursor.h; sourceTree = "<group>"; }; 320E773C1A7FBD84001FB8BC /* UnitServerAckBatchCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnitServerAckBatchCommand.cpp; sourceTree = "<group>"; }; @@ -1371,8 +1348,6 @@ 3211CCD81B021B8D00F9B80E /* GetBestEndpoints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetBestEndpoints.h; sourceTree = "<group>"; }; 3211CCDB1B03402800F9B80E /* QuantumKeyConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = QuantumKeyConsumer.cpp; sourceTree = "<group>"; }; 3211CCDC1B03402800F9B80E /* QuantumKeyConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QuantumKeyConsumer.h; sourceTree = "<group>"; }; - 3211FD1B1698699D00424A3C /* LiveDataFetcher.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LiveDataFetcher.cpp; sourceTree = "<group>"; }; - 3211FD1C1698699D00424A3C /* LiveDataFetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiveDataFetcher.h; sourceTree = "<group>"; }; 3214E73E1DC1081100A67414 /* AlarmDescription.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = AlarmDescription.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; 3214E73F1DC1081100A67414 /* AlarmDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = AlarmDescription.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 3214E7421DC10B9500A67414 /* MultiSeverityAlarm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = MultiSeverityAlarm.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; @@ -1393,6 +1368,7 @@ 3215860C178756B40090E7E6 /* AbstractDriverPlugin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AbstractDriverPlugin.cpp; sourceTree = "<group>"; }; 3215860E17875FDB0090E7E6 /* DriverPluginLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DriverPluginLoader.cpp; sourceTree = "<group>"; }; 3215860F17875FDB0090E7E6 /* DriverPluginLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DriverPluginLoader.h; sourceTree = "<group>"; }; + 32161D1B20E29E9E00C4F750 /* ZmqMemoryManagement.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZmqMemoryManagement.h; sourceTree = "<group>"; }; 3216601014D49D0F008DADD2 /* ObjectWaitSemaphore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ObjectWaitSemaphore.h; sourceTree = "<group>"; }; 3219E69D18CC7AE600C2F795 /* DirectIOClientConnection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DirectIOClientConnection.cpp; sourceTree = "<group>"; }; 3219E69E18CC7AE600C2F795 /* DirectIOClientConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectIOClientConnection.h; sourceTree = "<group>"; }; @@ -1442,7 +1418,6 @@ 322EC1BA1D34F2E10012467C /* StateFlagCatalog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StateFlagCatalog.h; sourceTree = "<group>"; }; 3230BEBB1817A9E100EA5793 /* libchaos_common.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libchaos_common.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 3230BEBC1817A9E100EA5793 /* libchaos_cutoolkit.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libchaos_cutoolkit.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; - 3230BEBD1817A9E100EA5793 /* libchaos_uitoolkit.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libchaos_uitoolkit.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 3230BEBE1817A9E100EA5793 /* ChaosMetadataService */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ChaosMetadataService; sourceTree = BUILT_PRODUCTS_DIR; }; 3230BEC0181A6ADB00EA5793 /* DatasetDB.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DatasetDB.cpp; sourceTree = "<group>"; }; 3230BEC1181A6ADB00EA5793 /* DatasetDB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DatasetDB.h; sourceTree = "<group>"; }; @@ -1738,8 +1713,6 @@ 32655AD81E9CE1E700829266 /* RemoveScript.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RemoveScript.cpp; sourceTree = "<group>"; }; 32655AD91E9CE1E700829266 /* RemoveScript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoveScript.h; sourceTree = "<group>"; }; 326573F218CCD365009E9B6B /* TemplatedKeyObjectContainer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TemplatedKeyObjectContainer.h; sourceTree = "<group>"; }; - 3265BF4515D1A9CA00C3CAC6 /* ChaosUIToolkitCWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChaosUIToolkitCWrapper.h; sourceTree = "<group>"; }; - 3265BF4815D1AA9F00C3CAC6 /* ChaosUIToolkitCWrapper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ChaosUIToolkitCWrapper.cc; sourceTree = "<group>"; }; 3265F9101FB8997300FEA246 /* b64_ntop.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = b64_ntop.h; sourceTree = "<group>"; }; 3265F9111FB8997300FEA246 /* bson-context.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-context.c"; sourceTree = "<group>"; }; 3265F9121FB8997300FEA246 /* bson-oid.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "bson-oid.c"; sourceTree = "<group>"; }; @@ -1912,16 +1885,6 @@ 326DB4B214B3A3E50018A8D0 /* DataManagerException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = DataManagerException.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 326DB4B314B3A3E50018A8D0 /* KeyDataStorage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = KeyDataStorage.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; 326DB4B414B3A3E50018A8D0 /* KeyDataStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = KeyDataStorage.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - 326DB4D714B3B0070018A8D0 /* ChaosUIToolkit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ChaosUIToolkit.cpp; sourceTree = "<group>"; }; - 326DB4D814B3B0070018A8D0 /* ChaosUIToolkit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChaosUIToolkit.h; sourceTree = "<group>"; }; - 326DB4DA14B3B0070018A8D0 /* HLDataApi.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = HLDataApi.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; - 326DB4DB14B3B0070018A8D0 /* HLDataApi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = HLDataApi.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - 326DB4DC14B3B0070018A8D0 /* HLInfrastructureApi.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = HLInfrastructureApi.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; - 326DB4DD14B3B0070018A8D0 /* HLInfrastructureApi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = HLInfrastructureApi.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - 326DB4E114B3B0070018A8D0 /* LLDataApi.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LLDataApi.cpp; sourceTree = "<group>"; }; - 326DB4E214B3B0070018A8D0 /* LLDataApi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLDataApi.h; sourceTree = "<group>"; }; - 326DB4E314B3B0070018A8D0 /* LLRpcApi.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = LLRpcApi.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; - 326DB4E414B3B0070018A8D0 /* LLRpcApi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = LLRpcApi.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 326EA57714D2D8EE00D4962A /* MultiKeyObjectWaitSemaphore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MultiKeyObjectWaitSemaphore.h; sourceTree = "<group>"; }; 3270D5E61CCFAC4F0072017B /* AbstractExecutionUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AbstractExecutionUnit.cpp; sourceTree = "<group>"; }; 3270D5E71CCFAC4F0072017B /* AbstractExecutionUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AbstractExecutionUnit.h; sourceTree = "<group>"; }; @@ -1963,6 +1926,10 @@ 3277A22D20973A0100FD7307 /* CPPScriptVM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CPPScriptVM.h; sourceTree = "<group>"; }; 3277A233209C4AFD00FD7307 /* ClingRootInterpreter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ClingRootInterpreter.cpp; sourceTree = "<group>"; }; 3277A234209C4AFD00FD7307 /* ClingRootInterpreter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ClingRootInterpreter.h; sourceTree = "<group>"; }; + 3278855420EB91CE004D1A34 /* SendStorageBurst.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SendStorageBurst.h; sourceTree = "<group>"; }; + 3278855520EB91CE004D1A34 /* SendStorageBurst.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SendStorageBurst.cpp; sourceTree = "<group>"; }; + 3278855720EB97BC004D1A34 /* SendStorageBurst.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SendStorageBurst.h; sourceTree = "<group>"; }; + 3278855820EB97BC004D1A34 /* SendStorageBurst.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SendStorageBurst.cpp; sourceTree = "<group>"; }; 32788D7D1F277207009BBB1E /* OpcodeDriverWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpcodeDriverWrapper.h; sourceTree = "<group>"; }; 32788D811F27766A009BBB1E /* OpcodeExternalCommandMapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpcodeExternalCommandMapper.h; sourceTree = "<group>"; }; 327967B415DF99FB0003C6DA /* RpcClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = RpcClient.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; @@ -2092,7 +2059,6 @@ 32936C661D9280BA00485F71 /* GetSnapshotForNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetSnapshotForNode.h; sourceTree = "<group>"; }; 3294905A159AF4BF00E86BD1 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = CMakeLists.txt; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = "<none>"; }; 3294905B159AF4D700E86BD1 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; }; - 3294905C159AF4E600E86BD1 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; }; 3296030F1876B45000CDCADA /* AttributeValueSharedCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AttributeValueSharedCache.cpp; sourceTree = "<group>"; }; 329603101876B45000CDCADA /* AttributeValueSharedCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AttributeValueSharedCache.h; sourceTree = "<group>"; }; 329603141876B45000CDCADA /* BatchCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BatchCommand.cpp; sourceTree = "<group>"; }; @@ -2801,13 +2767,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 3260278414B307DA00C906CE /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 326413961E44ACE60035E175 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -2994,15 +2953,6 @@ path = serialization; sourceTree = "<group>"; }; - 3211FD061698666700424A3C /* caching */ = { - isa = PBXGroup; - children = ( - 3211FD1B1698699D00424A3C /* LiveDataFetcher.cpp */, - 3211FD1C1698699D00424A3C /* LiveDataFetcher.h */, - ); - path = caching; - sourceTree = "<group>"; - }; 3214EF0C1D466F41004DB689 /* manipulation */ = { isa = PBXGroup; children = ( @@ -3293,6 +3243,8 @@ 32B299A31BE25ABE000D3716 /* RecoverError.h */, 32A13EBA1C2016C60010F3FC /* Delete.cpp */, 32A13EBB1C2016C60010F3FC /* Delete.h */, + 3278855520EB91CE004D1A34 /* SendStorageBurst.cpp */, + 3278855420EB91CE004D1A34 /* SendStorageBurst.h */, ); path = control_unit; sourceTree = "<group>"; @@ -3322,6 +3274,8 @@ 32B299A91BE27945000D3716 /* RecoverError.h */, 32A13EB61C2014170010F3FC /* Delete.cpp */, 32A13EB71C2014170010F3FC /* Delete.h */, + 3278855820EB97BC004D1A34 /* SendStorageBurst.cpp */, + 3278855720EB97BC004D1A34 /* SendStorageBurst.h */, 3221D73A1CF5F31F001BE971 /* control_unit.h */, ); path = control_unit; @@ -3601,7 +3555,6 @@ 32F9C79A1E81943F00D4B250 /* CouchTest */, 3230BEBB1817A9E100EA5793 /* libchaos_common.dylib */, 3230BEBC1817A9E100EA5793 /* libchaos_cutoolkit.dylib */, - 3230BEBD1817A9E100EA5793 /* libchaos_uitoolkit.dylib */, 3230BEBE1817A9E100EA5793 /* ChaosMetadataService */, 32661C661AA73D5B00F1A721 /* libchaos_metadata_service_client.dylib */, 322085DA1AC5A0E100F1B71A /* ChaosMetadataServiceClientTest */, @@ -3882,6 +3835,7 @@ 3268CE32161608D100FCDB10 /* ZMQClient.h */, 3268CE33161608D100FCDB10 /* ZMQServer.cpp */, 3268CE34161608D100FCDB10 /* ZMQServer.h */, + 32161D1B20E29E9E00C4F750 /* ZmqMemoryManagement.h */, ); path = zmq; sourceTree = "<group>"; @@ -3964,7 +3918,6 @@ isa = PBXGroup; children = ( 326DB3B314B38BC00018A8D0 /* common */, - 326DB4CF14B3B0040018A8D0 /* ui_toolkit */, 326DB49914B3A3E20018A8D0 /* cu_toolkit */, ); path = chaos; @@ -4350,45 +4303,6 @@ path = data_manager; sourceTree = "<group>"; }; - 326DB4CF14B3B0040018A8D0 /* ui_toolkit */ = { - isa = PBXGroup; - children = ( - 3294905C159AF4E600E86BD1 /* CMakeLists.txt */, - 326DB4D714B3B0070018A8D0 /* ChaosUIToolkit.cpp */, - 326DB4D814B3B0070018A8D0 /* ChaosUIToolkit.h */, - 3265BF4815D1AA9F00C3CAC6 /* ChaosUIToolkitCWrapper.cc */, - 3265BF4515D1A9CA00C3CAC6 /* ChaosUIToolkitCWrapper.h */, - 326DB4D914B3B0070018A8D0 /* HighLevelApi */, - 326DB4E014B3B0070018A8D0 /* LowLevelApi */, - 3211FD061698666700424A3C /* caching */, - ); - path = ui_toolkit; - sourceTree = "<group>"; - }; - 326DB4D914B3B0070018A8D0 /* HighLevelApi */ = { - isa = PBXGroup; - children = ( - 326DB4DA14B3B0070018A8D0 /* HLDataApi.cpp */, - 326DB4DB14B3B0070018A8D0 /* HLDataApi.h */, - 326DB4DC14B3B0070018A8D0 /* HLInfrastructureApi.cpp */, - 326DB4DD14B3B0070018A8D0 /* HLInfrastructureApi.h */, - 320DF98F14E17E3D00251621 /* DeviceController.cpp */, - 320DF98C14E17E2700251621 /* DeviceController.h */, - ); - path = HighLevelApi; - sourceTree = "<group>"; - }; - 326DB4E014B3B0070018A8D0 /* LowLevelApi */ = { - isa = PBXGroup; - children = ( - 326DB4E114B3B0070018A8D0 /* LLDataApi.cpp */, - 326DB4E214B3B0070018A8D0 /* LLDataApi.h */, - 326DB4E314B3B0070018A8D0 /* LLRpcApi.cpp */, - 326DB4E414B3B0070018A8D0 /* LLRpcApi.h */, - ); - path = LowLevelApi; - sourceTree = "<group>"; - }; 3270E06A1C6CBA7D00105726 /* logging */ = { isa = PBXGroup; children = ( @@ -6078,21 +5992,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 3260278514B307DA00C906CE /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 326DB4EC14B3B0070018A8D0 /* ChaosUIToolkit.h in Headers */, - 326DB4EE14B3B0070018A8D0 /* HLDataApi.h in Headers */, - 326DB4F014B3B0070018A8D0 /* HLInfrastructureApi.h in Headers */, - 326DB4F414B3B0070018A8D0 /* LLDataApi.h in Headers */, - 326DB4F614B3B0070018A8D0 /* LLRpcApi.h in Headers */, - 320DF98D14E17E2700251621 /* DeviceController.h in Headers */, - 3265BF4615D1A9CA00C3CAC6 /* ChaosUIToolkitCWrapper.h in Headers */, - 3211FD1E1698699D00424A3C /* LiveDataFetcher.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 32661C641AA73D5B00F1A721 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -6204,6 +6103,7 @@ 3211CCDA1B021B8D00F9B80E /* GetBestEndpoints.h in Headers */, 32661C6E1AA741D000F1A721 /* ChaosMetadataServiceClient.h in Headers */, 32B299AB1BE27945000D3716 /* RecoverError.h in Headers */, + 3278855920EB97BC004D1A34 /* SendStorageBurst.h in Headers */, 326413941E40C72C0035E175 /* CUController.h in Headers */, 3243608C20288BB500B03037 /* ForwardNodeRpcMessage.h in Headers */, 32FC49B01E080FB80087D82C /* GetVariable.h in Headers */, @@ -6300,23 +6200,6 @@ productReference = 3230BEBC1817A9E100EA5793 /* libchaos_cutoolkit.dylib */; productType = "com.apple.product-type.library.dynamic"; }; - 3260278614B307DA00C906CE /* chaos_uitoolkit */ = { - isa = PBXNativeTarget; - buildConfigurationList = 3260278814B307DA00C906CE /* Build configuration list for PBXNativeTarget "chaos_uitoolkit" */; - buildPhases = ( - 3260278314B307DA00C906CE /* Sources */, - 3260278414B307DA00C906CE /* Frameworks */, - 3260278514B307DA00C906CE /* Headers */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = chaos_uitoolkit; - productName = chaos_uitoolkit; - productReference = 3230BEBD1817A9E100EA5793 /* libchaos_uitoolkit.dylib */; - productType = "com.apple.product-type.library.dynamic"; - }; 326413981E44ACE60035E175 /* ChaosAgent */ = { isa = PBXNativeTarget; buildConfigurationList = 3264139D1E44ACE60035E175 /* Build configuration list for PBXNativeTarget "ChaosAgent" */; @@ -6395,7 +6278,6 @@ targets = ( 326026E814B301F600C906CE /* chaos_common */, 3260276514B3068100C906CE /* chaos_cutoolkit */, - 3260278614B307DA00C906CE /* chaos_uitoolkit */, 32661C651AA73D5B00F1A721 /* chaos_metadata_service_client */, 324D08921F30CD7A00836E29 /* chaos_micro_unit_toolkit */, 323236C6164573C60052CE06 /* ChaosMetadataService */, @@ -6491,6 +6373,7 @@ 326ACF9C1E01594C00AD011E /* QueryDataConsumer.cpp in Sources */, 326ACF9B1E01594C00AD011E /* DriverPoolManager.cpp in Sources */, 32610F961AE671AF00779B84 /* StartStop.cpp in Sources */, + 3278855620EB91CE004D1A34 /* SendStorageBurst.cpp in Sources */, 32B9F3F41AC3E74C00380FE9 /* AbstractPersistenceDriver.cpp in Sources */, 324360802024A29800B03037 /* KillCurrentCommand.cpp in Sources */, 32E09CF71C0DED340069752F /* RestoreSnapshot.cpp in Sources */, @@ -6962,21 +6845,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 3260278314B307DA00C906CE /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 326DB4EB14B3B0070018A8D0 /* ChaosUIToolkit.cpp in Sources */, - 326DB4ED14B3B0070018A8D0 /* HLDataApi.cpp in Sources */, - 326DB4EF14B3B0070018A8D0 /* HLInfrastructureApi.cpp in Sources */, - 326DB4F314B3B0070018A8D0 /* LLDataApi.cpp in Sources */, - 326DB4F514B3B0070018A8D0 /* LLRpcApi.cpp in Sources */, - 320DF99114E190BB00251621 /* DeviceController.cpp in Sources */, - 3265BF4915D1AA9F00C3CAC6 /* ChaosUIToolkitCWrapper.cc in Sources */, - 3211FD1D1698699D00424A3C /* LiveDataFetcher.cpp in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 326413951E44ACE60035E175 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -7004,6 +6872,7 @@ files = ( 3252F35C1C298755004436A8 /* GetNodeChilds.cpp in Sources */, 32661C6D1AA741D000F1A721 /* ChaosMetadataServiceClient.cpp in Sources */, + 3278855A20EB97BC004D1A34 /* SendStorageBurst.cpp in Sources */, 32FFA3EC1B00D43900C57E07 /* QuantumSlot.cpp in Sources */, 32B1E7F61B2AD1CC00221E49 /* CommandTemplateGet.cpp in Sources */, 32B1E7E91B297C7F00221E49 /* CommandTemplateSet.cpp in Sources */, @@ -7122,11 +6991,6 @@ target = 3260276514B3068100C906CE /* chaos_cutoolkit */; targetProxy = 3211C6791C146252003B38BF /* PBXContainerItemProxy */; }; - 3211C67C1C146252003B38BF /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 3260278614B307DA00C906CE /* chaos_uitoolkit */; - targetProxy = 3211C67B1C146252003B38BF /* PBXContainerItemProxy */; - }; 3211C67E1C146252003B38BF /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 323236C6164573C60052CE06 /* ChaosMetadataService */; @@ -7268,42 +7132,6 @@ }; name = "[GPERF]Debug"; }; - 3217816520C559AA00C079C9 /* [GPERF]Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CONFIGURATION_BUILD_DIR = "$(SRCROOT)/usr/local/lib"; - COPY_PHASE_STRIP = NO; - DSTROOT = /; - EXECUTABLE_PREFIX = lib; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_VERSION = ""; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = ( - ., - usr/local/include, - ); - INSTALL_PATH = "$(SRCROOT)/usr/local/lib"; - LIBRARY_SEARCH_PATHS = "$(SRCROOT)/usr/local/lib"; - MACOSX_DEPLOYMENT_TARGET = 10.10; - ONLY_ACTIVE_ARCH = YES; - OTHER_LDFLAGS = "-lchaos_common"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx; - }; - name = "[GPERF]Debug"; - }; 3217816620C559AA00C079C9 /* [GPERF]Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -7345,6 +7173,7 @@ ., usr/local/include, ); + INSTALL_PATH = "$(SRCROOT)/usr/local/lib"; LIBRARY_SEARCH_PATHS = "$(SRCROOT)/usr/local/lib"; MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = YES; @@ -7405,6 +7234,7 @@ ., usr/local/include, ); + INSTALL_PATH = "$(SRCROOT)/usr/local/lib"; LIBRARY_SEARCH_PATHS = "$(SRCROOT)/usr/local/lib"; MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = YES; @@ -7807,6 +7637,7 @@ ., usr/local/include, ); + INSTALL_PATH = "$(SRCROOT)/usr/local/lib"; LIBRARY_SEARCH_PATHS = "$(SRCROOT)/usr/local/lib"; MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = YES; @@ -7861,6 +7692,7 @@ ., usr/local/include, ); + INSTALL_PATH = "$(SRCROOT)/usr/local/lib"; LIBRARY_SEARCH_PATHS = "$(SRCROOT)/usr/local/lib"; MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = NO; @@ -8064,71 +7896,6 @@ }; name = Release; }; - 3260278914B307DA00C906CE /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CONFIGURATION_BUILD_DIR = "$(SRCROOT)/usr/local/lib"; - COPY_PHASE_STRIP = NO; - DSTROOT = /; - EXECUTABLE_PREFIX = lib; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_VERSION = ""; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = ( - ., - usr/local/include, - ); - INSTALL_PATH = "$(SRCROOT)/usr/local/lib"; - LIBRARY_SEARCH_PATHS = "$(SRCROOT)/usr/local/lib"; - MACOSX_DEPLOYMENT_TARGET = 10.10; - ONLY_ACTIVE_ARCH = YES; - OTHER_LDFLAGS = "-lchaos_common"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx; - }; - name = Debug; - }; - 3260278A14B307DA00C906CE /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CONFIGURATION_BUILD_DIR = "$(SRCROOT)/usr/local/lib"; - COPY_PHASE_STRIP = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DSTROOT = /; - EXECUTABLE_PREFIX = lib; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_VERSION = ""; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = ( - ., - usr/local/include, - ); - INSTALL_PATH = "$(SRCROOT)/usr/local/lib"; - LIBRARY_SEARCH_PATHS = "$(SRCROOT)/usr/local/lib"; - MACOSX_DEPLOYMENT_TARGET = 10.10; - OTHER_LDFLAGS = "-lchaos_common"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx; - }; - name = Release; - }; 3264139E1E44ACE60035E175 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -8284,6 +8051,7 @@ ., usr/local/include, ); + INSTALL_PATH = "$(SRCROOT)/usr/local/lib"; LIBRARY_SEARCH_PATHS = "$(SRCROOT)/usr/local/lib"; MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = YES; @@ -8329,6 +8097,7 @@ ., usr/local/include, ); + INSTALL_PATH = "$(SRCROOT)/usr/local/lib"; LIBRARY_SEARCH_PATHS = "$(SRCROOT)/usr/local/lib"; MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; @@ -8411,16 +8180,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 3260278814B307DA00C906CE /* Build configuration list for PBXNativeTarget "chaos_uitoolkit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 3260278914B307DA00C906CE /* Debug */, - 3217816520C559AA00C079C9 /* [GPERF]Debug */, - 3260278A14B307DA00C906CE /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 3264139D1E44ACE60035E175 /* Build configuration list for PBXNativeTarget "ChaosAgent" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/CHAOSFrameworkTests/CHAOSFrameworkTests.xcodeproj/project.pbxproj b/CHAOSFrameworkTests/CHAOSFrameworkTests.xcodeproj/project.pbxproj index b4d7c9186..709e30281 100644 --- a/CHAOSFrameworkTests/CHAOSFrameworkTests.xcodeproj/project.pbxproj +++ b/CHAOSFrameworkTests/CHAOSFrameworkTests.xcodeproj/project.pbxproj @@ -684,7 +684,6 @@ OTHER_LDFLAGS = ( $inherited, "-lgtest", - "-ltcmalloc", ); PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -711,7 +710,6 @@ OTHER_LDFLAGS = ( $inherited, "-lgtest", - "-ltcmalloc", ); PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/CHAOSFrameworkTests/FrameworkTest/cache/EmbeddedLFCacheTest.cpp b/CHAOSFrameworkTests/FrameworkTest/cache/EmbeddedLFCacheTest.cpp index 57143bc0b..33658149e 100644 --- a/CHAOSFrameworkTests/FrameworkTest/cache/EmbeddedLFCacheTest.cpp +++ b/CHAOSFrameworkTests/FrameworkTest/cache/EmbeddedLFCacheTest.cpp @@ -68,7 +68,7 @@ void EmbeddedLFCacheTest::cacheGarbage(chaos::common::data::cache::KeyGroupCache } while (threadWriteExecution); } -TEST_F(EmbeddedLFCacheTest, EmbeddedLFCacheTest) { +//TEST_F(EmbeddedLFCacheTest, EmbeddedLFCacheTest) { // boost::thread_group tWriterGroup; // boost::thread_group tGarbageGroup; // boost::thread_group tReadersGroup; @@ -98,6 +98,6 @@ TEST_F(EmbeddedLFCacheTest, EmbeddedLFCacheTest) { // //deinit all cache // ASSERT_NO_THROW(dsCache->stop();); // ASSERT_NO_THROW(dsCache->deinit();); -} +//} diff --git a/CHAOSFrameworkTests/FrameworkTest/data/TestCDataWrapper.cpp b/CHAOSFrameworkTests/FrameworkTest/data/TestCDataWrapper.cpp index 5bae3ca6c..b765d0b9d 100644 --- a/CHAOSFrameworkTests/FrameworkTest/data/TestCDataWrapper.cpp +++ b/CHAOSFrameworkTests/FrameworkTest/data/TestCDataWrapper.cpp @@ -60,7 +60,7 @@ TEST(CDataWrapperTest, MemoryLeaks) { data_pack.appendStringToArray("array_lement"); data_pack.finalizeArrayForKey("array"); const std::string json_serialization = data_pack.getJSONString(); - for (; idx < 1000000; idx++) { + for (; idx < 1000; idx++) { bson_deserialized = CDWUniquePtr(new CDataWrapper(data_pack.getBSONRawData(), data_pack.getBSONRawSize())); ASSERT_TRUE(bson_deserialized.get()); json_deserialized = CDataWrapper::instanceFromJson(json_serialization); @@ -77,13 +77,14 @@ TEST(CDataWrapperTest, MemoryLeaks) { ASSERT_EQ(array_ptr->getInt64ElementAtIndex(1), 2); ASSERT_EQ(array_ptr->getDoubleElementAtIndex(2), 3.0); ASSERT_STREQ(array_ptr->getStringElementAtIndex(3).c_str(), "array_lement"); + array_ptr.reset(); } } TEST(CDataWrapperTest, Performance) { int idx = 0; CDataWrapper data_pack; CDWUniquePtr cloned; - for (; idx < 1000000; idx++) { + for (; idx < 1000; idx++) { data_pack.addBoolValue("bv", (int32_t)0); data_pack.addInt32Value("i32v", (int32_t)0); data_pack.addInt64Value("i64v", (int64_t)0); @@ -107,6 +108,7 @@ TEST(CDataWrapperTest, TestJsonDouble) { for(int cnt=0;cnt<p->size();cnt++){ ASSERT_EQ( test_var[cnt], p->getDoubleElementAtIndex(cnt)); } + p.reset(); } TEST(CDataWrapperTest, TestEmptyBSONToJSON) { CDataWrapper bson_a((const char*)NULL, 0); @@ -176,6 +178,7 @@ TEST(CDataWrapperTest, TestConcatenation) { ASSERT_EQ( test_var[cnt], p->getDoubleElementAtIndex(cnt)); } ASSERT_STREQ("{ \"empty\" : { }, \"notempty\" : { \"double_key\" : [ 1.0, 2.1000000000000000888, -1.0, -0.9000000000000000222 ], \"string_vector\" : [ \"ciao\", \"come stai\" ] }, \"empty2\" : { }, \"pieno\" : { \"ts1\" : 1, \"ts2\" : 2, \"ts3\" : 3, \"ts4\" : 4, \"double_key\" : -2.0, \"ts5\" : 5, \"ts6\" : 6, \"string_empty\" : \"\", \"int_key\" : 3, \"string_key\" : \"this is a long text that try to do some space on bson\", \"bool_key\" : true, \"bool_key1\" : false } }", dconcat.getCompliantJSONString().c_str()); + p.reset(); } TEST(CDataWrapperTest, DateToLong) { const char * json = "{ \"ndk_heartbeat\" : { \"$date\" : { \"$numberLong\" : \"1511968737899\" } } }"; diff --git a/CHAOSFrameworkTests/FrameworkTest/direct_io/DirectIODeviceServerChannelTest.cpp b/CHAOSFrameworkTests/FrameworkTest/direct_io/DirectIODeviceServerChannelTest.cpp index 313123237..c08dc620d 100644 --- a/CHAOSFrameworkTests/FrameworkTest/direct_io/DirectIODeviceServerChannelTest.cpp +++ b/CHAOSFrameworkTests/FrameworkTest/direct_io/DirectIODeviceServerChannelTest.cpp @@ -49,9 +49,10 @@ class DeviceServerHandler: public DirectIODeviceServerChannel::DirectIODeviceServerChannelHandler { public: ~DeviceServerHandler(){} - int consumePutEvent(opcode_headers::DirectIODeviceChannelHeaderPutOpcode& header, - BufferSPtr channel_data, - uint32_t channel_data_len) { + int consumePutEvent(const std::string& key, + const uint8_t hst_tag, + const ChaosStringSetConstSPtr meta_tag_set, + chaos::common::data::BufferSPtr channel_data) { int err = 0; if((++consumePutEvent_counter % 2) == 0) { //right result the data need to be savet @@ -59,7 +60,7 @@ public: if(!push_data->hasKey("key") || !push_data->isInt32Value("key")) { err = -1; - } else if(header.tag != push_data->getInt32Value("key")) { + } else if(hst_tag != push_data->getInt32Value("key")) { err = -1; } } else { @@ -69,9 +70,10 @@ public: return err; }; - int consumeHealthDataEvent(opcode_headers::DirectIODeviceChannelHeaderPutOpcode& header, - BufferSPtr channel_data, - uint32_t channel_data_len) { + int consumeHealthDataEvent(const std::string& key, + const uint8_t hst_tag, + const ChaosStringSetConstSPtr meta_tag_set, + chaos::common::data::BufferSPtr channel_data) { int err = 0; if((++consumeHealthDataEvent_counter % 2) == 0) { //right result the data need to be savet @@ -79,7 +81,7 @@ public: if(!push_data->hasKey("key") || !push_data->isInt32Value("key")) { err = -1; - } else if(header.tag != push_data->getInt32Value("key")) { + } else if(hst_tag != push_data->getInt32Value("key")) { err = -1; } } else { @@ -147,8 +149,9 @@ public: int consumeDataCloudQuery(opcode_headers::DirectIODeviceChannelHeaderOpcodeQueryDataCloud& query_header, const std::string& search_key, - uint64_t search_start_ts, - uint64_t search_end_ts, + const ChaosStringSet& meta_tags, + const uint64_t search_start_ts, + const uint64_t search_end_ts, opcode_headers::SearchSequence& last_element_found_seq, opcode_headers::QueryResultPage& result_page) { int err = 0; @@ -346,8 +349,8 @@ TEST_F(DirectIOChannelTest, DeviceChannelTest) { QueryResultPage results; SearchSequence sseq = {1,2}; int page_dimension = 100; - ASSERT_TRUE(client_channel->queryDataCloud("search", std::numeric_limits<uint32_t>::min(), std::numeric_limits<uint32_t>::max(), page_dimension, sseq, results)); - ASSERT_FALSE(client_channel->queryDataCloud("search", std::numeric_limits<uint32_t>::min(), std::numeric_limits<uint32_t>::max(), page_dimension, sseq, results)); + ASSERT_TRUE(client_channel->queryDataCloud("search", ChaosStringSet(), std::numeric_limits<uint32_t>::min(), std::numeric_limits<uint32_t>::max(), page_dimension, sseq, results)); + ASSERT_FALSE(client_channel->queryDataCloud("search", ChaosStringSet(), std::numeric_limits<uint32_t>::min(), std::numeric_limits<uint32_t>::max(), page_dimension, sseq, results)); ASSERT_EQ(page_dimension, results.size()); ASSERT_EQ(sseq.run_id, 2); ASSERT_EQ(sseq.datapack_counter, 3); diff --git a/CHAOSWorkspace.xcworkspace/contents.xcworkspacedata b/CHAOSWorkspace.xcworkspace/contents.xcworkspacedata index fb811328e..4a83261c8 100644 --- a/CHAOSWorkspace.xcworkspace/contents.xcworkspacedata +++ b/CHAOSWorkspace.xcworkspace/contents.xcworkspacedata @@ -10,13 +10,7 @@ <FileRef location = "group:CHAOSFrameworkTests/CHAOSFrameworkTests.xcodeproj"> </FileRef> - <FileRef - location = "group:example/ChaosCLI/ChaosCLI.xcodeproj"> - </FileRef> <FileRef location = "group:ChaosDataExport/ChaosDataExport.xcodeproj"> </FileRef> - <FileRef - location = "group:example/ChaosPerformanceTester/ChaosPerformanceTester.xcodeproj"> - </FileRef> </Workspace> diff --git a/CMakeLists.txt b/CMakeLists.txt index abdecb133..6741eedac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,9 +128,6 @@ if(NOT CHAOS_ONLY_DEPENDECY) MESG("Configure CUToolkit Layer") ADD_SUBDIRECTORY(chaos/cu_toolkit) - MESG("Configure UIToolkit Layer") - ADD_SUBDIRECTORY(chaos/ui_toolkit) - MESG("Configure Chaos Metadata Service Client Library") ADD_SUBDIRECTORY(chaos_metadata_service_client) @@ -143,30 +140,28 @@ MESG("Configure Chaos Agent Service") ADD_SUBDIRECTORY(ChaosAgent) ENDIF() -IF (CHAOS_MDS AND NOT CHAOS_ONLY_DEPENDECY) - MESG("Configure Chaos Metadata Service") - ADD_SUBDIRECTORY(ChaosMetadataService) +IF (CHAOS_MDS AND + NOT CHAOS_ONLY_DEPENDECY) + IF("${CMAKE_CXX_COMPILE_FEATURES}" MATCHES "cxx_std_11") + MESG("Configure Chaos Data Service") + ADD_SUBDIRECTORY(ChaosMetadataService) + ELSE() + WARN("Chaos Data Service require a c11 compliant compiler") + ENDIF() ENDIF() IF(NOT CHAOS_ONLY_DEPENDECY) MESG("Configure Chaos Metadata Service Client Library Test Application") ADD_SUBDIRECTORY(ChaosMetadataServiceClientTest) - IF (CHAOS_DATA_EXPORT) MESG("Configure Chaos Data Export ") ADD_SUBDIRECTORY(ChaosDataExport) ENDIF() IF(CHAOS_EXAMPLES) - MESG("Configure Chaos CLI") - ADD_SUBDIRECTORY(example/ChaosCLI) - MESG("Configure Chaos ChaosMDSCmd") ADD_SUBDIRECTORY(example/ChaosMDSCmd) - - MESG("Configure Chaos Performance Tester") - ADD_SUBDIRECTORY(example/ChaosPerformanceTester) ENDIF() ENDIF() diff --git a/ChaosDataExport/CMakeLists.txt b/ChaosDataExport/CMakeLists.txt index c9dd77624..4468a5e6e 100644 --- a/ChaosDataExport/CMakeLists.txt +++ b/ChaosDataExport/CMakeLists.txt @@ -12,6 +12,6 @@ ENDIF() ADD_EXECUTABLE(ChaosDataExport ${chaos_cde_src}) -TARGET_LINK_LIBRARIES(ChaosDataExport chaos_uitoolkit chaos_common ${FrameworkLib}) +TARGET_LINK_LIBRARIES(ChaosDataExport chaos_metadata_service_client chaos_common ${FrameworkLib}) INSTALL_TARGETS(/bin ChaosDataExport) diff --git a/ChaosDataExport/ChaosDataExport.xcodeproj/project.pbxproj b/ChaosDataExport/ChaosDataExport.xcodeproj/project.pbxproj index 7c8c379e4..82b8c9123 100644 --- a/ChaosDataExport/ChaosDataExport.xcodeproj/project.pbxproj +++ b/ChaosDataExport/ChaosDataExport.xcodeproj/project.pbxproj @@ -353,12 +353,9 @@ CLANG_CXX_LIBRARY = "libc++"; CONFIGURATION_BUILD_DIR = "$(SRCROOT)/../../usr/local/bin"; HEADER_SEARCH_PATHS = ../../usr/local/include; - LIBRARY_SEARCH_PATHS = ( - /usr/local/lib, - "$(SRCROOT)/../../usr/local/lib", - ); + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../usr/local/lib"; OTHER_LDFLAGS = ( - "-lchaos_uitoolkit", + "-lchaos_metadata_service_client", "-lchaos_common", ); PRODUCT_NAME = "$(TARGET_NAME)"; @@ -372,12 +369,9 @@ CLANG_CXX_LIBRARY = "libc++"; CONFIGURATION_BUILD_DIR = "$(SRCROOT)/../../usr/local/bin"; HEADER_SEARCH_PATHS = ../../usr/local/include; - LIBRARY_SEARCH_PATHS = ( - /usr/local/lib, - "$(SRCROOT)/../../usr/local/lib", - ); + LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../usr/local/lib"; OTHER_LDFLAGS = ( - "-lchaos_uitoolkit", + "-lchaos_metadata_service_client", "-lchaos_common", ); PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/ChaosDataExport/TestDatasetIO/ChaosDatasetIO.cpp b/ChaosDataExport/TestDatasetIO/ChaosDatasetIO.cpp index dca76d998..68bac98dc 100644 --- a/ChaosDataExport/TestDatasetIO/ChaosDatasetIO.cpp +++ b/ChaosDataExport/TestDatasetIO/ChaosDatasetIO.cpp @@ -66,6 +66,21 @@ namespace driver{ } uid=groupName+"/"+datasetName; +// ChaosUniquePtr<char[]> buff(new char [10024]); +// CDWUniquePtr result_uptr; +// CDWUniquePtr data_uptr(new CDataWrapper()); +// data_uptr->addStringValue("echo_key", "echo value"); +// data_uptr->addBinaryValue("bin_value", buff.get(), 1024); +// for(int idx = 0; +// idx < 100000000; +// idx++) { +// int err = mds_message_channel->sendEchoMessage(*data_uptr, result_uptr); +// if(!err && +// result_uptr) { +// DPD_LAPP << result_uptr->getCompliantJSONString(); +// } +// } +// DPD_LAPP << "end"; } int ChaosDatasetIO::setAgeing(uint64_t secs){ageing=secs;return 0;} @@ -109,7 +124,7 @@ namespace driver{ int ChaosDatasetIO::pushDataset(int type) { int err = 0; //ad producer key - CDataWrapper*new_dataset=datasets[type].get(); + CDWShrdPtr new_dataset = datasets[type]; uint64_t ts = chaos::common::utility::TimingUtil::getTimeStamp(); uint64_t tsh = chaos::common::utility::TimingUtil::getTimeStampInMicroseconds(); @@ -145,7 +160,7 @@ namespace driver{ // DPD_LDBG <<" PUSHING:"<<new_dataset->getJSONString(); // DirectIOChannelsInfo *next_client = static_cast<DirectIOChannelsInfo*>(connection_feeder.getService()); // serialization->disposeOnDelete = !next_client; - ioLiveDataDriver->storeData(uid+chaos::datasetTypeToPostfix(type),new_dataset,(chaos::DataServiceNodeDefinitionType::DSStorageType)storageType,false); + ioLiveDataDriver->storeData(uid+chaos::datasetTypeToPostfix(type),new_dataset,(chaos::DataServiceNodeDefinitionType::DSStorageType)storageType); return err; @@ -430,7 +445,7 @@ namespace driver{ query_cursor_map.erase(i++); } - + DEBUG_CODE(DPD_LDBG << "Shared Manager deinitialized"); DEBUG_CODE(DPD_LDBG << "Deinitialized"); diff --git a/ChaosDataExport/cde.cpp b/ChaosDataExport/cde.cpp index 654bf1d7e..926f00e35 100644 --- a/ChaosDataExport/cde.cpp +++ b/ChaosDataExport/cde.cpp @@ -27,9 +27,8 @@ #include <chaos/common/additional_lib/base64.h> #include <chaos/common/utility/TimingUtil.h> #include <chaos/common/network/CNodeNetworkAddress.h> -#include <chaos/ui_toolkit/ChaosUIToolkit.h> -#include <chaos/ui_toolkit/LowLevelApi/LLRpcApi.h> -#include <chaos/ui_toolkit/HighLevelApi/HLDataApi.h> +#include <chaos_metadata_service_client/ChaosMetadataServiceClient.h> + #include <chaos/common/bson/bson.h> @@ -42,7 +41,9 @@ using namespace std; using namespace chaos; using namespace chaos::common::data; using namespace chaos::common::utility; -using namespace chaos::ui; + +using namespace chaos::metadata_service_client; +using namespace chaos::metadata_service_client::node_controller; using namespace boost; #define OPT_CU_ID "device-id" @@ -53,6 +54,7 @@ using namespace boost; #define OPT_PAGE_LENGHT "page-lenght" #define OPT_START_TIME "start-time" #define OPT_END_TIME "end-time" +#define OPT_TAGS "tags" void sendBackOnRow() { @@ -79,7 +81,9 @@ int computePercent(uint64_t done, uint64_t all) { return result; } -chaos::common::data::SerializationBuffer *getCSVDecoding( DeviceController& controller, const std::vector<std::string>& output_element_name, CDataWrapper& data_pack) { +chaos::common::data::SerializationBuffer *getCSVDecoding(CUController& controller, + const std::vector<std::string>& output_element_name, + CDataWrapper& data_pack) { chaos::common::data::SerializationBuffer *result = NULL; std::stringstream csv_lin; chaos::common::data::RangeValueInfo attribute_info; @@ -166,6 +170,7 @@ int main(int argc, const char* argv[]) { uint32_t page_len; string start_time; string end_time; + ChaosStringVector meta_tags; std::string err_str; std::ostream *destination_stream = NULL; std::ofstream destination_file; @@ -175,7 +180,6 @@ int main(int argc, const char* argv[]) { int rett=0; int retry = 0; - uint32_t cicle_number = 0; //clear buffer memset(buf, 0, 255); @@ -186,24 +190,25 @@ int main(int argc, const char* argv[]) { try{ //std::cout << "\x1B[?25l"; //! [UIToolkit Attribute Init] - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<string>(OPT_CU_ID, "The identification string of the device", &device_id); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<uint32_t>(OPT_TIMEOUT, "Timeout for wait the answer in milliseconds", 2000, &timeout); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<uint32_t>(OPT_DST_TYPE, "Destination date type [binary(0), JSON(1), CSV(2)]", 0, &dest_type); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<string>(OPT_DST_FILE, "Destination file for save found datapack", &dst_file); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<string>(OPT_START_TIME, "Time for first datapack to find [format from %Y-%m-%dT%H:%M:%S.%f to %Y]", &start_time); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<string>(OPT_END_TIME, "Time for last datapack to find [format from %Y-%m-%dT%H:%M:%S.%f to %Y]", &end_time); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<uint32_t>(OPT_PAGE_LENGHT, "query page lenght", 30, &page_len); + ChaosMetadataServiceClient::getInstance()->getGlobalConfigurationInstance()->addOption<string>(OPT_CU_ID, "The identification string of the device", &device_id); + ChaosMetadataServiceClient::getInstance()->getGlobalConfigurationInstance()->addOption<uint32_t>(OPT_TIMEOUT, "Timeout for wait the answer in milliseconds", 2000, &timeout); + ChaosMetadataServiceClient::getInstance()->getGlobalConfigurationInstance()->addOption<uint32_t>(OPT_DST_TYPE, "Destination date type [binary(0), JSON(1), CSV(2)]", 0, &dest_type); + ChaosMetadataServiceClient::getInstance()->getGlobalConfigurationInstance()->addOption<string>(OPT_DST_FILE, "Destination file for save found datapack", &dst_file); + ChaosMetadataServiceClient::getInstance()->getGlobalConfigurationInstance()->addOption<string>(OPT_START_TIME, "Time for first datapack to find [format from %Y-%m-%dT%H:%M:%S.%f to %Y]", &start_time); + ChaosMetadataServiceClient::getInstance()->getGlobalConfigurationInstance()->addOption<string>(OPT_END_TIME, "Time for last datapack to find [format from %Y-%m-%dT%H:%M:%S.%f to %Y]", &end_time); + ChaosMetadataServiceClient::getInstance()->getGlobalConfigurationInstance()->addOption<uint32_t>(OPT_PAGE_LENGHT, "query page lenght", 30, &page_len); + ChaosMetadataServiceClient::getInstance()->getGlobalConfigurationInstance()->addOption<ChaosStringVector>(OPT_TAGS, "Meta tags list", &meta_tags); //! [UIToolkit Attribute Init] //! [UIToolkit Init] - ChaosUIToolkit::getInstance()->init(argc, argv); + ChaosMetadataServiceClient::getInstance()->init(argc, argv); //! [UIToolkit Init] - if(!ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->hasOption(OPT_CU_ID)){ + if(!ChaosMetadataServiceClient::getInstance()->getGlobalConfigurationInstance()->hasOption(OPT_CU_ID)){ throw CException(-1, "invalid device identification string", "check param"); } //get the timestamp for query boundary - if(ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->hasOption(OPT_START_TIME)){ + if(ChaosMetadataServiceClient::getInstance()->getGlobalConfigurationInstance()->hasOption(OPT_START_TIME)){ //try to check if the string is a number try { start_ts = lexical_cast<uint64_t>(start_time); @@ -216,7 +221,7 @@ int main(int argc, const char* argv[]) { std::cout << "Set start data to:"<< start_time << std::endl; } - if(ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->hasOption(OPT_END_TIME)){ + if(ChaosMetadataServiceClient::getInstance()->getGlobalConfigurationInstance()->hasOption(OPT_END_TIME)){ //try to check if the string is a number try { end_ts = lexical_cast<uint64_t>(end_time); @@ -256,14 +261,22 @@ int main(int argc, const char* argv[]) { //we can allocate the channel std::cout << "Acquiring controller" << std::endl; - DeviceController *controller = HLDataApi::getInstance()->getControllerForDeviceID(device_id, timeout); + CUController *controller = NULL; + ChaosMetadataServiceClient::getInstance()->getNewCUController(device_id, &controller); if(!controller) throw CException(4, "Error allocating decive controller", "device controller creation"); - + ChaosStringSet search_tags; chaos::common::io::QueryCursor *query_cursor = NULL; - controller->executeTimeIntervallQuery(DatasetDomainOutput, + for(ChaosStringVectorIterator it = meta_tags.begin(), + end = meta_tags.end(); + it != end; + it++) { + search_tags.insert(*it); + } + controller->executeTimeIntervallQuery(chaos::cu::data_manager::KeyDataStorageDomainOutput, start_ts, end_ts, + search_tags, &query_cursor, page_len); @@ -298,18 +311,18 @@ int main(int argc, const char* argv[]) { ChaosSharedPtr<CDataWrapper> q_result(query_cursor->next()); if(q_result.get()) { retry = 0; - ChaosUniquePtr<chaos::common::data::SerializationBuffer> ser; + SerializationBufferUPtr ser; //get serialization buffer by type switch (dest_type) { //BSON case 0:{ - ser.reset(q_result->getBSONData()); + ser = q_result->getBSONData(); break; } //JSON case 1:{ std::string ser_str = q_result->getJSONString(); - ser.reset(new SerializationBuffer(ser_str.c_str(), ser_str.size())); + //ser = ChaosMakeSharedPtr<SerializationBuffer>(ser_str.c_str(), ser_str.size())); break; } //CSV @@ -333,7 +346,7 @@ int main(int argc, const char* argv[]) { } destination_stream->flush(); std::cout << "Releasing controller" << std::endl; - HLDataApi::getInstance()->disposeDeviceControllerPtr(controller); + ChaosMetadataServiceClient::getInstance()->deleteCUController(controller); } catch (CException& e) { std::cout << "\x1B[?25h"; std::cerr << e.errorCode << " - "<< e.errorDomain << " - " << e.errorMessage << std::endl; @@ -346,7 +359,7 @@ int main(int argc, const char* argv[]) { try { //! [UIToolkit Deinit] - ChaosUIToolkit::getInstance()->deinit(); + ChaosMetadataServiceClient::getInstance()->deinit(); //! [UIToolkit Deinit] } catch (CException& e) { std::cout << "\x1B[?25h"; diff --git a/ChaosMetadataService/CMakeLists.txt b/ChaosMetadataService/CMakeLists.txt index 00b904ae0..6b219ff1a 100644 --- a/ChaosMetadataService/CMakeLists.txt +++ b/ChaosMetadataService/CMakeLists.txt @@ -119,7 +119,8 @@ SET(cnd_src ${cnd_src} api/control_unit/SetInputDatasetAttributeValues.cpp api/control_unit/CopyInstance.cpp api/control_unit/RecoverError.cpp api/control_unit/GetCurrentDataset.cpp - api/control_unit/GetFullDescription.cpp) + api/control_unit/GetFullDescription.cpp + api/control_unit/SendStorageBurst.cpp) SET(cnd_src ${cnd_src} api/node/NodeGroup.cpp api/node/NodeCreateUnitServer.cpp diff --git a/ChaosMetadataService/QueryDataConsumer.cpp b/ChaosMetadataService/QueryDataConsumer.cpp index ddec5c4d9..e44f224bd 100644 --- a/ChaosMetadataService/QueryDataConsumer.cpp +++ b/ChaosMetadataService/QueryDataConsumer.cpp @@ -149,52 +149,38 @@ void QueryDataConsumer::deinit() throw (chaos::CException) { } #pragma mark DirectIODeviceServerChannelHandler -int QueryDataConsumer::consumePutEvent(DirectIODeviceChannelHeaderPutOpcode& header, - BufferSPtr channel_data, - uint32_t channel_data_len) { +int QueryDataConsumer::consumePutEvent(const std::string& key, + const uint8_t hst_tag, + const ChaosStringSetConstSPtr meta_tag_set, + BufferSPtr channel_data) { CHAOS_ASSERT(channel_data) int err = 0; - const int8_t key_tag = header.tag; - const std::string key_to_store = std::string((const char *)GET_PUT_OPCODE_KEY_PTR(&header), - header.key_len); - DataServiceNodeDefinitionType::DSStorageType storage_type = static_cast<DataServiceNodeDefinitionType::DSStorageType>(key_tag); + + DataServiceNodeDefinitionType::DSStorageType storage_type = static_cast<DataServiceNodeDefinitionType::DSStorageType>(hst_tag); //! if tag is == 1 the datapack is in liveonly - bool send_to_storage_layer = (storage_type != DataServiceNodeDefinitionType::DSStorageTypeLive && - storage_type != DataServiceNodeDefinitionType::DSStorageTypeUndefined); - switch(storage_type) { - case DataServiceNodeDefinitionType::DSStorageTypeLiveHistory: - case DataServiceNodeDefinitionType::DSStorageTypeLive:{ - //protected access to cached driver - CachePoolSlot *cache_slot = DriverPoolManager::getInstance()->getCacheDriverInstance(); - if(cache_slot) { - err = cache_slot->resource_pooled->putData(key_to_store, - channel_data); - DriverPoolManager::getInstance()->releaseCacheDriverInstance(cache_slot); - } else { - ERR << "Error allocating cache slot"; - } - break; - } - case DataServiceNodeDefinitionType::DSStorageTypeHistory: - case DataServiceNodeDefinitionType::DSStorageTypeUndefined: - break; - - default: { - ERR << "Bad storage tag: " << key_tag; - break; + + if(storage_type & DataServiceNodeDefinitionType::DSStorageTypeLive) { + //protected access to cached driver + CachePoolSlot *cache_slot = DriverPoolManager::getInstance()->getCacheDriverInstance(); + if(cache_slot) { + err = cache_slot->resource_pooled->putData(key, + channel_data); + DriverPoolManager::getInstance()->releaseCacheDriverInstance(cache_slot); + } else { + ERR << "Error allocating cache slot"; } } - if(send_to_storage_layer) { + if(storage_type & DataServiceNodeDefinitionType::DSStorageTypeHistory) { //compute the index to use for the data worker uint32_t index_to_use = device_data_worker_index++ % ChaosMetadataService::getInstance()->setting.worker_setting.instances; CHAOS_ASSERT(device_data_worker[index_to_use]) //create storage job information auto job = ChaosMakeSharedPtr<DeviceSharedWorkerJob>(); - job->key = key_to_store; - job->key_tag = key_tag; + job->key = key; + job->key_tag = hst_tag; job->data_pack = channel_data; - job->data_pack_len = channel_data_len; + job->meta_tag = ChaosMoveOperator(meta_tag_set); if((err = device_data_worker[index_to_use]->submitJobInfo(job))) { DEBUG_CODE(DBG << "Error pushing data into worker queue"); } @@ -202,9 +188,10 @@ int QueryDataConsumer::consumePutEvent(DirectIODeviceChannelHeaderPutOpcode& hea return err; } -int QueryDataConsumer::consumeHealthDataEvent(DirectIODeviceChannelHeaderPutOpcode& header, - BufferSPtr channel_data, - uint32_t channel_data_len) { +int QueryDataConsumer::consumeHealthDataEvent(const std::string& key, + const uint8_t hst_tag, + const ChaosStringSetConstSPtr meta_tag_set, + BufferSPtr channel_data) { int err = 0; CDataWrapper health_data_pack((char *)channel_data->data()); @@ -217,15 +204,17 @@ int QueryDataConsumer::consumeHealthDataEvent(DirectIODeviceChannelHeaderPutOpco attribute_reference_wrapper()))) { ERR << "error storing health data into database for key " << attribute_reference_wrapper().node_uid; } - return consumePutEvent(header, - channel_data, - channel_data_len); + return consumePutEvent(key, + hst_tag, + ChaosMoveOperator(meta_tag_set), + channel_data); } int QueryDataConsumer::consumeDataCloudQuery(DirectIODeviceChannelHeaderOpcodeQueryDataCloud& query_header, const std::string& search_key, - uint64_t search_start_ts, - uint64_t search_end_ts, + const ChaosStringSet& meta_tags, + const uint64_t search_start_ts, + const uint64_t search_end_ts, SearchSequence& last_element_found_seq, QueryResultPage& page_element_found) { @@ -233,6 +222,7 @@ int QueryDataConsumer::consumeDataCloudQuery(DirectIODeviceChannelHeaderOpcodeQu //execute the query ObjectStorageDataAccess *obj_storage_da = object_storage_driver->getDataAccess<object_storage::abstraction::ObjectStorageDataAccess>(); if((err = obj_storage_da->findObject(search_key, + meta_tags, search_start_ts, search_end_ts, query_header.field.record_for_page, diff --git a/ChaosMetadataService/QueryDataConsumer.h b/ChaosMetadataService/QueryDataConsumer.h index df82d615f..19065b7c7 100644 --- a/ChaosMetadataService/QueryDataConsumer.h +++ b/ChaosMetadataService/QueryDataConsumer.h @@ -67,13 +67,15 @@ namespace chaos{ chaos::data_service::worker::DataWorker **device_data_worker; //---------------- DirectIODeviceServerChannelHandler ----------------------- - int consumePutEvent(DirectIODeviceChannelHeaderPutOpcode& header, - chaos::common::data::BufferSPtr channel_data, - uint32_t channel_data_len); + int consumePutEvent(const std::string& key, + const uint8_t hst_tag, + const ChaosStringSetConstSPtr meta_tag_set, + chaos::common::data::BufferSPtr channel_data); - int consumeHealthDataEvent(DirectIODeviceChannelHeaderPutOpcode& header, - chaos::common::data::BufferSPtr channel_data, - uint32_t channel_data_len); + int consumeHealthDataEvent(const std::string& key, + const uint8_t hst_tag, + const ChaosStringSetConstSPtr meta_tag_set, + chaos::common::data::BufferSPtr channel_data); int consumeGetEvent(chaos::common::data::BufferSPtr key_data, uint32_t key_len, @@ -88,8 +90,9 @@ namespace chaos{ int consumeDataCloudQuery(opcode_headers::DirectIODeviceChannelHeaderOpcodeQueryDataCloud& query_header, const std::string& search_key, - uint64_t search_start_ts, - uint64_t search_end_ts, + const ChaosStringSet& meta_tags, + const uint64_t search_start_ts, + const uint64_t search_end_ts, opcode_headers::SearchSequence& last_element_found_seq, opcode_headers::QueryResultPage& page_element_found); diff --git a/ChaosMetadataService/api/control_unit/ControlUnitGroup.cpp b/ChaosMetadataService/api/control_unit/ControlUnitGroup.cpp index 8ef574028..71a44ebd0 100644 --- a/ChaosMetadataService/api/control_unit/ControlUnitGroup.cpp +++ b/ChaosMetadataService/api/control_unit/ControlUnitGroup.cpp @@ -31,6 +31,7 @@ #include "CopyInstance.h" #include "RecoverError.h" #include "Delete.h" +#include "SendStorageBurst.h" using namespace chaos::metadata_service::api::control_unit; DEFINE_CLASS_FACTORY_NO_ALIAS(ControlUnitGroup, chaos::metadata_service::api::AbstractApiGroup); @@ -49,8 +50,9 @@ AbstractApiGroup("control_unit"){ addApi<CopyInstance>(); addApi<RecoverError>(); addApi<Delete>(); + addApi<SendStorageBurst>(); } ControlUnitGroup::~ControlUnitGroup() { -} \ No newline at end of file +} diff --git a/ChaosMetadataService/api/control_unit/SendStorageBurst.cpp b/ChaosMetadataService/api/control_unit/SendStorageBurst.cpp new file mode 100644 index 000000000..cfec2f654 --- /dev/null +++ b/ChaosMetadataService/api/control_unit/SendStorageBurst.cpp @@ -0,0 +1,102 @@ +/* + * Copyright 2012, 03/07/2018 INFN + * + * Licensed under the EUPL, Version 1.2 or – as soon they + * will be approved by the European Commission - subsequent + * versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the + * Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in + * writing, software distributed under the Licence is + * distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. + * See the Licence for the specific language governing + * permissions and limitations under the Licence. + */ + +#include "SendStorageBurst.h" +#include "../../batch/node/SendRpcCommand.h" + +#include <chaos/common/chaos_constants.h> +#include <chaos/common/data/structured/Dataset.h> + +using namespace chaos::common::data; +using namespace chaos::common::data::structured; +using namespace chaos::metadata_service::api::control_unit; +using namespace chaos::metadata_service::persistence::data_access; + +#define CU_RNU_INFO INFO_LOG(RecoverError) +#define CU_RNU_DBG DBG_LOG(RecoverError) +#define CU_RNU_ERR ERR_LOG(RecoverError) + +SendStorageBurst::SendStorageBurst(): +AbstractApi("sendStorageBurst"){} + +SendStorageBurst::~SendStorageBurst() {} + +CDataWrapper *SendStorageBurst::execute(CDataWrapper *api_data, + bool& detach_data) throw(chaos::CException) { + CHECK_CDW_THROW_AND_LOG(api_data, CU_RNU_ERR, -1, "No parameter found") + CHECK_KEY_THROW_AND_LOG(api_data, chaos::NodeDefinitionKey::NODE_UNIQUE_ID , CU_RNU_ERR, -2, "The ndk_uid key is mandatory") + CHECK_ASSERTION_THROW_AND_LOG((!api_data->isVectorValue(chaos::NodeDefinitionKey::NODE_UNIQUE_ID) || + !api_data->isStringValue(chaos::NodeDefinitionKey::NODE_UNIQUE_ID)), CU_RNU_ERR, -3, "ndk_uid key need to be a vector of string"); + + //check burst information + DatasetBurstSDWrapper db_sdw; + db_sdw.deserialize(api_data); + CHECK_ASSERTION_THROW_AND_LOG(db_sdw().type != chaos::ControlUnitNodeDefinitionType::DSStorageBurstTypeUndefined, CU_RNU_ERR, -4, "The type of burst is mandatory"); + CHECK_ASSERTION_THROW_AND_LOG(db_sdw().value.isValid(), CU_RNU_ERR, -5, "The value ofburst is mandatory"); + + GET_DATA_ACCESS(ControlUnitDataAccess, cu_da, -4) + + int err = 0; + uint64_t command_id = 0; + bool presence = false; + std::string temp_node_uid; + ChaosStringVector control_unit_to_recover; + + if(api_data->isVector(chaos::NodeDefinitionKey::NODE_UNIQUE_ID)) { + CMultiTypeDataArrayWrapperSPtr control_unit_ids = api_data->getVectorValue(chaos::NodeDefinitionKey::NODE_UNIQUE_ID); + for(int idx = 0; idx < control_unit_ids->size(); idx++) { + temp_node_uid = control_unit_ids->getStringElementAtIndex(idx); + if((err = cu_da->checkPresence(temp_node_uid, presence))) { + CU_RNU_ERR << "Error checking the presence of control unit" << temp_node_uid << "with code:"<<err; + } else if(presence){ + control_unit_to_recover.push_back(temp_node_uid); + } else { + CU_RNU_ERR << "The control unit" << temp_node_uid << "is not present"; + } + } + } else { + const std::string node_uid = api_data->getStringValue(chaos::NodeDefinitionKey::NODE_UNIQUE_ID); + if((err = cu_da->checkPresence(node_uid, presence))) { + CU_RNU_ERR << "Error checking the presence of control unit" << temp_node_uid << "with code:"<<err; + } else if(presence){ + control_unit_to_recover.push_back(node_uid); + } else { + CU_RNU_ERR << "The control unit" << temp_node_uid << "is not present"; + } + } + + CDWUniquePtr burst_ser = db_sdw.serialize(); + for(ChaosStringVectorIterator it = control_unit_to_recover.begin(), + end = control_unit_to_recover.end(); + it!= end; + it++){ + ChaosUniquePtr<chaos::common::data::CDataWrapper> batch_data(new CDataWrapper()); + + batch_data->addStringValue(chaos::NodeDefinitionKey::NODE_UNIQUE_ID, *it); + batch_data->addStringValue(chaos::RpcActionDefinitionKey::CS_CMDM_ACTION_NAME, chaos::ControlUnitNodeDomainAndActionRPC::ACTION_STORAGE_BURST); + batch_data->addCSDataValue(chaos::RpcActionDefinitionKey::CS_CMDM_ACTION_MESSAGE, *burst_ser); + //launch the batch command + command_id = getBatchExecutor()->submitCommand(std::string(GET_MDS_COMMAND_ALIAS(batch::node::SendRpcCommand)), + batch_data.release()); + } + + return NULL; +} diff --git a/ChaosMetadataService/api/control_unit/SendStorageBurst.h b/ChaosMetadataService/api/control_unit/SendStorageBurst.h new file mode 100644 index 000000000..0df0fede9 --- /dev/null +++ b/ChaosMetadataService/api/control_unit/SendStorageBurst.h @@ -0,0 +1,45 @@ +/* + * Copyright 2012, 03/07/2018 INFN + * + * Licensed under the EUPL, Version 1.2 or – as soon they + * will be approved by the European Commission - subsequent + * versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the + * Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in + * writing, software distributed under the Licence is + * distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. + * See the Licence for the specific language governing + * permissions and limitations under the Licence. + */ + +#ifndef __CHAOSFramework__SendStorageBurst_h +#define __CHAOSFramework__SendStorageBurst_h + +#include "../AbstractApi.h" + +namespace chaos { + namespace metadata_service { + namespace api { + namespace control_unit { + class SendStorageBurst: + public AbstractApi { + + public: + SendStorageBurst(); + ~SendStorageBurst(); + chaos::common::data::CDataWrapper *execute(chaos::common::data::CDataWrapper *api_data, + bool& detach_data) throw(chaos::CException); + }; + } + } + } +} + +#endif /* __CHAOSFramework__SendStorageBurst_h */ diff --git a/ChaosMetadataService/object_storage/abstraction/ObjectStorageDataAccess.h b/ChaosMetadataService/object_storage/abstraction/ObjectStorageDataAccess.h index 3662925e2..23dfce9ec 100644 --- a/ChaosMetadataService/object_storage/abstraction/ObjectStorageDataAccess.h +++ b/ChaosMetadataService/object_storage/abstraction/ObjectStorageDataAccess.h @@ -50,6 +50,7 @@ namespace chaos { //!Put an object within the object persistence layer virtual int pushObject(const std::string& key, + const ChaosStringSetConstSPtr meta_tags, const chaos::common::data::CDataWrapper& stored_object) = 0; //!Retrieve an object from the object persistence layer @@ -68,6 +69,7 @@ namespace chaos { //!search object into object persistence layer virtual int findObject(const std::string& key, + const ChaosStringSet& meta_tags, const uint64_t timestamp_from, const uint64_t timestamp_to, const uint32_t page_len, diff --git a/ChaosMetadataService/object_storage/mongodb/MongoDBObjectStorageDataAccess.cpp b/ChaosMetadataService/object_storage/mongodb/MongoDBObjectStorageDataAccess.cpp index fff176ffb..f18b97089 100644 --- a/ChaosMetadataService/object_storage/mongodb/MongoDBObjectStorageDataAccess.cpp +++ b/ChaosMetadataService/object_storage/mongodb/MongoDBObjectStorageDataAccess.cpp @@ -75,15 +75,27 @@ storage_write_concern(&mongo::WriteConcern::unacknowledged) { MongoDBObjectStorageDataAccess::~MongoDBObjectStorageDataAccess() {} int MongoDBObjectStorageDataAccess::pushObject(const std::string& key, + const ChaosStringSetConstSPtr meta_tags, const CDataWrapper& stored_object) { int err = 0; try { int buffer_size = 0; const int64_t now_in_ms = TimingUtil::getTimeStamp() & 0xFFFFFFFFFFFFFF00; const char *buffer = stored_object.getBSONRawData(buffer_size); + //add tags + mongo::BSONArrayBuilder tag_array_builder; mongo::BSONObjBuilder insert_builder; insert_builder << chaos::DataPackCommonKey::DPCK_DEVICE_ID << key << chaos::DataPackCommonKey::DPCK_TIMESTAMP << mongo::Date_t(now_in_ms); + if(meta_tags && meta_tags->size()) { + for(ChaosStringSetConstIterator it = meta_tags->begin(), + end = meta_tags->end(); + it != end; + it++){ + tag_array_builder << *it; + } + } + insert_builder << chaos::DataPackCommonKey::DPCK_DATASET_TAGS << tag_array_builder.arr(); //add zone sharding information mongo::BSONObj zone_pack = shrd_key_manager.getNewDataPack(key, now_in_ms, @@ -197,7 +209,7 @@ int MongoDBObjectStorageDataAccess::deleteObject(const std::string& key, end_timestamp) { builder << chaos::DataPackCommonKey::DPCK_TIMESTAMP << time_query_builder.obj(); } - + builder << "$or" << BSON_ARRAY(BSON(chaos::DataPackCommonKey::DPCK_DATASET_TAGS << BSON("$exists" << false)) << BSON(chaos::DataPackCommonKey::DPCK_DATASET_TAGS << BSON("$eq" << mongo::BSONArrayBuilder().arr()))); mongo::BSONObj q = builder.obj(); DEBUG_CODE(DBG<<log_message("deleteObject", @@ -219,8 +231,9 @@ int MongoDBObjectStorageDataAccess::deleteObject(const std::string& key, } int MongoDBObjectStorageDataAccess::findObject(const std::string& key, - uint64_t timestamp_from, - uint64_t timestamp_to, + const ChaosStringSet& meta_tags, + const uint64_t timestamp_from, + const uint64_t timestamp_to, const uint32_t page_len, object_storage::abstraction::VectorObject& found_object_page, SearchSequence& last_record_found_seq) { @@ -228,6 +241,7 @@ int MongoDBObjectStorageDataAccess::findObject(const std::string& key, std::vector<mongo::BSONObj> object_found; try { mongo::Query q; + mongo::BSONObjBuilder q_builder; bool reverse_order = false; const std::string run_key = CHAOS_FORMAT("%1%.%2%",%MONGODB_DAQ_DATA_FIELD%chaos::ControlUnitDatapackCommonKey::RUN_ID); const std::string counter_key = CHAOS_FORMAT("%1%.%2%",%MONGODB_DAQ_DATA_FIELD%chaos::DataPackCommonKey::DPCK_SEQ_ID); @@ -235,19 +249,29 @@ int MongoDBObjectStorageDataAccess::findObject(const std::string& key, reverse_order = timestamp_from>timestamp_to; if(reverse_order == false) { - q = BSON(chaos::DataPackCommonKey::DPCK_DEVICE_ID << key << + q_builder << chaos::DataPackCommonKey::DPCK_DEVICE_ID << key << chaos::DataPackCommonKey::DPCK_TIMESTAMP << BSON("$gte" << mongo::Date_t(timestamp_from) << "$lte" << mongo::Date_t(timestamp_to)) << run_key << BSON("$gte" << (long long)last_record_found_seq.run_id) << - counter_key << BSON("$gte" << (long long)last_record_found_seq.datapack_counter)); + counter_key << BSON("$gte" << (long long)last_record_found_seq.datapack_counter); } else { - BSON(chaos::DataPackCommonKey::DPCK_DEVICE_ID << key << + q_builder << chaos::DataPackCommonKey::DPCK_DEVICE_ID << key << chaos::DataPackCommonKey::DPCK_TIMESTAMP << BSON("$lte" << mongo::Date_t(timestamp_from) << "$gte" << mongo::Date_t(timestamp_to)) << run_key << BSON("$lte" << (long long)last_record_found_seq.run_id) << - counter_key << BSON("$lte" << (long long)last_record_found_seq.datapack_counter)); + counter_key << BSON("$lte" << (long long)last_record_found_seq.datapack_counter); + } + + //add tags + if(meta_tags.size()) { + mongo::BSONArrayBuilder tags_arr_b; + for(auto& it: meta_tags) { + tags_arr_b << it; + } + q_builder << chaos::DataPackCommonKey::DPCK_DATASET_TAGS << BSON("$all" << tags_arr_b.arr()); } + q = q_builder.obj(); if(reverse_order) { q = q.sort(BSON(run_key<<-1<<counter_key<<-1<<chaos::DataPackCommonKey::DPCK_TIMESTAMP<<-1)); } else { @@ -276,12 +300,10 @@ int MongoDBObjectStorageDataAccess::findObject(const std::string& key, } if( object_found[object_found.size()-1].getFieldDotted(run_key).type()==mongo::NumberInt){ last_record_found_seq.run_id = object_found[object_found.size()-1].getFieldDotted(run_key).Number(); - } else { last_record_found_seq.run_id = object_found[object_found.size()-1].getFieldDotted(run_key).Long(); } - if( object_found[object_found.size()-1].getFieldDotted(counter_key).type()==mongo::NumberInt){ last_record_found_seq.datapack_counter = object_found[object_found.size()-1].getFieldDotted(counter_key).Number(); diff --git a/ChaosMetadataService/object_storage/mongodb/MongoDBObjectStorageDataAccess.h b/ChaosMetadataService/object_storage/mongodb/MongoDBObjectStorageDataAccess.h index cb5b6fc30..320aef162 100644 --- a/ChaosMetadataService/object_storage/mongodb/MongoDBObjectStorageDataAccess.h +++ b/ChaosMetadataService/object_storage/mongodb/MongoDBObjectStorageDataAccess.h @@ -56,6 +56,7 @@ namespace chaos { public: //inhertied method int pushObject(const std::string& key, + const ChaosStringSetConstSPtr meta_tags, const chaos::common::data::CDataWrapper& stored_object); //inhertied method @@ -72,8 +73,9 @@ namespace chaos { uint64_t end_timestamp); //inhertied method int findObject(const std::string& key, - uint64_t timestamp_from, - uint64_t timestamp_to, + const ChaosStringSet& meta_tags, + const uint64_t timestamp_from, + const uint64_t timestamp_to, const uint32_t page_len, object_storage::abstraction::VectorObject& found_object_page, common::direct_io::channel::opcode_headers::SearchSequence& last_record_found_seq); diff --git a/ChaosMetadataService/persistence/mongodb/MongoDBControlUnitDataAccess.cpp b/ChaosMetadataService/persistence/mongodb/MongoDBControlUnitDataAccess.cpp index 056724795..87f60c4c8 100644 --- a/ChaosMetadataService/persistence/mongodb/MongoDBControlUnitDataAccess.cpp +++ b/ChaosMetadataService/persistence/mongodb/MongoDBControlUnitDataAccess.cpp @@ -1175,8 +1175,8 @@ int MongoDBControlUnitDataAccess::eraseControlUnitDataBeforeTS(const std::string int err = 0; try { mongo::BSONObj q = BSON(chaos::DataPackCommonKey::DPCK_DEVICE_ID << control_unit_id << - DataPackCommonKey::DPCK_TIMESTAMP << BSON( "$lte" << mongo::Date_t(unit_ts))); - + DataPackCommonKey::DPCK_TIMESTAMP << BSON( "$lte" << mongo::Date_t(unit_ts)) << + "$or" << BSON_ARRAY(BSON(chaos::DataPackCommonKey::DPCK_DATASET_TAGS << BSON("$exists" << false)) << BSON(chaos::DataPackCommonKey::DPCK_DATASET_TAGS << BSON("$eq" << mongo::BSONArrayBuilder().arr())))); DEBUG_CODE(MDBCUDA_DBG<<log_message("eraseControlUnitDataBeforeTS", "delete", DATA_ACCESS_LOG_1_ENTRY("Query", diff --git a/ChaosMetadataService/worker/DeviceSharedDataWorker.cpp b/ChaosMetadataService/worker/DeviceSharedDataWorker.cpp index 13f6c69b2..1ab5bcad6 100644 --- a/ChaosMetadataService/worker/DeviceSharedDataWorker.cpp +++ b/ChaosMetadataService/worker/DeviceSharedDataWorker.cpp @@ -84,6 +84,7 @@ void DeviceSharedDataWorker::executeJob(WorkerJobPtr job_info, void* cookie) { CDataWrapper data_pack((char *)job.data_pack->data()); //push received datapack into object storage if((err = obj_storage_da->pushObject(job.key, + ChaosMoveOperator(job.meta_tag), data_pack))) { ERR << "Error pushing datapack into object storage driver"; } diff --git a/ChaosMetadataService/worker/DeviceSharedDataWorker.h b/ChaosMetadataService/worker/DeviceSharedDataWorker.h index b0cfa358c..f2c4e0b9a 100644 --- a/ChaosMetadataService/worker/DeviceSharedDataWorker.h +++ b/ChaosMetadataService/worker/DeviceSharedDataWorker.h @@ -47,8 +47,8 @@ namespace chaos{ public WorkerJob { uint8_t key_tag; std::string key; - int put_operation; //0 -storicize only, 1-live only, 2-storicize and live - uint32_t data_pack_len; + int put_operation; //0 -storicize only, 1-live only, 2-storicize and liveb + ChaosStringSetConstSPtr meta_tag; chaos::common::data::BufferSPtr data_pack; }; diff --git a/ChaosMetadataService/worker/DeviceSharedDataWorkerMetricCollector.cpp b/ChaosMetadataService/worker/DeviceSharedDataWorkerMetricCollector.cpp index ee3d2a553..732aa7629 100644 --- a/ChaosMetadataService/worker/DeviceSharedDataWorkerMetricCollector.cpp +++ b/ChaosMetadataService/worker/DeviceSharedDataWorkerMetricCollector.cpp @@ -37,7 +37,7 @@ void DeviceSharedDataWorkerMetricCollector::executeJob(WorkerJobPtr job_info, void* cookie) { DeviceSharedWorkerJob& job = *reinterpret_cast<DeviceSharedWorkerJob*>(job_info.get()); int tag = job.key_tag; - uint32_t total_data = job.data_pack_len + (uint32_t)job.key.size(); + uint32_t total_data = (uint32_t)job.data_pack->size() + (uint32_t)job.key.size(); DeviceSharedDataWorker::executeJob(job_info, cookie); switch(tag) { case 0:// storicize only @@ -58,7 +58,7 @@ int DeviceSharedDataWorkerMetricCollector::submitJobInfo(WorkerJobPtr job_info) int err = 0; DeviceSharedWorkerJob& job = *reinterpret_cast<DeviceSharedWorkerJob*>(job_info.get()); int tag = job.key_tag; - uint32_t total_data = job.data_pack_len + (uint32_t)job.key.size(); + uint32_t total_data = (uint32_t)job.data_pack->size() + (uint32_t)job.key.size(); data_worker_metric->incrementInputBandwith(total_data); switch(tag) { diff --git a/ccs/ccs.pro b/ccs/ccs.pro index 33834b655..1a5419e34 100644 --- a/ccs/ccs.pro +++ b/ccs/ccs.pro @@ -188,7 +188,8 @@ SOURCES += main.cpp\ node/connection_manager/ConnectionEditor.cpp \ node/connection_manager/model/ControlUnitNodeDataModel.cpp \ language_editor/LuaLanguageSupport.cpp \ - language_editor/CLINGLanguageSupport.cpp + language_editor/CLINGLanguageSupport.cpp \ + widget/StorageBurst.cpp HEADERS += \ search/SearchNodeResult.h \ @@ -365,7 +366,8 @@ HEADERS += \ node/connection_manager/model/ControlUnitNodeDataModel.h \ language_editor/LanguageEditorSupport.h \ language_editor/LuaLanguageSupport.h \ - language_editor/CLINGLanguageSupport.h + language_editor/CLINGLanguageSupport.h \ + widget/StorageBurst.h FORMS += \ search/searchnoderesult.ui \ @@ -408,7 +410,8 @@ FORMS += \ widget/CPopupWidgetContainer.ui \ widget/ChaosStorageTypeWidget.ui \ preference/SelectNetworkDomain.ui \ - node/connection_manager/ConnectionEditor.ui + node/connection_manager/ConnectionEditor.ui \ + widget/StorageBurst.ui DISTFILES += \ dark_orange.stylesheet \ diff --git a/ccs/node/control_unit/ControUnitInstanceEditor.ui b/ccs/node/control_unit/ControUnitInstanceEditor.ui index 520dda132..464b3da55 100644 --- a/ccs/node/control_unit/ControUnitInstanceEditor.ui +++ b/ccs/node/control_unit/ControUnitInstanceEditor.ui @@ -158,7 +158,7 @@ <enum>QTabWidget::North</enum> </property> <property name="currentIndex"> - <number>0</number> + <number>2</number> </property> <property name="usesScrollButtons"> <bool>true</bool> @@ -613,26 +613,26 @@ </size> </property> <property name="currentIndex"> - <number>3</number> + <number>0</number> </property> <item> <property name="text"> - <string>History</string> + <string>Not Set</string> </property> </item> <item> <property name="text"> - <string>Live</string> + <string>History</string> </property> </item> <item> <property name="text"> - <string>History & Live</string> + <string>Live</string> </property> </item> <item> <property name="text"> - <string>Not Set</string> + <string>History & Live</string> </property> </item> </widget> diff --git a/ccs/node/control_unit/ControlUnitEditor.ui b/ccs/node/control_unit/ControlUnitEditor.ui index 0225b5bb8..3b41c3ad9 100644 --- a/ccs/node/control_unit/ControlUnitEditor.ui +++ b/ccs/node/control_unit/ControlUnitEditor.ui @@ -1031,13 +1031,13 @@ <widget class="ChaosStorageTypeWidget" name="widgetStorageType" native="true"> <property name="minimumSize"> <size> - <width>110</width> + <width>130</width> <height>20</height> </size> </property> <property name="maximumSize"> <size> - <width>110</width> + <width>130</width> <height>20</height> </size> </property> diff --git a/ccs/widget/ChaosStorageTypeWidget.cpp b/ccs/widget/ChaosStorageTypeWidget.cpp index de58ae12f..fd2689648 100644 --- a/ccs/widget/ChaosStorageTypeWidget.cpp +++ b/ccs/widget/ChaosStorageTypeWidget.cpp @@ -1,6 +1,7 @@ #include "ChaosStorageTypeWidget.h" #include "CPropertyTextEdit.h" #include "CPopupWidgetContainer.h" +#include "StorageBurst.h" #include "ui_ChaosStorageTypeWidget.h" #include <QDebug> @@ -210,3 +211,14 @@ void ChaosStorageTypeWidget::on_pushButtonEdit_clicked() { wc->setWindowModality(Qt::WindowModal); wc->show(); } + +void ChaosStorageTypeWidget::on_pushButton_clicked() { + CPopupWidgetContainer *wc = new CPopupWidgetContainer(this); + StorageBurst *sb = new StorageBurst(wc); + sb->setNodeUID(nodeUID()); + wc->addWidget(sb); + QRect rect = QRect(0,0,parentWidget()->width(),0); + wc->setGeometry(rect); + wc->setWindowModality(Qt::WindowModal); + wc->show(); +} diff --git a/ccs/widget/ChaosStorageTypeWidget.h b/ccs/widget/ChaosStorageTypeWidget.h index a40d043f9..5b86660b2 100644 --- a/ccs/widget/ChaosStorageTypeWidget.h +++ b/ccs/widget/ChaosStorageTypeWidget.h @@ -38,6 +38,8 @@ private slots: void on_pushButtonEdit_clicked(); + void on_pushButton_clicked(); + private: bool data_found; QString last_pushbutton_in_error; diff --git a/ccs/widget/ChaosStorageTypeWidget.ui b/ccs/widget/ChaosStorageTypeWidget.ui index 694b90bf3..419778dbe 100644 --- a/ccs/widget/ChaosStorageTypeWidget.ui +++ b/ccs/widget/ChaosStorageTypeWidget.ui @@ -6,7 +6,7 @@ <rect> <x>0</x> <y>0</y> - <width>166</width> + <width>130</width> <height>22</height> </rect> </property> @@ -18,7 +18,7 @@ </property> <property name="minimumSize"> <size> - <width>110</width> + <width>130</width> <height>22</height> </size> </property> @@ -203,6 +203,24 @@ </property> </widget> </item> + <item> + <widget class="QPushButton" name="pushButton"> + <property name="maximumSize"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + <property name="font"> + <font> + <pointsize>11</pointsize> + </font> + </property> + <property name="text"> + <string>B</string> + </property> + </widget> + </item> </layout> </widget> <customwidgets> diff --git a/ccs/widget/StorageBurst.cpp b/ccs/widget/StorageBurst.cpp new file mode 100644 index 000000000..cb02e62fe --- /dev/null +++ b/ccs/widget/StorageBurst.cpp @@ -0,0 +1,53 @@ +#include "StorageBurst.h" +#include "ui_StorageBurst.h" +#include <chaos/common/data/CDataVariant.h> +#include <chaos/common/data/structured/Dataset.h> + +using namespace chaos::common::data; +using namespace chaos::common::data::structured; + +StorageBurst::StorageBurst(QWidget *parent) : + QWidget(parent), + ui(new Ui::StorageBurst) { + ui->setupUi(this); + ui->comboBoxType->clear(); + ui->comboBoxType->addItem("Push", QVariant(chaos::ControlUnitNodeDefinitionType::DSStorageBurstTypeNPush)); + ui->comboBoxType->addItem("Millliseconds", QVariant(chaos::ControlUnitNodeDefinitionType::DSStorageBurstTypeMSec)); +} + +StorageBurst::~StorageBurst() { + delete ui; +} + +void StorageBurst::on_comboBox_currentIndexChanged(const QString &selected_item) { + if(selected_item.compare("Push") == 0) { + ui->lineEditValue->setPlaceholderText("Number of pushes[up to 10000]"); + ui->lineEditValue->setValidator(new QIntValidator(1, 10000, ui->lineEditValue)); + } else if(selected_item.compare("Timed")) { + ui->lineEditValue->setPlaceholderText("Number of milliseconds[up to 1h]"); + ui->lineEditValue->setValidator(new QIntValidator(1, 1000*60*60, ui->lineEditValue)); + } +} + +void StorageBurst::apiHasStarted(const QString& api_tag) { + setEnabled(false); +} + +void StorageBurst::apiHasEnded(const QString& api_tag) { + setEnabled(true); +} + +void StorageBurst::apiHasEndedWithError(const QString& api_tag, + QSharedPointer<chaos::CException> api_exception) { + setEnabled(true); +} + +void StorageBurst::on_pushButtonSubmit_clicked() { + chaos::common::data::structured::DatasetBurst ds_burst; + ds_burst.type = static_cast<chaos::ControlUnitNodeDefinitionType::DSStorageBurstType>(ui->comboBoxType->currentData().toInt()); + ds_burst.value = CDataVariant(ui->lineEditValue->text().toInt()); + ds_burst.tag = ui->lineEditTagName->text().toStdString(); + submitApiResult("submit_burst", + GET_CHAOS_API_PTR(chaos::metadata_service_client::api_proxy::control_unit::SendStorageBurst)->execute(nodeUID().toStdString(), + ds_burst)); +} diff --git a/ccs/widget/StorageBurst.h b/ccs/widget/StorageBurst.h new file mode 100644 index 000000000..87ba324e8 --- /dev/null +++ b/ccs/widget/StorageBurst.h @@ -0,0 +1,32 @@ +#ifndef STORAGEBURST_H +#define STORAGEBURST_H + +#include <QWidget> +#include "ChaosWidgetCompanion.h" +namespace Ui { +class StorageBurst; +} + +class StorageBurst : + public QWidget, + public ChaosWidgetCompanion { + Q_OBJECT + +public: + explicit StorageBurst(QWidget *parent = 0); + ~StorageBurst(); + +private slots: + void on_comboBox_currentIndexChanged(const QString &selected_item); + + void on_pushButtonSubmit_clicked(); + +private: + void apiHasStarted(const QString& api_tag); + void apiHasEnded(const QString& api_tag); + void apiHasEndedWithError(const QString& api_tag, + QSharedPointer<chaos::CException> api_exception); + Ui::StorageBurst *ui; +}; + +#endif // STORAGEBURST_H diff --git a/ccs/widget/StorageBurst.ui b/ccs/widget/StorageBurst.ui new file mode 100644 index 000000000..10ae57e97 --- /dev/null +++ b/ccs/widget/StorageBurst.ui @@ -0,0 +1,168 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>StorageBurst</class> + <widget class="QWidget" name="StorageBurst"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>320</width> + <height>108</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>320</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>108</height> + </size> + </property> + <property name="font"> + <font> + <pointsize>11</pointsize> + </font> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QFormLayout" name="formLayout"> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <property name="labelAlignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="horizontalSpacing"> + <number>4</number> + </property> + <property name="verticalSpacing"> + <number>4</number> + </property> + <property name="leftMargin"> + <number>4</number> + </property> + <property name="topMargin"> + <number>4</number> + </property> + <property name="rightMargin"> + <number>4</number> + </property> + <property name="bottomMargin"> + <number>4</number> + </property> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="font"> + <font> + <pointsize>11</pointsize> + </font> + </property> + <property name="text"> + <string>Type:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="comboBoxType"> + <item> + <property name="text"> + <string extracomment="Execute the burst for a number of determinated pushes">Push</string> + </property> + </item> + <item> + <property name="text"> + <string extracomment="Execute the burst for a determinated number of milliseconds">Timed</string> + </property> + </item> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label"> + <property name="font"> + <font> + <pointsize>11</pointsize> + </font> + </property> + <property name="text"> + <string>Tag:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="lineEditTagName"> + <property name="placeholderText"> + <string>tag name</string> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_3"> + <property name="font"> + <font> + <pointsize>11</pointsize> + </font> + </property> + <property name="text"> + <string>Value:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QLineEdit" name="lineEditValue"> + <property name="placeholderText"> + <string>value</string> + </property> + </widget> + </item> + <item row="5" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="pushButtonSubmit"> + <property name="text"> + <string>Submit</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/chaos/common/chaos_constants.h b/chaos/common/chaos_constants.h index 350114097..28f62a6f7 100644 --- a/chaos/common/chaos_constants.h +++ b/chaos/common/chaos_constants.h @@ -623,6 +623,7 @@ namespace chaos { store another datapack into the live system[uint64] */ static const char * const DS_STORAGE_LIVE_TIME = "dsndk_storage_live_time"; + } /** @} */ // end of DataServiceNodeDefinitionKey @@ -637,14 +638,14 @@ namespace chaos { so every datapack can be considere with different store behaviour */ typedef enum DSStorageType { + //!no storage behaviour defined + DSStorageTypeUndefined = 0, //!the datapack is store into the storage system and not in live - DSStorageTypeHistory, + DSStorageTypeHistory = 1, //!the datapack is publish in live shared memory - DSStorageTypeLive, + DSStorageTypeLive = 2, //!datapack is published and stored in live and history - DSStorageTypeLiveHistory, - //!no storage behaviour defined - DSStorageTypeUndefined + DSStorageTypeLiveHistory = 3 } DSStorageType; } /** @} */ // end of DataServiceNodeDefinitionType @@ -744,12 +745,41 @@ namespace chaos { //!The key represent an array with the object taht represent, each one, the command description array[object...] static const char * const CONTROL_UNIT_DATASET_COMMAND_DESCRIPTION = "cudk_ds_command_description"; + /*! + Whatever storage type is actually in use, the set of this property will send data to + the history engine with the type and value specified by the cdata wrapper seriled in it + */ + static const char * const CONTROL_UNIT_DATASET_HISTORY_BURST = "dsndk_history_burst"; + //! Is the key used for specify the type f burts function + static const char * const CONTROL_UNIT_DATASET_HISTORY_BURST_TYPE = "dsndk_history_burst_type"; + //! is the value related to the type + static const char * const CONTROL_UNIT_DATASET_HISTORY_BURST_VALUE = "dsndk_history_burst_value"; + //! is the tag associated to the burst + static const char * const CONTROL_UNIT_DATASET_HISTORY_BURST_TAG = "dsndk_history_burst_tag"; } /** @} */ // end of ControlUnitNodeDefinitionKey + /** @defgroup ControlUnitNodeDefinitionKey List of control unit node type attribute key + * @{ + */ + //! Name space for grupping key for the control unit node type + namespace ControlUnitNodeDefinitionType { + //! define the tipe of hisoty burst function + typedef enum DSStorageBurstType { + //!no storage behaviour defined + DSStorageBurstTypeUndefined = 0, + DSStorageBurstTypeNPush, + DSStorageBurstTypeMSec + } DSStorageBurstType; + } + /** @} */ // end of ControlUnitNodeDefinitionKey namespace ControlUnitNodeDomainAndActionRPC { //!Alias associated to thefunction that apply the value changes set to the input dataset attribute static const char * const CONTROL_UNIT_APPLY_INPUT_DATASET_ATTRIBUTE_CHANGE_SET = "cunrpc_ida_cs"; + + //! Deinitialization of a control unit, if it is in run, the stop phase + //! is started befor deinitialization one + static const char * const ACTION_STORAGE_BURST = "cunrpc_start_storage_burst"; } /** @defgroup ExecutionUnitNodeDefinitionKey List of execution unit node type attribute key @@ -1201,6 +1231,8 @@ namespace chaos { static const char * const DPCK_HIGH_RESOLUTION_TIMESTAMP = "dpck_hr_ats";//chaos::NodeDefinitionKey::NODE_TIMESTAMP; //!define the type of the dataset uint32_t [output(0) - input(1) - custom(2) - system(3) - ....others int32_t] static const char * const DPCK_DATASET_TYPE = "dpck_ds_type"; + //!define the list of tags associated to the datapack + static const char * const DPCK_DATASET_TAGS = "dpck_ds_tag"; //! the constant that represent the output dataset type static const unsigned int DPCK_DATASET_TYPE_OUTPUT = 0; //! the constant that represent the input dataset type @@ -1215,6 +1247,8 @@ namespace chaos { static const unsigned int DPCK_DATASET_TYPE_DEV_ALARM = 5; //! the constant that represent the alarm dataset type static const unsigned int DPCK_DATASET_TYPE_CU_ALARM = 6; + //!define tags associated to the dataset[array of string] + static const char * const DPCK_DATASET_TAG = "dpck_ds_tag"; } diff --git a/chaos/common/chaos_types.h b/chaos/common/chaos_types.h index 40a9217a4..42397c9d4 100644 --- a/chaos/common/chaos_types.h +++ b/chaos/common/chaos_types.h @@ -133,8 +133,8 @@ typedef typename std::vector< t >::iterator n ## Iterator;\ typedef typename std::vector< t >::const_iterator n ## ConstIterator; #define CHAOS_DEFINE_QUEUE_FOR_TYPE(t, n)\ -typedef std::queue< t > n;\ -typedef std::queue< t >::iterator n ## Iterator; +typedef std::queue< t > n; +//typedef std::queue< t >::iterator n ## Iterator; //typedef std::queue< t >::const_iterator n ## ConstIterator; #define CHAOS_DEFINE_DEQUE_FOR_TYPE(t, n)\ @@ -173,7 +173,16 @@ typedef boost::ptr_map< t1, t2 >::const_iterator n ## ConstIterator; dynamic_cast<element_type*>(&map.at(element_key)); CHAOS_DEFINE_VECTOR_FOR_TYPE(std::string, ChaosStringVector) +typedef ChaosUniquePtr<ChaosStringVector> ChaosStringVectorUPtr; +typedef ChaosSharedPtr<ChaosStringVector> ChaosStringVectorSPtr; +typedef ChaosUniquePtr<const ChaosStringVector> ChaosStringVectorConstUPtr; +typedef ChaosSharedPtr<const ChaosStringVector> ChaosStringVectorConstSPtr; + CHAOS_DEFINE_SET_FOR_TYPE(std::string, ChaosStringSet) +typedef ChaosUniquePtr<ChaosStringSet> ChaosStringSetUPtr; +typedef ChaosSharedPtr<ChaosStringSet> ChaosStringSetSPtr; +typedef ChaosUniquePtr<const ChaosStringSet> ChaosStringSetConstUPtr; +typedef ChaosSharedPtr<const ChaosStringSet> ChaosStringSetConstSPtr; #define CHAOS_SCAN_VECTOR_ITERATOR(iter, vec, to_execute)\ for(iter it = vec.begin();\ diff --git a/chaos/common/data/CDataBuffer.cpp b/chaos/common/data/CDataBuffer.cpp index 4340fea2f..1b39ec392 100644 --- a/chaos/common/data/CDataBuffer.cpp +++ b/chaos/common/data/CDataBuffer.cpp @@ -26,45 +26,35 @@ using namespace chaos::common::data; CDataBuffer::CDataBuffer(): - own_buffer(false), - buffer_size(0), - buffer(NULL) { } + internal_buffer(){} CDataBuffer::CDataBuffer(const char *_buffer, - uint32_t _buffer_size, - bool copy): -own_buffer(copy) { - buffer_size = _buffer_size; - if(copy) { - buffer = new char[_buffer_size]; - memcpy(buffer, _buffer, buffer_size); - } else { - buffer = (char*)_buffer; - } -} + uint32_t _buffer_size): +internal_buffer(_buffer, + _buffer_size){} + +CDataBuffer::CDataBuffer(char *buffer, + uint32_t buffer_size, + bool own): +internal_buffer(buffer, + buffer_size, + buffer_size, + true){} CDataBuffer::CDataBuffer(const CDataBuffer& cdata_buffer): -own_buffer(cdata_buffer.own_buffer), -buffer(cdata_buffer.buffer), -buffer_size(cdata_buffer.buffer_size){} +internal_buffer(cdata_buffer.internal_buffer){} -CDataBuffer::~CDataBuffer() { - if(own_buffer) delete(buffer); -} +CDataBuffer::~CDataBuffer() {} const char *CDataBuffer::getBuffer() const { - return buffer; + return internal_buffer.data(); } -uint32_t CDataBuffer::getBufferSize() const { - return buffer_size; +std::size_t CDataBuffer::getBufferSize() const { + return internal_buffer.size(); } -CDataBuffer *CDataBuffer::newOwnBufferFromBuffer(char * buffer, - uint32_t _buffer_size) { - CDataBuffer *result = new CDataBuffer(); - result->own_buffer = true; - result->buffer = buffer; - result->buffer_size = _buffer_size; - return result; +CDBufferUniquePtr CDataBuffer::newOwnBufferFromBuffer(char * buffer, + uint32_t _buffer_size) { + return CDBufferUniquePtr(new CDataBuffer(buffer, _buffer_size, true)); } diff --git a/chaos/common/data/CDataBuffer.h b/chaos/common/data/CDataBuffer.h index 0ed8126a4..4f04751dc 100644 --- a/chaos/common/data/CDataBuffer.h +++ b/chaos/common/data/CDataBuffer.h @@ -23,37 +23,39 @@ #define __CHAOSFramework__CDataBuffer_h #include <chaos/common/chaos_types.h> - +#include <chaos/common/data/Buffer.hpp> #include <stdint.h> namespace chaos { namespace common { namespace data { + class CDataBuffer; + + typedef ChaosUniquePtr<chaos::common::data::CDataBuffer> CDBufferUniquePtr; + typedef ChaosSharedPtr<chaos::common::data::CDataBuffer> CDBufferShrdPtr; class CDataBuffer { - bool own_buffer; - char * buffer; - uint32_t buffer_size; - + Buffer internal_buffer; + CDataBuffer(char *buffer, + uint32_t buffer_size, + bool own); public: CDataBuffer(); CDataBuffer(const char *buffer, - uint32_t buffer_size, - bool copy = false); + uint32_t buffer_size); CDataBuffer(const CDataBuffer& cdata_buffer); ~CDataBuffer(); const char *getBuffer() const; - uint32_t getBufferSize() const; + std::size_t getBufferSize() const; - static CDataBuffer *newOwnBufferFromBuffer(char * buffer, - uint32_t _buffer_size); + static CDBufferUniquePtr newOwnBufferFromBuffer(char * buffer, + uint32_t _buffer_size); }; - typedef ChaosUniquePtr<chaos::common::data::CDataBuffer> CDBufferUniquePtr; - typedef ChaosSharedPtr<chaos::common::data::CDataBuffer> CDBufferShrdPtr; + } } } diff --git a/chaos/common/data/CDataVariant.cpp b/chaos/common/data/CDataVariant.cpp index 34d95666e..38c4f0f06 100644 --- a/chaos/common/data/CDataVariant.cpp +++ b/chaos/common/data/CDataVariant.cpp @@ -122,15 +122,15 @@ std::string string_visitor::operator()(const ChaosSharedPtr<CDataWrapper>& buffe #pragma mark CDataBuffervisitor -ChaosSharedPtr<CDataBuffer> CDataBuffer_visitor::operator()(const bool bv) const {return ChaosSharedPtr<CDataBuffer>(new CDataBuffer((const char*)&bv,sizeof(bool),true));} -ChaosSharedPtr<CDataBuffer> CDataBuffer_visitor::operator()(const int32_t i32v) const {return ChaosSharedPtr<CDataBuffer>(new CDataBuffer((const char*)&i32v,sizeof(int32_t),true));} -ChaosSharedPtr<CDataBuffer> CDataBuffer_visitor::operator()(const uint32_t ui32v) const {return ChaosSharedPtr<CDataBuffer>(new CDataBuffer((const char*)&ui32v,sizeof(uint32_t),true));} -ChaosSharedPtr<CDataBuffer> CDataBuffer_visitor::operator()(const int64_t i64v) const {return ChaosSharedPtr<CDataBuffer>(new CDataBuffer((const char*)&i64v,sizeof(int64_t),true));} -ChaosSharedPtr<CDataBuffer> CDataBuffer_visitor::operator()(const uint64_t ui64v) const {return ChaosSharedPtr<CDataBuffer>(new CDataBuffer((const char*)&ui64v,sizeof(uint64_t),true));} -ChaosSharedPtr<CDataBuffer> CDataBuffer_visitor::operator()(const double dv) const {return ChaosSharedPtr<CDataBuffer>(new CDataBuffer((const char*)&dv,sizeof(double),true));} -ChaosSharedPtr<CDataBuffer> CDataBuffer_visitor::operator()(const std::string& str) const {return ChaosSharedPtr<CDataBuffer>(new CDataBuffer(str.c_str(), (uint32_t)str.size(), true));} +ChaosSharedPtr<CDataBuffer> CDataBuffer_visitor::operator()(const bool bv) const {return ChaosSharedPtr<CDataBuffer>(new CDataBuffer((const char*)&bv,sizeof(bool)));} +ChaosSharedPtr<CDataBuffer> CDataBuffer_visitor::operator()(const int32_t i32v) const {return ChaosSharedPtr<CDataBuffer>(new CDataBuffer((const char*)&i32v,sizeof(int32_t)));} +ChaosSharedPtr<CDataBuffer> CDataBuffer_visitor::operator()(const uint32_t ui32v) const {return ChaosSharedPtr<CDataBuffer>(new CDataBuffer((const char*)&ui32v,sizeof(uint32_t)));} +ChaosSharedPtr<CDataBuffer> CDataBuffer_visitor::operator()(const int64_t i64v) const {return ChaosSharedPtr<CDataBuffer>(new CDataBuffer((const char*)&i64v,sizeof(int64_t)));} +ChaosSharedPtr<CDataBuffer> CDataBuffer_visitor::operator()(const uint64_t ui64v) const {return ChaosSharedPtr<CDataBuffer>(new CDataBuffer((const char*)&ui64v,sizeof(uint64_t)));} +ChaosSharedPtr<CDataBuffer> CDataBuffer_visitor::operator()(const double dv) const {return ChaosSharedPtr<CDataBuffer>(new CDataBuffer((const char*)&dv,sizeof(double)));} +ChaosSharedPtr<CDataBuffer> CDataBuffer_visitor::operator()(const std::string& str) const {return ChaosSharedPtr<CDataBuffer>(new CDataBuffer(str.c_str(), (uint32_t)str.size()));} ChaosSharedPtr<CDataBuffer> CDataBuffer_visitor::operator()(const ChaosSharedPtr<CDataBuffer>& buffer) const {return buffer;} -ChaosSharedPtr<CDataBuffer> CDataBuffer_visitor::operator()(const ChaosSharedPtr<CDataWrapper>& buffer) const {return ChaosSharedPtr<CDataBuffer>(new CDataBuffer(buffer->getJSONString().c_str(), (uint32_t)buffer->getJSONString().size(), true));;} +ChaosSharedPtr<CDataBuffer> CDataBuffer_visitor::operator()(const ChaosSharedPtr<CDataWrapper>& buffer) const {return ChaosSharedPtr<CDataBuffer>(new CDataBuffer(buffer->getJSONString().c_str(), (uint32_t)buffer->getJSONString().size()));} #pragma mark CDataWrappervisitor ChaosSharedPtr<CDataWrapper> CDataWrapper_visitor::operator()(const bool bv) const {throw CFatalException(-1,"invalid conversion to CDataWrapper from bool",__PRETTY_FUNCTION__);return ChaosSharedPtr<CDataWrapper>(new CDataWrapper());} @@ -187,9 +187,9 @@ CDataVariant::CDataVariant(const char * string_value):_internal_variant(std::str } } -CDataVariant::CDataVariant(CDataBuffer *buffer_value): +CDataVariant::CDataVariant(CDBufferUniquePtr buffer_value): type(DataType::TYPE_BYTEARRAY), -_internal_variant(ChaosSharedPtr<CDataBuffer>(buffer_value)) { } +_internal_variant(ChaosSharedPtr<CDataBuffer>(buffer_value.release())) { } CDataVariant::CDataVariant(CDataWrapper *buffer_value): type(DataType::TYPE_CLUSTER), @@ -237,8 +237,7 @@ type(_type){ } case DataType::TYPE_BYTEARRAY:{ _internal_variant = ChaosSharedPtr<CDataBuffer>(new CDataBuffer(static_cast<const char*>(_value_pointer), - _value_size, - true)); + _value_size)); break; } default: diff --git a/chaos/common/data/CDataVariant.h b/chaos/common/data/CDataVariant.h index 37d35c822..717d0a029 100644 --- a/chaos/common/data/CDataVariant.h +++ b/chaos/common/data/CDataVariant.h @@ -110,7 +110,7 @@ namespace chaos { explicit CDataVariant(const std::string& string_value); explicit CDataVariant(const char * string_value); //! take the ownership of the object - explicit CDataVariant(CDataBuffer *buffer_value); + explicit CDataVariant(CDBufferUniquePtr buffer_value); explicit CDataVariant(CDataWrapper *buffer_value); CDataVariant(const CDataVariant& to_copy); diff --git a/chaos/common/data/CDataWrapper.cpp b/chaos/common/data/CDataWrapper.cpp index 4ead91d84..334dc45d7 100644 --- a/chaos/common/data/CDataWrapper.cpp +++ b/chaos/common/data/CDataWrapper.cpp @@ -32,10 +32,8 @@ using namespace chaos::common::data; #pragma mark Utility #define ADD_VECTOR(v,ctype,bsontype){\ - for( std::vector<ctype>::const_iterator i=v.begin();i!=v.end();i++){\ - append ##bsontype ##ToArray(*i);}} - - +for( std::vector<ctype>::const_iterator i=v.begin();i!=v.end();i++){\ +append ##bsontype ##ToArray(*i);}} #define ITER_TYPE(i) ((bson_type_t) * ((i)->raw + (i)->type)) @@ -43,38 +41,40 @@ using namespace chaos::common::data; #define ACCESS_BSON(x) static_cast<bson_t*>(x.get()) #define CW_CAST_EXCEPTION(type){\ - std::stringstream ss;\ - ss<<"cannot get or cast to '" #type "' "<<key<<"' ds:" << getJSONString();\ - throw CException(1, ss.str(), __PRETTY_FUNCTION__);} +std::stringstream ss;\ +ss<<"cannot get or cast to '" #type "' "<<key<<"' ds:" << getJSONString();\ +throw CException(1, ss.str(), __PRETTY_FUNCTION__);} #define ENSURE_ARRAY(x) \ - if(x.get() == NULL) {array_index = 0; x = ALLOCATE_BSONT(bson_new());} +if(x.get() == NULL) {array_index = 0; x = ALLOCATE_BSONT(bson_new());} #define FIND_AND_CHECK(k,c)\ - bson_iter_t element_found;\ - bson_iter_init(&element_found, ACCESS_BSON(bson));\ - if(bson_iter_find_case(&element_found, key.c_str()) && c(&element_found)) +bson_iter_t element_found;\ +bson_iter_init(&element_found, ACCESS_BSON(bson));\ +if(bson_iter_find_case(&element_found, key.c_str()) && c(&element_found)) #define INIT_ITERATOR(key) \ - bool keyfound;\ - bson_iter_t element_found;\ - bson_iter_init(&element_found, ACCESS_BSON(bson));\ - keyfound=bson_iter_find_case(&element_found, key.c_str()); +bool keyfound;\ +bson_iter_t element_found;\ +bson_iter_init(&element_found, ACCESS_BSON(bson));\ +keyfound=bson_iter_find_case(&element_found, key.c_str()); #define GET_VALUE(t,c) \ - if(keyfound&& (c(&element_found))){return bson_iter_##t (&element_found);} +if(keyfound&& (c(&element_found))){return bson_iter_##t (&element_found);} static void bsonDeallocator(bson_t* bson) {if(bson){bson_destroy(bson);}} +static void bsonValueDestroy(bson_value_t* bson_values) {if(bson_values){bson_value_destroy(bson_values);}} + #pragma mark CDataWrapper CDataWrapper::CDataWrapper(): - bson(ALLOCATE_BSONT(bson_new())), - array_index(0){ +bson(ALLOCATE_BSONT(bson_new())), +array_index(0){ CHAOS_ASSERT(bson); } CDataWrapper::CDataWrapper(const bson_t *copy_bson): - array_index(0){ +array_index(0){ if(copy_bson != NULL) { bson = ALLOCATE_BSONT(bson_copy(copy_bson)); } else { @@ -85,7 +85,7 @@ CDataWrapper::CDataWrapper(const bson_t *copy_bson): CDataWrapper::CDataWrapper(const char* mem_ser, uint32_t mem_size): - array_index(0){ +array_index(0){ if(mem_ser != NULL || mem_size) { bson = ALLOCATE_BSONT(bson_new_from_data((const uint8_t*)mem_ser, mem_size)); @@ -96,7 +96,7 @@ CDataWrapper::CDataWrapper(const char* mem_ser, } CDataWrapper::CDataWrapper(const char* mem_ser): - array_index(0) { +array_index(0) { if(mem_ser) { uint32_t size = BSON_UINT32_FROM_LE(*reinterpret_cast<const uint32_t *>(mem_ser)); bson = ALLOCATE_BSONT(bson_new_from_data((const uint8_t*)mem_ser, @@ -108,7 +108,7 @@ CDataWrapper::CDataWrapper(const char* mem_ser): } CDataWrapper::CDataWrapper(const std::string& json_document): - array_index(0) { +array_index(0) { bson_error_t err; bson = ALLOCATE_BSONT(bson_new_from_json((const uint8_t*)json_document.c_str(), json_document.size(), @@ -159,9 +159,9 @@ void CDataWrapper::appendStringToArray(const string& value) { void CDataWrapper::appendBooleanToArray(bool value){ ENSURE_ARRAY(bson_tmp_array); bson_append_bool(ACCESS_BSON(bson_tmp_array), - boost::lexical_cast<std::string>(array_index++).c_str(), - -1, - value); + boost::lexical_cast<std::string>(array_index++).c_str(), + -1, + value); } //append a strin gto an open array @@ -442,30 +442,30 @@ void CDataWrapper::addVariantValue(const std::string& key, const CDataVariant& variant_value) { //create variant using the typed data switch (variant_value.getType()) { - case DataType::TYPE_BOOLEAN: - addBoolValue(key, variant_value.asBool()); - break; - case DataType::TYPE_INT32: - addInt32Value(key, variant_value.asInt32()); - break; - case DataType::TYPE_INT64: - addInt64Value(key, variant_value.asInt64()); - break; - case DataType::TYPE_DOUBLE: - addDoubleValue(key, variant_value.asDouble()); - break; - case DataType::TYPE_CLUSTER:{ - addJsonValue(key,variant_value.asString()); - break; - } - case DataType::TYPE_STRING: - addStringValue(key, variant_value.asString()); - break; - case DataType::TYPE_BYTEARRAY: - addBinaryValue(key, - variant_value.asCDataBuffer()->getBuffer(), - variant_value.asCDataBuffer()->getBufferSize()); - break; + case DataType::TYPE_BOOLEAN: + addBoolValue(key, variant_value.asBool()); + break; + case DataType::TYPE_INT32: + addInt32Value(key, variant_value.asInt32()); + break; + case DataType::TYPE_INT64: + addInt64Value(key, variant_value.asInt64()); + break; + case DataType::TYPE_DOUBLE: + addDoubleValue(key, variant_value.asDouble()); + break; + case DataType::TYPE_CLUSTER:{ + addJsonValue(key,variant_value.asString()); + break; + } + case DataType::TYPE_STRING: + addStringValue(key, variant_value.asString()); + break; + case DataType::TYPE_BYTEARRAY: + addBinaryValue(key, + variant_value.asCDataBuffer()->getBuffer(), + (uint32_t)variant_value.asCDataBuffer()->getBufferSize()); + break; } } @@ -486,8 +486,7 @@ ChaosUniquePtr<CDataBuffer> CDataWrapper::getBinaryValueAsCDataBuffer(const std: uint32_t buf_len = 0; const char* buffer = getBinaryValue(key, buf_len); return ChaosUniquePtr<CDataBuffer>(new CDataBuffer(buffer, - buf_len, - true)); + buf_len)); } //check if the key is present in data wrapper @@ -528,30 +527,30 @@ uint32_t CDataWrapper::getValueSize(const std::string& key) const{ if(bson_iter_find_case(&it, key.c_str()) == false) return 0; const bson_value_t *v = bson_iter_value(&it); switch(v->value_type) { - case BSON_TYPE_INT64: - return sizeof(int64_t); - case BSON_TYPE_INT32: - return sizeof(int32_t); - case BSON_TYPE_BOOL: - return sizeof(bool); - case BSON_TYPE_DOUBLE: - return sizeof(double); - case BSON_TYPE_UTF8: - return v->value.v_utf8.len; - case BSON_TYPE_BINARY: - return v->value.v_binary.data_len; - case BSON_TYPE_ARRAY:{ - uint32_t array_len = 0; - const uint8_t *array = NULL; - bson_iter_array(&it, &array_len, &array); - return array_len; - } - case BSON_TYPE_DOCUMENT:{ - return v->value.v_doc.data_len; - } - default: - return 0; - break; + case BSON_TYPE_INT64: + return sizeof(int64_t); + case BSON_TYPE_INT32: + return sizeof(int32_t); + case BSON_TYPE_BOOL: + return sizeof(bool); + case BSON_TYPE_DOUBLE: + return sizeof(double); + case BSON_TYPE_UTF8: + return v->value.v_utf8.len; + case BSON_TYPE_BINARY: + return v->value.v_binary.data_len; + case BSON_TYPE_ARRAY:{ + uint32_t array_len = 0; + const uint8_t *array = NULL; + bson_iter_array(&it, &array_len, &array); + return array_len; + } + case BSON_TYPE_DOCUMENT:{ + return v->value.v_doc.data_len; + } + default: + return 0; + break; } return 0; } @@ -563,30 +562,30 @@ const char * CDataWrapper::getRawValuePtr(const std::string& key) const{ if(bson_iter_find_case(&it, key.c_str()) == false) return 0; const bson_value_t *v = bson_iter_value(&it); switch(v->value_type) { - case BSON_TYPE_INT64: - return reinterpret_cast<const char*>(&v->value.v_int64); - case BSON_TYPE_INT32: - return reinterpret_cast<const char*>(&v->value.v_int32); - case BSON_TYPE_BOOL: - return reinterpret_cast<const char*>(&v->value.v_bool); - case BSON_TYPE_DOUBLE: - return reinterpret_cast<const char*>(&v->value.v_double); - case BSON_TYPE_UTF8: - return static_cast<const char*>(v->value.v_utf8.str); - case BSON_TYPE_BINARY: - return reinterpret_cast<const char*>(v->value.v_binary.data); - case BSON_TYPE_ARRAY:{ - uint32_t array_len = 0; - const uint8_t *array = NULL; - bson_iter_array(&it, &array_len, &array); - return reinterpret_cast<const char*>(array); - } - case BSON_TYPE_DOCUMENT:{ - return reinterpret_cast<const char*>(v->value.v_doc.data); - } - default: - return NULL; - break; + case BSON_TYPE_INT64: + return reinterpret_cast<const char*>(&v->value.v_int64); + case BSON_TYPE_INT32: + return reinterpret_cast<const char*>(&v->value.v_int32); + case BSON_TYPE_BOOL: + return reinterpret_cast<const char*>(&v->value.v_bool); + case BSON_TYPE_DOUBLE: + return reinterpret_cast<const char*>(&v->value.v_double); + case BSON_TYPE_UTF8: + return static_cast<const char*>(v->value.v_utf8.str); + case BSON_TYPE_BINARY: + return reinterpret_cast<const char*>(v->value.v_binary.data); + case BSON_TYPE_ARRAY:{ + uint32_t array_len = 0; + const uint8_t *array = NULL; + bson_iter_array(&it, &array_len, &array); + return reinterpret_cast<const char*>(array); + } + case BSON_TYPE_DOCUMENT:{ + return reinterpret_cast<const char*>(v->value.v_doc.data); + } + default: + return NULL; + break; } } @@ -602,10 +601,11 @@ void CDataWrapper::addBoolValue(const std::string& key, bool value) { Return the Serialized buffer object taht contain the memory, the requester of this method shuld be deallocate the object */ -SerializationBuffer* CDataWrapper::getBSONData() const{ +__attribute__((__deprecated__)) +SerializationBufferUPtr CDataWrapper::getBSONData() const{ const char * buff = reinterpret_cast<const char*>(bson_get_data(ACCESS_BSON(bson))); - if(!buff) return NULL; - return new SerializationBuffer(buff, bson->len); + if(!buff) return SerializationBufferUPtr(); + return SerializationBufferUPtr(new SerializationBuffer(buff, bson->len)); } /* @@ -756,27 +756,27 @@ CDataVariant CDataWrapper::getVariantValue(const std::string& key) const{ if(!hasKey(key)) return CDataVariant(); //create variant using the typed data switch (getValueType(key)) { - case chaos::DataType::TYPE_BOOLEAN: - return CDataVariant(getBoolValue(key)); - break; - case chaos::DataType::TYPE_INT32: - return CDataVariant(getInt32Value(key)); - break; - case chaos::DataType::TYPE_INT64: - return CDataVariant(getInt64Value(key)); - break; - case chaos::DataType::TYPE_DOUBLE: - return CDataVariant(getDoubleValue(key)); - break; - case chaos::DataType::TYPE_STRING: - return CDataVariant(getStringValue(key)); - break; - case chaos::DataType::TYPE_BYTEARRAY: - return CDataVariant(getBinaryValueAsCDataBuffer(key).release()); - break; - default: - return CDataVariant(); - break; + case chaos::DataType::TYPE_BOOLEAN: + return CDataVariant(getBoolValue(key)); + break; + case chaos::DataType::TYPE_INT32: + return CDataVariant(getInt32Value(key)); + break; + case chaos::DataType::TYPE_INT64: + return CDataVariant(getInt64Value(key)); + break; + case chaos::DataType::TYPE_DOUBLE: + return CDataVariant(getDoubleValue(key)); + break; + case chaos::DataType::TYPE_STRING: + return CDataVariant(getStringValue(key)); + break; + case chaos::DataType::TYPE_BYTEARRAY: + return CDataVariant(getBinaryValueAsCDataBuffer(key).release()); + break; + default: + return CDataVariant(); + break; } } @@ -863,41 +863,41 @@ bool CDataWrapper::isVectorValue(const std::string& key) const{ return false; } - chaos::DataType::DataType CDataWrapper::getValueType(const std::string& key) const{ +chaos::DataType::DataType CDataWrapper::getValueType(const std::string& key) const{ chaos::DataType::DataType result = chaos::DataType::TYPE_UNDEFINED; bson_iter_t it; bson_iter_init(&it, ACCESS_BSON(bson)); if(bson_iter_find_case(&it, key.c_str()) == false) return result; switch(bson_iter_type(&it)) { - case BSON_TYPE_ARRAY: - result = chaos::DataType::TYPE_ACCESS_ARRAY; - break; - case BSON_TYPE_DOCUMENT: - result = chaos::DataType::TYPE_CLUSTER; - break; - case BSON_TYPE_BINARY: - result = chaos::DataType::TYPE_BYTEARRAY; - break; - case BSON_TYPE_UTF8: - result = chaos::DataType::TYPE_STRING; - break; - case BSON_TYPE_DOUBLE: - result = chaos::DataType::TYPE_DOUBLE; - break; - case BSON_TYPE_INT32: - result = chaos::DataType::TYPE_INT32; - break; - case BSON_TYPE_INT64: - result = chaos::DataType::TYPE_INT64; - break; - case BSON_TYPE_BOOL: - result = chaos::DataType::TYPE_BOOLEAN; - break; - case BSON_TYPE_NULL: - result = chaos::DataType::TYPE_UNDEFINED; - break; - default: - break; + case BSON_TYPE_ARRAY: + result = chaos::DataType::TYPE_ACCESS_ARRAY; + break; + case BSON_TYPE_DOCUMENT: + result = chaos::DataType::TYPE_CLUSTER; + break; + case BSON_TYPE_BINARY: + result = chaos::DataType::TYPE_BYTEARRAY; + break; + case BSON_TYPE_UTF8: + result = chaos::DataType::TYPE_STRING; + break; + case BSON_TYPE_DOUBLE: + result = chaos::DataType::TYPE_DOUBLE; + break; + case BSON_TYPE_INT32: + result = chaos::DataType::TYPE_INT32; + break; + case BSON_TYPE_INT64: + result = chaos::DataType::TYPE_INT64; + break; + case BSON_TYPE_BOOL: + result = chaos::DataType::TYPE_BOOLEAN; + break; + case BSON_TYPE_NULL: + result = chaos::DataType::TYPE_UNDEFINED; + break; + default: + break; } return result; @@ -933,8 +933,8 @@ int CDataWrapper::setBson(const bson_iter_t *v ,const double& val){ if(ITER_TYPE(v)==BSON_TYPE_DOUBLE){ memcpy((void*)(v->raw + v->d1), (void*)&val,sizeof(double)); return sizeof(double); - } - return -1; + } + return -1; } int CDataWrapper::setBson(const bson_iter_t *v ,const bool& val){ @@ -966,22 +966,25 @@ int CDataWrapper::setBson(const bson_iter_t *v ,const void* val){ #pragma mark CMultiTypeDataArrayWrapper CMultiTypeDataArrayWrapper::CMultiTypeDataArrayWrapper(const ChaosBsonShrdPtr& _document_shrd_ptr, const std::string& key): - document_shrd_ptr(_document_shrd_ptr) { +document_shrd_ptr(_document_shrd_ptr), +array_doc(new bson_t()) { bson_iter_t element_found; bson_iter_init(&element_found, ACCESS_BSON(_document_shrd_ptr)); if(bson_iter_find_case(&element_found, key.c_str())&& - BSON_ITER_HOLDS_ARRAY(&element_found)) { + BSON_ITER_HOLDS_ARRAY(&element_found)) { uint32_t array_len; const uint8_t *array; bson_iter_array(&element_found, &array_len, &array); - if (bson_init_static(&array_doc, array, array_len)) { + if (bson_init_static(array_doc, array, array_len)) { bson_iter_t iter; - if(bson_iter_init(&iter, &array_doc)) { + if(bson_iter_init(&iter, array_doc)) { while(bson_iter_next(&iter)) { - bson_value_t copy; - bson_value_copy(bson_iter_value(&iter), ©); + //ChaosBsonValuesShrdPtr copy = ChaosBsonValuesShrdPtr(new bson_value_t(), &bsonValueDestroy); + //bson_value_t copy; + bson_value_t*copy = new bson_value_t(); + bson_value_copy(bson_iter_value(&iter), copy); values.push_back(copy); } } @@ -990,120 +993,125 @@ CMultiTypeDataArrayWrapper::CMultiTypeDataArrayWrapper(const ChaosBsonShrdPtr& _ } CMultiTypeDataArrayWrapper::~CMultiTypeDataArrayWrapper() { - for(VectorBsonValuesIterator it = values.begin(), - end = values.end(); - it != end; - it++) { - bson_value_destroy(&(*it)); + for(VectorBsonValuesIterator it = values.begin(), + end = values.end(); + it != end; + it++) { + bson_value_destroy(*it); + delete(*it); } + values.clear(); + delete(array_doc); } std::string CMultiTypeDataArrayWrapper::getJSONString() { size_t str_size; - char * str_c = bson_as_canonical_extended_json(static_cast<const bson_t*>(&array_doc),&str_size); + char * str_c = bson_as_canonical_extended_json(static_cast<const bson_t*>(array_doc),&str_size); return std::string(str_c,str_size); } std::string CMultiTypeDataArrayWrapper::getCanonicalJSONString() { size_t str_size; - char * str_c = bson_as_relaxed_extended_json(static_cast<const bson_t*>(&array_doc),&str_size); + char * str_c = bson_as_relaxed_extended_json(static_cast<const bson_t*>(array_doc),&str_size); return std::string(str_c,str_size); } string CMultiTypeDataArrayWrapper::getStringElementAtIndex(const int pos) const{ - // CHAOS_ASSERT(values[pos].value_type == BSON_TYPE_UTF8); - if(values[pos].value_type != BSON_TYPE_UTF8){ + // CHAOS_ASSERT(values[pos]->value_type == BSON_TYPE_UTF8); + if(values[pos]->value_type != BSON_TYPE_UTF8){ std::stringstream ss; - ss<<"type at index ["<<pos<<"] is not String, typeid:"<<values[pos].value_type; + ss<<"type at index ["<<pos<<"] is not String, typeid:"<<values[pos]->value_type; throw CException(1, ss.str(), __PRETTY_FUNCTION__); - } - return std::string(values[pos].value.v_utf8.str, values[pos].value.v_utf8.len); + } + return std::string(values[pos]->value.v_utf8.str, values[pos]->value.v_utf8.len); } double CMultiTypeDataArrayWrapper::getDoubleElementAtIndex(const int pos) const{ - if(values[pos].value_type != BSON_TYPE_DOUBLE){ + if(values[pos]->value_type != BSON_TYPE_DOUBLE){ std::stringstream ss; - ss<<"type at index ["<<pos<<"] is not double, typeid:"<<values[pos].value_type; + ss<<"type at index ["<<pos<<"] is not double, typeid:"<<values[pos]->value_type; throw CException(1, ss.str(), __PRETTY_FUNCTION__); - } - return values[pos].value.v_double; + } + return values[pos]->value.v_double; } + int32_t CMultiTypeDataArrayWrapper::getInt32ElementAtIndex(const int pos) const{ - return values[pos].value.v_int32; + return values[pos]->value.v_int32; } + bool CMultiTypeDataArrayWrapper::getBoolElementAtIndex(const int pos) const{ - return values[pos].value.v_bool; + return values[pos]->value.v_bool; } int64_t CMultiTypeDataArrayWrapper::getInt64ElementAtIndex(const int pos) const{ - //CHAOS_ASSERT(values[pos].value_type == BSON_TYPE_INT64); - if(values[pos].value_type != BSON_TYPE_INT64){ + //CHAOS_ASSERT(values[pos]->value_type == BSON_TYPE_INT64); + if(values[pos]->value_type != BSON_TYPE_INT64){ std::stringstream ss; - ss<<"type at index ["<<pos<<"] is not int64, typeid:"<<values[pos].value_type; + ss<<"type at index ["<<pos<<"] is not int64, typeid:"<<values[pos]->value_type; throw CException(1, ss.str(), __PRETTY_FUNCTION__); - } - return values[pos].value.v_int64; + } + return values[pos]->value.v_int64; } bool CMultiTypeDataArrayWrapper::isStringElementAtIndex(const int pos) const{ - return values[pos].value_type == BSON_TYPE_UTF8; + return values[pos]->value_type == BSON_TYPE_UTF8; } bool CMultiTypeDataArrayWrapper::isDoubleElementAtIndex(const int pos) const{ - return values[pos].value_type == BSON_TYPE_DOUBLE; + return values[pos]->value_type == BSON_TYPE_DOUBLE; } bool CMultiTypeDataArrayWrapper::isInt32ElementAtIndex(const int pos) const{ - return values[pos].value_type == BSON_TYPE_INT32; + return values[pos]->value_type == BSON_TYPE_INT32; } bool CMultiTypeDataArrayWrapper::isBoolElementAtIndex(const int pos) const{ - return values[pos].value_type == BSON_TYPE_BOOL; + return values[pos]->value_type == BSON_TYPE_BOOL; } bool CMultiTypeDataArrayWrapper::isInt64ElementAtIndex(const int pos) const{ - return values[pos].value_type == BSON_TYPE_INT64; + return values[pos]->value_type == BSON_TYPE_INT64; } bool CMultiTypeDataArrayWrapper::isCDataWrapperElementAtIndex(const int pos) const{ - return values[pos].value_type == BSON_TYPE_DOCUMENT; + return values[pos]->value_type == BSON_TYPE_DOCUMENT; } + const char * CMultiTypeDataArrayWrapper::getRawValueAtIndex(const int pos,uint32_t& size) const{ - switch(values[pos].value_type ) { - case BSON_TYPE_INT64: - size=sizeof(int64_t); - return reinterpret_cast<const char*>(&values[pos].value.v_int64); - case BSON_TYPE_INT32: - size=sizeof(int32_t); - - return reinterpret_cast<const char*>(&values[pos].value.v_int32); - case BSON_TYPE_BOOL: - size=sizeof(bool); - - return reinterpret_cast<const char*>(&values[pos].value.v_bool); - case BSON_TYPE_DOUBLE: - size=sizeof(double); - - return reinterpret_cast<const char*>(&values[pos].value.v_double); - case BSON_TYPE_UTF8: - size = values[pos].value.v_utf8.len; - return static_cast<const char*>(values[pos].value.v_utf8.str); - case BSON_TYPE_BINARY: - size = values[pos].value.v_binary.data_len; - return reinterpret_cast<const char*>(values[pos].value.v_binary.data); + switch(values[pos]->value_type ) { + case BSON_TYPE_INT64: + size=sizeof(int64_t); + return reinterpret_cast<const char*>(&values[pos]->value.v_int64); + case BSON_TYPE_INT32: + size=sizeof(int32_t); + return reinterpret_cast<const char*>(&values[pos]->value.v_int32); + case BSON_TYPE_BOOL: + size=sizeof(bool); + return reinterpret_cast<const char*>(&values[pos]->value.v_bool); + case BSON_TYPE_DOUBLE: + size=sizeof(double); + return reinterpret_cast<const char*>(&values[pos]->value.v_double); + case BSON_TYPE_UTF8: + size = values[pos]->value.v_utf8.len; + return static_cast<const char*>(values[pos]->value.v_utf8.str); + case BSON_TYPE_BINARY: + size = values[pos]->value.v_binary.data_len; + return reinterpret_cast<const char*>(values[pos]->value.v_binary.data); + default: + break; } return NULL; } CDataWrapper* CMultiTypeDataArrayWrapper::getCDataWrapperElementAtIndex(const int pos) const{ - // CHAOS_ASSERT(values[pos].value_type == BSON_TYPE_DOCUMENT); - if(values[pos].value_type != BSON_TYPE_DOCUMENT){ + // CHAOS_ASSERT(values[pos]->value_type == BSON_TYPE_DOCUMENT); + if(values[pos]->value_type != BSON_TYPE_DOCUMENT){ std::stringstream ss; - ss<<"type at index ["<<pos<<"] is not CDataWrapper, typeid:"<<values[pos].value_type; + ss<<"type at index ["<<pos<<"] is not CDataWrapper, typeid:"<<values[pos]->value_type; throw CException(1, ss.str(), __PRETTY_FUNCTION__); - } - return new CDataWrapper((const char *)values[pos].value.v_doc.data, values[pos].value.v_doc.data_len); + } + return new CDataWrapper((const char *)values[pos]->value.v_doc.data, values[pos]->value.v_doc.data_len); } size_t CMultiTypeDataArrayWrapper::size() const{ diff --git a/chaos/common/data/CDataWrapper.h b/chaos/common/data/CDataWrapper.h index b7c0866f5..de1280a87 100644 --- a/chaos/common/data/CDataWrapper.h +++ b/chaos/common/data/CDataWrapper.h @@ -44,7 +44,7 @@ namespace chaos { class CMultiTypeDataArrayWrapper; typedef ChaosUniquePtr<CMultiTypeDataArrayWrapper> CMultiTypeDataArrayWrapperUPtr; typedef ChaosSharedPtr<CMultiTypeDataArrayWrapper> CMultiTypeDataArrayWrapperSPtr; - + /*! Class for contain the serialization buffer the class deallocation will dealloc all the @@ -70,7 +70,11 @@ namespace chaos { size_t getBufferLen(){return bSize;}; const char *getBufferPtr(){return buffer;}; }; + typedef ChaosUniquePtr<SerializationBuffer> SerializationBufferUPtr; typedef ChaosSharedPtr<struct _bson_t> ChaosBsonShrdPtr; + typedef ChaosSharedPtr<struct _bson_value_t> ChaosBsonValuesShrdPtr; + + /*! Class that wrap the serializaiton system for data storage */ @@ -165,12 +169,12 @@ namespace chaos { bool getBoolValue(const std::string&) const; //get a json value std::string getJsonValue(const std::string&) const; - + #define THROW_TYPE_EXC(type)\ std::stringstream ss;\ ss<<"cannot get or cast to '" << #type;\ throw chaos::CException(-2, ss.str(), __PRETTY_FUNCTION__); - + template<typename T> int setValue(const std::string& key,const T& val){ bson_iter_t it; @@ -252,7 +256,7 @@ throw chaos::CException(-2, ss.str(), __PRETTY_FUNCTION__); int bufLen); ChaosUniquePtr<CDataBuffer> getBinaryValueAsCDataBuffer(const std::string &key) const; //return the bson data - SerializationBuffer* getBSONData() const; + SerializationBufferUPtr getBSONData() const; const char* getBSONRawData(int& size) const; const char* getBSONRawData() const; const int getBSONRawSize() const; @@ -307,14 +311,14 @@ throw chaos::CException(-2, ss.str(), __PRETTY_FUNCTION__); chaos::DataType::DataType getValueType(const std::string& key) const; bool isEmpty() const; }; - CHAOS_DEFINE_VECTOR_FOR_TYPE(bson_value_t, VectorBsonValues); + CHAOS_DEFINE_VECTOR_FOR_TYPE(bson_value_t*, VectorBsonValues); /*! Class to read the and arry of multivalue */ class CMultiTypeDataArrayWrapper { friend class CDataWrapper; const ChaosBsonShrdPtr document_shrd_ptr; - bson_t array_doc; + bson_t *array_doc; VectorBsonValues values; CMultiTypeDataArrayWrapper(const ChaosBsonShrdPtr& _document_shrd_ptr, const std::string& key); @@ -325,7 +329,7 @@ throw chaos::CException(-2, ss.str(), __PRETTY_FUNCTION__); int32_t getInt32ElementAtIndex(const int) const; int64_t getInt64ElementAtIndex(const int) const; bool getBoolElementAtIndex(const int) const; - + CDataWrapper* getCDataWrapperElementAtIndex(const int) const; std::string getJSONString(); std::string getCanonicalJSONString(); @@ -334,31 +338,31 @@ throw chaos::CException(-2, ss.str(), __PRETTY_FUNCTION__); bool isInt32ElementAtIndex(const int) const; bool isInt64ElementAtIndex(const int) const; bool isBoolElementAtIndex(const int) const; - + bool isCDataWrapperElementAtIndex(const int) const; template<class T> T getElementAtIndex(const int pos) const{ - if(values[pos].value_type == BSON_TYPE_DOUBLE){ - return static_cast<T>(values[pos].value.v_double); + if(values[pos]->value_type == BSON_TYPE_DOUBLE){ + return static_cast<T>(values[pos]->value.v_double); } - if(values[pos].value_type == BSON_TYPE_INT32){ - return static_cast<T>(values[pos].value.v_int32); + if(values[pos]->value_type == BSON_TYPE_INT32){ + return static_cast<T>(values[pos]->value.v_int32); } - if(values[pos].value_type == BSON_TYPE_INT64){ - return static_cast<T>(values[pos].value.v_int64); + if(values[pos]->value_type == BSON_TYPE_INT64){ + return static_cast<T>(values[pos]->value.v_int64); } - if(values[pos].value_type == BSON_TYPE_BOOL){ - return static_cast<T>(values[pos].value.v_bool); + if(values[pos]->value_type == BSON_TYPE_BOOL){ + return static_cast<T>(values[pos]->value.v_bool); } std::stringstream ss; - ss<<"type at index ["<<pos<<"] cannot convert, typeid:"<<values[pos].value_type; + ss<<"type at index ["<<pos<<"] cannot convert, typeid:"<<values[pos]->value_type; throw CException(1, ss.str(), __PRETTY_FUNCTION__); return 0; } const char * getRawValueAtIndex(const int key,uint32_t& size) const; size_t size() const; }; - + #define CDW_GET_SRT_WITH_DEFAULT(c, k, d) ((c)->hasKey(k)?(c)->getStringValue(k):d) #define CDW_GET_BOOL_WITH_DEFAULT(c, k, d) ((c)->hasKey(k)?(c)->getBoolValue(k):d) #define CDW_GET_INT32_WITH_DEFAULT(c, k, d) ((c)->hasKey(k)?(c)->getInt32Value(k):d) @@ -366,11 +370,11 @@ throw chaos::CException(-2, ss.str(), __PRETTY_FUNCTION__); #define CDW_GET_DOUBLE_WITH_DEFAULT(c, k, d) ((c)->hasKey(k)?(c)->getDoubleValue(k):d) #define CDW_CHECK_AND_SET(chk, cdw, t, k, v) if(chk){cdw->t(k,v);} #define CDW_GET_VALUE_WITH_DEFAULT(c, k, t, d) ((c)->hasKey(k)?(c)->t(k):d) - + typedef ChaosUniquePtr<chaos::common::data::CDataWrapper> CDWUniquePtr; typedef ChaosSharedPtr<chaos::common::data::CDataWrapper> CDWShrdPtr; CHAOS_DEFINE_VECTOR_FOR_TYPE(CDWShrdPtr, VectorCDWShrdPtr); - + typedef std::pair<std::string, CDWShrdPtr> PairStrCDWShrdPtr; CHAOS_DEFINE_VECTOR_FOR_TYPE(PairStrCDWShrdPtr, VectorStrCDWShrdPtr); } diff --git a/chaos/common/data/structured/Dataset.cpp b/chaos/common/data/structured/Dataset.cpp index 3c3439d26..da1f4c980 100644 --- a/chaos/common/data/structured/Dataset.cpp +++ b/chaos/common/data/structured/Dataset.cpp @@ -122,4 +122,20 @@ void Dataset::setDatasetKey(const std::string& ds_key) { const std::string& Dataset::getDatasetKey() const { return dataset_key; } +#pragma mark DatasetBurst +DatasetBurst::DatasetBurst(): +tag(), +value(), +type(chaos::ControlUnitNodeDefinitionType::DSStorageBurstTypeUndefined){} + +DatasetBurst::DatasetBurst(const DatasetBurst& copy_src): +tag(copy_src.tag), +value(copy_src.value), +type(copy_src.type){} +DatasetBurst& DatasetBurst::operator=(DatasetBurst const &rhs) { + tag = rhs.tag; + value = rhs.value; + type = rhs.type; + return *this; +} diff --git a/chaos/common/data/structured/Dataset.h b/chaos/common/data/structured/Dataset.h index fb9920f2d..9c3e81c3d 100644 --- a/chaos/common/data/structured/Dataset.h +++ b/chaos/common/data/structured/Dataset.h @@ -25,6 +25,7 @@ #include <chaos/common/chaos_constants.h> #include <chaos/common/chaos_types.h> +#include <chaos/common/data/CDataVariant.h> #include <chaos/common/data/TemplatedDataSDWrapper.h> #include <chaos/common/data/structured/DatasetAttribute.h> @@ -185,6 +186,38 @@ namespace chaos { return result; } CHAOS_CLOSE_SDWRAPPER() + + //!define the information for store dataset in burst mode + typedef struct DatasetBurst { + //!is the tag associated to the burst + std::string tag; + //!is the valued asscoiated to the burst type + chaos::common::data::CDataVariant value; + //!is the type the specified the burst function + chaos::ControlUnitNodeDefinitionType::DSStorageBurstType type; + + DatasetBurst(); + DatasetBurst(const DatasetBurst& copy_src); + DatasetBurst& operator=(DatasetBurst const &rhs); + } DatasetBurst; + + typedef ChaosSharedPtr<DatasetBurst> DatasetBurstShrdPtr; + + CHAOS_OPEN_SDWRAPPER(DatasetBurst) + void deserialize(chaos::common::data::CDataWrapper *serialized_data) { + Subclass::dataWrapped().tag = CDW_GET_SRT_WITH_DEFAULT(serialized_data, ControlUnitNodeDefinitionKey::CONTROL_UNIT_DATASET_HISTORY_BURST_TAG, ""); + Subclass::dataWrapped().type = static_cast<chaos::ControlUnitNodeDefinitionType::DSStorageBurstType>(CDW_GET_INT32_WITH_DEFAULT(serialized_data, ControlUnitNodeDefinitionKey::CONTROL_UNIT_DATASET_HISTORY_BURST_TYPE, chaos::ControlUnitNodeDefinitionType::DSStorageBurstTypeUndefined)); + Subclass::dataWrapped().value = CDW_GET_VALUE_WITH_DEFAULT(serialized_data, ControlUnitNodeDefinitionKey::CONTROL_UNIT_DATASET_HISTORY_BURST_VALUE, getVariantValue, CDataVariant()); + } + + CDWUniquePtr serialize() { + CDWUniquePtr result(new CDataWrapper()); + result->addStringValue(ControlUnitNodeDefinitionKey::CONTROL_UNIT_DATASET_HISTORY_BURST_TAG, Subclass::dataWrapped().tag); + result->addInt32Value(ControlUnitNodeDefinitionKey::CONTROL_UNIT_DATASET_HISTORY_BURST_TYPE, Subclass::dataWrapped().type); + result->addVariantValue(ControlUnitNodeDefinitionKey::CONTROL_UNIT_DATASET_HISTORY_BURST_VALUE, Subclass::dataWrapped().value); + return result; + } + CHAOS_CLOSE_SDWRAPPER() } } } diff --git a/chaos/common/direct_io/DirectIODispatcher.cpp b/chaos/common/direct_io/DirectIODispatcher.cpp index 893f3cd1c..5b5711c76 100644 --- a/chaos/common/direct_io/DirectIODispatcher.cpp +++ b/chaos/common/direct_io/DirectIODispatcher.cpp @@ -85,7 +85,6 @@ void DirectIODispatcher::stop() throw(chaos::CException) { // Deinit the implementation void DirectIODispatcher::deinit() throw(chaos::CException) { - if(endpoint_slot_array) { DIOD_LDBG_ << "Deallocating all endpoint slot"; //allocate all endpoint slot @@ -102,6 +101,8 @@ void DirectIODispatcher::deinit() throw(chaos::CException) { free(endpoint_slot_array); endpoint_slot_array=NULL; } + unsigned int tmp; + while(!available_endpoint_slot.empty()){available_endpoint_slot.pop(tmp);} } //allocate new endpoint diff --git a/chaos/common/direct_io/channel/DirectIODeviceChannelGlobal.h b/chaos/common/direct_io/channel/DirectIODeviceChannelGlobal.h index dc5c2d3e2..14e6849ae 100644 --- a/chaos/common/direct_io/channel/DirectIODeviceChannelGlobal.h +++ b/chaos/common/direct_io/channel/DirectIODeviceChannelGlobal.h @@ -61,6 +61,8 @@ namespace chaos { Parameter for the query used in CDataWrapper structure */ namespace DeviceChannelOpcodeQueryDataCloudParam { + //!is the timestamp for wich we want to search our key + static const char * const QUERY_PARAM_META_TAGS = "qp_data_cloud_meta_tags"; //!is the timestamp for wich we want to search our key static const char * const QUERY_PARAM_STAR_TS_I64 = "qp_data_cloud_start_ts"; //!is the timestamp that close the time offset of the search [packet that are <= are included into the result] @@ -90,12 +92,14 @@ namespace chaos { //! Header for the DeviceChannelOpcodePutOutput[WithCache] opcodes typedef struct DirectIODeviceChannelHeaderPutOpcode { - //! The 8 bit tag field + //! The tag associated to the uint8_t tag; - //! The 8 bit key length field + //! The lenght of the key uint8_t key_len; - //the pointer to key data - void* key_data; + //! Thenumber of tags for this dataset, every tag is terminated by '\0' + uint16_t tag_num; + //the pointer to hedaer payload + void* data; } DirectIODeviceChannelHeaderData, *DirectIODeviceChannelHeaderDataPtr; diff --git a/chaos/common/direct_io/channel/DirectIODeviceClientChannel.cpp b/chaos/common/direct_io/channel/DirectIODeviceClientChannel.cpp index ea0ab9070..3b7e38074 100644 --- a/chaos/common/direct_io/channel/DirectIODeviceClientChannel.cpp +++ b/chaos/common/direct_io/channel/DirectIODeviceClientChannel.cpp @@ -61,24 +61,38 @@ int DirectIODeviceClientChannel::storeAndCacheDataOutputChannel(const std::strin void *buffer, uint32_t buffer_len, DataServiceNodeDefinitionType::DSStorageType _put_mode, + const ChaosStringSet& tag_set, bool wait_result) { int err = 0; if(key.size() > 250) return -1; + + DataBuffer data_buffer; DirectIODataPackSPtr answer; + + //write mode and tags number + data_buffer.writeInt8((int8_t) _put_mode); + data_buffer.writeInt16(tag_set.size()); + //write key + data_buffer.writeByte(key.c_str(), (int32_t)key.size()); + data_buffer.writeByte('\0'); + //write tags + for(ChaosStringSetConstIterator it = tag_set.begin(), + end = tag_set.end(); + it!=end; + it++) { + data_buffer.writeByte(it->c_str(), (int32_t)it->size()); + data_buffer.writeByte('\0'); + } + DirectIODataPackSPtr data_pack = ChaosMakeSharedPtr<DirectIODataPack>(); - BufferSPtr put_opcode_header = ChaosMakeSharedPtr<Buffer>(sizeof(DirectIODeviceChannelHeaderPutOpcode)+key.size()); + BufferSPtr put_opcode_header = data_buffer.detachBuffer(); BufferSPtr channel_data = ChaosMakeSharedPtr<Buffer>(buffer, buffer_len, buffer_len, true); - put_opcode_header->data<DirectIODeviceChannelHeaderPutOpcode>()->tag = (uint8_t) _put_mode; - put_opcode_header->data<DirectIODeviceChannelHeaderPutOpcode>()->key_len = key.size(); - //put_opcode_header->key_data - std::memcpy(GET_PUT_OPCODE_KEY_PTR(put_opcode_header->data<DirectIODeviceChannelHeaderPutOpcode>()), key.c_str(), put_opcode_header->data<DirectIODeviceChannelHeaderPutOpcode>()->key_len); - //set opcode data_pack->header.dispatcher_header.fields.channel_opcode = static_cast<uint8_t>(opcode::DeviceChannelOpcodePutOutput); //set the header - DIRECT_IO_SET_CHANNEL_HEADER(data_pack, put_opcode_header, (uint32_t)PUT_HEADER_LEN(key)) + DIRECT_IO_SET_CHANNEL_HEADER(data_pack, put_opcode_header, (uint32_t)put_opcode_header->size()) //set data if the have some if(buffer_len){DIRECT_IO_SET_CHANNEL_DATA(data_pack, channel_data, (uint32_t)channel_data->size());} if(wait_result) { @@ -96,24 +110,37 @@ int DirectIODeviceClientChannel::storeAndCacheHealthData(const std::string& key, void *buffer, uint32_t buffer_len, DataServiceNodeDefinitionType::DSStorageType _put_mode, + const ChaosStringSet& tag_set, bool wait_result) { int err = 0; if(key.size() > 250) return -1; + DataBuffer data_buffer; DirectIODataPackSPtr answer; + + //write mode and tags number + data_buffer.writeInt8((int8_t) _put_mode); + data_buffer.writeInt16(tag_set.size()); + //write key + data_buffer.writeByte(key.c_str(), (int32_t)key.size()); + data_buffer.writeByte('\0'); + //write tags + for(ChaosStringSetConstIterator it = tag_set.begin(), + end = tag_set.end(); + it!=end; + it++) { + data_buffer.writeByte(it->c_str(), (int32_t)it->size()); + data_buffer.writeByte('\0'); + } + DirectIODataPackSPtr data_pack = ChaosMakeSharedPtr<DirectIODataPack>(); - BufferSPtr put_opcode_header = ChaosMakeSharedPtr<Buffer>((PUT_HEADER_LEN(key)+key.size())); + BufferSPtr put_opcode_header = data_buffer.detachBuffer(); BufferSPtr channel_data = ChaosMakeSharedPtr<Buffer>(buffer, buffer_len, buffer_len, true); - put_opcode_header->data<DirectIODeviceChannelHeaderPutOpcode>()->tag = (uint8_t) _put_mode; - put_opcode_header->data<DirectIODeviceChannelHeaderPutOpcode>()->key_len = key.size(); - //put_opcode_header->key_data - std::memcpy(GET_PUT_OPCODE_KEY_PTR(put_opcode_header->data()), key.c_str(), put_opcode_header->data<DirectIODeviceChannelHeaderPutOpcode>()->key_len); - //set opcode data_pack->header.dispatcher_header.fields.channel_opcode = static_cast<uint8_t>(opcode::DeviceChannelOpcodePutHeathData); //set the header - DIRECT_IO_SET_CHANNEL_HEADER(data_pack, put_opcode_header, (uint32_t)PUT_HEADER_LEN(key)) + DIRECT_IO_SET_CHANNEL_HEADER(data_pack, put_opcode_header, (uint32_t)put_opcode_header->size()) //set data if the have some if(buffer_len){DIRECT_IO_SET_CHANNEL_DATA(data_pack, channel_data, (uint32_t)channel_data->size());} if(wait_result) { @@ -218,9 +245,10 @@ int DirectIODeviceClientChannel::requestLastOutputData(const ChaosStringVector& } int DirectIODeviceClientChannel::queryDataCloud(const std::string& key, - uint64_t start_ts, - uint64_t end_ts, - uint32_t page_dimension, + const ChaosStringSet& meta_tags, + const uint64_t start_ts, + const uint64_t end_ts, + const uint32_t page_dimension, SearchSequence& last_sequence_id, QueryResultPage& found_element_page) { int err = 0; @@ -236,7 +264,13 @@ int DirectIODeviceClientChannel::queryDataCloud(const std::string& key, query_description.addInt64Value(DeviceChannelOpcodeQueryDataCloudParam::QUERY_PARAM_END_TS_I64, (int64_t)end_ts); query_description.addInt64Value(DeviceChannelOpcodeQueryDataCloudParam::QUERY_PARAM_SEARCH_LAST_RUN_ID, last_sequence_id.run_id); query_description.addInt64Value(DeviceChannelOpcodeQueryDataCloudParam::QUERY_PARAM_SEARCH_LAST_DP_COUNTER, last_sequence_id.datapack_counter); - + for(ChaosStringSetConstIterator it = meta_tags.begin(), + end = meta_tags.end(); + it != end; + it++) { + query_description.appendStringToArray(*it); + } + query_description.finalizeArrayForKey(DeviceChannelOpcodeQueryDataCloudParam::QUERY_PARAM_META_TAGS); //copy the query id on header query_data_cloud_header->data<DirectIODeviceChannelHeaderOpcodeQueryDataCloud>()->field.record_for_page = TO_LITTEL_ENDNS_NUM(uint32_t, page_dimension); //set opcode diff --git a/chaos/common/direct_io/channel/DirectIODeviceClientChannel.h b/chaos/common/direct_io/channel/DirectIODeviceClientChannel.h index 8da06640a..46d77c644 100644 --- a/chaos/common/direct_io/channel/DirectIODeviceClientChannel.h +++ b/chaos/common/direct_io/channel/DirectIODeviceClientChannel.h @@ -56,6 +56,7 @@ namespace chaos { void *buffer, uint32_t buffer_len, DataServiceNodeDefinitionType::DSStorageType _put_mode, + const ChaosStringSet& tag_set = ChaosStringSet(), bool wait_result = true); //! Send device serialization with priority @@ -63,6 +64,7 @@ namespace chaos { void *buffer, uint32_t buffer_len, DataServiceNodeDefinitionType::DSStorageType _put_mode, + const ChaosStringSet& tag_set = ChaosStringSet(), bool wait_result = true); //! Send a request for the last output data @@ -85,9 +87,10 @@ namespace chaos { \return error */ int queryDataCloud(const std::string& key, - uint64_t start_ts, - uint64_t end_ts, - uint32_t page_dimension, + const ChaosStringSet& meta_tags, + const uint64_t start_ts, + const uint64_t end_ts, + const uint32_t page_dimension, opcode_headers::SearchSequence& last_sequence, opcode_headers::QueryResultPage& found_element_page); diff --git a/chaos/common/direct_io/channel/DirectIODeviceServerChannel.cpp b/chaos/common/direct_io/channel/DirectIODeviceServerChannel.cpp index 6509fec0e..fa3712abe 100644 --- a/chaos/common/direct_io/channel/DirectIODeviceServerChannel.cpp +++ b/chaos/common/direct_io/channel/DirectIODeviceServerChannel.cpp @@ -48,22 +48,54 @@ int DirectIODeviceServerChannel::consumeDataPack(chaos::common::direct_io::Direc opcode::DeviceChannelOpcode channel_opcode = static_cast<opcode::DeviceChannelOpcode>(data_pack->header.dispatcher_header.fields.channel_opcode); switch (channel_opcode) { case opcode::DeviceChannelOpcodePutOutput: { - DirectIODeviceChannelHeaderPutOpcode *header = data_pack->channel_header_data->data<DirectIODeviceChannelHeaderPutOpcode>(); - //reallign the pointer to the start of the key - header->tag = FROM_LITTLE_ENDNS_NUM(uint32_t, header->tag); - err = handler->consumePutEvent(*header, - data_pack->channel_data, - data_pack->header.channel_data_size); + DataBuffer data_buffer(data_pack->channel_header_data->data(), + (uint32_t)data_pack->channel_header_data->size(), + false); + //write mode and tags number + int8_t hst_tag; + std::string key; + int16_t meta_tag_num; + ChaosStringSetSPtr meta_tag_set = ChaosMakeSharedPtr<ChaosStringSet>(); + + hst_tag = data_buffer.readInt8(); + meta_tag_num = data_buffer.readInt16(); + //write key + key = data_buffer.readStringUntilNull(); + //write tags + while(meta_tag_num--){ + meta_tag_set->insert(data_buffer.readStringUntilNull()); + } + + err = handler->consumePutEvent(key, + hst_tag, + ChaosMoveOperator(meta_tag_set), + data_pack->channel_data); break; } case opcode::DeviceChannelOpcodePutHeathData: { - DirectIODeviceChannelHeaderPutOpcode *header = data_pack->channel_header_data->data<DirectIODeviceChannelHeaderPutOpcode>(); //reallign the pointer to the start of the key - header->tag = FROM_LITTLE_ENDNS_NUM(uint32_t, header->tag); - err = handler->consumeHealthDataEvent(*header, - data_pack->channel_data, - data_pack->header.channel_data_size); + DataBuffer data_buffer(data_pack->channel_header_data->data(), + (uint32_t)data_pack->channel_header_data->size(), + false); + //write mode and tags number + int8_t hst_tag; + std::string key; + int16_t meta_tag_num; + ChaosStringSetSPtr meta_tag_set = ChaosMakeSharedPtr<ChaosStringSet>(); + + hst_tag = data_buffer.readInt8(); + meta_tag_num = data_buffer.readInt16(); + //write key + key = data_buffer.readStringUntilNull(); + //write tags + while(meta_tag_num--){ + meta_tag_set->insert(data_buffer.readStringUntilNull()); + } + err = handler->consumeHealthDataEvent(key, + hst_tag, + ChaosMoveOperator(meta_tag_set), + data_pack->channel_data); break; } @@ -126,8 +158,9 @@ int DirectIODeviceServerChannel::consumeDataPack(chaos::common::direct_io::Direc if (data_pack && data_pack->channel_data) { BufferSPtr result_data; + ChaosStringSet meta_tags; QueryResultPage result_page; - chaos_data::CDataWrapper query(data_pack->channel_data->data()); + CDWUniquePtr query(new CDataWrapper(data_pack->channel_data->data())); BufferSPtr result_header = ChaosMakeSharedPtr<Buffer>(sizeof(DirectIODeviceChannelHeaderOpcodeQueryDataCloudResult)); DirectIODeviceChannelHeaderOpcodeQueryDataCloudResult *result_header_t = result_header->data<DirectIODeviceChannelHeaderOpcodeQueryDataCloudResult>(); @@ -135,19 +168,29 @@ int DirectIODeviceServerChannel::consumeDataPack(chaos::common::direct_io::Direc header->field.record_for_page = FROM_LITTLE_ENDNS_NUM(uint32_t, header->field.record_for_page); //decode the endianes off the data - std::string key = CDW_GET_SRT_WITH_DEFAULT(&query, DeviceChannelOpcodeQueryDataCloudParam::QUERY_PARAM_SEARCH_KEY_STRING, ""); - uint64_t start_ts = CDW_GET_VALUE_WITH_DEFAULT(&query, DeviceChannelOpcodeQueryDataCloudParam::QUERY_PARAM_STAR_TS_I64, getUInt64Value, 0); - uint64_t end_ts = CDW_GET_VALUE_WITH_DEFAULT(&query, DeviceChannelOpcodeQueryDataCloudParam::QUERY_PARAM_END_TS_I64, getUInt64Value, 0); - SearchSequence last_sequence_info = {CDW_GET_VALUE_WITH_DEFAULT(&query, DeviceChannelOpcodeQueryDataCloudParam::QUERY_PARAM_SEARCH_LAST_RUN_ID, getInt64Value, 0), - CDW_GET_VALUE_WITH_DEFAULT(&query, DeviceChannelOpcodeQueryDataCloudParam::QUERY_PARAM_SEARCH_LAST_DP_COUNTER, getInt64Value, 0)}; + std::string key = CDW_GET_SRT_WITH_DEFAULT(query, DeviceChannelOpcodeQueryDataCloudParam::QUERY_PARAM_SEARCH_KEY_STRING, ""); + uint64_t start_ts = CDW_GET_VALUE_WITH_DEFAULT(query, DeviceChannelOpcodeQueryDataCloudParam::QUERY_PARAM_STAR_TS_I64, getUInt64Value, 0); + uint64_t end_ts = CDW_GET_VALUE_WITH_DEFAULT(query, DeviceChannelOpcodeQueryDataCloudParam::QUERY_PARAM_END_TS_I64, getUInt64Value, 0); + SearchSequence last_sequence_info = {CDW_GET_VALUE_WITH_DEFAULT(query, DeviceChannelOpcodeQueryDataCloudParam::QUERY_PARAM_SEARCH_LAST_RUN_ID, getInt64Value, 0), + CDW_GET_VALUE_WITH_DEFAULT(query, DeviceChannelOpcodeQueryDataCloudParam::QUERY_PARAM_SEARCH_LAST_DP_COUNTER, getInt64Value, 0)}; + if(query->hasKey(DeviceChannelOpcodeQueryDataCloudParam::QUERY_PARAM_META_TAGS) && + query->isVectorValue(DeviceChannelOpcodeQueryDataCloudParam::QUERY_PARAM_META_TAGS)) { + CMultiTypeDataArrayWrapperSPtr meta_tags_vec = query->getVectorValue(DeviceChannelOpcodeQueryDataCloudParam::QUERY_PARAM_META_TAGS); + for(int idx = 0; + idx < meta_tags_vec->size(); + idx++) { + meta_tags.insert(meta_tags_vec->getStringElementAtIndex(idx)); + } + } //call server api if we have at least the key if((key.compare("") != 0)) {err = handler->consumeDataCloudQuery(*header, key, + meta_tags, start_ts, end_ts, last_sequence_info,//in-out result_page);} - if(err == 0){ + if(err == 0) { //manage emory for retur data if((result_header_t->numer_of_record_found = (uint32_t)result_page.size())){ result_data = ChaosMakeSharedPtr<Buffer>(); diff --git a/chaos/common/direct_io/channel/DirectIODeviceServerChannel.h b/chaos/common/direct_io/channel/DirectIODeviceServerChannel.h index b167668c5..57dd22616 100644 --- a/chaos/common/direct_io/channel/DirectIODeviceServerChannel.h +++ b/chaos/common/direct_io/channel/DirectIODeviceServerChannel.h @@ -51,9 +51,10 @@ namespace chaos { \param channel_data the data sent by the device \synchronous_answer possible async answer (not used for now) */ - virtual int consumePutEvent(opcode_headers::DirectIODeviceChannelHeaderPutOpcode& header, - data::BufferSPtr channel_data, - uint32_t channel_data_len) + virtual int consumePutEvent(const std::string& key, + const uint8_t hst_tag, + const ChaosStringSetConstSPtr meta_tag_set, + data::BufferSPtr channel_data) {return -1;}; //! Receive the CDataWrapper forwarded by the channel that contains the helath data @@ -62,9 +63,10 @@ namespace chaos { \param header the header of the channel api \param channel_data contains the health data */ - virtual int consumeHealthDataEvent(opcode_headers::DirectIODeviceChannelHeaderPutOpcode& header, - data::BufferSPtr channel_data, - uint32_t channel_data_len) + virtual int consumeHealthDataEvent(const std::string& key, + const uint8_t hst_tag, + const ChaosStringSetConstSPtr meta_tag_set, + data::BufferSPtr channel_data) {return -1;}; //! Receive the key of the live data channel to read @@ -73,8 +75,8 @@ namespace chaos { in synchronous way the ansert to the client \param key_data the data of the key \param key_len the size of the key data - \param result_header - \param result_value + \param result_header the ehader that specify information of the result + \param result_value the values of the result */ virtual int consumeGetEvent(chaos::common::data::BufferSPtr key_data, uint32_t key_len, @@ -87,11 +89,11 @@ namespace chaos { Receive the keys set to fetch from the live cache and fill the synchronous_answer to return in synchronous way the result of the answre \param header header containing the information where send the answer - \param key_data the data of the key - \param key_len the size of the key data + \param keys the set of key to retrieve \param result_header - \param result_value is the merory that contains the bson document answer for each key in sequence, - \param result_value_size is the size of memory allocated into result_value pointer + \param result_header is the merory that contains the bson document answer for each key in sequence, + \param result_value is the size of memory allocated into result_value pointer + \param result_value if a key is not found in live an empy bson document is add. */ virtual int consumeGetEvent(opcode_headers::DirectIODeviceChannelHeaderMultiGetOpcode& header, @@ -104,17 +106,17 @@ namespace chaos { //! Execute a paged query into a time intervall /*! Execute a paged query in sinchronous way - \param header of the request containing the naswer information + \param query_header of the request containing the naswer information \param search_key the key that we need to query \param search_start_ts the start of the time that delimit the lower time stamp of result \param search_end_ts the end of the time stamp that delimit the upper time stamp of result - \param last_sequence_id is an in-out parameter, at in it specific the last found element, in output it need to be filled with the sequence information of the last item found \param */ virtual int consumeDataCloudQuery(opcode_headers::DirectIODeviceChannelHeaderOpcodeQueryDataCloud& query_header, const std::string& search_key, - uint64_t search_start_ts, - uint64_t search_end_ts, + const ChaosStringSet& meta_tags, + const uint64_t search_start_ts, + const uint64_t search_end_ts, opcode_headers::SearchSequence& last_element_found_seq, opcode_headers::QueryResultPage& result_page) {return -1;}; diff --git a/chaos/common/direct_io/impl/ZMQDirectIOClient.cpp b/chaos/common/direct_io/impl/ZMQDirectIOClient.cpp index 0cf7f0f58..5b5feff3b 100644 --- a/chaos/common/direct_io/impl/ZMQDirectIOClient.cpp +++ b/chaos/common/direct_io/impl/ZMQDirectIOClient.cpp @@ -130,10 +130,8 @@ void ZMQDirectIOClient::_releaseConnectionImpl(DirectIOClientConnection *connect DEBUG_CODE(ZMQDIOLDBG_ << "Release the connection for: " << connection_to_release->getServerDescription() <<" ptr:"<<std::hex<<(uint64_t)connection_to_release;) map_connections.deregisterElementKey(conn->getUniqueUUID()); delete(connection_to_release); - } - void ZMQDirectIOClient::freeObject(const DCKeyObjectContainer::TKOCElement& element) { if(!element.element) return; DirectIOClientConnection *connection = element.element; diff --git a/chaos/common/external_unit/http_adapter/HTTPBaseAdapter.h b/chaos/common/external_unit/http_adapter/HTTPBaseAdapter.h index 4900d0385..e93f9884d 100644 --- a/chaos/common/external_unit/http_adapter/HTTPBaseAdapter.h +++ b/chaos/common/external_unit/http_adapter/HTTPBaseAdapter.h @@ -59,7 +59,7 @@ namespace chaos { nc(NULL), uri(), s_type(), - buffer(new chaos::common::data::CDataBuffer(ptr, size, true)){} + buffer(new chaos::common::data::CDataBuffer(ptr, size)){} }; typedef ChaosSharedPtr<ServerWorkRequest> ServerWorkRequestShrdPtr; diff --git a/chaos/common/external_unit/http_adapter/HTTPClientAdapter.cpp b/chaos/common/external_unit/http_adapter/HTTPClientAdapter.cpp index 6ac0bf417..dc239a375 100644 --- a/chaos/common/external_unit/http_adapter/HTTPClientAdapter.cpp +++ b/chaos/common/external_unit/http_adapter/HTTPClientAdapter.cpp @@ -246,8 +246,7 @@ void HTTPClientAdapter::ev_handler(struct mg_connection *conn, } else { //accepted connection ca received data ChaosUniquePtr<CDataBuffer> buffer(new CDataBuffer((const char *)wm->data, - (uint32_t)wm->size, - true)); + (uint32_t)wm->size)); if((err = ci->class_instance->sendDataToEndpoint(*ci->ext_unit_conn, ChaosMoveOperator(buffer)))) { //weh don't have found the sriealizer diff --git a/chaos/common/external_unit/serialization/ExternalBSONExtJsonSerialization.cpp b/chaos/common/external_unit/serialization/ExternalBSONExtJsonSerialization.cpp index e54f0c5f9..d0f132db1 100644 --- a/chaos/common/external_unit/serialization/ExternalBSONExtJsonSerialization.cpp +++ b/chaos/common/external_unit/serialization/ExternalBSONExtJsonSerialization.cpp @@ -33,7 +33,7 @@ ExternalBSONExtJsonSerialization::~ExternalBSONExtJsonSerialization(){} ChaosUniquePtr<CDataBuffer> ExternalBSONExtJsonSerialization::serialize(const CDataWrapper& cdw_in) { const std::string json_result = cdw_in.getJSONString(); - return ChaosUniquePtr<CDataBuffer>(new CDataBuffer(json_result.c_str(), (uint32_t)json_result.size(), true)); + return ChaosUniquePtr<CDataBuffer>(new CDataBuffer(json_result.c_str(), (uint32_t)json_result.size())); } ChaosUniquePtr<CDataWrapper> ExternalBSONExtJsonSerialization::deserialize(const CDataBuffer& cdb_in) { diff --git a/chaos/common/external_unit/serialization/ExternalBSONJsonSerialization.cpp b/chaos/common/external_unit/serialization/ExternalBSONJsonSerialization.cpp index 774535b4d..bf6daa047 100644 --- a/chaos/common/external_unit/serialization/ExternalBSONJsonSerialization.cpp +++ b/chaos/common/external_unit/serialization/ExternalBSONJsonSerialization.cpp @@ -32,7 +32,7 @@ ExternalBSONJsonSerialization::~ExternalBSONJsonSerialization(){} ChaosUniquePtr<CDataBuffer> ExternalBSONJsonSerialization::serialize(const CDataWrapper& cdw_in) { const std::string json_result = cdw_in.getCompliantJSONString(); - return ChaosUniquePtr<CDataBuffer>(new CDataBuffer(json_result.c_str(), (uint32_t)json_result.size(), true)); + return ChaosUniquePtr<CDataBuffer>(new CDataBuffer(json_result.c_str(), (uint32_t)json_result.size())); } ChaosUniquePtr<CDataWrapper> ExternalBSONJsonSerialization::deserialize(const CDataBuffer& cdb_in) { diff --git a/chaos/common/healt_system/HealtManager.cpp b/chaos/common/healt_system/HealtManager.cpp index 78a21ba7a..3c35d5991 100644 --- a/chaos/common/healt_system/HealtManager.cpp +++ b/chaos/common/healt_system/HealtManager.cpp @@ -178,21 +178,21 @@ int HealtManager::sayHello() throw (chaos::CException) { void HealtManager::start() throw (chaos::CException) { AsyncCentralManager::getInstance()->addTimer(this, 0, (HEALT_FIRE_TIMEOUT / HEALT_FIRE_SLOTS)*1000); //say hello to mds -// int32_t retry =HELLO_PHASE_RETRY; -// while(retry--){ -// try{ -// if(sayHello()==0){ -// HM_INFO << "Found ("<<retry<<")"; -// //add timer to publish all node healt very 5 second -// -// return; -// } -// } catch(chaos::CException& ex) { -// DECODE_CHAOS_EXCEPTION(ex); -// } -// HM_INFO << "Retry hello again ("<<retry<<")"; -// } -// throw CException(-4, "Cannot find a valid MDS node" , __PRETTY_FUNCTION__); + // int32_t retry =HELLO_PHASE_RETRY; + // while(retry--){ + // try{ + // if(sayHello()==0){ + // HM_INFO << "Found ("<<retry<<")"; + // //add timer to publish all node healt very 5 second + // + // return; + // } + // } catch(chaos::CException& ex) { + // DECODE_CHAOS_EXCEPTION(ex); + // } + // HM_INFO << "Retry hello again ("<<retry<<")"; + // } + // throw CException(-4, "Cannot find a valid MDS node" , __PRETTY_FUNCTION__); } void HealtManager::stop() throw (chaos::CException) { @@ -201,10 +201,10 @@ void HealtManager::stop() throw (chaos::CException) { } void HealtManager::deinit() throw (chaos::CException) { -// if(mds_message_channel) { -// NetworkBroker::getInstance()->disposeMessageChannel(mds_message_channel); -// mds_message_channel = NULL; -// } + // if(mds_message_channel) { + // NetworkBroker::getInstance()->disposeMessageChannel(mds_message_channel); + // mds_message_channel = NULL; + // } } const ProcInfo& HealtManager::getLastProcInfo() { @@ -410,9 +410,9 @@ void HealtManager::addNodeMetricValue(const std::string& node_uid, }CHAOS_BOOST_LOCK_EXCEPTION_CACTH(lock_exception,) } -CDataWrapper* HealtManager::prepareNodeDataPack(NodeHealtSet& node_health_set, - uint64_t push_timestamp) { - CDataWrapper *node_data_pack = new CDataWrapper(); +CDWShrdPtr HealtManager::prepareNodeDataPack(NodeHealtSet& node_health_set, + uint64_t push_timestamp) { + CDWShrdPtr node_data_pack = ChaosMakeSharedPtr<CDataWrapper>(); int64_t cur_ts_usec = TimingUtil::getTimeStampInMicroseconds(); if(node_data_pack) { //add device unique id @@ -441,7 +441,7 @@ CDataWrapper* HealtManager::prepareNodeDataPack(NodeHealtSet& node_health_set, //scan all metrics BOOST_FOREACH(HealtNodeElementMap::value_type map_metric_element, node_health_set.map_metric) { //add metric to cdata wrapper - map_metric_element.second->addMetricToCD(node_data_pack); + map_metric_element.second->addMetricToCD(node_data_pack.get()); } } return node_data_pack; @@ -480,15 +480,15 @@ void HealtManager::_publish(const ChaosSharedPtr<NodeHealtSet>& heath_set, boost::unique_lock<boost::mutex> wl_io(mutex_publishing); //update infromation abour process updateProcInfo(); - + //send datapack - ChaosUniquePtr<chaos::common::data::CDataWrapper> data_pack(prepareNodeDataPack(*heath_set, - publish_ts)); + CDWShrdPtr data_pack = prepareNodeDataPack(*heath_set, + publish_ts); if(data_pack.get()) { //store data on cache SharedManagedDirecIoDataDriver::getInstance()->getSharedDriver()->storeHealthData(heath_set->node_publish_key, - *data_pack, - DataServiceNodeDefinitionType::DSStorageTypeLiveHistory); + ChaosMoveOperator(data_pack), + DataServiceNodeDefinitionType::DSStorageTypeLiveHistory); } else { HM_ERR << "Error allocating health datapack for node:" << heath_set->node_uid; } diff --git a/chaos/common/healt_system/HealtManager.h b/chaos/common/healt_system/HealtManager.h index a801a649d..c8d9709ef 100644 --- a/chaos/common/healt_system/HealtManager.h +++ b/chaos/common/healt_system/HealtManager.h @@ -42,7 +42,7 @@ namespace chaos { class SendHealthStatAsyncJob: public chaos::common::async_central::AsyncRunnable { - + protected: void run(); public: @@ -50,7 +50,7 @@ namespace chaos { ~SendHealthStatAsyncJob(); }; - //retry for 12h + //retry for 12h #define HELLO_PHASE_RETRY 12*3600 struct ProcInfo { double usr_time; @@ -164,8 +164,8 @@ namespace chaos { //! timer handler for check what slot needs to be fired void timeout(); - chaos::common::data::CDataWrapper* prepareNodeDataPack(NodeHealtSet& node_health_set, - uint64_t push_timestamp); + chaos::common::data::CDWShrdPtr prepareNodeDataPack(NodeHealtSet& node_health_set, + uint64_t push_timestamp); //!protected mehoto to talk with mds to receive the cds server where publish the data int sayHello() throw (chaos::CException); @@ -272,7 +272,7 @@ namespace chaos { //!publish health information for a node /*! \param node_uid the node identification id for which we need to - publish the healt data. + publish the healt data. */ void publishNodeHealt(const std::string& node_uid); }; diff --git a/chaos/common/healt_system/HealtMetric.cpp b/chaos/common/healt_system/HealtMetric.cpp index 5c7d77120..9dd6b0fed 100644 --- a/chaos/common/healt_system/HealtMetric.cpp +++ b/chaos/common/healt_system/HealtMetric.cpp @@ -58,4 +58,4 @@ HealtMetric(_name, value(""){} void StringHealtMetric::addMetricToCD(CDataWrapper& data) { data.addStringValue(name, value); -} \ No newline at end of file +} diff --git a/chaos/common/io/IODataDriver.cpp b/chaos/common/io/IODataDriver.cpp index 8c7c61f12..2d77e01eb 100644 --- a/chaos/common/io/IODataDriver.cpp +++ b/chaos/common/io/IODataDriver.cpp @@ -35,23 +35,6 @@ void IODataDriver::deinit() throw(CException) { } -/*--------------------------------------------------------------------------------- - - ---------------------------------------------------------------------------------*/ -void IODataDriver::storeData(const std::string& key, - CDataWrapper *dataToStore, - DataServiceNodeDefinitionType::DSStorageType storage_type, - bool delete_data_to_store) throw(CException){ - CHAOS_ASSERT(dataToStore) -// boost::mutex::scoped_lock l(iomutex); - - SerializationBuffer* serialization = dataToStore->getBSONData(); - - storeRawData(key, serialization, storage_type); - - if(delete_data_to_store){delete(dataToStore);} -} - int IODataDriver::removeData(const std::string& key, uint64_t start_ts, uint64_t end_ts) throw(CException) { diff --git a/chaos/common/io/IODataDriver.h b/chaos/common/io/IODataDriver.h index d7a2679a0..7fee824b6 100644 --- a/chaos/common/io/IODataDriver.h +++ b/chaos/common/io/IODataDriver.h @@ -69,14 +69,15 @@ namespace chaos{ * This method cache all object passed to driver * \param storage_type one of values as @DataServiceNodeDefinitionType::DSStorageType */ - void storeData(const std::string& key, - chaos_data::CDataWrapper *dataToStore, - DataServiceNodeDefinitionType::DSStorageType storage_type, - bool delete_data_to_store = true) throw(CException); + virtual void storeData(const std::string& key, + chaos_data::CDWShrdPtr dataToStore, + DataServiceNodeDefinitionType::DSStorageType storage_type, + const ChaosStringSet& tag_set = ChaosStringSet()) throw(CException) = 0; virtual void storeHealthData(const std::string& key, - chaos_data::CDataWrapper& dataToStore, - DataServiceNodeDefinitionType::DSStorageType storage_type) throw(CException) = 0; + chaos_data::CDWShrdPtr dataToStore, + DataServiceNodeDefinitionType::DSStorageType storage_type, + const ChaosStringSet& tag_set = ChaosStringSet()) throw(CException) = 0; //!remove data between the time intervall (extreme included) operation is not undoable virtual int removeData(const std::string& key, @@ -97,13 +98,6 @@ namespace chaos{ virtual utility::ArrayPointer<chaos_data::CDataWrapper>* retriveData(const std::string& key) throw(CException); - /*! - * This method store a buffer into live cached - */ - virtual void storeRawData(const std::string& key, - chaos_data::SerializationBuffer *serialization, - DataServiceNodeDefinitionType::DSStorageType storage_type) throw(CException) = 0; - /*! * This method retrive the cached object by CSDawrapperUsed as query key and * return a pointer to the class ArrayPointer of CDataWrapper type @@ -135,12 +129,18 @@ namespace chaos{ //! perform a query since and virtual QueryCursor *performQuery(const std::string& key, - uint64_t start_ts, - uint64_t end_ts,uint32_t page_len=DEFAULT_PAGE_LEN) = 0; - + const uint64_t start_ts, + const uint64_t end_ts, + const ChaosStringSet& meta_tags, + const uint32_t page_len=DEFAULT_PAGE_LEN) = 0; + virtual QueryCursor *performQuery(const std::string& key, - uint64_t start_ts, - uint64_t end_ts,uint64_t sequid,uint64_t runid,uint32_t page=DEFAULT_PAGE_LEN)=0; + const uint64_t start_ts, + const uint64_t end_ts, + const uint64_t sequid, + const uint64_t runid, + const ChaosStringSet& meta_tags, + const uint32_t page=DEFAULT_PAGE_LEN)=0; virtual void releaseQuery(QueryCursor *query) = 0; }; diff --git a/chaos/common/io/IODirectIODriver.cpp b/chaos/common/io/IODirectIODriver.cpp index 8b71cd8df..7b0fe88b6 100644 --- a/chaos/common/io/IODirectIODriver.cpp +++ b/chaos/common/io/IODirectIODriver.cpp @@ -41,6 +41,7 @@ using namespace chaos; using namespace chaos::common::io; +using namespace chaos::common::data; using namespace chaos::common::utility; using namespace std; @@ -136,49 +137,47 @@ void IODirectIODriver::deinit() throw(CException) { IODataDriver::deinit(); } -void IODirectIODriver::storeRawData(const std::string& key, - chaos::common::data::SerializationBuffer *serialization, - DataServiceNodeDefinitionType::DSStorageType storage_type) throw(CException) { - CHAOS_ASSERT(serialization) +void IODirectIODriver::storeData(const std::string& key, + CDWShrdPtr data_to_store, + DataServiceNodeDefinitionType::DSStorageType storage_type, + const ChaosStringSet& tag_set) throw(CException) { int err = 0; + CHAOS_ASSERT(data_to_store) ChaosReadLock rl(mutext_feeder); - //if(next_client->connection->getState() == chaos_direct_io::DirectIOClientConnectionStateType::DirectIOClientConnectionEventConnected) IODirectIODriverClientChannels *next_client = static_cast<IODirectIODriverClientChannels*>(connectionFeeder.getService()); - serialization->disposeOnDelete = !next_client; + SerializationBufferUPtr serialization = data_to_store->getBSONData(); if(next_client) { - //free the packet serialization->disposeOnDelete = false; if((err = (int)next_client->device_client_channel->storeAndCacheDataOutputChannel(key, (void*)serialization->getBufferPtr(), (uint32_t)serialization->getBufferLen(), - storage_type))) { - IODirectIODriver_LERR_ << "Error storing data into data service "<<next_client->connection->getServerDescription()<<" with code:" << err; + storage_type, + tag_set))) { + IODirectIODriver_LERR_ << CHAOS_FORMAT("Error storing data into data service %1% with code %2%",%next_client->connection->getServerDescription()%err); } } else { DEBUG_CODE(IODirectIODriver_DLDBG_ << "No available socket->loose packet, key '"<<key<<"' storage_type:"<<storage_type<<" buffer len:"<<serialization->getBufferLen()); } - delete(serialization); } - void IODirectIODriver::storeHealthData(const std::string& key, - chaos_data::CDataWrapper& dataToStore, - DataServiceNodeDefinitionType::DSStorageType storage_type) throw(CException) { + CDWShrdPtr data_to_store, + DataServiceNodeDefinitionType::DSStorageType storage_type, + const ChaosStringSet& tag_set) throw(CException) { int err = 0; + CHAOS_ASSERT(data_to_store) try{ ChaosReadLock rl(mutext_feeder); IODirectIODriverClientChannels *next_client = static_cast<IODirectIODriverClientChannels*>(connectionFeeder.getService()); - - ChaosUniquePtr<chaos::common::data::SerializationBuffer> serialization(dataToStore.getBSONData()); - - if(next_client && - serialization.get()) { + SerializationBufferUPtr serialization = data_to_store->getBSONData(); + if(next_client) { serialization->disposeOnDelete = false; if((err = (int)next_client->device_client_channel->storeAndCacheHealthData(key, (void*)serialization->getBufferPtr(), (uint32_t)serialization->getBufferLen(), - storage_type))) { - IODirectIODriver_LERR_ << "Error storing health data into data service "<<next_client->connection->getServerDescription()<<" with code:" << err; + storage_type, + tag_set))) { + IODirectIODriver_LERR_ << CHAOS_FORMAT("Error storing data into data service %1% with code %2%",%next_client->connection->getServerDescription()%err); } } else { DEBUG_CODE(IODirectIODriver_DLDBG_ << "No available socket->loose packet, key '"<<key<<"' storage_type:"<<storage_type<<" buffer len:"<<serialization->getBufferLen()); @@ -395,14 +394,16 @@ void IODirectIODriver::handleEvent(chaos_direct_io::DirectIOClientConnection *cl } QueryCursor *IODirectIODriver::performQuery(const std::string& key, - uint64_t start_ts, - uint64_t end_ts, - uint32_t page_len) { + const uint64_t start_ts, + const uint64_t end_ts, + const ChaosStringSet& meta_tags, + const uint32_t page_len) { QueryCursor *q = new QueryCursor(UUIDUtil::generateUUID(), connectionFeeder, key, start_ts, end_ts, + meta_tags, page_len); if(q) { //add query to map @@ -414,11 +415,11 @@ QueryCursor *IODirectIODriver::performQuery(const std::string& key, return q; } QueryCursor *IODirectIODriver::performQuery(const std::string& key, - uint64_t start_ts, - uint64_t end_ts, - uint64_t sequid, - uint64_t runid, - + const uint64_t start_ts, + const uint64_t end_ts, + const uint64_t sequid, + const uint64_t runid, + const ChaosStringSet& meta_tags, uint32_t page_len) { QueryCursor *q = new QueryCursor(UUIDUtil::generateUUID(), connectionFeeder, @@ -427,6 +428,7 @@ QueryCursor *IODirectIODriver::performQuery(const std::string& key, end_ts, sequid, runid, + meta_tags, page_len); if(q) { //add query to map diff --git a/chaos/common/io/IODirectIODriver.h b/chaos/common/io/IODirectIODriver.h index 05316058d..aef452cdc 100644 --- a/chaos/common/io/IODirectIODriver.h +++ b/chaos/common/io/IODirectIODriver.h @@ -126,15 +126,17 @@ namespace chaos{ void deinit() throw(CException); void storeHealthData(const std::string& key, - chaos_data::CDataWrapper & dataToStore, - DataServiceNodeDefinitionType::DSStorageType storage_type) throw(CException); + chaos_data::CDWShrdPtr data_to_store, + DataServiceNodeDefinitionType::DSStorageType storage_type, + const ChaosStringSet& tag_set = ChaosStringSet()) throw(CException); /* * storeRawData */ - void storeRawData(const std::string& key, - chaos_data::SerializationBuffer *serialization, - DataServiceNodeDefinitionType::DSStorageType storage_type) throw(CException); + void storeData(const std::string& key, + chaos_data::CDWShrdPtr data_to_store, + DataServiceNodeDefinitionType::DSStorageType storage_type, + const ChaosStringSet& tag_set = ChaosStringSet()) throw(CException); int removeData(const std::string& key, uint64_t start_ts, @@ -160,11 +162,17 @@ namespace chaos{ QueryCursor *performQuery(const std::string& key, uint64_t start_ts, - uint64_t end_ts,uint32_t page=DEFAULT_PAGE_LEN); - + uint64_t end_ts, + const ChaosStringSet& meta_tags = ChaosStringSet(), + uint32_t page=DEFAULT_PAGE_LEN); + QueryCursor *performQuery(const std::string& key, uint64_t start_ts, - uint64_t end_ts,uint64_t sequid,uint64_t runid,uint32_t page=DEFAULT_PAGE_LEN); + uint64_t end_ts, + uint64_t sequid, + uint64_t runid, + const ChaosStringSet& meta_tags = ChaosStringSet(), + uint32_t page=DEFAULT_PAGE_LEN); void releaseQuery(QueryCursor *query_cursor); }; diff --git a/chaos/common/io/QueryCursor.cpp b/chaos/common/io/QueryCursor.cpp index 8d8877bae..1985ad579 100644 --- a/chaos/common/io/QueryCursor.cpp +++ b/chaos/common/io/QueryCursor.cpp @@ -59,6 +59,7 @@ QueryCursor::QueryCursor(const std::string& _query_id, const std::string& _node_id, uint64_t _start_ts, uint64_t _end_ts, + const ChaosStringSet& _meta_tags, uint32_t default_page_len): query_id(_query_id), connection_feeder(_connection_feeder), @@ -69,7 +70,9 @@ page_len(default_page_len), phase(QueryPhaseNotStarted), start_seq(0), runid_seq(0), +meta_tags(_meta_tags), api_error(0){} + QueryCursor::QueryCursor(const std::string& _query_id, URLServiceFeeder& _connection_feeder, const std::string& _node_id, @@ -77,7 +80,7 @@ QueryCursor::QueryCursor(const std::string& _query_id, uint64_t _end_ts, uint64_t _sequid, uint64_t _runid, - + const ChaosStringSet& _meta_tags, uint32_t default_page_len): query_id(_query_id), connection_feeder(_connection_feeder), @@ -88,6 +91,7 @@ page_len(default_page_len), phase(QueryPhaseNotStarted), start_seq(_sequid), runid_seq(_runid), +meta_tags(_meta_tags), api_error(0){ if(_sequid>0){ phase = QueryPhaseStarted; @@ -153,6 +157,7 @@ int64_t QueryCursor::fetchNewPage() { return 0; } if((api_error = next_client->device_client_channel->queryDataCloud(node_id, + meta_tags, start_ts, end_ts, page_len, diff --git a/chaos/common/io/QueryCursor.h b/chaos/common/io/QueryCursor.h index dda9a871f..60308990e 100644 --- a/chaos/common/io/QueryCursor.h +++ b/chaos/common/io/QueryCursor.h @@ -64,7 +64,7 @@ namespace chaos { uint64_t end_ts; uint64_t start_seq; uint64_t runid_seq; - + const ChaosStringSet meta_tags; //!is the reuslt page dimension uint32_t page_len; QueryPhase phase; @@ -77,6 +77,7 @@ namespace chaos { const std::string& _node_id, uint64_t _start_ts, uint64_t _end_ts, + const ChaosStringSet& _meta_tags, uint32_t page_len=DEFAULT_PAGE_LEN); QueryCursor(const std::string& _query_id, @@ -86,7 +87,7 @@ namespace chaos { uint64_t _end_ts, uint64_t _sequid, uint64_t _runid, - + const ChaosStringSet& _meta_tags, uint32_t page_len=DEFAULT_PAGE_LEN); ~QueryCursor(); diff --git a/chaos/common/message/MDSMessageChannel.cpp b/chaos/common/message/MDSMessageChannel.cpp index b57a0461b..fe994021e 100644 --- a/chaos/common/message/MDSMessageChannel.cpp +++ b/chaos/common/message/MDSMessageChannel.cpp @@ -77,6 +77,21 @@ void MDSMessageChannel::sendHeartBeatForDeviceID(const std::string& identificati hb_message.get()); } +int MDSMessageChannel::sendEchoMessage(CDataWrapper& data, CDWUniquePtr& result) { + int err = 0; + CDWUniquePtr message(new CDataWrapper()); + data.copyAllTo(*message); + ChaosUniquePtr<MultiAddressMessageRequestFuture> request_future = sendRequestWithFuture(NodeDomainAndActionRPC::RPC_DOMAIN, + NodeDomainAndActionRPC::ACTION_ECHO_TEST, + message.release()); + if(request_future->wait()) { + result.reset(request_future->detachResult()); + } else { + result.reset(); + err = request_future->getError(); + } + return err; +} //! Send unit server CU states to MDS int MDSMessageChannel::sendUnitServerCUStates(CDataWrapper& deviceDataset, @@ -295,18 +310,12 @@ int MDSMessageChannel::loadSnapshotNodeDataset(const std::string& snapname, std::string ret=datasetTypeToHuman(val->getUInt32Value(chaos::DataPackCommonKey::DPCK_DATASET_TYPE)); data_set.addCSDataValue(ret,*val); } - } } - - } else { err = -1; } - - } - return err; } int MDSMessageChannel::getFullNodeDescription(const std::string& identification_id, diff --git a/chaos/common/message/MDSMessageChannel.h b/chaos/common/message/MDSMessageChannel.h index dacae95de..eb8f8267b 100644 --- a/chaos/common/message/MDSMessageChannel.h +++ b/chaos/common/message/MDSMessageChannel.h @@ -67,6 +67,9 @@ namespace chaos { */ void sendHeartBeatForDeviceID(const std::string& identification_id); + //!Send echo message to one of mds + int sendEchoMessage(CDataWrapper& data, chaos::common::data::CDWUniquePtr& result); + //! Send Unit server registration to MDS /*! Perform the registration of the unit server diff --git a/chaos/common/rpc/zmq/ZMQClient.cpp b/chaos/common/rpc/zmq/ZMQClient.cpp index 53e7fdcdf..fb297893c 100644 --- a/chaos/common/rpc/zmq/ZMQClient.cpp +++ b/chaos/common/rpc/zmq/ZMQClient.cpp @@ -20,6 +20,7 @@ */ #include <chaos/common/global.h> #include <chaos/common/rpc/zmq/ZMQClient.h> +#include <chaos/common/rpc/zmq/ZmqMemoryManagement.h> #include <chaos/common/chaos_constants.h> #include <chaos/common/configuration/GlobalConfiguration.h> #include <string> @@ -45,7 +46,10 @@ using namespace boost::algorithm; DEFINE_CLASS_FACTORY(ZMQClient, RpcClient); static void my_free (void *data, void *hint) { - free(data); + if(hint) { + MemoryManagement *tmp = static_cast<MemoryManagement*>(hint); + delete(tmp); + } else {free(data);}; } @@ -251,7 +255,7 @@ void ZMQClient::processBufferElement(NetworkForwardInfo *messageInfo, ElementMan ZMQSocketPool::ResourceSlot *socket_info = NULL; messageInfo->message->addBoolValue("syncrhonous_call", RpcClient::syncrhonous_call); - ChaosUniquePtr<chaos::common::data::SerializationBuffer> callSerialization(messageInfo->message->getBSONData()); + CDWShrdPtr message_data = CDWShrdPtr(messageInfo->message.release()); try{ socket_info = getSocketForNFI(messageInfo); if(socket_info == NULL){ @@ -273,9 +277,7 @@ void ZMQClient::processBufferElement(NetworkForwardInfo *messageInfo, ElementMan return; } - //detach buffer from carrier object so we don't need to copy anymore the data - callSerialization->disposeOnDelete = false; - if((err = zmq_msg_init_data(&message, (void*)callSerialization->getBufferPtr(), callSerialization->getBufferLen(), my_free, NULL)) == -1) { + if((err = zmq_msg_init_data(&message, (void*)message_data->getBSONRawData(), message_data->getBSONRawSize(), my_free, new MemoryManagement(message_data))) == -1) { int32_t sent_error = zmq_errno(); std::string error_message =zmq_strerror(sent_error); ZMQC_LERR << "Error allocating zmq messagecode:" << sent_error << " message:" <<error_message; diff --git a/chaos/common/rpc/zmq/ZMQServer.cpp b/chaos/common/rpc/zmq/ZMQServer.cpp index c78a8a204..43eaa2d2a 100644 --- a/chaos/common/rpc/zmq/ZMQServer.cpp +++ b/chaos/common/rpc/zmq/ZMQServer.cpp @@ -21,6 +21,7 @@ #include <chaos/common/global.h> #include <chaos/common/rpc/zmq/ZMQServer.h> +#include <chaos/common/rpc/zmq/ZmqMemoryManagement.h> #include <chaos/common/chaos_constants.h> #include <chaos/common/exception/exception.h> @@ -36,7 +37,10 @@ using namespace boost; using namespace chaos::common::data; static void my_free (void *data, void *hint) { - free (data); + if(hint) { + MemoryManagement *tmp = static_cast<MemoryManagement*>(hint); + delete(tmp); + } else {free(data);}; } DEFINE_CLASS_FACTORY(ZMQServer, RpcServer); @@ -218,7 +222,7 @@ void ZMQServer::worker() { } else { if(zmq_msg_size(&request)>0) { ZMQS_LDBG << "Message Received"; - ChaosUniquePtr<chaos::common::data::CDataWrapper> result_data_pack; + CDWShrdPtr result_data_pack; message_data.reset(new CDataWrapper((const char*)zmq_msg_data(&request))); //dispatch the command if(message_data->hasKey("syncrhonous_call") && @@ -227,10 +231,8 @@ void ZMQServer::worker() { } else { result_data_pack.reset(command_handler->dispatchCommand(message_data.release())); } - //get serailizaiton - ChaosUniquePtr<SerializationBuffer> result(result_data_pack->getBSONData()); //create zmq message - err = zmq_msg_init_data(&response, (void*)result->getBufferPtr(), result->getBufferLen(), my_free, NULL); + err = zmq_msg_init_data(&response, (void*)result_data_pack->getBSONRawData(), result_data_pack->getBSONRawSize(), my_free, new MemoryManagement(ChaosMoveOperator(result_data_pack))); if(err == -1) { //there was an error int32_t sent_error = zmq_errno(); @@ -238,10 +240,6 @@ void ZMQServer::worker() { ZMQS_LERR << "Error initializing the response message with code:" << sent_error << " message:" <<error_message; } else { //no error on create message - //at this time memory is managed by zmq - result->disposeOnDelete = false; - //ChaosUniquePtr<SerializationBuffer> result(result_data_pack->getBSONData()); - //result->disposeOnDelete = false; ZMQS_LDBG << "Send ack"; err = zmq_sendmsg(receiver, &response, ZMQ_NOBLOCK); if(err == -1) { @@ -252,14 +250,13 @@ void ZMQServer::worker() { ZMQS_LDBG << "ACK Sent"; } } - }else { + } else { ZMQS_LDBG << "Empty message received"; } } err = zmq_msg_close(&request); err = zmq_msg_close(&response); - } catch (CException& ex) { DECODE_CHAOS_EXCEPTION(ex) } diff --git a/chaos/ui_toolkit/LowLevelApi/LLDataApi.cpp b/chaos/common/rpc/zmq/ZmqMemoryManagement.h similarity index 61% rename from chaos/ui_toolkit/LowLevelApi/LLDataApi.cpp rename to chaos/common/rpc/zmq/ZmqMemoryManagement.h index 03a154bce..2cd8e70ab 100644 --- a/chaos/ui_toolkit/LowLevelApi/LLDataApi.cpp +++ b/chaos/common/rpc/zmq/ZmqMemoryManagement.h @@ -18,16 +18,19 @@ * See the Licence for the specific language governing * permissions and limitations under the Licence. */ -#include "LLDataApi.h" -#include "../../common/global.h" +#ifndef CHAOSFramework_ZmqMemoryManagement_h +#define CHAOSFramework_ZmqMemoryManagement_h -using namespace chaos; -using namespace chaos::ui; - -LLDataApi::LLDataApi() { +#include <chaos/common/data/CDataWrapper.h> +namespace chaos { + //!keep memory alive untile zmw require to dispose it + struct MemoryManagement { + chaos::common::data::CDWShrdPtr data; + MemoryManagement(chaos::common::data::CDWShrdPtr _data): + data(ChaosMoveOperator(_data)){} + }; } -LLDataApi::~LLDataApi() { -} +#endif /* CHAOSFramework_ZmqMemoryManagement_h */ diff --git a/chaos/common/state_flag/StateFlagCatalog.cpp b/chaos/common/state_flag/StateFlagCatalog.cpp index 4d8258285..dadb72091 100644 --- a/chaos/common/state_flag/StateFlagCatalog.cpp +++ b/chaos/common/state_flag/StateFlagCatalog.cpp @@ -203,11 +203,11 @@ void StateFlagCatalog::getFlagsForSeverity(StateFlagServerity severity, } #pragma mark Serialization Method -ChaosUniquePtr<chaos::common::data::CDataBuffer> StateFlagCatalog::getRawFlagsLevel() { +CDBufferUniquePtr StateFlagCatalog::getRawFlagsLevel() { //read lock on owned catalog LockableObjectReadLock_t rl; catalog_container.getReadLock(rl); - ChaosUniquePtr<CDataBuffer> result; + CDBufferUniquePtr result; char * raw_description = (char*)malloc(catalog_container().size()); if(raw_description) { //retrieve the ordered index @@ -218,16 +218,16 @@ ChaosUniquePtr<chaos::common::data::CDataBuffer> StateFlagCatalog::getRawFlagsLe it++){ raw_description[(*it)->seq_id] = static_cast<char>((*it)->status_flag->getCurrentLevel()); } - result.reset(CDataBuffer::newOwnBufferFromBuffer(raw_description, - (uint32_t)catalog_container().size())); + result = CDataBuffer::newOwnBufferFromBuffer(raw_description, + (uint32_t)catalog_container().size()); } return result; } -void StateFlagCatalog::setApplyRawFlagsValue(ChaosUniquePtr<chaos::common::data::CDataBuffer>& raw_level) { +void StateFlagCatalog::setApplyRawFlagsValue(CDBufferUniquePtr& raw_level) { if(raw_level.get() == NULL) return; const char * buffer = raw_level->getBuffer(); - uint32_t buffer_size = raw_level->getBufferSize(); + uint32_t buffer_size = (uint32_t)raw_level->getBufferSize(); if(buffer_size != catalog_container().size()) return; LockableObjectWriteLock_t wl; diff --git a/chaos/common/state_flag/StateFlagCatalog.h b/chaos/common/state_flag/StateFlagCatalog.h index d4a1885e4..9392093d4 100644 --- a/chaos/common/state_flag/StateFlagCatalog.h +++ b/chaos/common/state_flag/StateFlagCatalog.h @@ -182,10 +182,10 @@ namespace chaos { VectorStateFlag& found_flag); //!get data buffer describing all flag with own level - ChaosUniquePtr<chaos::common::data::CDataBuffer> getRawFlagsLevel(); + chaos::common::data::CDBufferUniquePtr getRawFlagsLevel(); //!set the falg value base on array description - void setApplyRawFlagsValue(ChaosUniquePtr<chaos::common::data::CDataBuffer>& raw_level); + void setApplyRawFlagsValue(chaos::common::data::CDBufferUniquePtr& raw_level); //!return the number of status flag in the catalog const size_t size() const; diff --git a/chaos/common/utility/DataBuffer.h b/chaos/common/utility/DataBuffer.h index 008069144..e561a1bc1 100644 --- a/chaos/common/utility/DataBuffer.h +++ b/chaos/common/utility/DataBuffer.h @@ -34,8 +34,6 @@ namespace chaos { namespace common { namespace utility { -#define CHECK_AND_GROW(m) if(cursor+m>=ChaosBuffer<Allocator>::size) {ChaosBuffer<Allocator>::grow(m);} - //! class DataBuffer { data::Buffer buffer; @@ -76,6 +74,28 @@ namespace chaos { cursor += 1; } + void writeInt8(const int8_t& number) { + buffer.append(&number, sizeof(int8_t)); + cursor+=sizeof(int8_t); + } + + int8_t readInt8() { + int8_t result = *(int8_t*)(buffer.data() + cursor); + cursor+=sizeof(int8_t); + return result; + } + + void writeInt16(const int16_t& number) { + buffer.append(&number, sizeof(int16_t)); + cursor+=sizeof(int16_t); + } + + int16_t readInt16() { + int16_t result = *(int16_t*)(buffer.data() + cursor); + cursor+=sizeof(int16_t); + return result; + } + void writeInt32(const int32_t& number) { buffer.append(&number, sizeof(int32_t)); cursor+=sizeof(int32_t); @@ -124,6 +144,12 @@ namespace chaos { uint32_t getCursorLocation() { return cursor; } + + chaos::common::data::BufferSPtr detachBuffer() { + chaos::common::data::BufferSPtr result = ChaosMakeSharedPtr<chaos::common::data::Buffer>(); + buffer.swap(*result); + return result; + } }; } } diff --git a/chaos/cu_toolkit/control_manager/AbstractControlUnit.cpp b/chaos/cu_toolkit/control_manager/AbstractControlUnit.cpp index 05e44c2f2..c71149b7e 100644 --- a/chaos/cu_toolkit/control_manager/AbstractControlUnit.cpp +++ b/chaos/cu_toolkit/control_manager/AbstractControlUnit.cpp @@ -38,6 +38,7 @@ using namespace boost::uuids; using namespace chaos::common::data; +using namespace chaos::common::data::structured; using namespace chaos::common::alarm; using namespace chaos::common::utility; using namespace chaos::common::property; @@ -191,6 +192,10 @@ void AbstractControlUnit::_initPropertyGroup() { pg_abstract_cu.addProperty(DataServiceNodeDefinitionKey::DS_STORAGE_TYPE, "Set the control unit storage type", DataType::TYPE_INT32, 0, CDataVariant((int32_t)0)); pg_abstract_cu.addProperty(DataServiceNodeDefinitionKey::DS_STORAGE_LIVE_TIME, "Set the control unit storage type", DataType::TYPE_INT64, 0, CDataVariant((int64_t)0)); pg_abstract_cu.addProperty(DataServiceNodeDefinitionKey::DS_STORAGE_HISTORY_TIME, "Set the control unit storage type", DataType::TYPE_INT64, 0, CDataVariant((int64_t)0)); + // CDWUniquePtr burst_type_desc(new CDataWrapper()); + // burst_type_desc->addInt32Value(DataServiceNodeDefinitionKey::DS_HISTORY_BURST_TYPE, DataServiceNodeDefinitionType::DSStorageBurstTypeUndefined); + // pg_abstract_cu.addProperty(DataServiceNodeDefinitionKey::DS_HISTORY_BURST, "Specify if the restore operation need to be done as real operation or not", DataType::TYPE_CLUSTER,0, CDataVariant(burst_type_desc.release())); + pg_abstract_cu.addProperty(ControlUnitDatapackSystemKey::THREAD_SCHEDULE_DELAY, "Set the control unit step repeat time in microseconds", DataType::TYPE_INT64, 0, CDataVariant((int64_t)1000000));//set to one seconds pg_abstract_cu.addProperty(ControlUnitPropertyKey::INIT_RESTORE_OPTION, "Specify the restore type operatio to do durint initialization phase", DataType::TYPE_INT32, 0, CDataVariant((int32_t)0)); pg_abstract_cu.addProperty(ControlUnitPropertyKey::INIT_RESTORE_APPLY, "Specify if the restore operation need to be done as real operation or not", DataType::TYPE_BOOLEAN,0, CDataVariant((bool)false)); @@ -280,56 +285,63 @@ void AbstractControlUnit::_defineActionAndDataset(CDataWrapper& setup_configurat //for now we need only to add custom action for expose to rpc //input element of the dataset AbstActionDescShrPtr - actionDescription = addActionDescritionInstance<AbstractControlUnit>(this, - &AbstractControlUnit::_setDatasetAttribute, - ControlUnitNodeDomainAndActionRPC::CONTROL_UNIT_APPLY_INPUT_DATASET_ATTRIBUTE_CHANGE_SET, - "method for set the input element for the dataset"); + action_description = addActionDescritionInstance<AbstractControlUnit>(this, + &AbstractControlUnit::_setDatasetAttribute, + ControlUnitNodeDomainAndActionRPC::CONTROL_UNIT_APPLY_INPUT_DATASET_ATTRIBUTE_CHANGE_SET, + "method for set the input element for the dataset"); //expose updateConfiguration Methdo to rpc - actionDescription = addActionDescritionInstance<AbstractControlUnit>(this, - &AbstractControlUnit::updateConfiguration, - NodeDomainAndActionRPC::ACTION_UPDATE_PROPERTY, - "Update control unit property"); - - actionDescription = addActionDescritionInstance<AbstractControlUnit>(this, - &AbstractControlUnit::_init, - NodeDomainAndActionRPC::ACTION_NODE_INIT, - "Perform the control unit initialization"); - - actionDescription = addActionDescritionInstance<AbstractControlUnit>(this, - &AbstractControlUnit::_deinit, - NodeDomainAndActionRPC::ACTION_NODE_DEINIT - , - "Perform the control unit deinitialization"); - actionDescription = addActionDescritionInstance<AbstractControlUnit>(this, - &AbstractControlUnit::_start, - NodeDomainAndActionRPC::ACTION_NODE_START, - "Start the control unit scheduling"); - - actionDescription = addActionDescritionInstance<AbstractControlUnit>(this, - &AbstractControlUnit::_stop, - NodeDomainAndActionRPC::ACTION_NODE_STOP, - "Stop the control unit scheduling"); - - actionDescription = addActionDescritionInstance<AbstractControlUnit>(this, - &AbstractControlUnit::_recover, - NodeDomainAndActionRPC::ACTION_NODE_RECOVER, - "Recovery a recoverable state, going to the last state"); - - actionDescription = addActionDescritionInstance<AbstractControlUnit>(this, - &AbstractControlUnit::_unitRestoreToSnapshot, - NodeDomainAndActionRPC::ACTION_NODE_RESTORE, - "Restore contorl unit to a snapshot tag"); - - actionDescription = addActionDescritionInstance<AbstractControlUnit>(this, - &AbstractControlUnit::_getState, - NodeDomainAndActionRPC::ACTION_NODE_GET_STATE, - "Get the state of the running control unit"); - - actionDescription = addActionDescritionInstance<AbstractControlUnit>(this, - &AbstractControlUnit::_getInfo, - NodeDomainAndActionRPC::ACTION_CU_GET_INFO, - "Get the information about running control unit"); + action_description = addActionDescritionInstance<AbstractControlUnit>(this, + &AbstractControlUnit::updateConfiguration, + NodeDomainAndActionRPC::ACTION_UPDATE_PROPERTY, + "Update control unit property"); + + action_description = addActionDescritionInstance<AbstractControlUnit>(this, + &AbstractControlUnit::_init, + NodeDomainAndActionRPC::ACTION_NODE_INIT, + "Perform the control unit initialization"); + + action_description = addActionDescritionInstance<AbstractControlUnit>(this, + &AbstractControlUnit::_deinit, + NodeDomainAndActionRPC::ACTION_NODE_DEINIT + , + "Perform the control unit deinitialization"); + action_description = addActionDescritionInstance<AbstractControlUnit>(this, + &AbstractControlUnit::_start, + NodeDomainAndActionRPC::ACTION_NODE_START, + "Start the control unit scheduling"); + + action_description = addActionDescritionInstance<AbstractControlUnit>(this, + &AbstractControlUnit::_stop, + NodeDomainAndActionRPC::ACTION_NODE_STOP, + "Stop the control unit scheduling"); + + action_description = addActionDescritionInstance<AbstractControlUnit>(this, + &AbstractControlUnit::_recover, + NodeDomainAndActionRPC::ACTION_NODE_RECOVER, + "Recovery a recoverable state, going to the last state"); + + action_description = addActionDescritionInstance<AbstractControlUnit>(this, + &AbstractControlUnit::_unitRestoreToSnapshot, + NodeDomainAndActionRPC::ACTION_NODE_RESTORE, + "Restore contorl unit to a snapshot tag"); + + action_description = addActionDescritionInstance<AbstractControlUnit>(this, + &AbstractControlUnit::_getState, + NodeDomainAndActionRPC::ACTION_NODE_GET_STATE, + "Get the state of the running control unit"); + + action_description = addActionDescritionInstance<AbstractControlUnit>(this, + &AbstractControlUnit::_getInfo, + NodeDomainAndActionRPC::ACTION_CU_GET_INFO, + "Get the information about running control unit"); + action_description = addActionDescritionInstance<AbstractControlUnit>(this, + &AbstractControlUnit::_startStorageBurst, + ControlUnitNodeDomainAndActionRPC::ACTION_STORAGE_BURST, + "Execute a storage burst on control unit"); + action_description->addParam(ControlUnitNodeDefinitionKey::CONTROL_UNIT_DATASET_HISTORY_BURST_TAG, DataType::TYPE_STRING, "Tag asosciated to the stored data during burst"); + action_description->addParam(ControlUnitNodeDefinitionKey::CONTROL_UNIT_DATASET_HISTORY_BURST_TYPE, DataType::TYPE_INT32, "The type of burst"); + action_description->addParam(ControlUnitNodeDefinitionKey::CONTROL_UNIT_DATASET_HISTORY_BURST_VALUE, DataType::TYPE_UNDEFINED, "The value of the burst is defined by the type"); //grab dataset description DatasetDB::fillDataWrapperWithDataSetDescription(setup_configuration); @@ -1383,6 +1395,20 @@ CDataWrapper* AbstractControlUnit::_getState(CDataWrapper* getStatedParam, return stateResult; } + +chaos::common::data::CDataWrapper* AbstractControlUnit::_startStorageBurst(CDataWrapper* data, + bool& detachParam) throw (CException) { + common::data::structured::DatasetBurstSDWrapper db_sdw; + db_sdw.deserialize(data); + DatasetBurstShrdPtr burst = ChaosMakeSharedPtr<DatasetBurst>(db_sdw()); + if(!key_data_storage->addStorageBurst(ChaosMoveOperator(burst))) { + ACULERR_ << CHAOS_FORMAT("Error adding new burst execution -> %1%",%data->getJSONString()); + } else { + ACULAPP_ << CHAOS_FORMAT("Succesfull add new burst execution -> %1%",%data->getJSONString()); + } + return NULL; +} + /* Get the current control unit state */ @@ -1662,12 +1688,6 @@ void AbstractControlUnit::propertyUpdatedHandler(const std::string& group_name, if(group_name.compare("property_abstract_control_unit") == 0) { //update property on driver key_data_storage->updateConfiguration(property_name, new_value); - - //TODO - // if(attribute_value_shared_cache->hasAttribute(DOMAIN_SYSTEM, property_name)){ - // attribute_value_shared_cache->getAttributeValue(DOMAIN_SYSTEM, property_name)->setValue(new_value); - // } - //reflect modification on dataset if(property_name.compare(ControlUnitDatapackSystemKey::BYPASS_STATE) == 0) { _setBypassState(new_value.asBool()); @@ -1700,7 +1720,7 @@ void AbstractControlUnit::pushOutputDataset() { //check if something as changed if(!output_attribute_cache.hasChanged()) return; - CDataWrapper *output_attribute_dataset = key_data_storage->getNewDataPackForDomain(KeyDataStorageDomainOutput); + CDWShrdPtr output_attribute_dataset = key_data_storage->getNewDataPackForDomain(KeyDataStorageDomainOutput); if(!output_attribute_dataset) return; output_attribute_dataset->addInt64Value(ControlUnitDatapackCommonKey::RUN_ID, run_id); output_attribute_dataset->addInt64Value(DataPackCommonKey::DPCK_TIMESTAMP, *timestamp_acq_cached_value->getValuePtr<uint64_t>()); @@ -1755,7 +1775,7 @@ void AbstractControlUnit::pushOutputDataset() { } } //now we nede to push the outputdataset - key_data_storage->pushDataSet(data_manager::KeyDataStorageDomainOutput, output_attribute_dataset); + key_data_storage->pushDataSet(data_manager::KeyDataStorageDomainOutput, ChaosMoveOperator(output_attribute_dataset)); //update counter push_dataset_counter++; @@ -1770,7 +1790,7 @@ void AbstractControlUnit::pushInputDataset() { if(!input_attribute_cache.hasChanged()) return; //get the cdatawrapper for the pack int64_t cur_us = TimingUtil::getTimeStampInMicroseconds(); - CDataWrapper *input_attribute_dataset = key_data_storage->getNewDataPackForDomain(KeyDataStorageDomainInput); + CDWShrdPtr input_attribute_dataset = key_data_storage->getNewDataPackForDomain(KeyDataStorageDomainInput); if(input_attribute_dataset) { input_attribute_dataset->addInt64Value(ControlUnitDatapackCommonKey::RUN_ID, run_id); //input dataset timestamp is added only when pushed on cache @@ -1780,7 +1800,7 @@ void AbstractControlUnit::pushInputDataset() { fillCDatawrapperWithCachedValue(cache_input_attribute_vector, *input_attribute_dataset); //push out the system dataset - key_data_storage->pushDataSet(data_manager::KeyDataStorageDomainInput, input_attribute_dataset); + key_data_storage->pushDataSet(data_manager::KeyDataStorageDomainInput, ChaosMoveOperator(input_attribute_dataset)); } input_attribute_cache.resetChangedIndex(); } @@ -1791,21 +1811,18 @@ void AbstractControlUnit::pushCustomDataset() { if(!custom_attribute_cache.hasChanged()) return; //get the cdatawrapper for the pack int64_t cur_us = TimingUtil::getTimeStampInMicroseconds(); - CDataWrapper *custom_attribute_dataset = key_data_storage->getNewDataPackForDomain(KeyDataStorageDomainCustom); + CDWShrdPtr custom_attribute_dataset = key_data_storage->getNewDataPackForDomain(KeyDataStorageDomainCustom); if(custom_attribute_dataset) { custom_attribute_dataset->addInt64Value(ControlUnitDatapackCommonKey::RUN_ID, run_id); //input dataset timestamp is added only when pushed on cache custom_attribute_dataset->addInt64Value(DataPackCommonKey::DPCK_TIMESTAMP, cur_us/1000); custom_attribute_dataset->addInt64Value(DataPackCommonKey::DPCK_HIGH_RESOLUTION_TIMESTAMP, cur_us); - //add dataset type - // custom_attribute_dataset->addInt32Value(DataPackCommonKey::DPCK_DATASET_TYPE, DataPackCommonKey::DPCK_DATASET_TYPE_CUSTOM); - //fill the dataset fillCDatawrapperWithCachedValue(cache_custom_attribute_vector, *custom_attribute_dataset); //push out the system dataset - key_data_storage->pushDataSet(data_manager::KeyDataStorageDomainCustom, custom_attribute_dataset); + key_data_storage->pushDataSet(data_manager::KeyDataStorageDomainCustom, ChaosMoveOperator(custom_attribute_dataset)); } } @@ -1814,35 +1831,29 @@ void AbstractControlUnit::pushSystemDataset() { if(!systemm_attribute_cache.hasChanged()) return; //get the cdatawrapper for the pack int64_t cur_us = TimingUtil::getTimeStampInMicroseconds(); - CDataWrapper *system_attribute_dataset = key_data_storage->getNewDataPackForDomain(KeyDataStorageDomainSystem); + CDWShrdPtr system_attribute_dataset = key_data_storage->getNewDataPackForDomain(KeyDataStorageDomainSystem); if(system_attribute_dataset) { system_attribute_dataset->addInt64Value(ControlUnitDatapackCommonKey::RUN_ID, run_id); //input dataset timestamp is added only when pushed on cache system_attribute_dataset->addInt64Value(DataPackCommonKey::DPCK_TIMESTAMP, cur_us/1000); system_attribute_dataset->addInt64Value(DataPackCommonKey::DPCK_HIGH_RESOLUTION_TIMESTAMP, cur_us); - //add dataset type - // system_attribute_dataset->addInt32Value(DataPackCommonKey::DPCK_DATASET_TYPE, DataPackCommonKey::DPCK_DATASET_TYPE_SYSTEM); //fill the dataset fillCDatawrapperWithCachedValue(cache_system_attribute_vector, *system_attribute_dataset); - //push out the system dataset - key_data_storage->pushDataSet(data_manager::KeyDataStorageDomainSystem, system_attribute_dataset); + key_data_storage->pushDataSet(data_manager::KeyDataStorageDomainSystem, ChaosMoveOperator(system_attribute_dataset)); } //reset changed index systemm_attribute_cache.resetChangedIndex(); } -CDataWrapper *AbstractControlUnit::writeCatalogOnCDataWrapper(AlarmCatalog& catalog, - int32_t dataset_type) { - CDataWrapper *attribute_dataset = key_data_storage->getNewDataPackForDomain((KeyDataStorageDomain)dataset_type); +CDWShrdPtr AbstractControlUnit::writeCatalogOnCDataWrapper(AlarmCatalog& catalog, + int32_t dataset_type) { + CDWShrdPtr attribute_dataset = key_data_storage->getNewDataPackForDomain((KeyDataStorageDomain)dataset_type); if(attribute_dataset) { //fill datapack with //! the dataaset can be pushed also in other moment attribute_dataset->addInt64Value(DataPackCommonKey::DPCK_TIMESTAMP, TimingUtil::getTimeStamp()); - //add dataset type - // attribute_dataset->addInt32Value(DataPackCommonKey::DPCK_DATASET_TYPE, dataset_type); - //scan all alarm ad create the datapack size_t alarm_size = catalog.size(); for(unsigned int idx = 0; @@ -1858,23 +1869,21 @@ CDataWrapper *AbstractControlUnit::writeCatalogOnCDataWrapper(AlarmCatalog& cata void AbstractControlUnit::pushDevAlarmDataset() { GET_CAT_OR_EXIT(StateVariableTypeAlarmDEV, ); - //get the cdatawrapper for the pack - CDataWrapper *attribute_dataset = writeCatalogOnCDataWrapper(catalog, - DataPackCommonKey::DPCK_DATASET_TYPE_DEV_ALARM); + CDWShrdPtr attribute_dataset = writeCatalogOnCDataWrapper(catalog, + DataPackCommonKey::DPCK_DATASET_TYPE_DEV_ALARM); if(attribute_dataset) { //push out the system dataset - key_data_storage->pushDataSet(KeyDataStorageDomainDevAlarm, attribute_dataset); + key_data_storage->pushDataSet(KeyDataStorageDomainDevAlarm, ChaosMoveOperator(attribute_dataset)); } } void AbstractControlUnit::pushCUAlarmDataset() { GET_CAT_OR_EXIT(StateVariableTypeAlarmCU, ); - //get the cdatawrapper for the pack - CDataWrapper *attribute_dataset = writeCatalogOnCDataWrapper(catalog, - DataPackCommonKey::DPCK_DATASET_TYPE_CU_ALARM); + CDWShrdPtr attribute_dataset = writeCatalogOnCDataWrapper(catalog, + DataPackCommonKey::DPCK_DATASET_TYPE_CU_ALARM); if(attribute_dataset) { //push out the system dataset - key_data_storage->pushDataSet(KeyDataStorageDomainCUAlarm, attribute_dataset); + key_data_storage->pushDataSet(KeyDataStorageDomainCUAlarm, ChaosMoveOperator(attribute_dataset)); } } diff --git a/chaos/cu_toolkit/control_manager/AbstractControlUnit.h b/chaos/cu_toolkit/control_manager/AbstractControlUnit.h index 0919819d8..732b86f9a 100644 --- a/chaos/cu_toolkit/control_manager/AbstractControlUnit.h +++ b/chaos/cu_toolkit/control_manager/AbstractControlUnit.h @@ -206,8 +206,8 @@ namespace chaos{ return -1; } - chaos::common::data::CDataWrapper *writeCatalogOnCDataWrapper(chaos::common::alarm::AlarmCatalog& catalog, - int32_t dataset_type); + chaos::common::data::CDWShrdPtr writeCatalogOnCDataWrapper(chaos::common::alarm::AlarmCatalog& catalog, + int32_t dataset_type); //check at initilization time ifr need to to a restore or only an apply void checkForRestoreOnInit() throw(CException); private: @@ -426,21 +426,28 @@ namespace chaos{ This method is called when the input attribute of the dataset need to be valorized, subclass need to perform all the appropiate action to set these attribute */ - chaos::common::data::CDataWrapper* _setDatasetAttribute(chaos::common::data::CDataWrapper*, bool&) throw (CException); + chaos::common::data::CDataWrapper* _setDatasetAttribute(chaos::common::data::CDataWrapper* data, + bool& detachParam) throw (CException); //! Return the state of the control unit /*! Return the current control unit state identifyed by ControlUnitState types fitted into the CDatawrapper with the key CUStateKey::CONTROL_UNIT_STATE */ - chaos::common::data::CDataWrapper* _getState(chaos::common::data::CDataWrapper*, bool& detachParam) throw(CException); + chaos::common::data::CDataWrapper* _getState(chaos::common::data::CDataWrapper* data, + bool& detachParam) throw(CException); //! Return the information about the type of the current instace of control unit /*! Return unit fitted into cdata wrapper: CU type: string type associated with the key @CUDefinitionKey::CS_CM_CU_TYPE */ - chaos::common::data::CDataWrapper* _getInfo(chaos::common::data::CDataWrapper*, bool& detachParam) throw(CException); + chaos::common::data::CDataWrapper* _getInfo(chaos::common::data::CDataWrapper* data, + bool& detachParam) throw(CException); + + //!start a new storicization burst execution + chaos::common::data::CDataWrapper* _startStorageBurst(chaos::common::data::CDataWrapper* data, + bool& detachParam) throw (CException); //! update the timestamp attribute of the output datapack void _updateAcquistionTimestamp(uint64_t alternative_ts); diff --git a/chaos/cu_toolkit/control_manager/AbstractExecutionUnit.cpp b/chaos/cu_toolkit/control_manager/AbstractExecutionUnit.cpp index b540da161..3d242debc 100644 --- a/chaos/cu_toolkit/control_manager/AbstractExecutionUnit.cpp +++ b/chaos/cu_toolkit/control_manager/AbstractExecutionUnit.cpp @@ -212,13 +212,15 @@ int AbstractExecutionUnit::performQuery(chaos::common::io::QueryCursor **cursor, KeyDataStorageDomain dataset_domain, const uint64_t start_ts, const uint64_t end_ts, + const ChaosStringSet& meta_tags, const uint32_t page_len) { CHAOS_ASSERT(key_data_storage.get()); int err = key_data_storage->performGeneralQuery(cursor, node_id, dataset_domain, start_ts, - end_ts); + end_ts, + meta_tags); if(!err || *cursor) { (*cursor)->setPageDimension(page_len); } diff --git a/chaos/cu_toolkit/control_manager/AbstractExecutionUnit.h b/chaos/cu_toolkit/control_manager/AbstractExecutionUnit.h index e4c162370..3763019b3 100644 --- a/chaos/cu_toolkit/control_manager/AbstractExecutionUnit.h +++ b/chaos/cu_toolkit/control_manager/AbstractExecutionUnit.h @@ -168,6 +168,7 @@ namespace chaos{ chaos::cu::data_manager::KeyDataStorageDomain dataset_domain, const uint64_t start_ts, const uint64_t end_ts, + const ChaosStringSet& meta_tags, const uint32_t page_len); //! release a cursor diff --git a/chaos/cu_toolkit/control_manager/script/api/EUSearch.cpp b/chaos/cu_toolkit/control_manager/script/api/EUSearch.cpp index 694fb70c0..df0c21383 100644 --- a/chaos/cu_toolkit/control_manager/script/api/EUSearch.cpp +++ b/chaos/cu_toolkit/control_manager/script/api/EUSearch.cpp @@ -113,6 +113,7 @@ int EUSearch::newSearch(const common::script::ScriptInParam& input_parameter, static_cast<KeyDataStorageDomain>(input_parameter[1].asInt32()), input_parameter[2].asInt64(),//start_ts input_parameter[3].asInt64(),//end_ts; + ChaosStringSet(), DEFAULT_PAGE_LEN); CHAOS_ASSERT(!err && cursor != NULL); @@ -145,6 +146,7 @@ int EUSearch::newSearchSinceSeconds(const common::script::ScriptInParam& input_p static_cast<KeyDataStorageDomain>(input_parameter[1].asInt32()), start_ts,//start_ts end_ts,//end_ts; + ChaosStringSet(), DEFAULT_PAGE_LEN); CHAOS_ASSERT(!err && cursor != NULL); @@ -271,6 +273,7 @@ int EUSearch::runAlgoSearchSinceSeconds(const common::script::ScriptInParam& inp search_domain, start_ts, end_ts, + ChaosStringSet(), DEFAULT_PAGE_LEN); CHAOS_ASSERT(!err && cursor != NULL); diff --git a/chaos/cu_toolkit/control_manager/script/api/plugin/EUPluginApiWrapper.cpp b/chaos/cu_toolkit/control_manager/script/api/plugin/EUPluginApiWrapper.cpp index ee407f0f9..7cdfbe6b8 100644 --- a/chaos/cu_toolkit/control_manager/script/api/plugin/EUPluginApiWrapper.cpp +++ b/chaos/cu_toolkit/control_manager/script/api/plugin/EUPluginApiWrapper.cpp @@ -63,7 +63,7 @@ int EUPluginApiWrapper::execPlugin(const ScriptInParam& input_parameter, if((err = api_plugin->execute(input_json.c_str(), (uint32_t)input_json.size(), &output_data, &output_size)) == 0) { //we have data const std::string output_json((output_data?output_data:""), output_size); - output_parameter.push_back(CDataVariant(CDataBuffer::newOwnBufferFromBuffer(output_data, output_size))); + output_parameter.push_back(CDataVariant(ChaosMoveOperator(CDataBuffer::newOwnBufferFromBuffer(output_data, output_size)))); output_parameter.push_back(CDataVariant(output_size)); EUSW_DBG << CHAOS_FORMAT("Result EU plugin with ---->%1%", %output_json); } diff --git a/chaos/cu_toolkit/data_manager/DataManager.cpp b/chaos/cu_toolkit/data_manager/DataManager.cpp index ea57c07af..e977ef375 100644 --- a/chaos/cu_toolkit/data_manager/DataManager.cpp +++ b/chaos/cu_toolkit/data_manager/DataManager.cpp @@ -176,14 +176,14 @@ void DataManager::updateConfigurationForDeviceIdKey(const string& device_id, CDa /* Submit a CDataWrapper on device id KeyDataStorage */ -void DataManager::pushDeviceDataByIdKey(const string& device_id, CDataWrapper* deviceCDataWrapper) throw(CException) { - deviceIDKeyDataStorageMap[device_id]->pushDataSet(data_manager::KeyDataStorageDomainOutput, deviceCDataWrapper); +void DataManager::pushDeviceDataByIdKey(const string& device_id, CDWShrdPtr dataset) throw(CException) { + deviceIDKeyDataStorageMap[device_id]->pushDataSet(data_manager::KeyDataStorageDomainOutput, ChaosMoveOperator(dataset)); } /* return a new instance of CDataWrapper filled with a mandatory data according to key */ -CDataWrapper *DataManager::getNewDataWrapperForDeviceIdKey(const string& device_id) { +CDWShrdPtr DataManager::getNewDataWrapperForDeviceIdKey(const string& device_id) { return deviceIDKeyDataStorageMap[device_id]->getNewDataPackForDomain(KeyDataStorageDomainOutput); } diff --git a/chaos/cu_toolkit/data_manager/DataManager.h b/chaos/cu_toolkit/data_manager/DataManager.h index b0b8579b7..ae8ecbb74 100644 --- a/chaos/cu_toolkit/data_manager/DataManager.h +++ b/chaos/cu_toolkit/data_manager/DataManager.h @@ -106,13 +106,13 @@ namespace chaos{ /* Submit a CDataWrapper on device id KeyDataStorage */ - void pushDeviceDataByIdKey(const std::string &device_id, chaos_data::CDataWrapper*) throw(CException); + void pushDeviceDataByIdKey(const std::string& device_id, chaos_data::CDWShrdPtr dataset) throw(CException); /* return a new instance of CDataWrapper filled with a mandatory data according to key */ - chaos_data::CDataWrapper *getNewDataWrapperForDeviceIdKey(const std::string &device_id); + chaos_data::CDWShrdPtr getNewDataWrapperForDeviceIdKey(const std::string &device_id); /* Configure the datamanager diff --git a/chaos/cu_toolkit/data_manager/KeyDataStorage.cpp b/chaos/cu_toolkit/data_manager/KeyDataStorage.cpp index 5ad1385b4..0493ac864 100644 --- a/chaos/cu_toolkit/data_manager/KeyDataStorage.cpp +++ b/chaos/cu_toolkit/data_manager/KeyDataStorage.cpp @@ -27,6 +27,7 @@ using namespace std; using namespace chaos; using namespace chaos::common::data; +using namespace chaos::common::data::structured; using namespace chaos::common::utility; using namespace chaos::cu::data_manager; @@ -34,6 +35,36 @@ using namespace chaos::cu::data_manager; #define KeyDataStorageLDBG DBG_LOG(KeyDataStorage) #define KeyDataStorageLERR ERR_LOG(KeyDataStorage) +#pragma mark StorageBurst +StorageBurst::StorageBurst(DatasetBurstShrdPtr _dataset_burst): +dataset_burst(_dataset_burst){} + +StorageBurst::~StorageBurst(){} + +#pragma mark PushStorageBurst +PushStorageBurst::PushStorageBurst(DatasetBurstShrdPtr _dataset_burst): +StorageBurst(ChaosMoveOperator(_dataset_burst)), +current_pushes(0){} + +PushStorageBurst::~PushStorageBurst(){} + +bool PushStorageBurst::active(void *data __attribute__((unused))) { + return current_pushes++<StorageBurst::dataset_burst->value.asUInt32(); +} + +#pragma mark MSecStorageBurst +MSecStorageBurst::MSecStorageBurst(DatasetBurstShrdPtr _dataset_burst): +StorageBurst(ChaosMoveOperator(_dataset_burst)), +timeout_msec(TimingUtil::getTimestampWithDelay(StorageBurst::dataset_burst->value.asInt32(), true)){} + +MSecStorageBurst::~MSecStorageBurst(){} + +bool MSecStorageBurst::active(void *data) { + int64_t *now = static_cast<int64_t*>(data); + return timeout_msec>*now; +} + +#pragma mark KeyDataStorage KeyDataStorage::KeyDataStorage(const std::string& _key, chaos_io::IODataDriver *_io_data_driver): key(_key), @@ -43,33 +74,27 @@ storage_history_time(0), storage_history_time_last_push(0), storage_live_time(0), storage_live_time_last_push(0), -sequence_id(0 /*std::numeric_limits<int64_t>::min()*/){ - output_key = _key + DataPackPrefixID::OUTPUT_DATASET_POSTFIX; - input_key = _key + DataPackPrefixID::INPUT_DATASET_POSTFIX; - system_key = _key + DataPackPrefixID::SYSTEM_DATASET_POSTFIX; - custom_key = _key + DataPackPrefixID::CUSTOM_DATASET_POSTFIX; - health_key = _key + DataPackPrefixID::HEALTH_DATASET_POSTFIX; - cu_alarm_key = _key + DataPackPrefixID::CU_ALARM_DATASET_POSTFIX; - dev_alarm_key = _key + DataPackPrefixID::DEV_ALARM_DATASET_POSTFIX; -} +sequence_id(0), +output_key(key + DataPackPrefixID::OUTPUT_DATASET_POSTFIX), +input_key(key + DataPackPrefixID::INPUT_DATASET_POSTFIX), +system_key(key + DataPackPrefixID::SYSTEM_DATASET_POSTFIX), +custom_key(key + DataPackPrefixID::CUSTOM_DATASET_POSTFIX), +health_key(key + DataPackPrefixID::HEALTH_DATASET_POSTFIX), +cu_alarm_key(key + DataPackPrefixID::CU_ALARM_DATASET_POSTFIX), +dev_alarm_key(key + DataPackPrefixID::DEV_ALARM_DATASET_POSTFIX){} KeyDataStorage::~KeyDataStorage() { restore_point_map.clear(); - if(io_data_driver) { - delete(io_data_driver); - io_data_driver = NULL; - } - } void KeyDataStorage::init(void *init_parameter) throw (chaos::CException) { - if(!io_data_driver) throw chaos::CException(-1, "IO data driver not set", __PRETTY_FUNCTION__); + if(!io_data_driver.get()) throw chaos::CException(-1, "IO data driver not set", __PRETTY_FUNCTION__); io_data_driver->init(init_parameter); } void KeyDataStorage::deinit() throw (chaos::CException) { - if(io_data_driver) io_data_driver->deinit(); + if(io_data_driver.get()) {io_data_driver->deinit();} restore_point_map.clear(); } @@ -133,8 +158,8 @@ std::string KeyDataStorage::getDomainString(const std::string& node_uid, Return a new instace for the CSDatawrapped filled with default madatory data */ -CDataWrapper* KeyDataStorage::getNewDataPackForDomain(const KeyDataStorageDomain domain) { - CDataWrapper *result = new CDataWrapper(); +CDWShrdPtr KeyDataStorage::getNewDataPackForDomain(const KeyDataStorageDomain domain) { + CDWShrdPtr result = ChaosMakeSharedPtr<CDataWrapper>(); int32_t node_type; switch(domain) { case KeyDataStorageDomainOutput: @@ -167,94 +192,111 @@ CDataWrapper* KeyDataStorage::getNewDataPackForDomain(const KeyDataStorageDomain } void KeyDataStorage::pushDataWithControlOnHistoryTime(const std::string& key, - CDataWrapper *dataToStore, + CDWShrdPtr dataset, DataServiceNodeDefinitionType::DSStorageType storage_type) { - uint64_t now = TimingUtil::getTimeStampInMicroseconds(); - switch(storage_type) { - case DataServiceNodeDefinitionType::DSStorageTypeLive: { - if((now - storage_live_time_last_push) >= storage_live_time) { - io_data_driver->storeData(key, - dataToStore, - DataServiceNodeDefinitionType::DSStorageTypeLive); - storage_live_time_last_push = now; + ChaosStringSet tags; + //check for burt information + if(!current_burst.get()) { + LQueueBurstReadLock wl = burst_queue.getReadLockObject(); + if(!burst_queue().empty()){ + switch(burst_queue().front()->type) { + case chaos::ControlUnitNodeDefinitionType::DSStorageBurstTypeNPush: + current_burst.reset(new PushStorageBurst(ChaosMoveOperator(burst_queue().front()))); + break; + case chaos::ControlUnitNodeDefinitionType::DSStorageBurstTypeMSec: + current_burst.reset(new MSecStorageBurst(ChaosMoveOperator(burst_queue().front()))); + break; + default: + break; } - - break; + burst_queue().pop(); } - case DataServiceNodeDefinitionType::DSStorageTypeHistory: { - + } + + uint64_t now = TimingUtil::getTimeStampInMicroseconds(); + int effective_storage_type = DataServiceNodeDefinitionType::DSStorageTypeUndefined; + + if(storage_type & DataServiceNodeDefinitionType::DSStorageTypeLive) { + //live is enbaled + if((now - storage_live_time_last_push) >= storage_live_time) { + effective_storage_type |= DataServiceNodeDefinitionType::DSStorageTypeLive; + storage_live_time_last_push = now; + } + } + + if(!current_burst.get()) { + if(storage_type & DataServiceNodeDefinitionType::DSStorageTypeHistory) { + //history is enabled if((now - storage_history_time_last_push) >= storage_history_time) { - io_data_driver->storeData(key, - dataToStore, - DataServiceNodeDefinitionType::DSStorageTypeHistory); + effective_storage_type |= DataServiceNodeDefinitionType::DSStorageTypeHistory; storage_history_time_last_push = now; } - break; } - case DataServiceNodeDefinitionType::DSStorageTypeLiveHistory: { - - DataServiceNodeDefinitionType::DSStorageType effective_storage_type = DataServiceNodeDefinitionType::DSStorageTypeLiveHistory; - bool push_history = (now - storage_history_time_last_push) >= storage_history_time; - bool push_live = (now - storage_live_time_last_push) >= storage_live_time; - if(push_live || push_history) { - if(push_history && push_live) { - storage_history_time_last_push = storage_live_time_last_push = now; - } else if(push_history) { - effective_storage_type = DataServiceNodeDefinitionType::DSStorageTypeHistory; - storage_history_time_last_push = now; - } else if(push_live) { - effective_storage_type = DataServiceNodeDefinitionType::DSStorageTypeLive; - storage_live_time_last_push = now; - } - io_data_driver->storeData(key, - dataToStore, - effective_storage_type); - } - break; + } else { + storage_history_time_last_push = now; + effective_storage_type |= DataServiceNodeDefinitionType::DSStorageTypeHistory; + if(current_burst->dataset_burst->tag.size()) { + tags.insert(current_burst->dataset_burst->tag); } - case DataServiceNodeDefinitionType::DSStorageTypeUndefined: - break; + //check for storage information + if(!current_burst->active(&now)) { + //we need to remove it + current_burst.reset(); + } + } + + if(effective_storage_type) { + io_data_driver->storeData(key, + ChaosMoveOperator(dataset), + static_cast<DataServiceNodeDefinitionType::DSStorageType>(effective_storage_type), + tags); } } void KeyDataStorage::pushDataSet(KeyDataStorageDomain domain, - chaos_data::CDataWrapper *dataset) { - CHAOS_ASSERT(io_data_driver); + CDWShrdPtr dataset) { + CHAOS_ASSERT(io_data_driver.get()); //lock for protect the access boost::unique_lock<boost::mutex> l(mutex_push_data); switch(domain) { case KeyDataStorageDomainOutput: pushDataWithControlOnHistoryTime(output_key, - dataset, + ChaosMoveOperator(dataset), storage_type); break; case KeyDataStorageDomainInput: //input channel need to be push ever either in live and in history io_data_driver->storeData(input_key, - dataset, + ChaosMoveOperator(dataset), DataServiceNodeDefinitionType::DSStorageTypeLiveHistory); break; case KeyDataStorageDomainSystem: //system channel need to be push ever either in live and in history io_data_driver->storeData(system_key, - dataset, + ChaosMoveOperator(dataset), DataServiceNodeDefinitionType::DSStorageTypeLiveHistory); break; case KeyDataStorageDomainCUAlarm: //system channel need to be push ever either in live and in history io_data_driver->storeData(cu_alarm_key, - dataset, + ChaosMoveOperator(dataset), DataServiceNodeDefinitionType::DSStorageTypeLiveHistory); break; case KeyDataStorageDomainDevAlarm: //system channel need to be push ever either in live and in history io_data_driver->storeData(dev_alarm_key, - dataset, + ChaosMoveOperator(dataset), DataServiceNodeDefinitionType::DSStorageTypeLiveHistory); break; + case KeyDataStorageDomainHealth: + //system channel need to be push ever either in live and in history + io_data_driver->storeHealthData(health_key, + ChaosMoveOperator(dataset), + DataServiceNodeDefinitionType::DSStorageTypeLiveHistory); + break; case KeyDataStorageDomainCustom: pushDataWithControlOnHistoryTime(custom_key, - dataset, + ChaosMoveOperator(dataset), storage_type); break; } @@ -292,7 +334,7 @@ int KeyDataStorage::loadRestorePoint(const std::string& restore_point_tag) { } else { if(dataset){ restore_point_map[restore_point_tag].insert(make_pair(input_key, ChaosMoveOperator(dataset)));dataset.reset(); - + } } @@ -357,8 +399,8 @@ ChaosSharedPtr<chaos_data::CDataWrapper> KeyDataStorage::getDatasetFromRestorePo void KeyDataStorage::updateConfiguration(CDataWrapper *configuration) { //update the driver configration - if(io_data_driver) io_data_driver->updateConfiguration(configuration); - + if(io_data_driver.get()) io_data_driver->updateConfiguration(configuration); + } void KeyDataStorage::updateConfiguration(const std::string& conf_name, @@ -373,6 +415,22 @@ void KeyDataStorage::updateConfiguration(const std::string& conf_name, KeyDataStorageLAPP << CHAOS_FORMAT("Set value %1% to property %2%", %conf_value.asString()%conf_name); } +//!add into the queue a noew storage burst mode +bool KeyDataStorage::addStorageBurst(chaos::common::data::structured::DatasetBurstShrdPtr burst_mode) { + if(burst_mode->type == chaos::ControlUnitNodeDefinitionType::DSStorageBurstTypeUndefined) { + KeyDataStorageLERR << "The type is mandatory"; + return false; + } + if(!burst_mode->value.isValid()) { + KeyDataStorageLERR << "The value is mandatory"; + return false; + } + + LQueueBurstWriteLock wl = burst_queue.getWriteLockObject(); + burst_queue().push(burst_mode); + return true; +} + DataServiceNodeDefinitionType::DSStorageType KeyDataStorage::getStorageType() { return storage_type; } @@ -413,12 +471,14 @@ int KeyDataStorage::performLiveFetch(const ChaosStringVector& node_uid, } int KeyDataStorage::performSelfQuery(chaos::common::io::QueryCursor **cursor, - KeyDataStorageDomain dataset_domain, + const KeyDataStorageDomain dataset_domain, const uint64_t start_ts, - const uint64_t end_ts) { + const uint64_t end_ts, + const ChaosStringSet& meta_tags) { *cursor = io_data_driver->performQuery(getDomainString(dataset_domain), start_ts, - end_ts); + end_ts, + meta_tags); return ((*cursor == NULL)?-1:0); } @@ -426,11 +486,13 @@ int KeyDataStorage::performGeneralQuery(chaos::common::io::QueryCursor **cursor, const std::string& node_id, KeyDataStorageDomain dataset_domain, const uint64_t start_ts, - const uint64_t end_ts) { + const uint64_t end_ts, + const ChaosStringSet& meta_tags) { *cursor = io_data_driver->performQuery(getDomainString(node_id, dataset_domain), start_ts, - end_ts); + end_ts, + meta_tags); return ((*cursor == NULL)?-1:0); } diff --git a/chaos/cu_toolkit/data_manager/KeyDataStorage.h b/chaos/cu_toolkit/data_manager/KeyDataStorage.h index b2529b22d..b73eace79 100644 --- a/chaos/cu_toolkit/data_manager/KeyDataStorage.h +++ b/chaos/cu_toolkit/data_manager/KeyDataStorage.h @@ -25,8 +25,12 @@ #include <map> #include <string> +#include <chaos/common/chaos_types.h> +#include <chaos/common/chaos_constants.h> #include <chaos/common/io/IODataDriver.h> +#include <chaos/common/data/structured/Dataset.h> #include <chaos/common/utility/ArrayPointer.h> +#include <chaos/common/utility/LockableObject.h> #include <boost/thread.hpp> #include <boost/atomic.hpp> @@ -37,7 +41,7 @@ namespace chaos_utility = chaos::common::utility; namespace chaos{ namespace cu { namespace data_manager { - + //!data domain managed by the driver typedef enum KeyDataStorageDomain { KeyDataStorageDomainOutput = DataPackCommonKey::DPCK_DATASET_TYPE_OUTPUT, KeyDataStorageDomainInput = DataPackCommonKey::DPCK_DATASET_TYPE_INPUT, @@ -48,26 +52,66 @@ namespace chaos{ KeyDataStorageDomainCUAlarm =DataPackCommonKey::DPCK_DATASET_TYPE_CU_ALARM } KeyDataStorageDomain; + //!define the hasmap for the dataset tags + CHAOS_DEFINE_MAP_FOR_TYPE(KeyDataStorageDomain, chaos::common::data::structured::DatasetBurstShrdPtr, MapDatasetBurst); + CHAOS_DEFINE_LOCKABLE_OBJECT(MapDatasetBurst, LMapDatasetBurst); + + CHAOS_DEFINE_QUEUE_FOR_TYPE(chaos::common::data::structured::DatasetBurstShrdPtr, QueueBurst); + CHAOS_DEFINE_LOCKABLE_OBJECT(QueueBurst, LQueueBurst); + + class StorageBurst { + public: + chaos::common::data::structured::DatasetBurstShrdPtr dataset_burst; + StorageBurst(chaos::common::data::structured::DatasetBurstShrdPtr _dataset_burst); + virtual ~StorageBurst(); + virtual bool active(void *data) = 0; + }; + + class PushStorageBurst: + public StorageBurst { + uint32_t current_pushes; + public: + PushStorageBurst(chaos::common::data::structured::DatasetBurstShrdPtr _dataset_burst); + virtual ~PushStorageBurst(); + bool active(void *data); + }; + + class MSecStorageBurst: + public StorageBurst { + int64_t timeout_msec; + public: + MSecStorageBurst(chaos::common::data::structured::DatasetBurstShrdPtr _dataset_burst); + virtual ~MSecStorageBurst(); + bool active(void *data); + }; + + //!High level driver for manage the push and query of data sets class KeyDataStorage { - std::string key; - std::string output_key; - std::string input_key; - std::string system_key; - std::string custom_key; - std::string health_key; - std::string cu_alarm_key; - std::string dev_alarm_key; - //is the sequence if + const std::string key; + const std::string output_key; + const std::string input_key; + const std::string system_key; + const std::string custom_key; + const std::string health_key; + const std::string cu_alarm_key; + const std::string dev_alarm_key; + + //!is the sequence if boost::atomic<int64_t> sequence_id; - //restore poitn map + //!restore poitn map std::map<std::string, std::map<std::string, chaos_data::CDWShrdPtr > > restore_point_map; - chaos_io::IODataDriver *io_data_driver; + //!instance driver for push data + ChaosUniquePtr<chaos_io::IODataDriver> io_data_driver; - //storage type + //!storage type DataServiceNodeDefinitionType::DSStorageType storage_type; + //!define the queur for burst information + LQueueBurst burst_queue; + ChaosUniquePtr<StorageBurst> current_burst; + //history time uint64_t storage_history_time; uint64_t storage_history_time_last_push; @@ -77,7 +121,7 @@ namespace chaos{ boost::mutex mutex_push_data; void pushDataWithControlOnHistoryTime(const std::string& key, - chaos::common::data::CDataWrapper *dataToStore, + chaos::common::data::CDWShrdPtr dataset, chaos::DataServiceNodeDefinitionType::DSStorageType storage_type); inline std::string getDomainString(const KeyDataStorageDomain dataset_domain); @@ -95,7 +139,7 @@ namespace chaos{ /* Return a new instace for the CSDatawrapped */ - chaos_data::CDataWrapper* getNewDataPackForDomain(const KeyDataStorageDomain domain); + chaos::common::data::CDWShrdPtr getNewDataPackForDomain(const KeyDataStorageDomain domain); /* Retrive the data from Live Storage @@ -103,7 +147,7 @@ namespace chaos{ //chaos_utility::ArrayPointer<chaos_data::CDataWrapper>* getLastDataSet(KeyDataStorageDomain domain); //! push a dataset associated to a domain - void pushDataSet(KeyDataStorageDomain domain, chaos_data::CDataWrapper *dataset); + void pushDataSet(KeyDataStorageDomain domain, chaos::common::data::CDWShrdPtr dataset); //! load all dataseet for a restore point int loadRestorePoint(const std::string& restore_point_tag); @@ -118,6 +162,9 @@ namespace chaos{ void updateConfiguration(chaos::common::data::CDataWrapper *configuration); void updateConfiguration(const std::string& conf_name, const chaos::common::data::CDataVariant& conf_value); + //!add into the queue a noew storage burst mode + bool addStorageBurst(chaos::common::data::structured::DatasetBurstShrdPtr burst_mode); + //!return the current storage type [live, history or both] setting DataServiceNodeDefinitionType::DSStorageType getStorageType(); @@ -139,13 +186,15 @@ namespace chaos{ int performSelfQuery(chaos::common::io::QueryCursor **cursor, KeyDataStorageDomain dataset_domain, const uint64_t start_ts, - const uint64_t end_ts); + const uint64_t end_ts, + const ChaosStringSet& meta_tags); int performGeneralQuery(chaos::common::io::QueryCursor **cursor, const std::string& node_id, KeyDataStorageDomain dataset_domain, const uint64_t start_ts, - const uint64_t end_ts); + const uint64_t end_ts, + const ChaosStringSet& meta_tags); void releseQuery(chaos::common::io::QueryCursor *cursor); }; diff --git a/chaos/ui_toolkit/CMakeLists.txt b/chaos/ui_toolkit/CMakeLists.txt deleted file mode 100644 index afaee5c28..000000000 --- a/chaos/ui_toolkit/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -project(chaos_uitoolkit) -INCLUDE_DIRECTORIES(chaos/ui_toolkit ../../) -SET(ui_lib_src ChaosUIToolkit.cpp ChaosUIToolkitCWrapper.cc - HighLevelApi/DeviceController.cpp HighLevelApi/HLDataApi.cpp - HighLevelApi/HLInfrastructureApi.cpp LowLevelApi/LLDataApi.cpp LowLevelApi/LLRpcApi.cpp) - -IF(BUILD_FORCE_STATIC) - ADD_LIBRARY(${PROJECT_NAME} STATIC ${ui_lib_src}) - ELSE() - ADD_LIBRARY(${PROJECT_NAME} SHARED ${ui_lib_src}) - set_target_properties(${PROJECT_NAME} PROPERTIES VERSION 1.0.0 SOVERSION 1) - ENDIF() - -# ADD_LIBRARY(${PROJECT_NAME} ${ui_lib_src}) -#Set_target_properties(${PROJECT_NAME}_static PROPERTIES output_name chaos_uitoolkit) - - -SET(chaos_uitoolkit_lib $ENV{CHAOS_LINK_LIBRARY}) -separate_arguments(chaos_uitoolkit_lib) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} chaos_common ${chaos_uitoolkit_lib}) - - - -FILE(GLOB files "*.h") -INSTALL(FILES ${files} DESTINATION include/chaos/ui_toolkit) - -FILE(GLOB files "Common/*.h") -INSTALL(FILES ${files} DESTINATION include/chaos/ui_toolkit/Common) - -FILE(GLOB files "HighLevelApi/*.h") -INSTALL(FILES ${files} DESTINATION include/chaos/ui_toolkit/HighLevelApi) - -FILE(GLOB files "LowLevelApi/*.h") -INSTALL(FILES ${files} DESTINATION include/chaos/ui_toolkit/LowLevelApi) - -INSTALL(TARGETS ${PROJECT_NAME} - DESTINATION "lib" - PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) -# INSTALL(TARGETS ${PROJECT_NAME}_static -# DESTINATION "lib" -# PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) diff --git a/chaos/ui_toolkit/ChaosUIToolkit.cpp b/chaos/ui_toolkit/ChaosUIToolkit.cpp deleted file mode 100644 index bb2b1d3b3..000000000 --- a/chaos/ui_toolkit/ChaosUIToolkit.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2012, 2017 INFN - * - * Licensed under the EUPL, Version 1.2 or – as soon they - * will be approved by the European Commission - subsequent - * versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the - * Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in - * writing, software distributed under the Licence is - * distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. - * See the Licence for the specific language governing - * permissions and limitations under the Licence. - */ - -#include <chaos/ui_toolkit/LowLevelApi/LLDataApi.h> -#include <chaos/ui_toolkit/LowLevelApi/LLRpcApi.h> -#include <chaos/ui_toolkit/ChaosUIToolkit.h> - -using namespace std; -using namespace chaos; -using namespace chaos::ui; - -#define UI_LAPP_ LAPP_ << "[UIToolkit] -" -/* - - */ -ChaosUIToolkit::ChaosUIToolkit(){ - clientInstanceUUID = common::utility::UUIDUtil::generateUUIDLite(); -} - -/* - - */ -ChaosUIToolkit::~ChaosUIToolkit(){ - deinit(); -} - - //! C and C++ attribute parser -/*! - Specialized option for startup c and cpp program main options parameter - */ -void ChaosUIToolkit::init(int argc, const char* argv[]) throw (CException) { - ChaosCommon<ChaosUIToolkit>::init(argc, argv); -} - //!stringbuffer parser -/* - specialized option for string stream buffer with boost semantics - */ -void ChaosUIToolkit::init(istringstream &initStringStream) throw (CException) { - ChaosCommon<ChaosUIToolkit>::init(initStringStream); -} - -/* - - */ -void ChaosUIToolkit::init(void *init_data) throw(CException) { - try{ - ChaosCommon<ChaosUIToolkit>::init(init_data); - - UI_LAPP_ << "Init LLRpcApi"; - LLRpcApi::getInstance()->init(); - UI_LAPP_ << "LLRpcApi Initilized"; - UI_LAPP_ << "Initialization terminated"; - } catch (CException& ex) { - DECODE_CHAOS_EXCEPTION(ex) - exit(1); - } -} - -/* - - */ -void ChaosUIToolkit::deinit() throw(CException) { - try{ - UI_LAPP_ << "Deinit HLDataApi"; - HLDataApi::getInstance()->deinit(); - UI_LAPP_ << "HLDataApi deinitilized"; - }catch(...) {} - - try{ - UI_LAPP_ << "Deinit LLRpcApi"; - LLRpcApi::getInstance()->deinit(); - UI_LAPP_ << "LLRpcApi Deinitialized"; - UI_LAPP_ << "Deinitialization terminated"; - }catch(...) {} - - try{ - //forward the deinitialization to the common sublayer - ChaosCommon<ChaosUIToolkit>::deinit(); - }catch(...) {} - -} - - diff --git a/chaos/ui_toolkit/ChaosUIToolkit.h b/chaos/ui_toolkit/ChaosUIToolkit.h deleted file mode 100644 index 9468e6668..000000000 --- a/chaos/ui_toolkit/ChaosUIToolkit.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2012, 2017 INFN - * - * Licensed under the EUPL, Version 1.2 or – as soon they - * will be approved by the European Commission - subsequent - * versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the - * Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in - * writing, software distributed under the Licence is - * distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. - * See the Licence for the specific language governing - * permissions and limitations under the Licence. - */ -#ifndef ChaosFramework_ChaosUIToolkit_h -#define ChaosFramework_ChaosUIToolkit_h - -#include <chaos/common/global.h> -#include <chaos/common/exception/exception.h> -#include <chaos/common/utility/Singleton.h> -#include <chaos/common/data/CDataWrapper.h> -#include <chaos/common/ChaosCommon.h> -#include <chaos/common/utility/Atomic.h> -#include <chaos/ui_toolkit/HighLevelApi/HLDataApi.h> -#include <chaos/ui_toolkit/HighLevelApi/HLInfrastructureApi.h> - -namespace chaos{ - //! Default chaos namespace used to group all ui api - namespace ui{ - - /*! \page page_cuit The Chaos User Interface Toolkit - * \section page_cuit_sec Why an User Interface Toolkit - * - */ - - //! ChaosUIToolkit class is the main singleton needed to use UI chaos API - /*! - Every developer that need to access chaos resource must use this pachecke to - allocate and instantiate other api pachage - */ - class ChaosUIToolkit : public ChaosCommon<ChaosUIToolkit> { - friend class common::utility::Singleton<ChaosUIToolkit>; - /** \brief Client unique id */ - string clientInstanceUUID; - /** \brief point to the class the need to be allert when this UIToolkit must exit*/ - ServerDelegator *serverDelegator; - - //!Constructor - ChaosUIToolkit(); - //!Destructor - ~ChaosUIToolkit(); - public: - //! C and C++ attribute parser - /*! - Specialized option for startup c and cpp program main options parameter - */ - void init(int argc, const char* argv[]) throw (CException); - //!stringbuffer parser - /* - specialized option for string stream buffer with boost semantics - */ - void init(istringstream &initStringStream) throw (CException); - - //!Initializaiton Method - /*! - This method provide at the all API package initialization it must be called only at applciaiton startup - \param argc the argc of main cpp program function - \param argv the argv of main cpp program function - \exception CException instance is created when something goes wrong - */ - void init(void *init_data) throw(CException); - - //!Deinitializaiton Method - /*! - this method provide all the resource deallocation - \exception CException instance is created when something goes wrong - */ - void deinit() throw(CException); - }; - } -} -#endif diff --git a/chaos/ui_toolkit/ChaosUIToolkitCWrapper.cc b/chaos/ui_toolkit/ChaosUIToolkitCWrapper.cc deleted file mode 100644 index 26f0ef616..000000000 --- a/chaos/ui_toolkit/ChaosUIToolkitCWrapper.cc +++ /dev/null @@ -1,512 +0,0 @@ -/* - * Copyright 2012, 2017 INFN - * - * Licensed under the EUPL, Version 1.2 or – as soon they - * will be approved by the European Commission - subsequent - * versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the - * Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in - * writing, software distributed under the Licence is - * distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. - * See the Licence for the specific language governing - * permissions and limitations under the Licence. - */ - -#include <map> -#include <string.h> -#include <memory.h> - -#include <chaos/ui_toolkit/ChaosUIToolkit.h> -#include <chaos/ui_toolkit/LowLevelApi/LLRpcApi.h> -#include <chaos/ui_toolkit/ChaosUIToolkitCWrapper.h> -#include <chaos/ui_toolkit/HighLevelApi/HLDataApi.h> - -#include <chaos/common/additional_lib/base64.h> -#include <chaos/common/data/CDataWrapper.h> - -#include <boost/lexical_cast.hpp> - -using namespace std; -using namespace chaos; -using namespace chaos::ui; - - - -uint32_t sequenceNumber = 0; -std::map<uint32_t, DeviceController *> chanelMap; - -//--------------------------------------------------------------- -inline DeviceController *getDeviceControllerFromID(uint32_t did) { - if(chanelMap.count(did)==0) return NULL; - return chanelMap[did]; -} - -//--------------------------------------------------------------- -inline char * convertStringToCharPtr(const string& orgString) { - char *result = NULL; - if(!orgString.length()) return NULL; - - const char *tmpCStr = orgString.c_str(); - result = (char*)malloc(strlen(tmpCStr)+1); - strcpy(result, tmpCStr); - return result; -} - -extern "C" { - //--------------------------------------------------------------- - int initToolkit(const char* startupParameter) { - int err = 0; - istringstream optionStream; - optionStream.str(startupParameter); - try { - ChaosUIToolkit::getInstance()->init(optionStream); - } catch (CException& e) { - err = e.errorCode; - } - return err; - } - - //--------------------------------------------------------------- - int getNewControllerForDeviceID(const char * const deviceID, uint32_t *devIDPtr) { - int err = 0; - DeviceController *controller = NULL; - try{ - string dID = deviceID; - controller = HLDataApi::getInstance()->getControllerForDeviceID(dID); - if(controller) { - chanelMap.insert(make_pair((*devIDPtr = ++sequenceNumber), controller)); - - //activate the traking - controller->setupTracking(); - } - } catch (CException& e) { - printf("eccezione %s\n",e.what()); - err = e.errorCode; - } - return err; - } - //--------------------------------------------------------------- - int setControllerTimeout(uint32_t devID, uint32_t timeout) { - int err = 0; - DeviceController *controller = NULL; - try{ - controller = getDeviceControllerFromID(devID); - if(controller) { - controller->setRequestTimeWaith(timeout); - } - } catch (CException& e) { - err = e.errorCode; - } - return err; - } - - //--------------------------------------------------------------- - int getDeviceDatasetAttributeNameForDirection(uint32_t devID, int16_t attributeDirection, char***attributeNameArrayHandle, uint32_t *attributeNumberPtr) { - int err = 0; - char **arrayPtr; - uint32_t attributeFound = 0; - vector<string> attributesName; - DataType::DataSetAttributeIOAttribute _attributeDirection = static_cast<DataType::DataSetAttributeIOAttribute>(attributeDirection); - try{ - if(devID) { - DeviceController * ctrl = getDeviceControllerFromID(devID); - if(ctrl){ - //get the name - ctrl->getDeviceDatasetAttributesName(attributesName, _attributeDirection); - - //copy yhe array dimension on function param - *attributeNumberPtr = attributeFound = static_cast<uint32_t>(attributesName.size()); - - //allcoate the memory for the array - *attributeNameArrayHandle = arrayPtr = (char**)malloc(attributeFound * sizeof(char*)); - - //scann all name and allocate the string - for (int idx = 0 ; idx < attributeFound; idx++) { - string curName = attributesName[idx]; - - //create and copy the attribute name into appropiate index - arrayPtr[idx] = (char*)malloc(strlen(curName.c_str()) * sizeof(char) + 1); - - //copy the string - strcpy(arrayPtr[idx], curName.c_str()); - } - }else{ - err = -1001; - } - } else { - err = -1000; - } - } catch (CException& e) { - err = e.errorCode; - } - return err; - - } - - //--------------------------------------------------------------- - int initDevice(uint32_t devID) { - int err = 0; - try{ - if(devID) { - DeviceController * ctrl = getDeviceControllerFromID(devID); - if(ctrl){ - err = ctrl->initDevice(); - }else{ - err = -1001; - } - } else { - err = -1000; - } - } catch (CException& e) { - err = e.errorCode; - } - return err; - } - - //--------------------------------------------------------------- - int startDevice(uint32_t devID) { - int err = 0; - try{ - if(devID) { - DeviceController * ctrl = getDeviceControllerFromID(devID); - if(ctrl){ - err = ctrl->startDevice(); - }else{ - err = -1001; - } - } else { - err = -1000; - } - } catch (CException& e) { - err = e.errorCode; - } - return err; - } - - //--------------------------------------------------------------- - int setDeviceRunScheduleDelay(uint32_t devID, int32_t delayTimeInMilliseconds) { - int err = 0; - try{ - if(devID) { - DeviceController * ctrl = getDeviceControllerFromID(devID); - if(ctrl){ - err = ctrl->setScheduleDelay(delayTimeInMilliseconds); - }else{ - err = -1001; - } - } else { - err = -1000; - } - } catch (CException& e) { - err = e.errorCode; - } - return err; - } - - //--------------------------------------------------------------- - int stopDevice(uint32_t devID) { - int err = 0; - try{ - if(devID) { - DeviceController * ctrl = getDeviceControllerFromID(devID); - if(ctrl){ - err = ctrl->stopDevice(); - }else{ - err = -1001; - } - } else { - err = -1000; - } - } catch (CException& e) { - err = e.errorCode; - } - return err; - } - - //--------------------------------------------------------------- - int deinitDevice(uint32_t devID) { - int err = 0; - try{ - if(devID) { - DeviceController * ctrl = getDeviceControllerFromID(devID); - if(ctrl){ - err = ctrl->deinitDevice(); - }else{ - err = -1001; - } - } else { - err = -1000; - } - } catch (CException& e) { - err = e.errorCode; - } - return err; - } - - //--------------------------------------------------------------- - int fetchLiveData(uint32_t devID) { - int err = 0; - try{ - if(devID) { - DeviceController * ctrl = getDeviceControllerFromID(devID); - if(ctrl){ - ctrl->fetchCurrentDeviceValue(); - }else{ - err = -1001; - } - } else { - err = -1000; - } - } catch (CException& e) { - err = e.errorCode; - } - return err; - } - - - //--------------------------------------------------------------- - int fetchLiveDatasetByDomain(uint32_t devID, - int16_t domain_type) { - int err = 0; - try{ - if(devID) { - DeviceController * ctrl = getDeviceControllerFromID(devID); - if(ctrl){ - if(domain_type >= 0 && - domain_type <= DatasetDomainSystem) { - ctrl->fetchCurrentDatatasetFromDomain((DatasetDomain)domain_type); - }else { - err = -1002; - } - }else{ - err = -1001; - } - } else { - err = -1000; - } - } catch (CException& e) { - err = e.errorCode; - } - return err; - } - - //--------------------------------------------------------------- - int getJSONDescriptionForDataset(uint32_t devID, - int16_t domain_type, - char ** json_dataset_handler) { - int err = 0; - try{ - if(devID) { - DeviceController * ctrl = getDeviceControllerFromID(devID); - if(ctrl){ - if(domain_type >= 0 && - domain_type <= DatasetDomainSystem) { - chaos::common::data::CDataWrapper *dataset = ctrl->getCurrentDatasetForDomain((DatasetDomain)domain_type); - if(dataset) { - //aloocate and copy cstring - *json_dataset_handler = convertStringToCharPtr(dataset->getJSONString()); - } else { - *json_dataset_handler = NULL; - err = -1003; - } - - }else { - err = -1002; - } - }else{ - err = -1001; - } - } else { - err = -1000; - } - } catch (CException& e) { - err = e.errorCode; - } - return err; - - } - - //--------------------------------------------------------------- - int getTimeStamp(uint32_t devID,uint64_t*ts){ - DeviceController *dCtrl = getDeviceControllerFromID(devID); - if(dCtrl){ - return dCtrl->getTimeStamp(*ts); - } - return -1; - } - - //--------------------------------------------------------------- - int getStrValueForAttribute(uint32_t devID, const char * const dsAttrName, char ** dsAttrValueHandle) { - int err = 0; - string tmpString; - try{ - DeviceController *dCtrl = getDeviceControllerFromID(devID); - if(dCtrl && dsAttrName && dsAttrValueHandle) { - chaos::common::data::CDataWrapper * dataWrapper = ((DeviceController*)dCtrl)->getCurrentDatasetForDomain(DatasetDomainOutput); - if(dataWrapper) { - if(dataWrapper->hasKey(dsAttrName)){ - DataType::DataType attributeType; - string attributesName = dsAttrName; - err = ((DeviceController*)dCtrl)->getDeviceAttributeType(attributesName, attributeType); - if(err == 0){ - switch (attributeType) { - case DataType::TYPE_INT64: - tmpString = boost::lexical_cast<string>(dataWrapper->getInt64Value(dsAttrName)); - *dsAttrValueHandle = convertStringToCharPtr(tmpString); - break; - - case DataType::TYPE_INT32: - tmpString = boost::lexical_cast<string>(dataWrapper->getInt64Value(dsAttrName)); - *dsAttrValueHandle = convertStringToCharPtr(tmpString); - break; - - case DataType::TYPE_DOUBLE: - tmpString = boost::lexical_cast<string>(dataWrapper->getDoubleValue(dsAttrName)); - *dsAttrValueHandle = convertStringToCharPtr(tmpString); - break; - - case DataType::TYPE_STRING: - tmpString = boost::lexical_cast<string>(dataWrapper->getStringValue(dsAttrName)); - *dsAttrValueHandle = convertStringToCharPtr(tmpString); - break; - - case DataType::TYPE_BOOLEAN: - tmpString = dataWrapper->getBoolValue(dsAttrName)?"true":"false"; - *dsAttrValueHandle = convertStringToCharPtr(tmpString); - break; - - case DataType::TYPE_BYTEARRAY: - uint32_t len; - std::string binary_field; - const char * base_addr = dataWrapper->getBinaryValue(dsAttrName, len); - binary_field = base64_encode((unsigned char const*)base_addr , len ); - *dsAttrValueHandle = convertStringToCharPtr(binary_field.c_str()); - break; - } - } else { - err = -1003; - } - } else { - err = -1002; - } - } else { - err = -1001; - } - } else { - err = -1000; - } - } catch (CException& e) { - err = e.errorCode; - } - return err; - } - - //--------------------------------------------------------------- - int getStrValueForAttr(uint32_t devID, const char * const dsAttrName, char * dsAttrValueHandle){ - char *pntS=0; - int ret; - ret=getStrValueForAttribute( devID, dsAttrName, &pntS); - if(dsAttrValueHandle && pntS){ - strcpy(dsAttrValueHandle,pntS); - free(pntS); - } else { - ret =-1; - } - return ret; - } - - - //--------------------------------------------------------------- - int setStrValueForAttribute(uint32_t devID, const char * const dsAttrName, const char * const dsAttrValueCStr) { - int err = 0; - string attributeName = dsAttrName; - DeviceController *dCtrl = getDeviceControllerFromID(devID); - if(dCtrl && dsAttrName && dsAttrValueCStr) { - //changed to use the new api - err = dCtrl->setAttributeToValue(dsAttrName, dsAttrValueCStr, false); - } else { - err = -1001; - } - return err; - } - - //--------------------------------------------------------------- - int submitSlowControlCommand(uint32_t dev_id, - const char * const command_alias, - uint16_t submissione_rule, - uint32_t priority, - uint64_t *command_id, - uint32_t scheduler_steps_delay, - uint32_t submission_checker_steps_delay, - const char * const slow_command_data) { - int err = 0; - uint64_t cmd_id_tmp; - DeviceController *dCtrl = getDeviceControllerFromID(dev_id); - if(dCtrl && command_alias) { - //changed to use the new api - ChaosUniquePtr<chaos::common::data::CDataWrapper> data_wrapper; - - std::string cmd_alias_str = command_alias; - if(slow_command_data) { - data_wrapper.reset(new chaos::common::data::CDataWrapper()); - if(data_wrapper.get()) - data_wrapper->setSerializedJsonData(slow_command_data); - else - return -1001; - } - - err = dCtrl->submitSlowControlCommand(cmd_alias_str, - static_cast<chaos::common::batch_command::SubmissionRuleType::SubmissionRule>(submissione_rule), - priority, - cmd_id_tmp, - 0, - scheduler_steps_delay, - submission_checker_steps_delay, - data_wrapper.get()); - if(!err && command_id) { - *command_id = cmd_id_tmp; - } - } else { - err = -1002; - } - return err; - } - - //--------------------------------------------------------------- - int deinitController(uint32_t devID) { - int err = 0; - try{ - if(devID) { - DeviceController * ctrl = getDeviceControllerFromID(devID); - if(ctrl){ - HLDataApi::getInstance()->disposeDeviceControllerPtr(ctrl); - }else{ - err = -1001; - } - } else { - err = -1000; - } - } catch (CException& e) { - err = e.errorCode; - } - return err; - } - - //--------------------------------------------------------------- - int deinitToolkit() { - int err = 0; - try{ - ChaosUIToolkit::getInstance()->deinit(); - } catch (CException& e) { - err = e.errorCode; - } - return err; - } -} diff --git a/chaos/ui_toolkit/ChaosUIToolkitCWrapper.h b/chaos/ui_toolkit/ChaosUIToolkitCWrapper.h deleted file mode 100644 index bcf6bbbfc..000000000 --- a/chaos/ui_toolkit/ChaosUIToolkitCWrapper.h +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright 2012, 2017 INFN - * - * Licensed under the EUPL, Version 1.2 or – as soon they - * will be approved by the European Commission - subsequent - * versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the - * Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in - * writing, software distributed under the Licence is - * distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. - * See the Licence for the specific language governing - * permissions and limitations under the Licence. - */ - -/*! \file ChaosUIToolkitCWrapper*/ - -/*! \page page_uicwrapper The Chaos "C Wrapper" for User Interface Toolkit - * \section page_cuit_sec Why an a "C" language wrapper? - * Some applications used in scentific experiment (as for example LabView) can be - * can be customized with the use of shared library written in "C" language. At this - * scope, !CHAOS give a simple interface to a DeviceController managed by user interface - * toolkit \link UIToolkitCWrapper wrapped with few simple "C" function\endlink. - */ - -/** @defgroup UIToolkitCWrapper "C" language interface to user interface toolkit - * These are the funciton to be used with the "C" language to use cpp UIToolkit library. - * The library to be linked is the same as the cpp language, libchoas_uitoolkit - * @{ - */ - -#ifndef CHAOSFramework_UIToolkitCWrapper_h -#define CHAOSFramework_UIToolkitCWrapper_h - -#include <stdint.h> -#ifdef LABVIEW -// labview unable to parse stdint -typedef unsigned long uint32_t; -typedef int int32_t; - -typedef unsigned short uint16_t; -typedef short int16_t; -typedef unsigned long long uint64_t; -#endif -#ifdef __cplusplus -extern "C" { -#endif - - - //! User interface toolkit initialization - /*! - Perform the user interface toolkit initialization, the startup parameter are the same of the complied - !CHAOS application. For example: --log-on-console is setupped with the string - "log-on-console=true" and for example "--metadata-server=host:5000" is "metadata-server=host:5000" - \param startupParameter the startup initialization string queal to the norma launch program - \return the error of operation, if all goes well the result is 0 - */ - int initToolkit(const char* startupParameter); - - //! Device Controller creation - /*! - Create an instance of the controller for a device. The function return the DeviceControl ID that - need to be used in other funtion. - \param deviceID is the unique string identification for a device. - \param devIDPtr is ap ointer toan unsigned int32 used for return the id for the create channel - \return the error of operation, if all goes well the result is 0 - */ - int getNewControllerForDeviceID(const char * const deviceID, uint32_t *devIDPtr); - - int setControllerTimeout(uint32_t devID, uint32_t timeout); - - //! Get device attribute names - /*! - Retrive the device attributes name giving a device identification string and a a direction. - \param deviceID is the unique string identification for a device. - \param attributeDirection can be one of these value: - - 0 -> input - - 1 -> output - - 2 -> bidirectional - \param attributeNameArrayPtr isthe handle to an array of "c" string - \param attributeNumber a pointer to an interger that will be filled - with the number for attribute names found - \return the error of operation, if all goes well the result is 0 - */ - int getDeviceDatasetAttributeNameForDirection(uint32_t devID, int16_t attributeDirection, char***attributeNameArrayHandle, uint32_t *attributeNumberPtr); - - //! Device initialization - /*! - Perform the initialization of the device, using the setup specified in the metadataserver - \param devID is the identification number got from \link getNewControllerForDeviceID \endlink function - \return the error of operation, if all goes well the result is 0 - */ - int initDevice(uint32_t devID); - - //! Startup the device - /*! - Perform the startup of the device - \param devID is the identification number got from \link getNewControllerForDeviceID \endlink function - \return the error of operation, if all goes well the result is 0 - */ - int startDevice(uint32_t devID); - - //! Setup of the run method delay - /*! - Setup of the delay of the run method schedule - \param devID is the identification number got from \link getNewControllerForDeviceID \endlink function - \param delayTimeInMilliseconds the number of millisecond between lat run method execution - \return the error of operation, if all goes well the result is 0 - */ - int setDeviceRunScheduleDelay(uint32_t devID, int32_t delayTimeInMilliseconds); - - //! Stop the device - /*! - Perform the interruption of the run method scehduling without deinitlize the control unit - \param devID is the identification number got from \link getNewControllerForDeviceID \endlink function - \return the error of operation, if all goes well the result is 0 - */ - int stopDevice(uint32_t devID); - - //! Deinit the device - /*! - Perform the deinitialization of the control unit - \param devID is the identification number got from \link getNewControllerForDeviceID \endlink function - \return the error of operation, if all goes well the result is 0 - */ - int deinitDevice(uint32_t devID); - - //! Fetch the device live data - /*! - Perform the update of device control internal live data cache - \param devID is the identification number got from \link getNewControllerForDeviceID \endlink function - \return the error of operation, if all goes well the result is 0 - */ - int fetchLiveData(uint32_t devID); - - //! fetch the live data for the required dataset - /*! - \param domain_type is the the domain the need to be fetched from the chaos - data chache: 0=DatasetDomainOutput, 1=DatasetDomainInput, 2=DatasetDomainCustom, 3=DatasetDomainSystem - */ - int fetchLiveDatasetByDomain(uint32_t devID, - int16_t domain_type); - - //! return the json representation of the dataset of the needed domain - /*! - the json representation is got form the latest live dataaset for the domain updated by the - last call to the fetchLiveDatasetByDomain api. - */ - int getJSONDescriptionForDataset(uint32_t devID, - int16_t domain_type, - char ** json_dataset_handler); - - //! Return a string represetnation of an attribute value - /*! - Return the stirng representation of an attribute value. The current attribute value is keept from the - device control interna cache, that is filled with \link fetchLiveData \endlink - \param devID is the identification number got from \link getNewControllerForDeviceID \endlink function - \param dsAttrName the name of the attribute - \param dsAttrValueHandle the handle to c string that will contain the attribute value - \return the error of operation, if all goes well the result is 0 - */ - int getStrValueForAttribute(uint32_t devID, const char * const dsAttrName, char ** dsAttrValueHandle); - - /*! - Return the stirng representation of an attribute value. The current attribute value is keept from the - device control interna cache, that is filled with \link fetchLiveData \endlink - \param devID is the identification number got from \link getNewControllerForDeviceID \endlink function - \param dsAttrName the name of the attribute - \param dsAttrValue a pointer to preallocated c string that will contain the attribute value - \return the error of operation, if all goes well the result is 0 - */ - int getStrValueForAttr(uint32_t devID, const char * const dsAttrName, char * dsAttrValue); - - //! Set the value for an attribute - /*! - Set an attribute value using a string reprpesentation for the new value to use. - \param devID is the identification number got from \link getNewControllerForDeviceID \endlink function - \param dsAttrName the name of the attribute - \param dsAttrValueCStr the "c" string representing the attribute value - \return the error of operation, if all goes well the result is 0 - */ - int setStrValueForAttribute(uint32_t devID, const char * const dsAttrName, const char * const dsAttrValueCStr); - - int getTimeStamp(uint32_t devID,uint64_t*ts); - //! Submit a new slow command - /*! - \ingroup API_Slow_Control - The submition of slow command is made collection all the information that permit to submit it - \param dev_id is the identification number got from \link getNewControllerForDeviceID \endlink function - \param command_alias represent the alias of the command the the control unit expost from RPC subsystem - \param submissione_rule determinate the rule with which the command is submitted. @SubmissionRuleType::SubmissionRule - \param command_id is the assigned command id to the submitted one - the execution of the current execution command in the control unit, according with his running state - \param scheduler_steps_delay rapresent the intervall beetween the step of the scehduler [...acquisition -> correlation -> scheduleInterval...] - \param submission_checker_steps_delay is the delay between two steps of the submission checker - \param slow_command_data is the abstraction of the command data that is passed to the set handler befor the scheduler loop of the new command - take palce. The memory of that parameter is not free - */ -/*#ifdef __cplusplus - int submitSlowControlCommand(uint32_t dev_id, - const char * const command_alias, - uint16_t submissione_rule, - uint32_t priority, - uint64_t *command_id, - uint32_t scheduler_steps_delay = 0, - uint32_t submission_checker_steps_delay = 0, - const char * const slow_command_data = NULL); -#else*/ - int submitSlowControlCommand(uint32_t dev_id, - const char * const command_alias, - uint16_t submissione_rule, - uint32_t priority, - uint64_t *command_id, - uint32_t scheduler_steps_delay , - uint32_t submission_checker_steps_delay , - const char * const slow_command_data ); - -//#endif - //! Device Control deinitialization - /*! - Perform deinitialization of a device control associated to an id - \param devID is the identification number got from \link getNewControllerForDeviceID \endlink function - \return the error of operation, if all goes well the result is 0 - */ - int deinitController(uint32_t devID); - - //! UiToolkit deinitialization - /*! - Perform the deinitialization of UIToolkit - \return the error of operation, if all goes well the result is 0 - */ - int deinitToolkit(); -#ifdef __cplusplus -} -#endif - - /** @} */ // end of UIToolkitCWrapper -#endif diff --git a/chaos/ui_toolkit/HighLevelApi/DeviceController.cpp b/chaos/ui_toolkit/HighLevelApi/DeviceController.cpp deleted file mode 100644 index 4d2cbb4aa..000000000 --- a/chaos/ui_toolkit/HighLevelApi/DeviceController.cpp +++ /dev/null @@ -1,1065 +0,0 @@ -/* - * Copyright 2012, 2017 INFN - * - * Licensed under the EUPL, Version 1.2 or – as soon they - * will be approved by the European Commission - subsequent - * versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the - * Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in - * writing, software distributed under the Licence is - * distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. - * See the Licence for the specific language governing - * permissions and limitations under the Licence. - */ - -#include "DeviceController.h" -#include <chaos/common/chaos_constants.h> -#include <chaos/common/data/CDataWrapper.h> -#include <chaos/ui_toolkit/LowLevelApi/LLRpcApi.h> -#include <boost/lexical_cast.hpp> - -using namespace std; -using namespace chaos; -using namespace chaos::ui; -using namespace chaos::common::io; -using namespace chaos::common::data; -using namespace chaos::common::utility; -using namespace chaos::common::message; -using namespace chaos::common::batch_command; - - - -//--------------------------------------------------------------------------------------------------- -DeviceController::DeviceController(string& _deviceID): -device_id(_deviceID), -datasetDB(true) { - - const ChaosUniquePtr<chaos::common::data::CDataWrapper> d; - mdsChannel = NULL; - deviceChannel = NULL; - ioLiveDataDriver = NULL; - millisecToWait = RpcConfigurationKey::GlobalRPCTimeoutinMSec; - channel_keys.push_back(device_id + DataPackPrefixID::OUTPUT_DATASET_POSTFIX); - channel_keys.push_back(device_id + DataPackPrefixID::INPUT_DATASET_POSTFIX); - channel_keys.push_back(device_id + DataPackPrefixID::CUSTOM_DATASET_POSTFIX); - channel_keys.push_back(device_id + DataPackPrefixID::SYSTEM_DATASET_POSTFIX); - channel_keys.push_back(device_id + DataPackPrefixID::DEV_ALARM_DATASET_POSTFIX); - channel_keys.push_back(device_id + DataPackPrefixID::CU_ALARM_DATASET_POSTFIX); - channel_keys.push_back(device_id + DataPackPrefixID::HEALTH_DATASET_POSTFIX); - - // current_dataset.push_back(d); - for(int cnt=0;cnt<channel_keys.size();cnt++) - current_dataset.push_back(ChaosSharedPtr<chaos::common::data::CDataWrapper>()); - - - //allocate device channel the memory of the CDeviceNetworkAddress * is managed by channel - CDeviceNetworkAddress *address = new CDeviceNetworkAddress(_deviceID); - //get a new message channel in a self manage way - deviceChannel = LLRpcApi::getInstance()->getNewDeviceMessageChannel(address, - true); - if(!deviceChannel) throw CException(-4, "Invalid device channel created", "DeviceController::init"); -} - -//--------------------------------------------------------------------------------------------------- -DeviceController::~DeviceController() { - LDBG_<<"["<<__PRETTY_FUNCTION__<<"] remove Device Controller:"<<device_id; - stopTracking(); - - if(mdsChannel){ - LLRpcApi::getInstance()->deleteMessageChannel(mdsChannel); - } - - - if(deviceChannel){ - LLRpcApi::getInstance()->deleteMessageChannel(deviceChannel); - - } - - if(ioLiveDataDriver){ - ioLiveDataDriver->deinit(); - delete(ioLiveDataDriver); - } -} - -//--------------------------------------------------------------------------------------------------- -void DeviceController::setRequestTimeWaith(uint32_t newMillisecToWait){ - millisecToWait = newMillisecToWait; -} - -//--------------------------------------------------------------------------------------------------- -uint32_t DeviceController::getRequestTimeWaith(){ - return millisecToWait; -} - -//--------------------------------------------------------------------------------------------------- -void DeviceController::getDeviceId(string& dId) { - dId = device_id; -} - -//--------------------------------------------------------------------------------------------------- -void DeviceController::updateChannel() throw(CException) { - int err = ErrorCode::EC_NO_ERROR; - CDataWrapper *tmp_data_handler = NULL; - CDeviceNetworkAddress *devAddress = NULL; - //make the live driver - if(!mdsChannel){ - mdsChannel = LLRpcApi::getInstance()->getNewMetadataServerChannel(); - if(!mdsChannel) throw CException(-1, "No MDS Channel created", "DeviceController::init"); - } - - err = mdsChannel->getLastDatasetForDevice(device_id, &tmp_data_handler, millisecToWait); - if(err!=ErrorCode::EC_NO_ERROR || !tmp_data_handler) throw CException(-2, "No device dataset received", "DeviceController::updateChannel"); - - ChaosUniquePtr<chaos::common::data::CDataWrapper> lastDeviceDefinition(tmp_data_handler); - - datasetDB.addAttributeToDataSetFromDataWrapper(*lastDeviceDefinition.get()); - - err = mdsChannel->getNetworkAddressForDevice(device_id, &devAddress, millisecToWait); - if(err!=ErrorCode::EC_NO_ERROR || !devAddress) throw CException(-3, "No Address found for device", "DeviceController::init"); - - //update live data driver - if(!ioLiveDataDriver) { - ioLiveDataDriver = LLRpcApi::getInstance()->getDataProxyChannelNewInstance(); - if(ioLiveDataDriver) { - ioLiveDataDriver->init(NULL); - if(!mdsChannel->getDataDriverBestConfiguration(&tmp_data_handler, millisecToWait)){ - ChaosUniquePtr<chaos::common::data::CDataWrapper> best_available_da_ptr(tmp_data_handler); - ioLiveDataDriver->updateConfiguration(best_available_da_ptr.get()); - } - } - } -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::setScheduleDelay(uint64_t microseconds) { - CHAOS_ASSERT(deviceChannel) - return deviceChannel->setScheduleDelay(microseconds, millisecToWait); -} - -//--------------------------------------------------------------------------------------------------- -void DeviceController::getDeviceDatasetAttributesName(vector<string>& attributesName) { - datasetDB.getDatasetAttributesName(attributesName); -} - -//--------------------------------------------------------------------------------------------------- -void DeviceController::getAttributeDescription(const string& attributesName, string& attributeDescription) { - datasetDB.getAttributeDescription(attributesName, attributeDescription); -} - -//--------------------------------------------------------------------------------------------------- -void DeviceController::getDeviceDatasetAttributesName(vector<string>& attributesName, DataType::DataSetAttributeIOAttribute directionType) { - datasetDB.getDatasetAttributesName(directionType, attributesName); -} - -//--------------------------------------------------------------------------------------------------- -void DeviceController::getDeviceAttributeRangeValueInfo(const string& attributesName, chaos::common::data::RangeValueInfo& rangeInfo) { - datasetDB.getAttributeRangeValueInfo(attributesName, rangeInfo); -} -//--------------------------------------------------------------------------------------------------- -int DeviceController::getDeviceAttributeDirection(const string& attributesName, DataType::DataSetAttributeIOAttribute& directionType) { - return datasetDB.getAttributeDirection(attributesName, directionType); -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::getAttributeStrValue(string attribute_name, string& attribute_value) { - int err = 0; - CDataWrapper * dataWrapper = getLiveCDataWrapperPtr(); - if(dataWrapper) { - DataType::DataType attributeType; - err = getDeviceAttributeType(attribute_name, attributeType); - if(err == 0){ - switch (attributeType) { - case DataType::TYPE_INT64: - attribute_value = boost::lexical_cast<string>(dataWrapper->getInt64Value(attribute_name.c_str())); - break; - - case DataType::TYPE_INT32: - attribute_value = boost::lexical_cast<string>(dataWrapper->getInt64Value(attribute_name.c_str())); - break; - - case DataType::TYPE_DOUBLE: - attribute_value = boost::lexical_cast<string>(dataWrapper->getDoubleValue(attribute_name.c_str())); - break; - - case DataType::TYPE_CLUSTER: - case DataType::TYPE_STRING: - attribute_value = boost::lexical_cast<string>(dataWrapper->getStringValue(attribute_name.c_str())); - break; - - case DataType::TYPE_BOOLEAN: - attribute_value = boost::lexical_cast<string>(dataWrapper->getBoolValue(attribute_name.c_str())); - break; - - case DataType::TYPE_BYTEARRAY: { - const char *buffer = NULL; - uint32_t size; - buffer = dataWrapper->getBinaryValue(attribute_name.c_str(), size); - if(buffer) attribute_value.assign(buffer, size); - break; - } - - default: - err = -1; - break; - } - } - - } - return err; -} -//--------------------------------------------------------------------------------------------------- -int DeviceController::getDeviceAttributeType(const string& attr, DataType::DataType& type) { - int err = 0; - if(attributeValueMap.count(attr)){ - type = attributeValueMap[attr].valueType; - } else { - err = -1; - } - return err; -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::getType(std::string& control_unit_type) { - int err = 0; - if(cu_type.empty()) { - CDataWrapper*tmp=fetchCurrentDatatasetFromDomain(DatasetDomainSystem); - if(tmp && tmp->hasKey(DataPackSystemKey::DP_SYS_UNIT_TYPE)){ - std::string t=tmp->getCStringValue(DataPackSystemKey::DP_SYS_UNIT_TYPE); - cu_type = t; - } else { - return -1; - } - - } - control_unit_type = cu_type; - - return err; -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::initDevice() { - CHAOS_ASSERT(mdsChannel && deviceChannel) - int err = 0; - CDataWrapper initConf; - datasetDB.fillDataWrapperWithDataSetDescription(initConf); - - //initialize the devica with the metadataserver data - err = deviceChannel->initDevice(&initConf, millisecToWait); - //configure the live data with the same server where the device write - return err; -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::startDevice() { - CHAOS_ASSERT(deviceChannel) - return deviceChannel->startDevice(millisecToWait); -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::stopDevice() { - CHAOS_ASSERT(deviceChannel) - return deviceChannel->stopDevice(millisecToWait); -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::deinitDevice() { - CHAOS_ASSERT(deviceChannel) - return deviceChannel->deinitDevice(millisecToWait); -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::restoreDeviceToTag(const std::string& restore_tag) { - CHAOS_ASSERT(deviceChannel) - return deviceChannel->restoreDeviceToTag(restore_tag, - millisecToWait); -} -int DeviceController::recoverDeviceFromError() { - CHAOS_ASSERT(deviceChannel) - return deviceChannel->recoverDeviceFromError(millisecToWait); -} -//--------------------------------------------------------------------------------------------------- -uint64_t DeviceController::getState(CUStateKey::ControlUnitState& deviceState) { - uint64_t ret=0; - CDataWrapper*tmp=fetchCurrentDatatasetFromDomain(DatasetDomainHealth); - deviceState=CUStateKey::UNDEFINED; - if(tmp && tmp->hasKey(NodeHealtDefinitionKey::NODE_HEALT_STATUS)){ - std::string state=tmp->getCStringValue(NodeHealtDefinitionKey::NODE_HEALT_STATUS); - if((state== NodeHealtDefinitionValue::NODE_HEALT_STATUS_START) || (state== NodeHealtDefinitionValue::NODE_HEALT_STATUS_STARTING)) - deviceState=CUStateKey::START; - else if((state== NodeHealtDefinitionValue::NODE_HEALT_STATUS_STOP) || (state== NodeHealtDefinitionValue::NODE_HEALT_STATUS_STOPING)) - deviceState= CUStateKey::STOP; - else if((state== NodeHealtDefinitionValue::NODE_HEALT_STATUS_INIT) || (state== NodeHealtDefinitionValue::NODE_HEALT_STATUS_INITING)) - deviceState= CUStateKey::INIT; - else if((state== NodeHealtDefinitionValue::NODE_HEALT_STATUS_DEINIT) || (state== NodeHealtDefinitionValue::NODE_HEALT_STATUS_DEINITING)|| (state== NodeHealtDefinitionValue::NODE_HEALT_STATUS_LOAD)) - deviceState= CUStateKey::DEINIT; - else if((state== NodeHealtDefinitionValue::NODE_HEALT_STATUS_RERROR)) - deviceState= CUStateKey::RECOVERABLE_ERROR; - else if((state== NodeHealtDefinitionValue::NODE_HEALT_STATUS_FERROR)) - deviceState= CUStateKey::FATAL_ERROR; - - if(tmp->hasKey(NodeHealtDefinitionKey::NODE_HEALT_TIMESTAMP)){ - ret = tmp->getInt64Value(NodeHealtDefinitionKey::NODE_HEALT_TIMESTAMP); - } - } - return ret; -} - -int DeviceController::getChannelsNum(){ - return channel_keys.size(); -} -//--------------------------------------------------------------------------------------------------- -int DeviceController::setAttributeValue(string& attributeName, int32_t attributeValue) { - return setAttributeValue(attributeName.c_str(), attributeValue); -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::setAttributeValue(const char *attributeName, int32_t attributeValue) { - CDataWrapper attributeValuePack; - attributeValuePack.addInt32Value(attributeName, attributeValue); - return deviceChannel->setAttributeValue(attributeValuePack, millisecToWait); -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::setAttributeValue(string& attributeName, double attributeValue) { - return setAttributeValue(attributeName.c_str(), attributeValue); -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::setAttributeValue(const char *attributeName, double attributeValue) { - CDataWrapper attributeValuePack; - attributeValuePack.addDoubleValue(attributeName, attributeValue); - return deviceChannel->setAttributeValue(attributeValuePack, millisecToWait); -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::setAttributeToValue(const char *attributeName, const char *attributeValue, bool noWait) { - int err = ErrorCode::EC_NO_ERROR; - CDataWrapper attributeValuePack; - RangeValueInfo range_info; - - //get type for the value - if((err = datasetDB.getAttributeRangeValueInfo(attributeName, range_info))) - return err; - - switch (range_info.valueType) { - case DataType::TYPE_BOOLEAN: { - bool boolValuePtr = lexical_cast<bool>(attributeValue); - attributeValuePack.addBoolValue(attributeName, boolValuePtr); - break; - } - case DataType::TYPE_CLUSTER: - attributeValuePack.addJsonValue(attributeName, attributeValue); - break; - - - case DataType::TYPE_STRING:{ - attributeValuePack.addStringValue(attributeName, attributeValue); - break; - } - case DataType::TYPE_DOUBLE:{ - double doubleValuePtr = lexical_cast<double>(attributeValue); - attributeValuePack.addDoubleValue(attributeName, doubleValuePtr); - break; - } - case DataType::TYPE_INT32:{ - int32_t i32ValuePtr = lexical_cast<int32_t>(attributeValue); - attributeValuePack.addInt32Value(attributeName, i32ValuePtr); - break; - } - case DataType::TYPE_INT64:{ - int64_t i64ValuePtr = lexical_cast<int64_t>(attributeValue); - attributeValuePack.addInt64Value(attributeName, i64ValuePtr); - break; - } - case DataType::TYPE_BYTEARRAY:{ - //const char *byteArrayValuePtr = static_cast<const char*>(attributeValue); - //attributeValuePack.addBinaryValue(attributeName, byteArrayValuePtr, bufferValuedDim); - throw CException(1, "The byte array set is not managed", "DeviceController::setAttributeToValue"); - break; - } - } - return deviceChannel->setAttributeValue(attributeValuePack, noWait, millisecToWait); -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::setAttributeToValue(const char *attributeName, void *attributeValue, bool noWait, int32_t bufferValuedDim) { - RangeValueInfo range_info; - - //get type for the value - datasetDB.getAttributeRangeValueInfo(attributeName, range_info); - - //call default API - return setAttributeToValue(attributeName, range_info.valueType, attributeValue, noWait, bufferValuedDim); -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::setAttributeToValue(const char *attributeName, DataType::DataType attributeType, void *attributeValue, bool noWait, int32_t bufferValuedDim) { - CDataWrapper attributeValuePack; - switch (attributeType) { - case DataType::TYPE_BOOLEAN: { - bool *boolValuePtr = static_cast<bool *>(attributeValue); - attributeValuePack.addBoolValue(attributeName, *boolValuePtr); - break; - } - case DataType::TYPE_CLUSTER:{ - - attributeValuePack.addJsonValue(attributeName,static_cast<const char *>(attributeValue)); - break; - } - case DataType::TYPE_STRING:{ - const char *strValuePtr = static_cast<const char *>(attributeValue); - attributeValuePack.addStringValue(attributeName, strValuePtr); - break; - } - case DataType::TYPE_DOUBLE:{ - double *doubleValuePtr = static_cast<double*>(attributeValue); - attributeValuePack.addDoubleValue(attributeName, *doubleValuePtr); - break; - } - case DataType::TYPE_INT32:{ - int32_t *i32ValuePtr = static_cast<int32_t*>(attributeValue); - attributeValuePack.addInt32Value(attributeName, *i32ValuePtr); - break; - } - case DataType::TYPE_INT64:{ - int64_t *i64ValuePtr = static_cast<int64_t*>(attributeValue); - attributeValuePack.addInt64Value(attributeName, *i64ValuePtr); - break; - } - case DataType::TYPE_BYTEARRAY:{ - const char *byteArrayValuePtr = static_cast<const char*>(attributeValue); - attributeValuePack.addBinaryValue(attributeName, byteArrayValuePtr, bufferValuedDim); - break; - } - } - return deviceChannel->setAttributeValue(attributeValuePack, noWait, millisecToWait); -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::submitSlowControlCommand(string commandAlias, - SubmissionRuleType::SubmissionRule submissionRule, - uint32_t priority, - uint64_t& command_id, - uint32_t execution_channel, - uint64_t scheduler_steps_delay, - uint32_t submission_checker_steps_delay, - CDataWrapper *slow_command_data) { - CDataWrapper local_command_pack; - CDataWrapper *result_data = NULL; - int err = ErrorCode::EC_NO_ERROR; - - if(slow_command_data) { - local_command_pack.appendAllElement(*slow_command_data); - } - - // set the default slow command information - local_command_pack.addStringValue(BatchCommandAndParameterDescriptionkey::BC_ALIAS, commandAlias); - local_command_pack.addInt32Value(BatchCommandSubmissionKey::SUBMISSION_RULE_UI32, (uint32_t) submissionRule); - local_command_pack.addInt32Value(BatchCommandSubmissionKey::SUBMISSION_PRIORITY_UI32, (uint32_t) priority); - - if(execution_channel) local_command_pack.addInt32Value(BatchCommandSubmissionKey::COMMAND_EXECUTION_CHANNEL, (uint32_t) execution_channel); - if(scheduler_steps_delay) local_command_pack.addInt64Value(BatchCommandSubmissionKey::SCHEDULER_STEP_TIME_INTERVALL_UI64, scheduler_steps_delay); - if(submission_checker_steps_delay) local_command_pack.addInt32Value(BatchCommandSubmissionKey::SUBMISSION_RETRY_DELAY_UI32, submission_checker_steps_delay); - - //err = deviceChannel->setAttributeValue(local_command_pack, false, millisecToWait); - local_command_pack.addStringValue(NodeDefinitionKey::NODE_UNIQUE_ID, device_id); - err = deviceChannel->sendCustomRequest(ControlUnitNodeDomainAndActionRPC::CONTROL_UNIT_APPLY_INPUT_DATASET_ATTRIBUTE_CHANGE_SET, &local_command_pack, &result_data, millisecToWait); - if(err == ErrorCode::EC_NO_ERROR && - result_data && - result_data->hasKey(BatchCommandExecutorRpcActionKey::RPC_GET_COMMAND_STATE_CMD_ID_UI64)) { - //fill the command id - command_id = result_data->getUInt64Value(BatchCommandExecutorRpcActionKey::RPC_GET_COMMAND_STATE_CMD_ID_UI64); - } else { - if(result_data) - LERR_<<"missing key:"<<BatchCommandExecutorRpcActionKey::RPC_GET_COMMAND_STATE_CMD_ID_UI64<<" :"<<result_data->getJSONString(); - } - //forward the request - if(result_data) delete(result_data); - return err; -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::submitSlowControlCommand(string commandAlias, - SubmissionRuleType::SubmissionRule submissionRule, - uint64_t& command_id, - uint32_t execution_channel, - uint64_t scheduler_steps_delay, - uint32_t submission_checker_steps_delay, - CDataWrapper *slow_command_data) { - CDataWrapper local_command_pack; - CDataWrapper *result_data = NULL; - int err = ErrorCode::EC_NO_ERROR; - - if(slow_command_data) { - local_command_pack.appendAllElement(*slow_command_data); - } - // set the default slow command information - local_command_pack.addStringValue(BatchCommandAndParameterDescriptionkey::BC_ALIAS, commandAlias); - local_command_pack.addInt32Value(BatchCommandSubmissionKey::SUBMISSION_RULE_UI32, (uint32_t) submissionRule); - - if(execution_channel) local_command_pack.addInt32Value(BatchCommandSubmissionKey::COMMAND_EXECUTION_CHANNEL, (uint32_t) execution_channel); - if(scheduler_steps_delay) local_command_pack.addInt64Value(BatchCommandSubmissionKey::SCHEDULER_STEP_TIME_INTERVALL_UI64, scheduler_steps_delay); - if(submission_checker_steps_delay) local_command_pack.addInt32Value(BatchCommandSubmissionKey::SUBMISSION_RETRY_DELAY_UI32, (uint32_t) submission_checker_steps_delay); - - //forward the request - local_command_pack.addStringValue(NodeDefinitionKey::NODE_UNIQUE_ID, device_id); - err = deviceChannel->sendCustomRequest(ControlUnitNodeDomainAndActionRPC::CONTROL_UNIT_APPLY_INPUT_DATASET_ATTRIBUTE_CHANGE_SET, - &local_command_pack, - &result_data, - millisecToWait); - if(err == ErrorCode::EC_NO_ERROR - && result_data - && result_data->hasKey(BatchCommandExecutorRpcActionKey::RPC_GET_COMMAND_STATE_CMD_ID_UI64)) { - //fill the command id - command_id = result_data->getUInt64Value(BatchCommandExecutorRpcActionKey::RPC_GET_COMMAND_STATE_CMD_ID_UI64); - } - //delete result data - if(result_data)delete(result_data); - return err; -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::setSlowCommandFeatures(features::Features& features, bool lock_features, uint32_t execution_channel) { - CDataWrapper local_command_pack; - if(features.featuresFlag & features::FeaturesFlagTypes::FF_LOCK_USER_MOD) { - local_command_pack.addBoolValue(BatchCommandExecutorRpcActionKey::RPC_SET_COMMAND_FEATURES_LOCK_BOOL, lock_features); - } - - if(features.featuresFlag & features::FeaturesFlagTypes::FF_SET_SCHEDULER_DELAY) { - local_command_pack.addInt64Value(BatchCommandExecutorRpcActionKey::RPC_SET_COMMAND_FEATURES_SCHEDULER_STEP_WAITH_UI64, features.featureSchedulerStepsDelay); - } - - if(execution_channel) local_command_pack.addInt32Value(BatchCommandSubmissionKey::COMMAND_EXECUTION_CHANNEL, (uint32_t) execution_channel); - - return deviceChannel->sendCustomRequest(BatchCommandExecutorRpcActionKey::RPC_SET_COMMAND_FEATURES, &local_command_pack, NULL, millisecToWait); -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::setSlowCommandLockOnFeatures(bool lock_features) { - CDataWrapper local_command_pack; - local_command_pack.addBoolValue(BatchCommandExecutorRpcActionKey::RPC_SET_COMMAND_FEATURES_LOCK_BOOL, lock_features); - return deviceChannel->sendCustomRequest(BatchCommandExecutorRpcActionKey::RPC_SET_COMMAND_FEATURES, &local_command_pack, NULL, millisecToWait); -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::getCommandState(CommandState& command_state) { - CDataWrapper local_command_pack; - CDataWrapper *result_data = NULL; - int err = ErrorCode::EC_NO_ERROR; - local_command_pack.addInt64Value(BatchCommandExecutorRpcActionKey::RPC_GET_COMMAND_STATE_CMD_ID_UI64, command_state.command_id); - err = deviceChannel->sendCustomRequest(BatchCommandExecutorRpcActionKey::RPC_GET_COMMAND_STATE, &local_command_pack, &result_data, millisecToWait); - if(err == ErrorCode::EC_NO_ERROR && - result_data) { - //fill the command state - command_state.last_event = static_cast<BatchCommandEventType::BatchCommandEventType>(result_data->getUInt32Value(BatchCommandExecutorRpcActionKey::RPC_GET_COMMAND_STATE_LAST_EVENT_UI32)); - if(command_state.last_event == BatchCommandEventType::EVT_FAULT) { - command_state.fault_description.code = result_data->getUInt32Value(BatchCommandExecutorRpcActionKey::RPC_GET_COMMAND_STATE_ERROR_CODE_UI32); - command_state.fault_description.description = result_data->getStringValue(BatchCommandExecutorRpcActionKey::RPC_GET_COMMAND_STATE_ERROR_DESC_STR); - command_state.fault_description.domain = BatchCommandExecutorRpcActionKey::RPC_GET_COMMAND_STATE_ERROR_DOMAIN_STR; - } else { - command_state.fault_description.code = 0; - command_state.fault_description.description.clear(); - command_state.fault_description.domain.clear(); - } - } - if(result_data) delete(result_data); - return err; -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::killCurrentCommand() { - return deviceChannel->sendCustomRequest(BatchCommandExecutorRpcActionKey::RPC_KILL_CURRENT_COMMAND, NULL, NULL, millisecToWait); -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::flushCommandStateHistory() { - return 0;//deviceChannel->sendCustomRequest(BatchCommandExecutorRpcActionKey::RPC_FLUSH_COMMAND_HISTORY, NULL, NULL, millisecToWait); -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::sendCustomRequest(const std::string& action, - common::data::CDataWrapper * const param, - common::data::CDataWrapper**const result) { - return deviceChannel->sendCustomRequest(action, param, result, millisecToWait); -} - -//--------------------------------------------------------------------------------------------------- -void DeviceController::sendCustomMessage(const std::string& action, - common::data::CDataWrapper * const param) { - deviceChannel->sendCustomMessage(action, - param); -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::checkRPCInformation(CDataWrapper **result_information, - uint32_t timeout) { - int err = -1; - ChaosUniquePtr<MessageRequestFuture> result = deviceChannel->checkRPCInformation(); - if(result.get() == NULL) return -1; - if(result->wait(timeout)) { - err = result->getError(); - if(err == 0) { - *result_information = result->detachResult(); - } - }else{ - err = -2; - } - return err; -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::echoTest(CDataWrapper * const echo_data, - CDataWrapper **echo_data_result, - uint32_t timeout) { - int err = -1; - ChaosUniquePtr<MessageRequestFuture> result = deviceChannel->echoTest(echo_data); - if(result.get() == NULL) return err; - if(result->wait(timeout)) { - err = result->getError(); - if(err == 0) { - *echo_data_result = result->detachResult(); - } - }else{ - err = -2; - } - return err; -} - -//--------------------------------------------------------------------------------------------------- -ChaosUniquePtr<MessageRequestFuture> DeviceController::sendCustomRequestWithFuture(const std::string& action_name, - common::data::CDataWrapper *request_date) { - return deviceChannel->sendCustomRequestWithFuture(action_name, - request_date); -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::setAttributeValue(string& attributeName, string& attributeValue) { - return setAttributeValue(attributeName, attributeValue.c_str(),(uint32_t)attributeValue.size()); -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::setAttributeValue(string& attributeName, const char* attributeValue) { - return setAttributeValue(attributeName, attributeValue,(uint32_t)strlen(attributeValue)); -} - -std::vector<chaos::common::data::RangeValueInfo> DeviceController::getDeviceValuesInfo(){ - std::vector<chaos::common::data::RangeValueInfo> ret; - for(std::map<std::string,chaos::common::data::RangeValueInfo>::iterator i= attributeValueMap.begin();i!=attributeValueMap.end();i++) - ret.push_back(i->second); - - return ret; -} -//--------------------------------------------------------------------------------------------------- -int DeviceController::setAttributeValue(string& attributeName, const char* attributeValue, uint32_t size) { - CDataWrapper attributeValuePack; - const char *attrname=attributeName.c_str(); - - if(attributeValueMap.find(attributeName) == attributeValueMap.end() ) - return ErrorCode::EC_ATTRIBUTE_NOT_FOUND; - - if(attributeValueMap[attributeName].dir==DataType::Output) - return ErrorCode::EC_ATTRIBUTE_BAD_DIR; - - switch (attributeValueMap[attributeName].valueType) { - - case DataType::TYPE_INT64: - attributeValuePack.addInt64Value(attrname, boost::lexical_cast<int64_t>(attributeValue)); - return deviceChannel->setAttributeValue(attributeValuePack,millisecToWait); - - case DataType::TYPE_INT32: - attributeValuePack.addInt32Value(attrname, boost::lexical_cast<int32_t>(attributeValue)); - return deviceChannel->setAttributeValue(attributeValuePack,millisecToWait); - - case DataType::TYPE_DOUBLE: - attributeValuePack.addDoubleValue(attrname, boost::lexical_cast<double>(attributeValue)); - return deviceChannel->setAttributeValue(attributeValuePack,millisecToWait); - - case DataType::TYPE_BYTEARRAY: - attributeValuePack.addBinaryValue(attrname,attributeValue,size); - return deviceChannel->setAttributeValue(attributeValuePack,millisecToWait); - case DataType::TYPE_CLUSTER:{ - - attributeValuePack.addJsonValue(attrname,attributeValue); - - return deviceChannel->setAttributeValue(attributeValuePack,millisecToWait); - } - case DataType::TYPE_STRING: - attributeValuePack.addStringValue(attrname,attributeValue); - return deviceChannel->setAttributeValue(attributeValuePack,millisecToWait); - default: - break; - }; - return ErrorCode::EC_ATTRIBUTE_TYPE_NOT_SUPPORTED; -} - -//--------------------------------------------------------------------------------------------------- -void DeviceController::initializeAttributeIndexMap() { - // boost::mutex::scoped_lock lock(trackMutext); - vector<string> attributeNames; - RangeValueInfo attributerangeInfo; - - attributeValueMap.clear(); - - - //get all attribute name from db - datasetDB.getDatasetAttributesName(DataType::Input, attributeNames); - for (vector<string>::iterator iter = attributeNames.begin(); - iter != attributeNames.end(); - iter++) { - - if(datasetDB.getAttributeRangeValueInfo(*iter, attributerangeInfo)!=0){ - LERR_<<"CANNOT RETRIVE attr range info of:"<<*iter; - } - LDBG_<<"IN attr:"<<attributerangeInfo.name<<" type:"<<attributerangeInfo.valueType; - attributeValueMap.insert(make_pair(*iter, attributerangeInfo)); - - } - - attributeNames.clear(); - datasetDB.getDatasetAttributesName(DataType::Output, attributeNames); - for (vector<string>::iterator iter = attributeNames.begin(); - iter != attributeNames.end(); - iter++) { - - - if(datasetDB.getAttributeRangeValueInfo(*iter, attributerangeInfo)!=0){ - LERR_<<"CANNOT RETRIVE attr range info of:"<<*iter; - - } - LDBG_<<"OUT attr:"<<attributerangeInfo.name<<" type:"<<attributerangeInfo.valueType; - attributeValueMap.insert(make_pair(*iter, attributerangeInfo)); - - } - -} - -//--------------------------------------------------------------------------------------------------- -void DeviceController::allocateNewLiveBufferForAttributeAndType(string& attributeName, - DataType::DataSetAttributeIOAttribute attributeDirection, - DataType::DataType attrbiuteType) { - //boost::mutex::scoped_lock lock(trackMutext); - if(attributeDirection == DataType::Output || - attributeDirection == DataType::Bidirectional ){ - - switch (attributeValueMap[attributeName].valueType) { - - - case DataType::TYPE_INT32:{ - SingleBufferCircularBuffer<int32_t> *newBuffer = new SingleBufferCircularBuffer<int32_t>(30); - int32AttributeLiveBuffer.insert(make_pair(attributeName, newBuffer)); - } - break; - - case DataType::TYPE_INT64:{ - SingleBufferCircularBuffer<int64_t> *newBuffer = new SingleBufferCircularBuffer<int64_t>(30); - int64AttributeLiveBuffer.insert(make_pair(attributeName, newBuffer)); - } - break; - - case DataType::TYPE_DOUBLE:{ - SingleBufferCircularBuffer<double_t> *newBuffer = new SingleBufferCircularBuffer<double_t>(30); - doubleAttributeLiveBuffer.insert(make_pair(attributeName, newBuffer)); - } - break; - case DataType::TYPE_BYTEARRAY:{ - PointerBuffer *newBuffer = new PointerBuffer(); - pointerAttributeLiveBuffer.insert(make_pair(attributeName, newBuffer)); - } - break; - } - } else if(attributeDirection == DataType::Input || - attributeDirection == DataType::Bidirectional ){ - - } - -} - -//--------------------------------------------------------------------------------------------------- -UIDataBuffer *DeviceController::getBufferForAttribute(string& attributeName) { - boost::mutex::scoped_lock lock(trackMutext); - UIDataBuffer * result = NULL; - //allocate attribute traccking - - if(attributeValueMap.count(attributeName) == 0 ) return result; - - switch (attributeValueMap[attributeName].valueType) { - - case DataType::TYPE_INT32: - result = int32AttributeLiveBuffer[attributeName]; - break; - - case DataType::TYPE_INT64: - result = int64AttributeLiveBuffer[attributeName]; - break; - - case DataType::TYPE_DOUBLE: - result = doubleAttributeLiveBuffer[attributeName]; - break; - } - return result; -} - -//--------------------------------------------------------------------------------------------------- -PointerBuffer *DeviceController::getPtrBufferForAttribute(string& attributeName) { - boost::mutex::scoped_lock lock(trackMutext); - PointerBuffer * result = NULL; - //allocate attribute traccking - if(attributeValueMap.count(attributeName) == 0 ) return result; - - switch (attributeValueMap[attributeName].valueType) { - - case DataType::TYPE_BYTEARRAY: - result = pointerAttributeLiveBuffer[attributeName]; - break; - default: - break; - } - return result; -} - -//--------------------------------------------------------------------------------------------------- -UIDataBuffer *DeviceController::getPtrBufferForTimestamp(const int initialDimension) { - return int64AttributeLiveBuffer.count(DataPackCommonKey::DPCK_TIMESTAMP)>0? int64AttributeLiveBuffer[DataPackCommonKey::DPCK_TIMESTAMP]:NULL; -} - -//--------------------------------------------------------------------------------------------------- -void DeviceController::deinitializeAttributeIndexMap() { - // boost::mutex::scoped_lock lock(trackMutext); - //dispose circula buffer - for (std::map<string, SingleBufferCircularBuffer<int32_t> *>::iterator iter = int32AttributeLiveBuffer.begin(); - iter != int32AttributeLiveBuffer.end(); - iter++) { - delete(iter->second); - } - int32AttributeLiveBuffer.clear(); - - for (std::map<string, SingleBufferCircularBuffer<int64_t> *>::iterator iter = int64AttributeLiveBuffer.begin(); - iter != int64AttributeLiveBuffer.end(); - iter++) { - delete(iter->second); - } - int64AttributeLiveBuffer.clear(); - - for (std::map<string, SingleBufferCircularBuffer<double_t> *>::iterator iter = doubleAttributeLiveBuffer.begin(); - iter != doubleAttributeLiveBuffer.end(); - iter++) { - delete(iter->second); - } - doubleAttributeLiveBuffer.clear(); - - for (std::map<string, PointerBuffer*>::iterator iter = pointerAttributeLiveBuffer.begin(); - iter != pointerAttributeLiveBuffer.end(); - iter++) { - delete(iter->second); - } - pointerAttributeLiveBuffer.clear(); -} - -//--------------------------------------------------------------------------------------------------- -void DeviceController::addAttributeToTrack(string& attr) { - boost::mutex::scoped_lock lock(trackMutext); - - //add attribute name to list of tracking attribute - trackingAttribute.push_back(attr); - - //allocate attribute traccking - if(attributeValueMap.count(attr) == 0 ) return; - - //allcoate the buffer for the new attribute to track - allocateNewLiveBufferForAttributeAndType(attr, attributeValueMap[attr].dir, attributeValueMap[attr].valueType); -} - -//--------------------------------------------------------------------------------------------------- -CDataWrapper * DeviceController::getLiveCDataWrapperPtr() { - return current_dataset[DatasetDomainOutput].get(); -} - - -//--------------------------------------------------------------------------------------------------- -CDataWrapper * DeviceController::getCurrentDatasetForDomain(DatasetDomain domain) { - if(domain<current_dataset.size()){ - return current_dataset[domain].get(); - } - return NULL; -} - -//--------------------------------------------------------------------------------------------------- -chaos::common::data::CDataWrapper * DeviceController::fetchCurrentDatatasetFromDomain(DatasetDomain domain) { - CHAOS_ASSERT(ioLiveDataDriver) - char *value = NULL; - size_t value_len = 0; - if(domain<current_dataset.size()){ - value = ioLiveDataDriver->retriveRawData(channel_keys[domain],(size_t*)&value_len); - if(value){ - chaos::common::data::CDataWrapper *tmp = new CDataWrapper(value); - current_dataset[domain].reset(tmp); - free(value); - return tmp; - } - } - return NULL; -} - -//--------------------------------------------------------------------------------------------------- -int DeviceController::getTimeStamp(uint64_t& live){ - CDataWrapper * d = current_dataset[DatasetDomainOutput].get(); - live =0; - if(d){ - live = d->getInt64Value(DataPackCommonKey::DPCK_TIMESTAMP); - return 0; - } - return -1; -} -//--------------------------------------------------------------------------------------------------- -void DeviceController::setupTracking() { - boost::mutex::scoped_lock lock(trackMutext); - - //init live buffer - initializeAttributeIndexMap(); - - //initialize timestamp buffer - SingleBufferCircularBuffer<int64_t> *newBuffer = new SingleBufferCircularBuffer<int64_t>(10); - int64AttributeLiveBuffer.insert(make_pair(DataPackCommonKey::DPCK_TIMESTAMP, newBuffer)); -} - -//--------------------------------------------------------------------------------------------------- -void DeviceController::stopTracking() { - boost::mutex::scoped_lock lock(trackMutext); - deinitializeAttributeIndexMap(); -} - -//--------------------------------------------------------------------------------------------------- -void DeviceController::fetchCurrentDeviceValue() { - boost::mutex::scoped_lock lock(trackMutext); - - //! fetch the output odmain - fetchCurrentDatatasetFromDomain(DatasetDomainOutput); - - if(trackingAttribute.size() == 0) return; - CDataWrapper *tmpPtr = current_dataset[DatasetDomainOutput].get(); - - //add timestamp value - int64_t got_ts = tmpPtr->getInt64Value(DataPackCommonKey::DPCK_TIMESTAMP); - if(int64AttributeLiveBuffer[DataPackCommonKey::DPCK_TIMESTAMP]->getLastValue() == got_ts) return; - - int64AttributeLiveBuffer[DataPackCommonKey::DPCK_TIMESTAMP]->addValue(got_ts); - - //update buffer for tracked attribute - for (std::vector<string>::iterator iter = trackingAttribute.begin(); - iter != trackingAttribute.end(); - iter++) { - const char *key = (*iter).c_str(); - if(!tmpPtr->hasKey(key)) continue; - - switch (attributeValueMap[*iter].valueType) { - - case DataType::TYPE_INT32: - int32AttributeLiveBuffer[*iter]->addValue(tmpPtr->getInt32Value(key)); - break; - - case DataType::TYPE_INT64: - int64AttributeLiveBuffer[*iter]->addValue(tmpPtr->getInt64Value(key)); - break; - - case DataType::TYPE_DOUBLE: - doubleAttributeLiveBuffer[*iter]->addValue(tmpPtr->getDoubleValue(key)); - break; - - case DataType::TYPE_BYTEARRAY: - uint32_t ptrLen = 0; - const char * tmpPtrAttribute = tmpPtr->getBinaryValue(key, ptrLen); - pointerAttributeLiveBuffer[*iter]->updateData(tmpPtrAttribute, ptrLen); - break; - } - } -} - -CDataWrapper *DeviceController::getCurrentData(){ - return current_dataset[DatasetDomainOutput].get(); -} - -//! get profile info -cu_prof_t DeviceController::getProfileInfo(){ - chaos::common::data::CDataWrapper *prof= fetchCurrentDatatasetFromDomain(DatasetDomainHealth); - cu_prof_t p; - bzero(&p,sizeof(cu_prof_t)); - if(prof){ - p.push_rate=prof->getDoubleValue(ControlUnitHealtDefinitionValue::CU_HEALT_OUTPUT_DATASET_PUSH_RATE); - p.sys_time =prof->getDoubleValue(NodeHealtDefinitionKey::NODE_HEALT_SYSTEM_TIME); - p.usr_time = prof->getDoubleValue(NodeHealtDefinitionKey::NODE_HEALT_USER_TIME); - p.upt_time = prof->getInt64Value(NodeHealtDefinitionKey::NODE_HEALT_PROCESS_UPTIME); - p.metric_time = prof->getInt64Value(NodeHealtDefinitionKey::NODE_HEALT_TIMESTAMP_LAST_METRIC); - } - return p; -} - -//! get datapack between time itervall -void DeviceController::executeTimeIntervallQuery(DatasetDomain domain, - uint64_t start_ts, - uint64_t end_ts, - QueryCursor **query_cursor, - uint32_t page) { - *query_cursor = ioLiveDataDriver->performQuery(channel_keys[domain], - start_ts, - end_ts, - page); -} - -//! release a query -void DeviceController::releaseQuery(QueryCursor *query_cursor) { - ioLiveDataDriver->releaseQuery(query_cursor); -} - -int DeviceController::loadDatasetTypeFromSnapshotTag(const std::string& snapshot_tag, - DatasetDomain dataset_type, - chaos_data::CDWShrdPtr& cdatawrapper_handler) { - return ioLiveDataDriver->loadDatasetTypeFromSnapshotTag(snapshot_tag, - device_id, - dataset_type, - cdatawrapper_handler); -} - -int DeviceController::createNewSnapshot(const std::string& snapshot_tag, - const std::vector<std::string>& other_snapped_device) { - CHAOS_ASSERT(ioLiveDataDriver) - std::vector<std::string> device_id_in_snap = other_snapped_device; - device_id_in_snap.push_back(device_id); - return mdsChannel->createNewSnapshot(snapshot_tag, - device_id_in_snap); -} - -int DeviceController::deleteSnapshot(const std::string& snapshot_tag) { - CHAOS_ASSERT(ioLiveDataDriver) - return mdsChannel->deleteSnapshot(snapshot_tag); -} - -int DeviceController::getSnapshotList(ChaosStringVector& snapshot_list) { - CHAOS_ASSERT(mdsChannel) - return mdsChannel->searchSnapshotForNode(device_id, - snapshot_list, - millisecToWait); -} - -int DeviceController::searchNode(const std::string& unique_id_filter, - unsigned int node_type_filter, - bool alive_only, - unsigned int last_node_sequence_id, - unsigned int page_length, - ChaosStringVector& node_found) { - - return mdsChannel->searchNode(unique_id_filter, - node_type_filter, - alive_only, - last_node_sequence_id, - page_length, - node_found, - millisecToWait); -} - diff --git a/chaos/ui_toolkit/HighLevelApi/DeviceController.h b/chaos/ui_toolkit/HighLevelApi/DeviceController.h deleted file mode 100644 index 01e42c40c..000000000 --- a/chaos/ui_toolkit/HighLevelApi/DeviceController.h +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright 2012, 2017 INFN - * - * Licensed under the EUPL, Version 1.2 or – as soon they - * will be approved by the European Commission - subsequent - * versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the - * Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in - * writing, software distributed under the Licence is - * distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. - * See the Licence for the specific language governing - * permissions and limitations under the Licence. - */ - -#ifndef CHAOSFramework_DeviceLiveDataFetcher_h -#define CHAOSFramework_DeviceLiveDataFetcher_h - -#include <chaos/common/chaos_types.h> -#include <chaos/common/data/DatasetDB.h> -#include <chaos/common/io/IODataDriver.h> -#include <chaos/common/exception/exception.h> -#include <chaos/common/message/MDSMessageChannel.h> -#include <chaos/common/network/CNodeNetworkAddress.h> -#include <chaos/common/message/DeviceMessageChannel.h> -#include <chaos/common/utility/SingleBufferCircularBuffer.h> - -#include <boost/thread/mutex.hpp> -#include <boost/shared_ptr.hpp> - -#include <map> - -namespace chaos { - namespace ui { - - //! identify the domain qhere fetch the data - typedef enum DatasetDomain { - DatasetDomainOutput = 0, - DatasetDomainInput, - DatasetDomainCustom, - DatasetDomainSystem, - DatasetDomainDevAlarm, - DatasetDomainCUAlarm, - DatasetDomainHealth, - } DatasetDomain; - - //! Controller for a single device instance - /*! - This represent a global controller for a single device, identified by DEVICE_ID. The contorlle rpermit to - contorl the initialization and operation phase for a device. Allow to send value for input dataset and read the last - freshenest value form the live data - */ - class DeviceController { - friend class HLDataApi; - //!time to waith for the answer to an request; - uint32_t millisecToWait; - //! represent the device id controlled by this instance - std::string device_id; - - std::vector<std::string> channel_keys; - - //!cached cu type - std::string cu_type; - - //! Metadata Server channel for get device information - chaos::common::message::MDSMessageChannel *mdsChannel; - //! Device MEssage channel to control via chaos rpc the device - chaos::common::message::DeviceMessageChannel *deviceChannel; - //! The io driver for accessing live data of the device - chaos::common::io::IODataDriver *ioLiveDataDriver; - //!Dataset database - chaos::common::data::DatasetDB datasetDB; - //!point to the freashest live value for this device dataset - //ChaosUniquePtr<chaos::common::data::CDataWrapper> lastDeviceDefinition; - - //!point to the freashest live value for this device dataset - std::vector< ChaosSharedPtr<chaos::common::data::CDataWrapper> >current_dataset; - - - //mutext for multi threading track operation - boost::mutex trackMutext; - - //!store the type of the attribute for fast retrieve - std::map<std::string, common::data::RangeValueInfo> attributeValueMap; - std::vector<std::string> trackingAttribute; - - //!map for live data circular buffer - std::map<std::string, common::utility::SingleBufferCircularBuffer<int32_t> *> int32AttributeLiveBuffer; - std::map<std::string, common::utility::SingleBufferCircularBuffer<int64_t> *> int64AttributeLiveBuffer; - std::map<std::string, common::utility::SingleBufferCircularBuffer<double_t> *> doubleAttributeLiveBuffer; - std::map<std::string, common::utility::PointerBuffer*> pointerAttributeLiveBuffer; - - //! Defautl Constructor - /*! - The visibility of the constructor is private becase it's is isntantiable only via HLDataApi singleton - */ - DeviceController(string& _deviceID); - - - //! update inromation for talking with device - /*! - Perform oall the orpeation to find the rigth chaos address of the device - */ - void updateChannel() throw(CException); - - /*! - Initialize the map for the devices - \param initiDevicedescription the reference to CDataWrapper that contain device initialization information - */ - void initializeAttributeIndexMap(); - - //!DeInitialize the map for the devices - /*! - Dispose all memory used for live data buffer - */ - void deinitializeAttributeIndexMap(); - - //! allocata new circular buffer for attribute and type - /* - - */ - void allocateNewLiveBufferForAttributeAndType(std::string& attributeName, DataType::DataSetAttributeIOAttribute type, DataType::DataType attrbiuteType); - protected: - //! the fetcher thread method - void executeOnThread(const std::string&) throw(CException); - public: - - //!Public destructor - /*! - All can destruct an isntance of the device controller - */ - ~DeviceController(); - - /** - * return the number of output channels - * @return return the nyumber of predefined output channels - */ - int getChannelsNum(); - - //!Return the deviceID of the device - /*! - Return the deviceID that identify the device managed by this controller - \param dID the string that will be filled with the device id - */ - void getDeviceId(std::string& dId); - - //!Set the request wait time - /*! - Set the controller globally wait time, used when a request is forwarded to an device. after that time - the method return with some information. - \param newMillisecToWait the time that the answer is waited - */ - void setRequestTimeWaith(uint32_t newMillisecToWait); - - //!Return the controller globally wait time - /*! - Return the controller globally wait time - \return the wait time - */ - uint32_t getRequestTimeWaith(); - - //! update the scudiling of device run method - /*! - Set the control unit run method scheduling delay - */ - int setScheduleDelay(uint64_t microsecondsDelay); - /*! - Get attribute name filtered by direction type - */ - void getDeviceDatasetAttributesName(vector<std::string>& attributesName); - - /*! - Get time stamp of last packet - * @param [out] live output timestamp, set 0 on error - * @return 0 on success, negative otherwise - */ - int getTimeStamp(uint64_t& live); - /*! - Get description for attribute name - */ - void getAttributeDescription(const std::string& attributesName, - std::string& attributeDescription); - /*! - Get all attribute name - */ - void getDeviceDatasetAttributesName(std::vector<std::string>& attributesName, - DataType::DataSetAttributeIOAttribute directionType); - /*! - Get range valu einfo for attrbiute name - */ - void getDeviceAttributeRangeValueInfo(const std::string& attributesName, - chaos::common::data::RangeValueInfo& rangeInfo); - /*! - Get the direction of the attribute - */ - int getDeviceAttributeDirection(const std::string& attributesName, - DataType::DataSetAttributeIOAttribute& directionType); - /*! - Get the direction of the attribute - */ - int getDeviceAttributeType(const std::string& attributesName, - DataType::DataType& type); - - /** - * - * @return a vector with the information of the dataset - */ - std::vector<chaos::common::data::RangeValueInfo> getDeviceValuesInfo(); - //! - int getAttributeStrValue(const std::string attributesName, - std::string& attribute_value); - - //! Get the type of the control unit - /*! - Get the type of the contro unit - \control_unit_type string that will be filled with the type of the control unit - */ - int getType(std::string& control_unit_type); - - //!Device initialization - /*! - Perform the device initialization phase - */ - int initDevice(); - - //!Start the device chaos driver acquisition data scheduler - /*! - Perform the device start pahse. Thsi phase represent the run methdo called at certain delay in athread - */ - int startDevice(); - - //!Stop(pause) the device driver acquisition data scheduler - /*! - Perform the device initialization phase - */ - int stopDevice(); - - //!Device deinitialization phase - /*! - Perform, if it's not be done the stop operation and afther the hardware deinitialization - */ - int deinitDevice(); - - /** - * recover the device from an error (recoverable) - * @return 0 on success - */ - int recoverDeviceFromError(); - //! restore the device to a saved tag - int restoreDeviceToTag(const std::string& restore_tag); - int setAttributeValue(std::string& attributeName, int32_t attributeValue); - int setAttributeValue(const char *attributeName, int32_t attributeValue); - - int setAttributeValue(std::string& attributeName, double attributeValue); - int setAttributeValue(const char *attributeName, double attributeValue); - - int setAttributeValue(std::string& attributeName, std::string& attributeValue); - int setAttributeValue(std::string& attributeName, const char* attributeValue); - // buffer - int setAttributeValue(std::string& attributeName, const char* attributeValue, uint32_t size); - - int setAttributeToValue(const char *attributeName, const char *attributeValue, bool noWait); - int setAttributeToValue(const char *attributeName, void *attributeValue, bool noWait, int32_t bufferValuedDim); - int setAttributeToValue(const char *attributeName, DataType::DataType attributeType, void *attributeValue, bool noWait = false, int32_t bufferValuedDim = 0); - - //! Submit a new slow command - /*! - \ingroup API_Slow_Control - The submition of slow command is made collection all the information that permit to submit it - \param commandAlias represent the alias of the command the the control unit expost from RPC subsystem - \param submissionRule determinate the rule with which the command is submitted. This can determinate the - the execution of the current execution command in the control unit, according with his running state - \param priority represent the priority beetwen the submitted command and all command in the queue that are - waiting to be submitted in the scheduler - \param command_id is the assigned command id to the submitted one - \param execution_channel (optional) choose the excution channel where execute the command [1 based] - \param scheduler_steps_delay (optional) rapresent the intervall beetween the step of the scehduler [...acquisition -> correlation -> scheduleInterval...] - \param submission_checker_steps_delay (optional) is the delay between two steps of the submission checker - \param slow_command_data (optional) is the abstraction of the command data that is passed to the set handler befor the scheduler loop of the new command - take palce. The memory of that parameter is not free - * @return 0 on success - */ - int submitSlowControlCommand(string commandAlias, - chaos::common::batch_command::SubmissionRuleType::SubmissionRule submissionRule, - uint32_t priority, - uint64_t& command_id, - uint32_t execution_channel = 0, - uint64_t scheduler_steps_delay = 0, - uint32_t submission_checker_steps_delay = 0, - chaos::common::data::CDataWrapper *slow_command_data = NULL); - - //! Submit a new slow command - /*! - \ingroup API_Slow_Control - The submition of slow command is made collection all the information that permit to submit it - \param commandAlias represent the alias of the command the the control unit expost from RPC subsystem - \param submissionRule determinate the rule with which the command is submitted. This can determinate the - \param command_id is the assigned command id to the submitted one - the execution of the current execution command in the control unit, according with his running state - \param execution_channel (optional) choose the excution channel where execute the command [1 based] - \param scheduler_steps_delay (optional) rapresent the intervall beetween the step of the scehduler [...acquisition -> correlation -> scheduleInterval...] - \param submission_checker_steps_delay (optional) is the delay between two steps of the submission checker - \param slow_command_data (optional) is the abstraction of the command data that is passed to the set handler befor the scheduler loop of the new command - take palce. The memory of that parameter is not free - * @return 0 on success - */ - int submitSlowControlCommand(string commandAlias, - chaos::common::batch_command::SubmissionRuleType::SubmissionRule submissionRule, - uint64_t& command_id, - uint32_t execution_channel = 0, - uint64_t scheduler_steps_delay = 0, - uint32_t submission_checker_steps_delay = 0, - chaos::common::data::CDataWrapper *slow_command_data = NULL); - - //! Set the current slow command features - /*! - \ingroup API_Slow_Control - Permit to set the features of the current running command. During execution the chaos::cu::control_manager::slow_command::features::Features::featuresFlag - field is checked to see what feature need to be set. The enumeration chaos::cu::control_manager::slow_command::features::FeaturesFlagTypes::FeatureFlag need to - bee used to set the featuresFlag property. - \param features valorization of the features - \param lock_features set the lock on all features - \param execution_channel set the execution channel where set the features - */ - int setSlowCommandFeatures(chaos::common::batch_command::features::Features& features, bool lock_features, uint32_t execution_channel = 0); - - //! Set the lock on slow command features - /*! - \ingroup API_Slow_Control - Lock the features modification by the slow command api on the current - \param lock_features set the lock on all features - */ - int setSlowCommandLockOnFeatures(bool lock_features); - - //! Get the statistick for a command - /*! - \ingroup API_Slow_Control - Permit to obtain the state of a command by it's unique id using the filed command_id of the command_state parameter - \param command_state will be filled with the state of the command on success - \return result of the execution - */ - int getCommandState(chaos::common::batch_command::CommandState& command_state); - - //! Kill the current executing command - /*! - \ingroup API_Slow_Control - Kill the current executing command in without respetting the running state. - */ - int killCurrentCommand(); - - //! Flush command states history - /*! - \ingroup API_Slow_Control - Flush all the slow control command state history for non active command. - */ - int flushCommandStateHistory(); - - //!Get device state - /*! - Return the current device state - * @param [out] deviceState returned state, if error UNDEFINED state set - * @return the timestamp of the hearthbeat, 0 if error - */ - uint64_t getState(CUStateKey::ControlUnitState& deviceState); - - /*! - Setup the structure to accelerate the tracking of the live data - */ - void setupTracking(); - - //!Stop the live data tracking - /*! - Interrupt the live data tracking operation - */ - void stopTracking(); - - //add attrbiute to track - /*! - Add attribute to tracking - */ - void addAttributeToTrack(std::string& attributeName); - - //get the CDatawrapper for the live value - /*! - the returned object is not own by requester but only by DeviceController isntance - \deprecated use new api getCurrentDatasetForDomain - */ - __attribute__((__deprecated__)) - chaos::common::data::CDataWrapper * getLiveCDataWrapperPtr(); - - //!return the last fetched dataset for the domain - chaos::common::data::CDataWrapper * getCurrentDatasetForDomain(DatasetDomain domain); - - //! fetch from the chaso central cache the dataset associated to the domain - chaos::common::data::CDataWrapper * fetchCurrentDatatasetFromDomain(DatasetDomain domain); - - /*! - Fetch the current live value form live storage - */ - void fetchCurrentDeviceValue(); - - common::utility::UIDataBuffer *getBufferForAttribute(string& attributeName); - common::utility::PointerBuffer *getPtrBufferForAttribute(string& attributeName); - common::utility::UIDataBuffer *getPtrBufferForTimestamp(const int initialDimension = 10); - - chaos::common::data::CDataWrapper *getCurrentData(); - - //! send custom request to device - int sendCustomRequest(const std::string& action, - common::data::CDataWrapper * const param, - common::data::CDataWrapper**const result); - - //! send custom request to device and return a future - ChaosUniquePtr<chaos::common::message::MessageRequestFuture> sendCustomRequestWithFuture(const std::string& action_name, - common::data::CDataWrapper *request_date); - - //! send custom message to device - void sendCustomMessage(const std::string& action, - common::data::CDataWrapper * const param); - - //! Send a request for receive RPC information - int checkRPCInformation(chaos::common::data::CDataWrapper **result_information, - uint32_t timeout = 1000); - - //! Send a request for an echo test - int echoTest(chaos::common::data::CDataWrapper * const echo_data, - chaos::common::data::CDataWrapper **echo_data_result, - uint32_t timeout = 1000); - - //! get datapack between time itervall - void executeTimeIntervallQuery(DatasetDomain domain, - uint64_t start_ts, - uint64_t end_ts, - chaos::common::io::QueryCursor **query_cursor,uint32_t page_len=DEFAULT_PAGE_LEN); - - //! release a query - void releaseQuery(chaos::common::io::QueryCursor *query_cursor); - - //! get profile info - cu_prof_t getProfileInfo(); - - //! restore from a tag a dataset associated to a key - int loadDatasetTypeFromSnapshotTag(const std::string& snapshot_tag, - DatasetDomain dataset_type, - chaos_data::CDWShrdPtr& cdatawrapper_handler); - //! restore from a tag a dataset associated to a key - int createNewSnapshot(const std::string& snapshot_tag, - const std::vector<std::string>& other_snapped_device); - //!delete the snapshot - int deleteSnapshot(const std::string& snapshot_tag); - - //!return the snapshot list for device controlled by this isntance - int getSnapshotList(ChaosStringVector& snapshot_list); - - int searchNode(const std::string& unique_id_filter, - unsigned int node_type_filter, - bool alive_only, - unsigned int last_node_sequence_id, - unsigned int page_length, - ChaosStringVector& node_found); - }; - } -} -#endif diff --git a/chaos/ui_toolkit/HighLevelApi/HLDataApi.cpp b/chaos/ui_toolkit/HighLevelApi/HLDataApi.cpp deleted file mode 100644 index 0a645c3bc..000000000 --- a/chaos/ui_toolkit/HighLevelApi/HLDataApi.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2012, 2017 INFN - * - * Licensed under the EUPL, Version 1.2 or – as soon they - * will be approved by the European Commission - subsequent - * versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the - * Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in - * writing, software distributed under the Licence is - * distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. - * See the Licence for the specific language governing - * permissions and limitations under the Licence. - */ -#include "HLDataApi.h" -using namespace std; -using namespace chaos; -using namespace chaos::ui; -using namespace chaos::common::message; - -/* - * Constructor - */ -HLDataApi::HLDataApi() { - -} - -/* - * Distructor - */ -HLDataApi::~HLDataApi() { -} - -/* - LL Rpc Api static initialization it should be called once for application - */ -void HLDataApi::init() throw (CException) { - -} -/* - Deinitialization of LL rpc api - */ -void HLDataApi::deinit() throw (CException) { - LDBG_<<"["<<__PRETTY_FUNCTION__<<"] deleting device controllers"; - - for (map<string, DeviceController*>::iterator controllerIterator = controllerMap.begin(); - controllerIterator != controllerMap.end(); - controllerIterator++) { - LDBG_<<"["<<__PRETTY_FUNCTION__<<"] deleting device controller:"<<controllerIterator->first<<" ptr:"<<(uintptr_t)std::hex<<controllerIterator->second; - - DeviceController *ctrl = controllerIterator->second; - //dispose it - delete(ctrl); - } - -} - - -DeviceController *HLDataApi::getControllerForDeviceID(string deviceID, - uint32_t controller_timeout) throw (CException) { - - DeviceController *deviceController = new DeviceController(deviceID); - deviceController->setRequestTimeWaith(controller_timeout); - deviceController->updateChannel(); - LDBG_<<"["<<__PRETTY_FUNCTION__<<"] inserting new device controller:"<<deviceID<<" ptr:"<<(uintptr_t)std::hex<<deviceController; - controllerMap.insert(make_pair(deviceID, - deviceController)); - - return deviceController; -} - -void HLDataApi::disposeDeviceControllerPtr(DeviceController *ctrl) throw (CException) { - if(!ctrl) return; - string deviceID; - ctrl->getDeviceId(deviceID); - - //remove device from the map of all active device - controllerMap.erase(deviceID); - - //dispose the devie - delete ctrl; - ctrl = NULL; -} - -void HLDataApi::createNewSnapshot(const std::string& snapshot_name) { - -} - -void HLDataApi::deleteSnapshot(const std::string& snapshot_name) { - -} diff --git a/chaos/ui_toolkit/HighLevelApi/HLDataApi.h b/chaos/ui_toolkit/HighLevelApi/HLDataApi.h deleted file mode 100644 index 5638c0abc..000000000 --- a/chaos/ui_toolkit/HighLevelApi/HLDataApi.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2012, 2017 INFN - * - * Licensed under the EUPL, Version 1.2 or – as soon they - * will be approved by the European Commission - subsequent - * versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the - * Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in - * writing, software distributed under the Licence is - * distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. - * See the Licence for the specific language governing - * permissions and limitations under the Licence. - */ -#ifndef ChaosFramework_HLDataApi_h -#define ChaosFramework_HLDataApi_h -#include <map> -#include <string> -#include <chaos/ui_toolkit/HighLevelApi/DeviceController.h> -#include <chaos/common/message/PerformanceNodeChannel.h> -#include <chaos/common/utility/Singleton.h> - -namespace chaos { - namespace ui { - /* - High level api for maning device datasert - */ - class HLDataApi: - public common::utility::Singleton<HLDataApi> { - friend class ChaosUIToolkit; - friend class common::utility::Singleton<HLDataApi>; - - std::map<std::string, DeviceController* > controllerMap; - /* - LL Rpc Api static initialization it should be called once for application - */ - void init() throw (CException); - /* - Deinitialization of LL rpc api - */ - void deinit() throw (CException); - - /* - * Constructor - */ - HLDataApi(); - - /* - * Distructor - */ - ~HLDataApi(); - - public: - DeviceController *getControllerForDeviceID(string deviceID, uint32_t controller_timeout=1000) throw (CException); - void disposeDeviceControllerPtr(DeviceController *) throw (CException); - - void createNewSnapshot(const std::string& snapshot_name); - - void deleteSnapshot(const std::string& snapshot_name); - }; - } -} -#endif diff --git a/chaos/ui_toolkit/HighLevelApi/HLInfrastructureApi.cpp b/chaos/ui_toolkit/HighLevelApi/HLInfrastructureApi.cpp deleted file mode 100644 index 5ca10dca6..000000000 --- a/chaos/ui_toolkit/HighLevelApi/HLInfrastructureApi.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2012, 2017 INFN - * - * Licensed under the EUPL, Version 1.2 or – as soon they - * will be approved by the European Commission - subsequent - * versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the - * Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in - * writing, software distributed under the Licence is - * distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. - * See the Licence for the specific language governing - * permissions and limitations under the Licence. - */ -#include "HLInfrastructureApi.h" - - -using namespace chaos::ui; - -/* - * Constructor - */ -HLInfrastructureApi::HLInfrastructureApi() { - -} - -/* - * Distructor - */ -HLInfrastructureApi::~HLInfrastructureApi() { - -} diff --git a/chaos/ui_toolkit/HighLevelApi/HLInfrastructureApi.h b/chaos/ui_toolkit/HighLevelApi/HLInfrastructureApi.h deleted file mode 100644 index cf8452aa7..000000000 --- a/chaos/ui_toolkit/HighLevelApi/HLInfrastructureApi.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2012, 2017 INFN - * - * Licensed under the EUPL, Version 1.2 or – as soon they - * will be approved by the European Commission - subsequent - * versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the - * Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in - * writing, software distributed under the Licence is - * distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. - * See the Licence for the specific language governing - * permissions and limitations under the Licence. - */ -#ifndef ChaosFramework_HLInfrastructureApi_h -#define ChaosFramework_HLInfrastructureApi_h - -namespace chaos{ - namespace ui{ - class HLInfrastructureApi { - friend class ChaosUIToolkit; - - /* - * Constructor - */ - HLInfrastructureApi(); - - /* - * Distructor - */ - ~HLInfrastructureApi(); - - public: - }; - } -} -#endif diff --git a/chaos/ui_toolkit/Labview/LV12/CUinfo.ctl b/chaos/ui_toolkit/Labview/LV12/CUinfo.ctl deleted file mode 100644 index 61ac6a3fed0d7b43355b4bb7db31e79ed32cabfc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4775 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 diff --git a/chaos/ui_toolkit/Labview/LV12/ChaosPowerSupply.vi b/chaos/ui_toolkit/Labview/LV12/ChaosPowerSupply.vi deleted file mode 100644 index 5917c6ac2e5d61b89e71202c251f8e6cbc706e70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27532 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 diff --git a/chaos/ui_toolkit/Labview/LV12/InitialiseChaosCUs.vi b/chaos/ui_toolkit/Labview/LV12/InitialiseChaosCUs.vi deleted file mode 100644 index fb8e3e09b3272219f43496cbf0ea805cb0c68088..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13566 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 A^8f$< diff --git a/chaos/ui_toolkit/LowLevelApi/LLDataApi.h b/chaos/ui_toolkit/LowLevelApi/LLDataApi.h deleted file mode 100644 index a7f795ab4..000000000 --- a/chaos/ui_toolkit/LowLevelApi/LLDataApi.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2012, 2017 INFN - * - * Licensed under the EUPL, Version 1.2 or – as soon they - * will be approved by the European Commission - subsequent - * versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the - * Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in - * writing, software distributed under the Licence is - * distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. - * See the Licence for the specific language governing - * permissions and limitations under the Licence. - */ -#ifndef ChaosFramework_LLDataApi_h -#define ChaosFramework_LLDataApi_h - -#include <string> -#include <chaos/common/utility/Singleton.h> -#include <chaos/common/data/CDataWrapper.h> -#include <chaos/common/io/IODataDriver.h> -using namespace chaos::common::io; -using namespace std; -namespace chaos { - namespace ui { - /* - Low level api for data access api - */ - class LLDataApi: - public common::utility::Singleton<LLDataApi> { - friend class ChaosUIToolkit; - friend class Singleton<LLDataApi>; - LLDataApi(); - ~LLDataApi(); - - public: - - }; - } -} -#endif diff --git a/chaos/ui_toolkit/LowLevelApi/LLRpcApi.cpp b/chaos/ui_toolkit/LowLevelApi/LLRpcApi.cpp deleted file mode 100644 index cd345a690..000000000 --- a/chaos/ui_toolkit/LowLevelApi/LLRpcApi.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2012, 2017 INFN - * - * Licensed under the EUPL, Version 1.2 or – as soon they - * will be approved by the European Commission - subsequent - * versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the - * Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in - * writing, software distributed under the Licence is - * distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. - * See the Licence for the specific language governing - * permissions and limitations under the Licence. - */ -#include "LLRpcApi.h" -#include <boost/format.hpp> -#include <chaos/common/global.h> -#include <chaos/common/data/CDataWrapper.h> - -using namespace boost; - -using namespace chaos; -using namespace chaos::ui; -using namespace chaos::common::io; -using namespace chaos::common::event; -using namespace chaos::common::message; -using namespace chaos::common::utility; -using namespace chaos::common::direct_io; -#define LLRA_LAPP_ LAPP_ << "[LLRpcApi] - " - -uint32_t DIOConn::garbage_counter = 0; - -/* - */ -LLRpcApi::LLRpcApi() { - direct_io_client = NULL; -} - -/* - */ -LLRpcApi::~LLRpcApi() { -} -void LLRpcApi::init(chaos::common::network::NetworkBroker *nb){ - LLRA_LAPP_ << "Using a specified NetworkBroker:"<<nb; - - direct_io_client = NetworkBroker::getInstance()->getSharedDirectIOClientInstance(); -} - -/* - LL Rpc Api static initialization it should be called once for application - */ -void LLRpcApi::init() throw (CException) { - - //get new direct io client - direct_io_client = NetworkBroker::getInstance()->getSharedDirectIOClientInstance(); -} - -/* - Deinitialization of LL rpc api - */ -void LLRpcApi::deinit() throw (CException) { - LLRA_LAPP_ << "Deinit LLRpcApi"; -} - -/* - * Return an instance for the configured data live driver - */ -IODataDriver *LLRpcApi::getDataProxyChannelNewInstance() throw(CException) { - IODataDriver *result = NULL; - std::string impl_name = boost::str( boost::format("%1%IODriver") % GlobalConfiguration::getInstance()->getOption<std::string>(InitOption::OPT_DATA_IO_IMPL)); - - result = ObjectFactoryRegister<IODataDriver>::getInstance()->getNewInstanceByName(impl_name); - if(result) { - if(impl_name.compare("IODirectIODriver") == 0) { - //set the information - IODirectIODriverInitParam init_param; - std::memset(&init_param, 0, sizeof(IODirectIODriverInitParam)); - init_param.client_instance = NULL; - init_param.endpoint_instance = NULL; - ((IODirectIODriver*)result)->setDirectIOParam(init_param); - } - } - return result; -} - -/* - */ -MDSMessageChannel *LLRpcApi::getNewMetadataServerChannel() { - return NetworkBroker::getInstance()->getMetadataserverMessageChannel(); -} - -/*! - Return a new device channel - */ -DeviceMessageChannel *LLRpcApi::getNewDeviceMessageChannel(CDeviceNetworkAddress *deviceNetworkAddress, - bool self_managed) { - return NetworkBroker::getInstance()->getDeviceMessageChannelFromAddress(deviceNetworkAddress, - self_managed); -} - -/*! - Return a new device channel - */ -chaos::common::message::PerformanceNodeChannel *LLRpcApi::getNewPerformanceChannel(CNetworkAddress *note_network_address) { - return NetworkBroker::getInstance()->getPerformanceChannelFromAddress(note_network_address); -} - -void LLRpcApi::deleteMessageChannel(MessageChannel *channelToDispose) { - NetworkBroker::getInstance()->disposeMessageChannel(channelToDispose); -} -/*! - Delete a previously instantiatedchannel - */ -void LLRpcApi::deleteMessageChannel(NodeMessageChannel *channelToDispose) { - NetworkBroker::getInstance()->disposeMessageChannel(channelToDispose); -} - -void LLRpcApi::deleteMessageChannel(chaos::common::message::MDSMessageChannel *channelToDispose) { - NetworkBroker::getInstance()->disposeMessageChannel(channelToDispose); -} - -chaos::common::event::channel::AlertEventChannel *LLRpcApi::getNewAlertEventChannel() throw (CException) { - return NetworkBroker::getInstance()->getNewAlertEventChannel(); -} - -chaos::common::event::channel::InstrumentEventChannel *LLRpcApi::getNewInstrumentEventChannel() throw (CException) { - return NetworkBroker::getInstance()->getNewInstrumentEventChannel(); -} - -void LLRpcApi::disposeEventChannel(chaos::common::event::channel::EventChannel *eventChannel) throw (CException) { - NetworkBroker::getInstance()->disposeEventChannel(eventChannel); -} - -SystemApiChannel *LLRpcApi::getSystemApiClientChannel(const std::string& direct_io_address) { - DIOConn *conn = NULL; - boost::unique_lock<boost::mutex> l(mutex_map_dio_addr_conn); - if(map_dio_addr_conn.count(direct_io_address)) { - conn = map_dio_addr_conn[direct_io_address]; - } else { - conn = new DIOConn(direct_io_client->getNewConnection(direct_io_address)); - } - conn->garbage_counter++; - return new SystemApiChannel(conn, (chaos::common::direct_io::channel::DirectIOSystemAPIClientChannel*)conn->connection->getNewChannelInstance("DirectIOSystemAPIClientChannel")); -} - -void LLRpcApi::releaseSystemApyChannel(SystemApiChannel *system_api_channel) { - boost::unique_lock<boost::mutex> l(mutex_map_dio_addr_conn); - if(!system_api_channel) return; - - DIOConn *conn = system_api_channel->connection; - if(conn) { - conn->garbage_counter--; - if(system_api_channel->system_api_channel) { - conn->connection->releaseChannelInstance(system_api_channel->system_api_channel); - } - - if(!conn->garbage_counter) { - //need to be deleted the connection from the map - map_dio_addr_conn.erase(conn->connection->getURL()); - - //and form the root client - direct_io_client->releaseConnection(conn->connection); - } - } - -} diff --git a/chaos/ui_toolkit/LowLevelApi/LLRpcApi.h b/chaos/ui_toolkit/LowLevelApi/LLRpcApi.h deleted file mode 100644 index 20af19f7b..000000000 --- a/chaos/ui_toolkit/LowLevelApi/LLRpcApi.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2012, 2017 INFN - * - * Licensed under the EUPL, Version 1.2 or – as soon they - * will be approved by the European Commission - subsequent - * versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the - * Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in - * writing, software distributed under the Licence is - * distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. - * See the Licence for the specific language governing - * permissions and limitations under the Licence. - */ - -#ifndef ChaosFramework_LLRpcApi_h -#define ChaosFramework_LLRpcApi_h - -#include <map> -#include <boost/shared_ptr.hpp> - -#include <chaos/common/utility/Singleton.h> -#include <chaos/common/exception/exception.h> -#include <chaos/common/network/NetworkBroker.h> -#include <chaos/common/message/MDSMessageChannel.h> -#include <chaos/common/message/DeviceMessageChannel.h> - -#include <chaos/common/event/channel/AlertEventChannel.h> -#include <chaos/common/event/channel/InstrumentEventChannel.h> -#include <chaos/common/io/IODirectIODriver.h> -#include <chaos/common/direct_io/DirectIOClient.h> -#include <chaos/common/direct_io/DirectIOClientConnection.h> -#include <chaos/common/direct_io/channel/DirectIOSystemAPIClientChannel.h> - -#include <boost/thread.hpp> -#include <boost/atomic.hpp> - -namespace chaos { - namespace ui{ - - class LLRpcApi; - - struct DIOConn { - friend class LLRpcApi; - private: - static uint32_t garbage_counter; - chaos::common::direct_io::DirectIOClientConnection *connection; - DIOConn(chaos::common::direct_io::DirectIOClientConnection *_connection):connection(_connection){}; - ~DIOConn(){}; - }; - - struct SystemApiChannel { - friend class LLRpcApi; - chaos::common::direct_io::channel::DirectIOSystemAPIClientChannel *system_api_channel; - private: - DIOConn *connection; - SystemApiChannel(DIOConn *_connection, - chaos::common::direct_io::channel::DirectIOSystemAPIClientChannel *_system_api_channel): - connection(_connection), - system_api_channel(_system_api_channel){}; - ~SystemApiChannel(){}; - }; - - /* - LLRpcApi Class api for rpc system - */ - class LLRpcApi: - public common::utility::Singleton<LLRpcApi> { - friend class ChaosUIToolkit; - friend class common::utility::Singleton<LLRpcApi>; - //!chaos network router - chaos::common::network::NetworkBroker *network_broker; - - //! root direct io client - chaos::common::direct_io::DirectIOClient *direct_io_client; - - //! hasmap for direct io address and connection struct - boost::mutex mutex_map_dio_addr_conn; - std::map<std::string, DIOConn*> map_dio_addr_conn; - - - - /* - */ - LLRpcApi(); - - /* - */ - ~LLRpcApi(); - - public: - - /* - LL Rpc Api static initialization it should be called once for application - */ - void init() throw (CException); - - /* - * use a specified network broker - */ - void init(chaos::common::network::NetworkBroker *network_broker); - /* - Deinitialization of LL rpc api - */ - void deinit() throw (CException); - chaos::common::io::IODataDriver *getDataProxyChannelNewInstance() throw(CException); - - /*! - Return a new channel for talk with metadata server - */ - chaos::common::message::MDSMessageChannel *getNewMetadataServerChannel(); - - /*! - Return a new device channel - */ - chaos::common::message::DeviceMessageChannel *getNewDeviceMessageChannel(chaos::common::network::CDeviceNetworkAddress *device_network_address, - bool self_managed = false); - - chaos::common::message::PerformanceNodeChannel *getNewPerformanceChannel(chaos::common::network::CNetworkAddress *note_network_address); - - /*! - Delete a previously instantiatedchannel - */ - void deleteMessageChannel(chaos::common::message::MessageChannel*); - - /*! - Delete a previously instantiatedchannel - */ - void deleteMessageChannel(chaos::common::message::NodeMessageChannel*); - - /*! - Delete a previously instantiatedchannel - */ - void deleteMessageChannel(chaos::common::message::MDSMessageChannel*); - - chaos::common::event::channel::AlertEventChannel *getNewAlertEventChannel() throw (CException); - chaos::common::event::channel::InstrumentEventChannel *getNewInstrumentEventChannel() throw (CException); - void disposeEventChannel(chaos::common::event::channel::EventChannel *) throw (CException); - - SystemApiChannel *getSystemApiClientChannel(const std::string& direct_io_address); - void releaseSystemApyChannel(SystemApiChannel *system_api_channel); - - }; - } -} -#endif diff --git a/chaos/ui_toolkit/caching/LiveDataFetcher.cpp b/chaos/ui_toolkit/caching/LiveDataFetcher.cpp deleted file mode 100644 index acc7d7536..000000000 --- a/chaos/ui_toolkit/caching/LiveDataFetcher.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// -// LiveDataFetcher.cpp -// CHAOSFramework -// -// Created by Claudio Bisegni on 1/5/13. -// Copyright (c) 2013 INFN. All rights reserved. -// - -#include <chaos/common/chaos_constants.h> -#include <chaos/common/io/IODataDriver.h> -#include <chaos/ui_toolkit/caching/LiveDataFetcher.h> - -using namespace chaos; -using namespace chaos::common::io; -using namespace chaos::common::data; -using namespace chaos::ui::chaching; - -LiveDataFetcher::LiveDataFetcher(IODataDriver *_dataDriver):dataDriver(_dataDriver) { - -} - -LiveDataFetcher::~LiveDataFetcher() { - if(dataDriver){ - dataDriver->deinit(); - delete(dataDriver); - } -} - -/* - Update the driver configuration - */ -CDataWrapper* LiveDataFetcher::updateConfiguration(CDataWrapper *configuration) { - if(dataDriver) dataDriver->updateConfiguration(configuration); - return NULL; -} - -// Initialize instance -void LiveDataFetcher::init(void *configuration) throw(chaos::CException) { - if(dataDriver) { - dataDriver->init(NULL); - } - updateConfiguration(static_cast<CDataWrapper*>(configuration)); -} - -// Start the implementation -void LiveDataFetcher::start() throw(chaos::CException) { - -} - -// Deinit the implementation -void LiveDataFetcher::deinit() throw(chaos::CException) { - if(dataDriver) { - dataDriver->deinit(); - } -} - -void LiveDataFetcher::getData(const std::string& key, CDataWrapper& newData, uint64_t& ts) { - currentRawDataPtr.reset(dataDriver->retriveRawData(key)); - - //create key/value chaos object - newData.setSerializedData(currentRawDataPtr.get()); - - //extras the timestamp of the pack - ts = newData.getInt64Value(DataPackCommonKey::DPCK_TIMESTAMP); -} \ No newline at end of file diff --git a/chaos/ui_toolkit/caching/LiveDataFetcher.h b/chaos/ui_toolkit/caching/LiveDataFetcher.h deleted file mode 100644 index cd48618b4..000000000 --- a/chaos/ui_toolkit/caching/LiveDataFetcher.h +++ /dev/null @@ -1,74 +0,0 @@ -// -// LiveDataFetcher.h -// CHAOSFramework -// -// Created by Claudio Bisegni on 1/5/13. -// Copyright (c) 2013 INFN. All rights reserved. -// - -#ifndef __CHAOSFramework__LiveDataFetcher__ -#define __CHAOSFramework__LiveDataFetcher__ - -#include <chaos/common/data/CDataWrapper.h> -#include <chaos/common/general/Configurable.h> -#include <chaos/common/utility/StartableService.h> -#include <chaos/common/caching_system/caching_thread/tracker_interface/DataFetcherInterface.h> - -namespace chaos_io = chaos::common::io; -namespace chaos_data = chaos::common::data; - -namespace chaos { - namespace common{ - namespace io { - class IODataDriver; - } - } - - namespace ui { - namespace chaching { - - /*! - Class that implemnt the CDatawrapper fetcher from !CHAOS live data. - */ - class LiveDataFetcher : - public chaos::caching_system::DataFetcherInterface<chaos_data::CDataWrapper>, - public chaos::Configurable, - public common::utility::StartableService { - ChaosUniquePtr<char> currentRawDataPtr; - - chaos_io::IODataDriver *dataDriver; - - void getData(const std::string& key, chaos_data::CDataWrapper& newData, uint64_t& ts); - - public: - - /*! - Default Constructor - \param _dataDriver the isntance ofthe driver to use with this fetcer - */ - LiveDataFetcher(chaos_io::IODataDriver *_dataDriver); - - /*! - Defaut Destructor - */ - virtual ~LiveDataFetcher(); - - /* - Update the driver configuration - */ - chaos_data::CDataWrapper* updateConfiguration(chaos_data::CDataWrapper*); - - // Initialize instance - void init(void*) throw(chaos::CException); - - // Start the implementation - void start() throw(chaos::CException); - - // Deinit the implementation - void deinit() throw(chaos::CException); - }; - } - } -} - -#endif /* defined(__CHAOSFramework__LiveDataFetcher__) */ diff --git a/chaos_metadata_service_client/CMakeLists.txt b/chaos_metadata_service_client/CMakeLists.txt index ad34a7209..ee8dee18e 100644 --- a/chaos_metadata_service_client/CMakeLists.txt +++ b/chaos_metadata_service_client/CMakeLists.txt @@ -73,13 +73,11 @@ SET(mcl_src ${mcl_src} api_proxy/node/GetNodeDescription.cpp api_proxy/node/CommandTemplateSubmit.cpp api_proxy/node/CommandInstanceSubmit.cpp api_proxy/node/UpdateProperty.cpp - api_proxy/node/GetPropertyDefaultValues.cpp - api_proxy/node/UpdatePropertyDefaultValues.cpp + api_proxy/node/GetPropertyDefaultValues.cpp + api_proxy/node/UpdatePropertyDefaultValues.cpp api_proxy/node/GetCommandAndTemplateDescription.cpp - api_proxy/node/KillCurrentCommand.cpp - api_proxy/node/ClearCommandQueue.cpp - - ) + api_proxy/node/KillCurrentCommand.cpp + api_proxy/node/ClearCommandQueue.cpp) SET(mcl_src ${mcl_src} api_proxy/data_service/NewDS.cpp api_proxy/data_service/UpdateDS.cpp @@ -99,7 +97,8 @@ SET(mcl_src ${mcl_src} api_proxy/control_unit/SetInputDatasetAttributeValue api_proxy/control_unit/InitDeinit.cpp api_proxy/control_unit/StartStop.cpp api_proxy/control_unit/CopyInstance.cpp - api_proxy/control_unit/RecoverError.cpp) + api_proxy/control_unit/RecoverError.cpp + api_proxy/control_unit/SendStorageBurst.cpp) SET(mcl_src ${mcl_src} api_proxy/unit_server/GetDescription.cpp api_proxy/unit_server/NewUS.cpp diff --git a/chaos_metadata_service_client/api_proxy/control_unit/Delete.h b/chaos_metadata_service_client/api_proxy/control_unit/Delete.h index 50fcb585b..7e35a89f3 100644 --- a/chaos_metadata_service_client/api_proxy/control_unit/Delete.h +++ b/chaos_metadata_service_client/api_proxy/control_unit/Delete.h @@ -22,7 +22,6 @@ #ifndef __CHAOSFramework__Delete_h #define __CHAOSFramework__Delete_h - #include <chaos_metadata_service_client/api_proxy/ApiProxy.h> #include <boost/shared_ptr.hpp> @@ -53,5 +52,4 @@ namespace chaos { } } - #endif /* Delete_h */ diff --git a/chaos_metadata_service_client/api_proxy/control_unit/SendStorageBurst.cpp b/chaos_metadata_service_client/api_proxy/control_unit/SendStorageBurst.cpp new file mode 100644 index 000000000..8ef6d3839 --- /dev/null +++ b/chaos_metadata_service_client/api_proxy/control_unit/SendStorageBurst.cpp @@ -0,0 +1,54 @@ +/* + * Copyright 2012, 03/07/2018 INFN + * + * Licensed under the EUPL, Version 1.2 or – as soon they + * will be approved by the European Commission - subsequent + * versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the + * Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in + * writing, software distributed under the Licence is + * distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. + * See the Licence for the specific language governing + * permissions and limitations under the Licence. + */ + +#include <chaos_metadata_service_client/api_proxy/control_unit/SendStorageBurst.h> + +using namespace chaos::common::data; +using namespace chaos::common::data::structured; +using namespace chaos::metadata_service_client::api_proxy; +using namespace chaos::metadata_service_client::api_proxy::control_unit; + + +API_PROXY_CD_DEFINITION(SendStorageBurst, + "control_unit", + "sendStorageBurst") + +ApiProxyResult SendStorageBurst::execute(const std::string& cu_uid, + chaos::common::data::structured::DatasetBurst& dataset_burst) { + ChaosStringSet cu_set; + cu_set.insert(cu_uid); + return execute(cu_set, dataset_burst); +} + +ApiProxyResult SendStorageBurst::execute(const ChaosStringSet& cu_set, + chaos::common::data::structured::DatasetBurst& dataset_burst) { + DatasetBurstSDWrapper db_sdw(CHAOS_DATA_WRAPPER_REFERENCE_AUTO_PTR(DatasetBurst, dataset_burst)); + ChaosUniquePtr<chaos::common::data::CDataWrapper> message(new chaos::common::data::CDataWrapper()); + for(ChaosStringSetIterator it = cu_set.begin(), + end = cu_set.end(); + it != end; + it++) { + message->appendStringToArray(*it); + } + message->finalizeArrayForKey(chaos::NodeDefinitionKey::NODE_UNIQUE_ID); + db_sdw.serialize()->copyAllTo(*message); + return callApi(message.release()); +} diff --git a/chaos_metadata_service_client/api_proxy/control_unit/SendStorageBurst.h b/chaos_metadata_service_client/api_proxy/control_unit/SendStorageBurst.h new file mode 100644 index 000000000..86851266f --- /dev/null +++ b/chaos_metadata_service_client/api_proxy/control_unit/SendStorageBurst.h @@ -0,0 +1,64 @@ +/* + * Copyright 2012, 03/07/2018 INFN + * + * Licensed under the EUPL, Version 1.2 or – as soon they + * will be approved by the European Commission - subsequent + * versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the + * Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in + * writing, software distributed under the Licence is + * distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. + * See the Licence for the specific language governing + * permissions and limitations under the Licence. + */ + +#ifndef __CHAOSFramework__SendStorageBurst_h +#define __CHAOSFramework__SendStorageBurst_h + +#include <chaos_metadata_service_client/api_proxy/ApiProxy.h> + +#include <chaos/common/data/structured/Dataset.h> + +namespace chaos { + namespace metadata_service_client { + namespace api_proxy { + namespace control_unit { + + //! Start a stoarge burst on a determinated constor unit + /*! + The stoarge burst a funciton taht permit to momentary enable the istoricization of + consotrlnit output dataset on determinate rule + */ + class SendStorageBurst: + public chaos::metadata_service_client::api_proxy::ApiProxy { + API_PROXY_CLASS(SendStorageBurst) + protected: + //! default constructor + API_PROXY_CD_DECLARATION(SendStorageBurst) + public: + /*! + \param cu_uid the uid of the control unit + \param dataset_burst is the information of burst + */ + ApiProxyResult execute(const std::string& cu_uid, + chaos::common::data::structured::DatasetBurst& dataset_burst); + /*! + \param cu_uid the set of uid of one or more control unit + \param dataset_burst is the information of burst + */ + ApiProxyResult execute(const ChaosStringSet& cu_set, + chaos::common::data::structured::DatasetBurst& dataset_burst); + }; + } + } + } +} + +#endif /* Delete_h */ diff --git a/chaos_metadata_service_client/api_proxy/control_unit/control_unit.h b/chaos_metadata_service_client/api_proxy/control_unit/control_unit.h index ad0dbe952..91ccefbae 100644 --- a/chaos_metadata_service_client/api_proxy/control_unit/control_unit.h +++ b/chaos_metadata_service_client/api_proxy/control_unit/control_unit.h @@ -21,7 +21,6 @@ #ifndef __CHAOSFramework__21F26AF_8477_485A_A08A_39F56D3644AE_control_unit_h #define __CHAOSFramework__21F26AF_8477_485A_A08A_39F56D3644AE_control_unit_h - #include <chaos_metadata_service_client/api_proxy/control_unit/Delete.h> #include <chaos_metadata_service_client/api_proxy/control_unit/StartStop.h> #include <chaos_metadata_service_client/api_proxy/control_unit/InitDeinit.h> @@ -29,6 +28,7 @@ #include <chaos_metadata_service_client/api_proxy/control_unit/CopyInstance.h> #include <chaos_metadata_service_client/api_proxy/control_unit/RecoverError.h> #include <chaos_metadata_service_client/api_proxy/control_unit/DeleteInstance.h> +#include <chaos_metadata_service_client/api_proxy/control_unit/SendStorageBurst.h> #include <chaos_metadata_service_client/api_proxy/control_unit/GetCurrentDataset.h> #include <chaos_metadata_service_client/api_proxy/control_unit/SearchInstancesByUS.h> #include <chaos_metadata_service_client/api_proxy/control_unit/SetInstanceDescription.h> diff --git a/chaos_metadata_service_client/node_controller/CUController.cpp b/chaos_metadata_service_client/node_controller/CUController.cpp index 26dca92a6..5d8b315fc 100644 --- a/chaos_metadata_service_client/node_controller/CUController.cpp +++ b/chaos_metadata_service_client/node_controller/CUController.cpp @@ -54,14 +54,14 @@ using namespace chaos::metadata_service_client; #define MDS_TIMEOUT 5000 #define DBGET LDBG_<<"["<<__PRETTY_FUNCTION__<<"]" #define EXECUTE_CHAOS_API(api_name,time_out,...) \ - DBGET<<" " <<" Executing Api:\""<< # api_name<<"\"" ;\ - chaos::metadata_service_client::api_proxy::ApiProxyResult apires= GET_CHAOS_API_PTR(api_name)->execute( __VA_ARGS__ );\ - apires->setTimeout(time_out);\ - apires->wait();\ - if(apires->getError()){\ - std::stringstream ss;\ - ss<<" error in :"<<__FUNCTION__<<"|"<<__LINE__<<"|"<< # api_name <<" " <<apires->getErrorMessage();\ - throw CException(-2,ss.str(),__PRETTY_FUNCTION__);} +DBGET<<" " <<" Executing Api:\""<< # api_name<<"\"" ;\ +chaos::metadata_service_client::api_proxy::ApiProxyResult apires= GET_CHAOS_API_PTR(api_name)->execute( __VA_ARGS__ );\ +apires->setTimeout(time_out);\ +apires->wait();\ +if(apires->getError()){\ +std::stringstream ss;\ +ss<<" error in :"<<__FUNCTION__<<"|"<<__LINE__<<"|"<< # api_name <<" " <<apires->getErrorMessage();\ +throw CException(-2,ss.str(),__PRETTY_FUNCTION__);} CUController::CUController(const std::string& _deviceID, chaos::common::io::IODataDriverShrdPtr _ioLiveDataDriver): @@ -127,6 +127,7 @@ CUController::~CUController() { } if(ioLiveDataDriver.get()){ + ioLiveDataDriver->deinit(); ioLiveDataDriver.reset(); } } @@ -156,7 +157,7 @@ void CUController::updateChannel() throw(CException) { CDataWrapper *tmp_data_handler = NULL; CHAOS_ASSERT(deviceChannel) LDBG_<<"UPDATING \""<<devId<<"\""; - /* + /* * if(deviceChannel==NULL){ LDBG_<<"["<<__PRETTY_FUNCTION__<<"] Device Channel not still ready..."; return; @@ -169,11 +170,11 @@ void CUController::updateChannel() throw(CException) { ChaosUniquePtr<chaos::common::data::CDataWrapper> lastDeviceDefinition(tmp_data_handler); datasetDB.addAttributeToDataSetFromDataWrapper(*lastDeviceDefinition.get()); - + } int CUController::setScheduleDelay(uint64_t microseconds) { - + chaos::common::property::PropertyGroup pg(chaos::ControlUnitPropertyKey::GROUP_NAME); pg.addProperty(chaos::ControlUnitDatapackSystemKey::THREAD_SCHEDULE_DELAY, CDataVariant(static_cast<uint64_t>(microseconds))); DBGET<<chaos::ControlUnitDatapackSystemKey::THREAD_SCHEDULE_DELAY<<":"<<microseconds; @@ -184,7 +185,7 @@ int CUController::setScheduleDelay(uint64_t microseconds) { int CUController::setBypass(bool onoff){ chaos::common::property::PropertyGroup pg(chaos::ControlUnitPropertyKey::GROUP_NAME); pg.addProperty(chaos::ControlUnitDatapackSystemKey::BYPASS_STATE, CDataVariant(static_cast<bool>(onoff))); - + EXECUTE_CHAOS_API(chaos::metadata_service_client::api_proxy::node::UpdateProperty,millisecToWait,devId,pg); return 0; } @@ -413,7 +414,7 @@ int CUController::setAttributeToValue(const char *attributeName, const char *att } } LDBG_<<"["<<__PRETTY_FUNCTION__<<"] Sending attribute '"<<attributeName<<"'='"<<attributeValuePack.getJSONString()<<"'"; - + return deviceChannel->setAttributeValue(attributeValuePack, noWait, millisecToWait); } @@ -927,10 +928,10 @@ int CUController::fetchAllDataset() { end = current_dataset.end(); (it != end) && (counter<results.size()); it++) { - - (*it) = results[counter++]; - - + + (*it) = results[counter++]; + + } } return err; @@ -951,31 +952,31 @@ ChaosSharedPtr<chaos::common::data::CDataWrapper> CUController::fetchCurrentDat } int CUController::getPackSeq(uint64_t& seq){ - CDataWrapper * d = current_dataset[KeyDataStorageDomainOutput].get(); - if(d){ - seq =d->getInt64Value(DataPackCommonKey::DPCK_SEQ_ID); - return 0; - } - seq=-1; - return -1; + CDataWrapper * d = current_dataset[KeyDataStorageDomainOutput].get(); + if(d){ + seq =d->getInt64Value(DataPackCommonKey::DPCK_SEQ_ID); + return 0; + } + seq=-1; + return -1; } int CUController::getTimeStamp(uint64_t& live,bool hr){ CDataWrapper * d = current_dataset[KeyDataStorageDomainOutput].get(); live =0; if(d){ - if(hr){ - if(d->hasKey(DataPackCommonKey::DPCK_HIGH_RESOLUTION_TIMESTAMP)) { - live = d->getInt64Value(DataPackCommonKey::DPCK_HIGH_RESOLUTION_TIMESTAMP); - } else if(d->hasKey(DataPackCommonKey::DPCK_TIMESTAMP)){ - live= d->getInt64Value(DataPackCommonKey::DPCK_TIMESTAMP)*1000; - } - } else { - if(d->hasKey(DataPackCommonKey::DPCK_TIMESTAMP)){ - live = d->getInt64Value(DataPackCommonKey::DPCK_TIMESTAMP); - } else if(d->hasKey(DataPackCommonKey::DPCK_HIGH_RESOLUTION_TIMESTAMP)){ - live= d->getInt64Value(DataPackCommonKey::DPCK_HIGH_RESOLUTION_TIMESTAMP)*1000; - } - } + if(hr){ + if(d->hasKey(DataPackCommonKey::DPCK_HIGH_RESOLUTION_TIMESTAMP)) { + live = d->getInt64Value(DataPackCommonKey::DPCK_HIGH_RESOLUTION_TIMESTAMP); + } else if(d->hasKey(DataPackCommonKey::DPCK_TIMESTAMP)){ + live= d->getInt64Value(DataPackCommonKey::DPCK_TIMESTAMP)*1000; + } + } else { + if(d->hasKey(DataPackCommonKey::DPCK_TIMESTAMP)){ + live = d->getInt64Value(DataPackCommonKey::DPCK_TIMESTAMP); + } else if(d->hasKey(DataPackCommonKey::DPCK_HIGH_RESOLUTION_TIMESTAMP)){ + live= d->getInt64Value(DataPackCommonKey::DPCK_HIGH_RESOLUTION_TIMESTAMP)*1000; + } + } return 0; } return -1; @@ -1064,32 +1065,36 @@ cu_prof_t CUController::getProfileInfo(){ void CUController::executeTimeIntervallQuery(DatasetDomain domain, uint64_t start_ts, uint64_t end_ts, + const ChaosStringSet& meta_tags, QueryCursor **query_cursor, uint32_t page) { if((domain>=0) && (domain<=DPCK_LAST_DATASET_INDEX)){ *query_cursor = ioLiveDataDriver->performQuery(channel_keys[domain], start_ts, end_ts, + meta_tags, page); } } -void CUController::executeTimeIntervalQuery(DatasetDomain domain, - uint64_t start_ts, - uint64_t end_ts, - uint64_t seqid, - uint64_t runid, - chaos::common::io::QueryCursor **query_cursor, - uint32_t page_len){ +void CUController::executeTimeIntervalQuery(const DatasetDomain domain, + const uint64_t start_ts, + const uint64_t end_ts, + const uint64_t seqid, + const uint64_t runid, + const ChaosStringSet& meta_tags, + chaos::common::io::QueryCursor **query_cursor, + const uint32_t page_len){ if((domain>=0) && (domain<=DPCK_LAST_DATASET_INDEX)){ *query_cursor = ioLiveDataDriver->performQuery(channel_keys[domain], start_ts, end_ts, seqid, runid, + meta_tags, page_len); } - + } //! release a query void CUController::releaseQuery(QueryCursor *query_cursor) { diff --git a/chaos_metadata_service_client/node_controller/CUController.h b/chaos_metadata_service_client/node_controller/CUController.h index 854d90f6d..d63ea5643 100644 --- a/chaos_metadata_service_client/node_controller/CUController.h +++ b/chaos_metadata_service_client/node_controller/CUController.h @@ -47,9 +47,9 @@ namespace chaos { namespace node_controller { //! identify the domain qhere fetch the data - - typedef chaos::cu::data_manager::KeyDataStorageDomain DatasetDomain; - + + typedef chaos::cu::data_manager::KeyDataStorageDomain DatasetDomain; + //! Controller for a single device instance /*! This represent a global controller for a single device, identified by DEVICE_ID. The contorlle rpermit to @@ -169,7 +169,7 @@ namespace chaos { Set the control unit run method scheduling delay */ int setScheduleDelay(uint64_t microsecondsDelay); - + //! update the scudiling of device run method /*! Set the control unit bypass @@ -193,7 +193,7 @@ namespace chaos { * @return 0 on success, negative otherwise */ int getPackSeq(uint64_t& seq); - + /*! Get description for attribute name */ @@ -260,7 +260,7 @@ namespace chaos { */ int deinitDevice(); - + /** * recover the device from an error (recoverable) * @return 0 on success @@ -410,7 +410,7 @@ namespace chaos { //!return the last fetched dataset for the domain ChaosSharedPtr<chaos::common::data::CDataWrapper> getCurrentDatasetForDomain(DatasetDomain domain); - + //!return the last fetched dataset for the domain int getCurrentDatasetForDomain(DatasetDomain domain,chaos::common::data::CDataWrapper* ret); @@ -439,7 +439,7 @@ namespace chaos { //! send custom request to device and return a future ChaosUniquePtr<chaos::common::message::MessageRequestFuture> sendCustomRequestWithFuture(const std::string& action_name, - common::data::CDataWrapper *request_date); + common::data::CDataWrapper *request_date); //! send custom message to device void sendCustomMessage(const std::string& action, @@ -448,7 +448,7 @@ namespace chaos { //! Send a request for receive RPC information int checkRPCInformation(chaos::common::data::CDataWrapper **result_information, uint32_t timeout = RpcConfigurationKey::GlobalRPCTimeoutinMSec -); + ); //! Send a request for an echo test int echoTest(chaos::common::data::CDataWrapper * const echo_data, @@ -456,18 +456,22 @@ namespace chaos { uint32_t timeout = RpcConfigurationKey::GlobalRPCTimeoutinMSec); //! get datapack between time itervall - void executeTimeIntervallQuery(DatasetDomain domain, - uint64_t start_ts, - uint64_t end_ts, - chaos::common::io::QueryCursor **query_cursor,uint32_t page_len=DEFAULT_PAGE_LEN); - - void executeTimeIntervalQuery(DatasetDomain domain, - uint64_t start_ts, - uint64_t end_ts, - uint64_t seqid, - uint64_t runid, - chaos::common::io::QueryCursor **query_cursor,uint32_t page_len=DEFAULT_PAGE_LEN); - + void executeTimeIntervallQuery(const DatasetDomain domain, + const uint64_t start_ts, + const uint64_t end_ts, + const ChaosStringSet& meta_tags, + chaos::common::io::QueryCursor **query_cursor, + const uint32_t page_len=DEFAULT_PAGE_LEN); + + void executeTimeIntervalQuery(const DatasetDomain domain, + const uint64_t start_ts, + const uint64_t end_ts, + const uint64_t seqid, + const uint64_t runid, + const ChaosStringSet& meta_tags, + chaos::common::io::QueryCursor **query_cursor, + const uint32_t page_len=DEFAULT_PAGE_LEN); + //! release a query void releaseQuery(chaos::common::io::QueryCursor *query_cursor); diff --git a/config/CMakeMacroUtils.txt b/config/CMakeMacroUtils.txt index 79f10b04c..b6e339f2e 100644 --- a/config/CMakeMacroUtils.txt +++ b/config/CMakeMacroUtils.txt @@ -5,6 +5,12 @@ macro (MESG parm) MESSAGE(STATUS "[${WHERE}] ${parm}") endmacro() +macro (WARN parm) +# get_filename_component(WHERE ${CMAKE_CURRENT_LIST_DIR} DIRECTORY) + SET(WHERE ${CMAKE_CURRENT_LIST_DIR}) + MESSAGE(WARNING "[${WHERE}] ${parm}") +endmacro() + macro (ERROR parm) # get_filename_component(WHERE ${CMAKE_CURRENT_LIST_DIR} DIRECTORY) SET(WHERE ${CMAKE_CURRENT_LIST_DIR}) diff --git a/example/ChaosCLI/CMakeLists.txt b/example/ChaosCLI/CMakeLists.txt deleted file mode 100644 index cc942ae0d..000000000 --- a/example/ChaosCLI/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -cmake_minimum_required(VERSION 2.6) -# IF (DEFINED ENV{CHAOS_BUNDLE} ) -# include($ENV{CHAOS_BUNDLE}/tools/project_template/CMakeChaos.txt) -# ENDIF() - -SET(chaos_cli_src main.cpp) - -ADD_EXECUTABLE(ChaosCLI ${chaos_cli_src}) - - -IF(BUILD_FORCE_STATIC) - SET(CMAKE_EXE_LINKER_FLAGS "-static -Wl,--whole-archive -lchaos_common -Wl,--no-whole-archive") -ENDIF() - -TARGET_LINK_LIBRARIES(ChaosCLI chaos_uitoolkit chaos_common ${FrameworkLib}) -INSTALL_TARGETS(/bin ChaosCLI) diff --git a/example/ChaosCLI/ChaosCLI b/example/ChaosCLI/ChaosCLI deleted file mode 100755 index c9548cd86d05ac0fdd045525a472bd015f7f1ed7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 553004 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 Mi)L^MBP`(m0j1vd`v3p{ diff --git a/example/ChaosCLI/ChaosCLI.xcodeproj/project.pbxproj b/example/ChaosCLI/ChaosCLI.xcodeproj/project.pbxproj deleted file mode 100644 index f520c354b..000000000 --- a/example/ChaosCLI/ChaosCLI.xcodeproj/project.pbxproj +++ /dev/null @@ -1,261 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 32DC4AE317903EB5005F1696 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 32DC4AE217903EB5005F1696 /* main.cpp */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 32DC4AD317903E87005F1696 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 32DC4AD517903E87005F1696 /* ChaosCLI */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ChaosCLI; sourceTree = BUILT_PRODUCTS_DIR; }; - 32DC4AE117903EB5005F1696 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = SOURCE_ROOT; }; - 32DC4AE217903EB5005F1696 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = main.cpp; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 32DC4AD217903E87005F1696 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 32DC4ACC17903E87005F1696 = { - isa = PBXGroup; - children = ( - 32DC4AD717903E87005F1696 /* ChaosCLI */, - 32DC4AD617903E87005F1696 /* Products */, - ); - sourceTree = "<group>"; - }; - 32DC4AD617903E87005F1696 /* Products */ = { - isa = PBXGroup; - children = ( - 32DC4AD517903E87005F1696 /* ChaosCLI */, - ); - name = Products; - sourceTree = "<group>"; - }; - 32DC4AD717903E87005F1696 /* ChaosCLI */ = { - isa = PBXGroup; - children = ( - 32DC4AE117903EB5005F1696 /* CMakeLists.txt */, - 32DC4AE217903EB5005F1696 /* main.cpp */, - ); - path = ChaosCLI; - sourceTree = "<group>"; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 32DC4AD417903E87005F1696 /* ChaosCLI */ = { - isa = PBXNativeTarget; - buildConfigurationList = 32DC4ADE17903E87005F1696 /* Build configuration list for PBXNativeTarget "ChaosCLI" */; - buildPhases = ( - 32DC4AD117903E87005F1696 /* Sources */, - 32DC4AD217903E87005F1696 /* Frameworks */, - 32DC4AD317903E87005F1696 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = ChaosCLI; - productName = ChaosCLI; - productReference = 32DC4AD517903E87005F1696 /* ChaosCLI */; - productType = "com.apple.product-type.tool"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 32DC4ACD17903E87005F1696 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0500; - ORGANIZATIONNAME = infn; - }; - buildConfigurationList = 32DC4AD017903E87005F1696 /* Build configuration list for PBXProject "ChaosCLI" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 32DC4ACC17903E87005F1696; - productRefGroup = 32DC4AD617903E87005F1696 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 32DC4AD417903E87005F1696 /* ChaosCLI */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXSourcesBuildPhase section */ - 32DC4AD117903E87005F1696 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 32DC4AE317903EB5005F1696 /* main.cpp in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 32DC4ADC17903E87005F1696 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++98"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.8; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - }; - name = Debug; - }; - 32DC4ADD17903E87005F1696 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++98"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.8; - SDKROOT = macosx; - }; - name = Release; - }; - 32DC4ADF17903E87005F1696 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++98"; - CLANG_CXX_LIBRARY = "libc++"; - CONFIGURATION_BUILD_DIR = "$(SRCROOT)/../../usr/local/bin"; - GCC_C_LANGUAGE_STANDARD = gnu99; - HEADER_SEARCH_PATHS = ( - ../../, - ../../usr/local/include, - ); - LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../usr/local/lib"; - OTHER_LDFLAGS = ( - "-lchaos_uitoolkit", - "-lchaos_common", - ); - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 32DC4AE017903E87005F1696 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++98"; - CLANG_CXX_LIBRARY = "libc++"; - CONFIGURATION_BUILD_DIR = "$(SRCROOT)/../../usr/local/bin"; - GCC_C_LANGUAGE_STANDARD = gnu99; - HEADER_SEARCH_PATHS = ( - ../../, - ../../usr/local/include, - ); - LIBRARY_SEARCH_PATHS = "$(SRCROOT)/../../usr/local/lib"; - OTHER_LDFLAGS = ( - "-lchaos_uitoolkit", - "-lchaos_common", - ); - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 32DC4AD017903E87005F1696 /* Build configuration list for PBXProject "ChaosCLI" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 32DC4ADC17903E87005F1696 /* Debug */, - 32DC4ADD17903E87005F1696 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 32DC4ADE17903E87005F1696 /* Build configuration list for PBXNativeTarget "ChaosCLI" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 32DC4ADF17903E87005F1696 /* Debug */, - 32DC4AE017903E87005F1696 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 32DC4ACD17903E87005F1696 /* Project object */; -} diff --git a/example/ChaosCLI/ChaosCLI.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/ChaosCLI/ChaosCLI.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/example/ChaosCLI/ChaosCLI.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<Workspace - version = "1.0"> - <FileRef - location = "self:"> - </FileRef> -</Workspace> diff --git a/example/ChaosCLI/main.cpp b/example/ChaosCLI/main.cpp deleted file mode 100644 index 6c99d6293..000000000 --- a/example/ChaosCLI/main.cpp +++ /dev/null @@ -1,518 +0,0 @@ -/* - * Copyright 2012, 2017 INFN - * - * Licensed under the EUPL, Version 1.2 or – as soon they - * will be approved by the European Commission - subsequent - * versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the - * Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in - * writing, software distributed under the Licence is - * distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. - * See the Licence for the specific language governing - * permissions and limitations under the Licence. - */ -#include <iostream> -#include <string> -#include <vector> -#include <chaos/common/global.h> -#include <chaos/common/utility/TimingUtil.h> -#include <chaos/common/chaos_constants.h> -#include <chaos/common/network/CNodeNetworkAddress.h> -#include <chaos/ui_toolkit/ChaosUIToolkit.h> -#include <chaos/ui_toolkit/LowLevelApi/LLRpcApi.h> -#include <chaos/ui_toolkit/HighLevelApi/HLDataApi.h> -#include <stdio.h> -#include <boost/date_time/posix_time/posix_time.hpp> -#include <boost/date_time/c_local_time_adjustor.hpp> -#include <boost/random/random_device.hpp> -#include <boost/random/uniform_int_distribution.hpp> - -using namespace std; -using namespace chaos; -using namespace chaos::common::data; -using namespace chaos::ui; -using namespace boost; -using namespace boost::posix_time; -using namespace boost::date_time; -namespace chaos_batch = chaos::common::batch_command; - -#define OPT_STATE "op" -#define OPT_TIMEOUT "timeout" -#define OPT_CU_ID "device-id" -#define OPT_SCHEDULE_TIME "stime" -#define OPT_PRINT_STATE "print-state" -#define OPT_PRINT_TYPE "print-type" -#define OPT_PRINT_DATASET "print-dataset" -#define OPT_GET_DS_VALUE "get_ds_value" -//--------------slow contorol option---------------------------------------------------- -#define OPT_SL_ALIAS "sc-alias" -#define OPT_SL_EXEC_CHANNEL "sc-exec-channel" -#define OPT_SL_PRIORITY "sc-priority" -#define OPT_SL_SUBMISSION_RULE "sc-sub-rule" -#define OPT_SL_COMMAND_DATA "sc-cmd-data" -#define OPT_SL_COMMAND_ID "sc-cmd-id" -#define OPT_SL_COMMAND_SCHEDULE_DELAY "sc-cmd-sched-wait" -#define OPT_SL_COMMAND_SUBMISSION_RETRY_DELAY "sc-cmd-submission-retry-delay" -#define OPT_SL_COMMAND_SET_FEATURES_LOCK "sc-cmd-features-lock" -#define OPT_SL_COMMAND_SET_FEATURES_SCHEDULER_WAIT "sc-cmd-features-sched-wait" -//--------------rt control unit option-------------------------------------------------- -#define OPT_RT_ATTRIBUTE_VALUE "rt-attr-val" - -const std::string rand_chars("abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "1234567890" - "!@#$%^&*()" - "`~-_=+[{]{\\|;:'\",<.>/? " - "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "1234567890" - "!@#$%^&*()" - "`~-_=+[{]{\\|;:'\",<.>/? " - "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "1234567890" - "!@#$%^&*()" - "`~-_=+[{]{\\|;:'\",<.>/? " - "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "1234567890" - "!@#$%^&*()" - "`~-_=+[{]{\\|;:'\",<.>/? "); - -inline ptime utcToLocalPTime(ptime utcPTime){ - c_local_adjustor<ptime> utcToLocalAdjustor; - ptime t11 = utcToLocalAdjustor.utc_to_local(utcPTime); - return t11; -} - -void print_state(CUStateKey::ControlUnitState state) { - switch (state) { - case CUStateKey::INIT: - std::cout << "Initialized:"<<state; - break; - case CUStateKey::START: - std::cout << "Started:"<<state; - break; - case CUStateKey::STOP: - std::cout << "Stopped:"<<state; - break; - case CUStateKey::DEINIT: - std::cout << "Deinitilized:"<<state; - break; - - case CUStateKey::RECOVERABLE_ERROR: - std::cout << "Recovable Error:"<<state; - break; - case CUStateKey::FATAL_ERROR: - std::cout << "Fatal Error:"<<state; - break; - default: - std::cout << "Uknown:"<<state; - - } - std::cout<<std::endl; -} - -int checkSubmissionRule(std::string scSubmissionRule) { - if( scSubmissionRule.compare("normal") == 0) { - return chaos_batch::SubmissionRuleType::SUBMIT_NORMAL; - } else if( scSubmissionRule.compare("stack") == 0) { - return chaos_batch::SubmissionRuleType::SUBMIT_AND_STACK; - } else if( scSubmissionRule.compare("kill") == 0) { - return chaos_batch::SubmissionRuleType::SUBMIT_AND_KILL; - } else return -1; -} - -int main (int argc, const char* argv[] ) -{ - try { - int err = 0; - int op =-1; - bool printState = false; - bool printType = false; - int32_t print_domain_current_value = -1; - long scheduleTime; - uint32_t timeout; - - string deviceID; - string scAlias; - string scSubmissionRule; - string scUserData; - uint64_t scCmdID; - uint32_t scSubmissionPriority; - uint32_t scSubmissionSchedulerDelay; - uint32_t scSubmissionSubmissionRetryDelay; - uint32_t scExecutionChannel; - string rtAttributeValue; - vector<string> key_to_show; - - - bool scFeaturesLock; - uint32_t scFeaturesSchedWait; - std::string control_unit_type; - CDeviceNetworkAddress deviceNetworkAddress; - CUStateKey::ControlUnitState deviceState; - - //! [UIToolkit Attribute Init] - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<string>(OPT_CU_ID, "The identification string of the device"); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<uint32_t>(OPT_TIMEOUT, "Timeout rpc in milliseconds", 2000, &timeout); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<int>(OPT_STATE, "The state to set on the device{1=init, 2=start, 3=stop, 4=deinit, 5=set schedule time, 6=submite slow command(slcu), 7=kill current command(slcu), 8=get command state by id, 9=set input channel(rtcu)}, 10=flush history state(slcu), 11=get dataset value for keys", 0); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<long>(OPT_SCHEDULE_TIME, "the time in microseconds for devide schedule time"); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<bool>(OPT_PRINT_STATE, "Print the state of the device", false, &printState); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<bool>(OPT_PRINT_TYPE, "Print the type of the control unit of the device", false, &printType); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<int32_t>(OPT_PRINT_DATASET, "print the dataset for the domain -1=no-print, 0=output, 1=input, 2=custom, 3=system 4=health 5=alarm", -1, &print_domain_current_value); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption< vector<string> >(OPT_GET_DS_VALUE, "Print last value of the dataset keys[to use with opcode 11]", &key_to_show, true); - - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<string>(OPT_SL_ALIAS, "The alias associted to the command for the slow control cu", "", &scAlias); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<uint32_t>(OPT_SL_EXEC_CHANNEL, "TThe alias used to execute the command [it's 1 based, 0 let choice the channel to the engine]", 0, &scExecutionChannel); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<string>(OPT_SL_SUBMISSION_RULE, "The rule used for submit the command for the slow control cu [normal, stack, kill]","stack", &scSubmissionRule); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<uint32_t>(OPT_SL_PRIORITY, "The priority used for submit the command for the slow control cu", 50,&scSubmissionPriority); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<string>(OPT_SL_COMMAND_DATA, "The bson pack (in text format) sent to the set handler of the command for the slow", &scUserData); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<uint64_t>(OPT_SL_COMMAND_ID, "The command identification number(cidn)", &scCmdID); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<uint32_t>(OPT_SL_COMMAND_SCHEDULE_DELAY, "The millisecond beetwen a step an the next of the scheduler[in milliseconds]", 1000000, &scSubmissionSchedulerDelay); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<uint32_t>(OPT_SL_COMMAND_SUBMISSION_RETRY_DELAY, "The millisecond beetwen submission checker run", 1000, &scSubmissionSubmissionRetryDelay); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<bool>(OPT_SL_COMMAND_SET_FEATURES_LOCK, "if true will lock the feature to the command modification", &scFeaturesLock); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<uint32_t>(OPT_SL_COMMAND_SET_FEATURES_SCHEDULER_WAIT, "The millisecond beetwen two step of the scheduler", &scFeaturesSchedWait); - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->addOption<string>(OPT_RT_ATTRIBUTE_VALUE, "The attribute and value for the input attribute in rt control unit [attribute:value]", &rtAttributeValue); - - //! [UIToolkit Attribute Init] - - //! [UIToolkit Init] - ChaosUIToolkit::getInstance()->init(argc, argv); - //! [UIToolkit Init] - - if(ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->hasOption(OPT_STATE)){ - op = ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->getOption<int>(OPT_STATE); - } - - if(ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->hasOption(OPT_CU_ID)){ - deviceID = ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->getOption<string>(OPT_CU_ID); - } - - if(deviceID.size()==0) throw CException(1, "invalid device identification string", "check param"); - - - if(op == 5 && !ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->hasOption(OPT_SCHEDULE_TIME)) - throw CException(3, "The set schedule time code need the param \"stime\"", "device controller creation"); - else{ - if(op == 5){ - scheduleTime = ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->getOption<long>(OPT_SCHEDULE_TIME); - } - } - - DeviceController *controller = HLDataApi::getInstance()->getControllerForDeviceID(deviceID, timeout); - if(!controller) throw CException(4, "Error allcoating decive controller", "device controller creation"); - - for(int idx = 0; idx < 8000000; idx++) { - CDataWrapper message_echo; - message_echo.addStringValue("echo_message", CHAOS_FORMAT("echo_test_message %1%/n%2%",%idx%rand_chars)); - - CDataWrapper *result = NULL; - try{ - if(controller->echoTest(&message_echo, &result) == 0) { - - } - }catch(...) { - - } - if(result) { - std::cout << idx << " - " <<result->getJSONString() << std::endl; - delete(result); - } - usleep(100); - } - - controller->fetchCurrentDeviceValue(); - - // use the RPC version for the moment - err = controller->getType(control_unit_type); - if(err == ErrorCode::EC_TIMEOUT) { - control_unit_type="unknown"; - } - // std::cout << "type:"<<control_unit_type<<std::endl; - if((control_unit_type =="rtcu") || (control_unit_type =="sccu")){ - err = controller->getState(deviceState); - if(err == ErrorCode::EC_TIMEOUT && op!=11) throw CException(5, "Time out on connection", "Get state for device"); - //std::cout << control_unit_type<<" device, state:"; - //print_state(deviceState); - } else { - std::cout << "State-less device, type:"<<control_unit_type<<std::endl; - // deviceState = CUStateKey::START; - } - - if(printState) { - uint64_t err; - //err = controller->getState(deviceState); - err = controller->getState(deviceState); - - if(err == 0) throw CException(5, "Error retrving the state", "Get state for device"); - std::cout << "Current state ["<<err<<"]:"; - print_state(deviceState); - std::cout << std::endl; - } - - if(printType) { - std::string control_unit_type; - err = controller->getState(deviceState); - if(err == ErrorCode::EC_TIMEOUT && op!=11) throw CException(5, "Time out on connection", "Get state for device"); - std::cout << "Control unit type:"; - - std::cout << control_unit_type << std::endl; - } - - if(print_domain_current_value >= 0) { - controller->fetchCurrentDatatasetFromDomain((DatasetDomain)print_domain_current_value); - if(controller->getCurrentDatasetForDomain((DatasetDomain)print_domain_current_value) != NULL) { - std::cout << controller->getCurrentDatasetForDomain((DatasetDomain)print_domain_current_value)->getJSONString() <<std::endl; - } - - } - - switch (op) { - case 1: - /* - Init the control unit - */ - - err = controller->initDevice(); - if(err == ErrorCode::EC_TIMEOUT) throw CException(6, "Time out on connection", "Set device to init state"); - - - /* if((deviceState == CUStateKey::START)||(deviceState == CUStateKey::STOP)) { - print_state(deviceState); - throw CException(deviceState, "%% The device is in start or stop state.", "Setting device to init state"); - - }*/ - break; - case 2: - /* - Start the control unit - */ - - err = controller->startDevice(); - if(err == ErrorCode::EC_TIMEOUT) throw CException(2, "Time out on connection", "Set device to start state"); - /*if(deviceState == CUStateKey::DEINIT ) { - print_state(deviceState); - throw CException(deviceState, "%% The device is in deinit state, cannot change state", "Set device to start state"); - }*/ - break; - case 3: - /* - Stop the control unit - */ - - - err = controller->stopDevice(); - if(err == ErrorCode::EC_TIMEOUT) throw CException(2, "Time out on connection", "Set device to stop state"); - /* if((deviceState == CUStateKey::INIT)||(deviceState == CUStateKey::DEINIT)) { - print_state(deviceState); - throw CException(deviceState, "%% The device is not in the start/stop", "Set device to stop state"); - }*/ - break; - case 4: - /* - deinit the control unit - */ - - err = controller->deinitDevice(); - if(err == ErrorCode::EC_TIMEOUT){ - throw CException(2, "Time out on connection", "Set device to deinit state"); - } - /* if(deviceState == CUStateKey::START){ - print_state(deviceState); - throw CException(deviceState, "%% Device is in start cannot change state", "Set device to deinit"); - }*/ - - break; - case 5: - /* - change schedule - */ - - err = controller->setScheduleDelay(scheduleTime); - if(err == ErrorCode::EC_TIMEOUT) throw CException(2, "Time out on connection", "Set device to deinit state"); - /* if(deviceState == CUStateKey::DEINIT) { - print_state(deviceState); - throw CException(29, "%% Device can't be in deinit state", "Set device schedule time"); - }*/ - break; - case 6: { - //check sc - uint64_t command_id = 0; - ChaosUniquePtr<chaos::common::data::CDataWrapper> userData; - bool canBeExecuted = scAlias.size() > 0; - canBeExecuted = canBeExecuted && (checkSubmissionRule(scSubmissionRule) != -1); - if(canBeExecuted) { - if(ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->hasOption(OPT_SL_COMMAND_SUBMISSION_RETRY_DELAY)) { - std::cout << "Custom checker delay submitted -> " << scSubmissionSubmissionRetryDelay << std::endl; - } - - if(ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->hasOption(OPT_SL_COMMAND_DATA)) { - userData.reset(new CDataWrapper()); - if(userData.get())userData->setSerializedJsonData(scUserData.c_str()); - std::cout << "User data submitted" << std::endl; - std::cout << "-----------------------------------------" << std::endl; - std::cout << userData->getJSONString() << std::endl; - std::cout << "-----------------------------------------" << std::endl; - } - err = controller->submitSlowControlCommand(scAlias, - static_cast<chaos_batch::SubmissionRuleType::SubmissionRule>(checkSubmissionRule(scSubmissionRule)), - scSubmissionPriority, - command_id, - scExecutionChannel, - scSubmissionSchedulerDelay, - scSubmissionSubmissionRetryDelay, - userData.get()); - if(err == ErrorCode::EC_TIMEOUT) throw CException(2, "Time out on connection", "Set device to deinit state"); - std::cout << "Command submitted successfully his command idedentification number(cidn) is= " << command_id << std::endl; - } else { - throw CException(29, "Device can't be in deinit state", "Send slow command"); - } - } - break; - case 7:{ - err = controller->killCurrentCommand(); - break; - } - case 8:{ - //chec if has been porvided a command ID - if(!ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->hasOption(OPT_SL_COMMAND_ID)) { - throw CException(1, "No command id provided", "OPCODE 8"); - } - chaos_batch::CommandState command_state; - command_state.command_id = scCmdID; - err = controller->getCommandState(command_state); - std::cout << "Device state start -------------------------------------------------------" << std::endl; - std::cout << "Command"; - switch (command_state.last_event) { - case chaos_batch::BatchCommandEventType::EVT_COMPLETED: - std::cout << " has completed"<< std::endl;; - break; - case chaos_batch::BatchCommandEventType::EVT_FAULT: - std::cout << " has fault"; - std::cout << "Error code :"<<command_state.fault_description.code<< std::endl; - std::cout << "Error domain :"<<command_state.fault_description.domain<< std::endl; - std::cout << "Error description :"<<command_state.fault_description.description<< std::endl; - break; - case chaos_batch::BatchCommandEventType::EVT_KILLED: - std::cout << " has been killed"<< std::endl; - break; - case chaos_batch::BatchCommandEventType::EVT_PAUSED: - std::cout << " has been paused"<< std::endl; - break; - case chaos_batch::BatchCommandEventType::EVT_QUEUED: - std::cout << " has been queued"<< std::endl; - break; - case chaos_batch::BatchCommandEventType::EVT_RUNNING: - std::cout << " is running"<< std::endl; - break; - case chaos_batch::BatchCommandEventType::EVT_WAITING: - std::cout << " is waiting"<< std::endl; - break; - } - std::cout << "Device state end ---------------------------------------------------------" << std::endl; - break; - } - case 9: { - //set an input attribute of the dataset(rtcu) - if(!ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->hasOption(OPT_RT_ATTRIBUTE_VALUE)) { - throw CException(1, "No attribute and value setupped", "OPCODE 9"); - } - if(rtAttributeValue.find(":")== string::npos) { - throw CException(2, "Attribute param not well formet, lak of ':' character (param_name:param_value)", "OPCODE 9"); - - } - std::string param_name = rtAttributeValue.substr(0, rtAttributeValue.find(":")); - std::string param_value = rtAttributeValue.substr(rtAttributeValue.find(":")+1); - //get name and value of the attribute - err = controller->setAttributeToValue(param_name.c_str(), param_value.c_str(), false); - if(err == ErrorCode::EC_TIMEOUT) - throw CException(3, "Time out on connection", "OPCODE 9"); - else if(err != ErrorCode::EC_NO_ERROR) - throw CException(3, "Time out on connection", "OPCODE 9"); - - break; - } - - case 10:{ - err = controller->flushCommandStateHistory(); - if(err == ErrorCode::EC_TIMEOUT) throw CException(3, "Time out on connection", "OPCODE 10"); - break; - } - - case 11:{ - controller->fetchCurrentDeviceValue(); - CDataWrapper * dataWrapper = controller->getLiveCDataWrapperPtr(); - if(dataWrapper) { - std::cout << dataWrapper->getJSONString() << std::endl; - } - std::string str_value; - for (int idx = 0; idx < key_to_show.size(); idx++) { - if(!controller->getAttributeStrValue(key_to_show[idx], str_value)) { - std::cout << key_to_show[idx] << " = " << str_value << std::endl; - } - } - - break; - } - - } - - if(ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->hasOption(OPT_SL_COMMAND_SET_FEATURES_LOCK) || - ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->hasOption(OPT_SL_COMMAND_SET_FEATURES_SCHEDULER_WAIT)){ - - chaos_batch::features::Features features; - - //we can set the features - if(ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->hasOption(OPT_SL_COMMAND_SET_FEATURES_LOCK)) { - features.featuresFlag |= chaos_batch::features::FeaturesFlagTypes::FF_LOCK_USER_MOD; - std::cout << "Set the lock feature to -> " << scFeaturesLock << std::endl; - //set the lock - err = controller->setSlowCommandLockOnFeatures(scFeaturesLock); - if(err == ErrorCode::EC_TIMEOUT) throw CException(5, "Time out on connection", "setSlowCommandLockOnFeatures"); - } - - if(ChaosUIToolkit::getInstance()->getGlobalConfigurationInstance()->hasOption(OPT_SL_COMMAND_SET_FEATURES_SCHEDULER_WAIT)) { - features.featuresFlag |= chaos_batch::features::FeaturesFlagTypes::FF_SET_SCHEDULER_DELAY; - features.featureSchedulerStepsDelay = scFeaturesSchedWait; - std::cout << "Set the sched wait feature to -> " << scFeaturesSchedWait << " on execution channel " << scExecutionChannel << std::endl; - //se the features - err = controller->setSlowCommandFeatures(features, scFeaturesLock, scExecutionChannel); - if(err == ErrorCode::EC_TIMEOUT) throw CException(5, "Time out on connection", "setSlowCommandFeatures"); - } - - } - - if( printState && (op>=1 && op<=4)){ - //get the actual state of device - err = controller->getState(deviceState); - if(err == ErrorCode::EC_TIMEOUT) throw CException(5, "Time out on connection", "Get state for device"); - std::cout << "State after operation:"; - print_state(deviceState); - std::cout << std::endl; - } - - if(controller) - HLDataApi::getInstance()->disposeDeviceControllerPtr(controller); - - } catch (CException& e) { - std::cerr << e.errorCode << " - "<< e.errorDomain << " - " << e.errorMessage << std::endl; - return -4; - } - try { - //! [UIToolkit Deinit] - ChaosUIToolkit::getInstance()->deinit(); - //! [UIToolkit Deinit] - } catch (CException& e) { - std::cerr << e.errorCode << " - "<< e.errorDomain << " - " << e.errorMessage << std::endl; - return -3; - } - return 0; -} diff --git a/example/ChaosPerformanceTester/main.cpp b/example/ChaosPerformanceTester/main.cpp index 9ad087528..3a6d16094 100644 --- a/example/ChaosPerformanceTester/main.cpp +++ b/example/ChaosPerformanceTester/main.cpp @@ -24,9 +24,6 @@ #include <chaos/common/global.h> #include <chaos/common/chaos_constants.h> #include <chaos/common/network/CNodeNetworkAddress.h> -#include <chaos/ui_toolkit/ChaosUIToolkit.h> -#include <chaos/ui_toolkit/LowLevelApi/LLRpcApi.h> -#include <chaos/ui_toolkit/HighLevelApi/HLDataApi.h> #include <stdio.h> #include <chaos/common/bson/bson.h> @@ -38,7 +35,6 @@ using namespace std; using namespace chaos; using namespace chaos::common::network; -using namespace chaos::ui; using namespace boost; using namespace boost::posix_time; using namespace boost::date_time; -- GitLab