cosmos 4.1.1-java → 4.2.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +0 -2
- data/.travis.yml +2 -0
- data/.yardopts +1 -0
- data/Gemfile +1 -0
- data/Manifest.txt +130 -0
- data/autohotkey/tools/ConfigEditorAHK +19 -0
- data/autohotkey/tools/cmd_extractor.ahk +4 -4
- data/autohotkey/tools/cmd_sequence.ahk +9 -5
- data/autohotkey/tools/config_editor.ahk +197 -0
- data/autohotkey/tools/packet_viewer.ahk +12 -6
- data/autohotkey/tools/replay.ahk +29 -29
- data/autohotkey/tools/script_runner.ahk +10 -2
- data/autohotkey/tools/tlm_extractor.ahk +7 -8
- data/autohotkey/tools/tlm_grapher.ahk +21 -9
- data/bin/dart_import +2 -0
- data/cosmos.gemspec +18 -16
- data/data/config/cmd_tlm_server.yaml +9 -0
- data/data/config/interface_modifiers.yaml +17 -0
- data/data/config/item_modifiers.yaml +3 -3
- data/data/crc.txt +184 -90
- data/data/dart.png +0 -0
- data/demo/Gemfile +1 -0
- data/demo/Rakefile +4 -0
- data/demo/config/dart/Gemfile +54 -0
- data/demo/config/data/crc.txt +28 -21
- data/demo/config/system/system.txt +3 -0
- data/demo/config/system/system2.txt +3 -0
- data/demo/config/targets/INST/cmd_tlm/inst_cmds.txt +3 -3
- data/demo/config/targets/INST/cmd_tlm/inst_tlm.txt +1 -1
- data/demo/config/targets/INST/lib/sim_inst.rb +1 -1
- data/demo/config/targets/INST/screens/adcs.txt +2 -1
- data/demo/config/targets/INST/screens/array.txt +1 -1
- data/demo/config/targets/INST/screens/block.txt +1 -1
- data/demo/config/targets/INST/screens/commanding.txt +7 -2
- data/demo/config/targets/INST/screens/graphs.txt +1 -1
- data/demo/config/targets/INST/screens/ground.txt +1 -1
- data/demo/config/targets/INST/screens/hs.txt +2 -1
- data/demo/config/targets/INST/screens/latest.txt +1 -1
- data/demo/config/targets/INST/screens/limits.txt +1 -1
- data/demo/config/targets/INST/screens/other.txt +1 -1
- data/demo/config/targets/INST/screens/tabs.txt +1 -1
- data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +2 -2
- data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +3 -1
- data/demo/config/tools/launcher/launcher.txt +3 -2
- data/demo/tools/Dart +16 -0
- data/demo/tools/Dart.bat +9 -0
- data/demo/tools/mac/CmdSequence.app/Contents/MacOS/main.sh +0 -0
- data/demo/tools/mac/ConfigEditor.app/Contents/MacOS/main.sh +0 -0
- data/install/Gemfile +1 -0
- data/install/Rakefile +4 -0
- data/install/config/dart/Gemfile +54 -0
- data/install/config/data/crc.txt +6 -3
- data/install/config/system/system.txt +3 -0
- data/install/config/tools/launcher/launcher.txt +3 -2
- data/install/tools/Dart +16 -0
- data/install/tools/Dart.bat +9 -0
- data/install/tools/mac/CmdSequence.app/Contents/MacOS/main.sh +0 -0
- data/install/tools/mac/ConfigEditor.app/Contents/MacOS/main.sh +0 -0
- data/lib/cosmos/core_ext/time.rb +8 -8
- data/lib/cosmos/dart/.rspec +1 -0
- data/lib/cosmos/dart/Gemfile +69 -0
- data/lib/cosmos/dart/Rakefile +7 -0
- data/lib/cosmos/dart/app/assets/config/manifest.js +4 -0
- data/lib/cosmos/dart/app/assets/images/.keep +0 -0
- data/lib/cosmos/dart/app/assets/javascripts/application.js +13 -0
- data/lib/cosmos/dart/app/assets/javascripts/cable.js +13 -0
- data/lib/cosmos/dart/app/assets/stylesheets/application.css.scss +15 -0
- data/lib/cosmos/dart/app/channels/application_cable/channel.rb +4 -0
- data/lib/cosmos/dart/app/channels/application_cable/connection.rb +4 -0
- data/lib/cosmos/dart/app/controllers/application_controller.rb +3 -0
- data/lib/cosmos/dart/app/helpers/application_helper.rb +2 -0
- data/lib/cosmos/dart/app/jobs/application_job.rb +2 -0
- data/lib/cosmos/dart/app/mailers/application_mailer.rb +4 -0
- data/lib/cosmos/dart/app/models/application_record.rb +3 -0
- data/lib/cosmos/dart/app/models/item.rb +6 -0
- data/lib/cosmos/dart/app/models/item_to_decom_table_mapping.rb +9 -0
- data/lib/cosmos/dart/app/models/packet.rb +4 -0
- data/lib/cosmos/dart/app/models/packet_config.rb +7 -0
- data/lib/cosmos/dart/app/models/packet_log.rb +3 -0
- data/lib/cosmos/dart/app/models/packet_log_entry.rb +41 -0
- data/lib/cosmos/dart/app/models/system_config.rb +2 -0
- data/lib/cosmos/dart/app/models/target.rb +4 -0
- data/lib/cosmos/dart/app/views/layouts/application.html.erb +14 -0
- data/lib/cosmos/dart/app/views/layouts/mailer.html.erb +13 -0
- data/lib/cosmos/dart/app/views/layouts/mailer.text.erb +1 -0
- data/lib/cosmos/dart/bin/bundle +3 -0
- data/lib/cosmos/dart/bin/rails +4 -0
- data/lib/cosmos/dart/bin/rake +4 -0
- data/lib/cosmos/dart/bin/setup +34 -0
- data/lib/cosmos/dart/bin/update +29 -0
- data/lib/cosmos/dart/config.ru +5 -0
- data/lib/cosmos/dart/config/application.rb +29 -0
- data/lib/cosmos/dart/config/boot.rb +3 -0
- data/lib/cosmos/dart/config/cable.yml +9 -0
- data/lib/cosmos/dart/config/database.yml +23 -0
- data/lib/cosmos/dart/config/environment.rb +5 -0
- data/lib/cosmos/dart/config/environments/development.rb +62 -0
- data/lib/cosmos/dart/config/environments/production.rb +84 -0
- data/lib/cosmos/dart/config/environments/test.rb +42 -0
- data/lib/cosmos/dart/config/initializers/application_controller_renderer.rb +6 -0
- data/lib/cosmos/dart/config/initializers/assets.rb +12 -0
- data/lib/cosmos/dart/config/initializers/backtrace_silencers.rb +7 -0
- data/lib/cosmos/dart/config/initializers/cookies_serializer.rb +5 -0
- data/lib/cosmos/dart/config/initializers/filter_parameter_logging.rb +4 -0
- data/lib/cosmos/dart/config/initializers/inflections.rb +16 -0
- data/lib/cosmos/dart/config/initializers/mime_types.rb +4 -0
- data/lib/cosmos/dart/config/initializers/new_framework_defaults.rb +25 -0
- data/lib/cosmos/dart/config/initializers/session_store.rb +3 -0
- data/lib/cosmos/dart/config/initializers/wrap_parameters.rb +14 -0
- data/lib/cosmos/dart/config/locales/en.yml +23 -0
- data/lib/cosmos/dart/config/puma.rb +47 -0
- data/lib/cosmos/dart/config/routes.rb +3 -0
- data/lib/cosmos/dart/config/secrets.yml +22 -0
- data/lib/cosmos/dart/db/migrate/20170406172907_create_targets.rb +8 -0
- data/lib/cosmos/dart/db/migrate/20170406172927_create_packets.rb +10 -0
- data/lib/cosmos/dart/db/migrate/20170406172937_create_packet_logs.rb +9 -0
- data/lib/cosmos/dart/db/migrate/20170406172943_create_packet_log_entries.rb +16 -0
- data/lib/cosmos/dart/db/migrate/20170406183500_change_packet_log_entries_primary_key.rb +5 -0
- data/lib/cosmos/dart/db/migrate/20170407153618_add_unique_requirements.rb +7 -0
- data/lib/cosmos/dart/db/migrate/20170511155447_add_meta_id_to_packet_log_entries.rb +6 -0
- data/lib/cosmos/dart/db/migrate/20170523185056_rename_received_time_and_add_is_tlm_to_packet_log_entries.rb +7 -0
- data/lib/cosmos/dart/db/migrate/20170525201157_create_items.rb +10 -0
- data/lib/cosmos/dart/db/migrate/20170525201315_create_system_configs.rb +9 -0
- data/lib/cosmos/dart/db/migrate/20170525201624_create_packet_configs.rb +11 -0
- data/lib/cosmos/dart/db/migrate/20170525201745_create_item_to_decom_table_mappings.rb +12 -0
- data/lib/cosmos/dart/db/migrate/20170525201939_create_decom_tables.rb +12 -0
- data/lib/cosmos/dart/db/migrate/20170525202051_add_decom_state_to_packet_log_entry.rb +5 -0
- data/lib/cosmos/dart/db/migrate/20170913160409_update_items.rb +6 -0
- data/lib/cosmos/dart/db/migrate/20170913160558_update_item_to_decom_table_mapping.rb +11 -0
- data/lib/cosmos/dart/db/migrate/20170913160916_udpate_decom_table.rb +6 -0
- data/lib/cosmos/dart/db/migrate/20170913212026_add_ready_to_packet_configs.rb +5 -0
- data/lib/cosmos/dart/db/migrate/20170913223556_modify_tables.rb +9 -0
- data/lib/cosmos/dart/db/migrate/20170914215744_modify_mapping_table.rb +6 -0
- data/lib/cosmos/dart/db/migrate/20170919201433_add_system_config_id_to_packet_config.rb +11 -0
- data/lib/cosmos/dart/db/migrate/20170919210307_add_max_table_index_to_packet_configs.rb +5 -0
- data/lib/cosmos/dart/db/migrate/20171215225546_add_ready_to_packet_log_entries.rb +5 -0
- data/lib/cosmos/dart/db/migrate/20180116214338_add_index_for_ple_ready_to_packet_log_entries.rb +5 -0
- data/lib/cosmos/dart/db/schema.rb +103 -0
- data/lib/cosmos/dart/db/seeds.rb +7 -0
- data/lib/cosmos/dart/examples/dart_decom_client.rb +45 -0
- data/lib/cosmos/dart/examples/dart_stream_client.rb +93 -0
- data/lib/cosmos/dart/lib/dart_common.rb +749 -0
- data/lib/cosmos/dart/lib/dart_database_cleaner.rb +172 -0
- data/lib/cosmos/dart/lib/dart_decom_query.rb +184 -0
- data/lib/cosmos/dart/lib/dart_decommutator.rb +235 -0
- data/lib/cosmos/dart/lib/dart_importer.rb +154 -0
- data/lib/cosmos/dart/lib/dart_logging.rb +50 -0
- data/lib/cosmos/dart/lib/dart_packet_log_writer.rb +139 -0
- data/lib/cosmos/dart/lib/dart_reducer_manager.rb +85 -0
- data/lib/cosmos/dart/lib/dart_reducer_worker_thread.rb +263 -0
- data/lib/cosmos/dart/lib/dart_tcpip_server_interface.rb +142 -0
- data/lib/cosmos/dart/processes/dart.rb +145 -0
- data/lib/cosmos/dart/processes/dart_decom_server.rb +39 -0
- data/lib/cosmos/dart/processes/dart_import.rb +63 -0
- data/lib/cosmos/dart/processes/dart_ingester.rb +92 -0
- data/lib/cosmos/dart/processes/dart_reducer.rb +27 -0
- data/lib/cosmos/dart/processes/dart_stream_server.rb +31 -0
- data/lib/cosmos/dart/processes/dart_worker.rb +37 -0
- data/lib/cosmos/dart/spec/dart/dart_common_spec.rb +333 -0
- data/lib/cosmos/dart/spec/dart/dart_database_cleaner_spec.rb +455 -0
- data/lib/cosmos/dart/spec/dart/dart_decom_query_spec.rb +153 -0
- data/lib/cosmos/dart/spec/dart/dart_decommutator_spec.rb +336 -0
- data/lib/cosmos/dart/spec/dart/dart_importer_spec.rb +83 -0
- data/lib/cosmos/dart/spec/dart/dart_logging_spec.rb +30 -0
- data/lib/cosmos/dart/spec/dart/dart_packet_log_writer_spec.rb +149 -0
- data/lib/cosmos/dart/spec/dart/dart_reducer_manager_spec.rb +289 -0
- data/lib/cosmos/dart/spec/dart/dart_tcpip_server_interface_spec.rb +241 -0
- data/lib/cosmos/dart/spec/rails_helper.rb +60 -0
- data/lib/cosmos/dart/spec/spec_helper.rb +139 -0
- data/lib/cosmos/gui/dialogs/about_dialog.rb +1 -1
- data/lib/cosmos/gui/dialogs/dart_dialog.rb +60 -0
- data/lib/cosmos/gui/dialogs/legal_dialog.rb +1 -0
- data/lib/cosmos/gui/dialogs/scroll_text_dialog.rb +0 -3
- data/lib/cosmos/gui/qt.rb +10 -1
- data/lib/cosmos/gui/text/completion.rb +10 -9
- data/lib/cosmos/gui/text/completion_text_edit.rb +16 -14
- data/lib/cosmos/gui/text/ruby_editor.rb +2 -2
- data/lib/cosmos/gui/widgets/dart_frame.rb +142 -0
- data/lib/cosmos/gui/widgets/dart_meta_frame.rb +119 -0
- data/lib/cosmos/gui/widgets/packet_log_frame.rb +42 -12
- data/lib/cosmos/interfaces/interface.rb +1 -2
- data/lib/cosmos/interfaces/protocols/crc_protocol.rb +26 -8
- data/lib/cosmos/interfaces/protocols/fixed_protocol.rb +8 -2
- data/lib/cosmos/interfaces/protocols/protocol.rb +2 -1
- data/lib/cosmos/interfaces/protocols/template_protocol.rb +1 -1
- data/lib/cosmos/interfaces/stream_interface.rb +1 -0
- data/lib/cosmos/interfaces/tcpip_server_interface.rb +2 -3
- data/lib/cosmos/io/json_drb_object.rb +1 -1
- data/lib/cosmos/io/json_rpc.rb +2 -1
- data/lib/cosmos/io/win32_serial_driver.rb +2 -9
- data/lib/cosmos/packet_logs/packet_log_writer.rb +1 -1
- data/lib/cosmos/packets/packet.rb +22 -12
- data/lib/cosmos/packets/packet_config.rb +2 -1
- data/lib/cosmos/packets/packet_item.rb +26 -24
- data/lib/cosmos/packets/parsers/macro_parser.rb +5 -2
- data/lib/cosmos/packets/parsers/packet_item_parser.rb +35 -17
- data/lib/cosmos/packets/parsers/packet_parser.rb +3 -10
- data/lib/cosmos/packets/parsers/xtce_converter.rb +21 -35
- data/lib/cosmos/packets/parsers/xtce_parser.rb +54 -46
- data/lib/cosmos/packets/structure.rb +10 -2
- data/lib/cosmos/packets/structure_item.rb +22 -8
- data/lib/cosmos/processors/statistics_processor.rb +2 -0
- data/lib/cosmos/script/api_shared.rb +13 -12
- data/lib/cosmos/script/cmd_tlm_server.rb +4 -0
- data/lib/cosmos/script/commands.rb +3 -15
- data/lib/cosmos/script/script.rb +69 -23
- data/lib/cosmos/streams/tcpip_client_stream.rb +2 -2
- data/lib/cosmos/system/system.rb +42 -25
- data/lib/cosmos/system/target.rb +6 -2
- data/lib/cosmos/tools/cmd_extractor/cmd_extractor.rb +177 -36
- data/lib/cosmos/tools/cmd_sender/cmd_param_table_item_delegate.rb +3 -2
- data/lib/cosmos/tools/cmd_sender/cmd_sender.rb +34 -8
- data/lib/cosmos/tools/cmd_sequence/cmd_sequence.rb +80 -25
- data/lib/cosmos/tools/cmd_tlm_server/api.rb +19 -4
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server.rb +15 -14
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui.rb +15 -9
- data/lib/cosmos/tools/cmd_tlm_server/gui/interfaces_tab.rb +1 -9
- data/lib/cosmos/tools/cmd_tlm_server/gui/logging_tab.rb +1 -6
- data/lib/cosmos/tools/cmd_tlm_server/gui/packets_tab.rb +1 -3
- data/lib/cosmos/tools/cmd_tlm_server/gui/replay_tab.rb +84 -7
- data/lib/cosmos/tools/cmd_tlm_server/gui/status_tab.rb +0 -1
- data/lib/cosmos/tools/cmd_tlm_server/gui/targets_tab.rb +1 -5
- data/lib/cosmos/tools/cmd_tlm_server/limits_groups_background_task.rb +3 -2
- data/lib/cosmos/tools/cmd_tlm_server/replay_backend.rb +159 -27
- data/lib/cosmos/tools/cmd_tlm_server/routers.rb +1 -1
- data/lib/cosmos/tools/config_editor/config_editor.rb +17 -52
- data/lib/cosmos/tools/config_editor/config_editor_frame.rb +0 -5
- data/lib/cosmos/tools/data_viewer/data_viewer.rb +111 -0
- data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +31 -18
- data/lib/cosmos/tools/packet_viewer/packet_viewer.rb +12 -3
- data/lib/cosmos/tools/script_runner/script_runner.rb +27 -14
- data/lib/cosmos/tools/script_runner/script_runner_frame.rb +104 -37
- data/lib/cosmos/tools/table_manager/table_config.rb +1 -1
- data/lib/cosmos/tools/table_manager/table_item_parser.rb +4 -2
- data/lib/cosmos/tools/table_manager/table_manager.rb +0 -5
- data/lib/cosmos/tools/table_manager/table_manager_core.rb +0 -1
- data/lib/cosmos/tools/test_runner/test.rb +1 -3
- data/lib/cosmos/tools/test_runner/test_runner.rb +26 -15
- data/lib/cosmos/tools/tlm_extractor/tlm_extractor.rb +290 -137
- data/lib/cosmos/tools/tlm_extractor/tlm_extractor_config.rb +122 -25
- data/lib/cosmos/tools/tlm_extractor/tlm_extractor_processor.rb +67 -0
- data/lib/cosmos/tools/tlm_grapher/data_object_editors/housekeeping_data_object_editor.rb +28 -0
- data/lib/cosmos/tools/tlm_grapher/data_object_editors/xy_data_object_editor.rb +36 -0
- data/lib/cosmos/tools/tlm_grapher/data_objects/data_object.rb +42 -3
- data/lib/cosmos/tools/tlm_grapher/data_objects/housekeeping_data_object.rb +88 -14
- data/lib/cosmos/tools/tlm_grapher/data_objects/linegraph_data_object.rb +2 -5
- data/lib/cosmos/tools/tlm_grapher/data_objects/singlexy_data_object.rb +2 -6
- data/lib/cosmos/tools/tlm_grapher/data_objects/xy_data_object.rb +74 -18
- data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_config.rb +3 -7
- data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_dart_thread.rb +159 -0
- data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_tool.rb +49 -2
- data/lib/cosmos/tools/tlm_viewer/screen.rb +3 -0
- data/lib/cosmos/tools/tlm_viewer/tlm_viewer_config.rb +0 -2
- data/lib/cosmos/tools/tlm_viewer/widgets.rb +1 -0
- data/lib/cosmos/tools/tlm_viewer/widgets/backgroundbutton_widget.rb +54 -0
- data/lib/cosmos/tools/tlm_viewer/widgets/button_widget.rb +5 -5
- data/lib/cosmos/top_level.rb +1 -0
- data/lib/cosmos/utilities/crc.rb +3 -0
- data/lib/cosmos/utilities/csv.rb +1 -0
- data/lib/cosmos/utilities/message_log.rb +2 -1
- data/lib/cosmos/utilities/simulated_target.rb +8 -8
- data/lib/cosmos/version.rb +5 -5
- data/lib/cosmos/win32/win32.rb +4 -10
- data/run_gui_tests.bat +2 -1
- data/spec/config/config_parser_spec.rb +4 -4
- data/spec/core_ext/array_spec.rb +1 -1
- data/spec/core_ext/exception_spec.rb +12 -12
- data/spec/core_ext/file_spec.rb +6 -6
- data/spec/core_ext/hash_spec.rb +1 -1
- data/spec/core_ext/socket_spec.rb +2 -2
- data/spec/core_ext/string_spec.rb +13 -13
- data/spec/core_ext/time_spec.rb +0 -2
- data/spec/gui/utilities/script_module_gui_spec.rb +3 -3
- data/spec/install/config/targets/INST/cmd_tlm/inst_tlm.txt +6 -6
- data/spec/install/config/tools/cmd_tlm_server/cmd_tlm_server.txt +4 -0
- data/spec/interfaces/cmd_tlm_server_interface_spec.rb +6 -2
- data/spec/interfaces/interface_spec.rb +0 -1
- data/spec/interfaces/linc_interface_spec.rb +0 -5
- data/spec/interfaces/protocols/crc_protocol_spec.rb +201 -85
- data/spec/interfaces/protocols/fixed_protocol_spec.rb +33 -9
- data/spec/interfaces/protocols/length_protocol_spec.rb +1 -1
- data/spec/interfaces/protocols/override_protocol_spec.rb +6 -2
- data/spec/interfaces/protocols/preidentified_protocol_spec.rb +1 -5
- data/spec/interfaces/protocols/template_protocol_spec.rb +0 -1
- data/spec/interfaces/simulated_target_interface_spec.rb +5 -5
- data/spec/interfaces/udp_interface_spec.rb +2 -4
- data/spec/io/buffered_file_spec.rb +8 -12
- data/spec/io/json_drb_spec.rb +9 -9
- data/spec/io/json_rpc_spec.rb +4 -4
- data/spec/io/raw_logger_spec.rb +4 -3
- data/spec/packet_logs/packet_log_reader_spec.rb +3 -6
- data/spec/packet_logs/packet_log_writer_spec.rb +4 -4
- data/spec/packets/binary_accessor_spec.rb +5 -8
- data/spec/packets/commands_spec.rb +2 -2
- data/spec/packets/limits_spec.rb +2 -2
- data/spec/packets/packet_config_spec.rb +12 -0
- data/spec/packets/packet_item_limits_spec.rb +1 -1
- data/spec/packets/packet_item_spec.rb +9 -9
- data/spec/packets/packet_spec.rb +15 -5
- data/spec/packets/parsers/packet_item_parser_spec.rb +27 -0
- data/spec/packets/parsers/xtce_parser_spec.rb +27 -30
- data/spec/packets/structure_spec.rb +2 -1
- data/spec/packets/telemetry_spec.rb +3 -5
- data/spec/processors/statistics_processor_spec.rb +35 -0
- data/spec/script/cmd_tlm_server_spec.rb +4 -21
- data/spec/script/commands_disconnect_spec.rb +46 -58
- data/spec/script/commands_spec.rb +40 -61
- data/spec/script/limits_spec.rb +1 -21
- data/spec/script/script_spec.rb +32 -41
- data/spec/script/scripting_spec.rb +166 -185
- data/spec/script/telemetry_spec.rb +10 -5
- data/spec/script/tools_spec.rb +2 -24
- data/spec/spec_helper.rb +11 -5
- data/spec/system/system_spec.rb +17 -12
- data/spec/tools/cmd_tlm_server/api_spec.rb +21 -10
- data/spec/tools/cmd_tlm_server/background_tasks_spec.rb +15 -16
- data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +0 -1
- data/spec/tools/cmd_tlm_server/cmd_tlm_server_spec.rb +16 -27
- data/spec/tools/cmd_tlm_server/commanding_spec.rb +2 -6
- data/spec/tools/cmd_tlm_server/connections_spec.rb +0 -4
- data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +13 -13
- data/spec/tools/cmd_tlm_server/interfaces_spec.rb +5 -9
- data/spec/tools/cmd_tlm_server/limits_groups_background_task_spec.rb +11 -3
- data/spec/tools/cmd_tlm_server/packet_logging_spec.rb +0 -4
- data/spec/tools/cmd_tlm_server/router_thread_spec.rb +5 -5
- data/spec/tools/cmd_tlm_server/routers_spec.rb +5 -9
- data/spec/tools/table_manager/table_config_spec.rb +0 -1
- data/spec/tools/table_manager/tablemanager_core_spec.rb +23 -23
- data/spec/tools/tlm_viewer/tlm_viewer_config_spec.rb +6 -4
- data/spec/top_level/top_level_spec.rb +9 -9
- data/spec/utilities/csv_spec.rb +2 -12
- data/spec/utilities/logger_spec.rb +6 -6
- data/spec/utilities/message_log_spec.rb +3 -11
- data/tasks/gemfile_stats.rake +2 -2
- metadata +167 -60
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# encoding: ascii-8bit
|
|
2
|
+
|
|
3
|
+
# Copyright 2018 Ball Aerospace & Technologies Corp.
|
|
4
|
+
# All Rights Reserved.
|
|
5
|
+
#
|
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
|
7
|
+
# under the terms of the GNU General Public License
|
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
|
10
|
+
|
|
11
|
+
require 'dart_common'
|
|
12
|
+
|
|
13
|
+
# Import COSMOS binary files into the DART database.
|
|
14
|
+
# This code must be run on the database server.
|
|
15
|
+
# The file to be imported should be placed in its final storage location.
|
|
16
|
+
# Note that files are imported in place with algorithms that attempt to prevent
|
|
17
|
+
# duplicate creation of Database entries.
|
|
18
|
+
class DartImporter
|
|
19
|
+
include DartCommon
|
|
20
|
+
|
|
21
|
+
# @param filename [String] Fully qualified filename to import
|
|
22
|
+
# @param force [Boolean] Whether to reverify all packets in a log file
|
|
23
|
+
# are in the database or just abort if the first and last are found.
|
|
24
|
+
def import(filename, force)
|
|
25
|
+
Cosmos::Logger.level = Cosmos::Logger::INFO
|
|
26
|
+
|
|
27
|
+
# Ensure all defined target and packets are in the database
|
|
28
|
+
sync_targets_and_packets()
|
|
29
|
+
|
|
30
|
+
dart_data_dir = File.expand_path(Cosmos::System.paths['DART_DATA'])
|
|
31
|
+
directory = File.dirname(File.expand_path(filename))
|
|
32
|
+
if directory != dart_data_dir
|
|
33
|
+
Cosmos::Logger.fatal("Imported files must be in \"#{dart_data_dir}\"")
|
|
34
|
+
Cosmos::Logger.fatal(" File is in: \"#{directory}\"")
|
|
35
|
+
return 1
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Make sure this file isn't already imported
|
|
39
|
+
packet_log = PacketLog.where("filename = ?", filename).first
|
|
40
|
+
if packet_log
|
|
41
|
+
Cosmos::Logger.warn("PacketLog already exists in database: #{filename}")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Determine if this is a command or telemetry packet log
|
|
45
|
+
begin
|
|
46
|
+
plr = Cosmos::PacketLogReader.new
|
|
47
|
+
plr.open(filename)
|
|
48
|
+
if plr.log_type == :TLM
|
|
49
|
+
is_tlm = true
|
|
50
|
+
else
|
|
51
|
+
is_tlm = false
|
|
52
|
+
end
|
|
53
|
+
rescue
|
|
54
|
+
Cosmos::Logger.fatal("Unable to open #{filename}. Exiting...")
|
|
55
|
+
return 1
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Check if first and last packet in the log are already in the database
|
|
59
|
+
last_packet = plr.last
|
|
60
|
+
first_packet = plr.first
|
|
61
|
+
plr.close
|
|
62
|
+
unless first_packet and last_packet
|
|
63
|
+
Cosmos::Logger.fatal("No packets found in file. Exiting...")
|
|
64
|
+
return 1
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
first_ple = find_packet_log_entry(first_packet, is_tlm)
|
|
68
|
+
last_ple = find_packet_log_entry(last_packet, is_tlm)
|
|
69
|
+
|
|
70
|
+
fast = false
|
|
71
|
+
if first_ple and last_ple
|
|
72
|
+
Cosmos::Logger.warn("First and Last Packet in File Already in Database.")
|
|
73
|
+
if force
|
|
74
|
+
Cosmos::Logger.warn("Reverifying all packets in database due to force...")
|
|
75
|
+
else
|
|
76
|
+
Cosmos::Logger.info("Complete")
|
|
77
|
+
return 1
|
|
78
|
+
end
|
|
79
|
+
elsif !first_ple and !last_ple
|
|
80
|
+
Cosmos::Logger.info("First and Last Packet in File not in database")
|
|
81
|
+
|
|
82
|
+
# Check if time range of packets is not present in database
|
|
83
|
+
ple = PacketLogEntry.where("time >= ? or time <= ?", first_packet.received_time, last_packet.received_time).first
|
|
84
|
+
if !ple # Can go fast if not present at all
|
|
85
|
+
Cosmos::Logger.info(" Fast Import Enabled...")
|
|
86
|
+
fast = true
|
|
87
|
+
end
|
|
88
|
+
else
|
|
89
|
+
Cosmos::Logger.warn("File partially in database. Will verify each packet before adding")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
unless packet_log
|
|
93
|
+
Cosmos::Logger.info("Creating PacketLog entry for file: #{filename}")
|
|
94
|
+
packet_log = PacketLog.create(:filename => filename, :is_tlm => is_tlm)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Read File and Create PacketLogEntries
|
|
98
|
+
count = 0
|
|
99
|
+
meta_id = nil
|
|
100
|
+
plr.open(filename)
|
|
101
|
+
data_offset = plr.bytes_read
|
|
102
|
+
plr.each(filename) do |packet|
|
|
103
|
+
target_name = packet.target_name
|
|
104
|
+
target_name = 'UNKNOWN' unless target_name
|
|
105
|
+
packet_name = packet.packet_name
|
|
106
|
+
packet_name = 'UNKNOWN' unless packet_name
|
|
107
|
+
|
|
108
|
+
target_id, packet_id = lookup_target_and_packet_id(target_name, packet_name, is_tlm)
|
|
109
|
+
|
|
110
|
+
# If packets aren't found in the database we don't have to bother looking
|
|
111
|
+
# for PacketLogEntrys in the database and can simply create new entries
|
|
112
|
+
if fast
|
|
113
|
+
ple = nil
|
|
114
|
+
else # File is partially in the DB so see if the packet already exists
|
|
115
|
+
ple = find_packet_log_entry(packet, is_tlm)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# No PacketLogEntry was found so create one from scratch
|
|
119
|
+
unless ple
|
|
120
|
+
ple = PacketLogEntry.new
|
|
121
|
+
ple.target_id = target_id
|
|
122
|
+
ple.packet_id = packet_id
|
|
123
|
+
ple.time = packet.received_time
|
|
124
|
+
ple.packet_log_id = packet_log.id
|
|
125
|
+
ple.data_offset = data_offset
|
|
126
|
+
ple.meta_id = meta_id
|
|
127
|
+
ple.is_tlm = is_tlm
|
|
128
|
+
ple.ready = true
|
|
129
|
+
ple.save!
|
|
130
|
+
count += 1
|
|
131
|
+
|
|
132
|
+
# SYSTEM META packets are special in that their meta_id is their own
|
|
133
|
+
# PacketLogEntry ID from the database. All other packets have meta_id
|
|
134
|
+
# values which point back to the last SYSTEM META PacketLogEntry ID.
|
|
135
|
+
if target_name == 'SYSTEM'.freeze and packet_name == 'META'.freeze
|
|
136
|
+
# Need to update meta_id for this and all subsequent packets
|
|
137
|
+
meta_id = ple.id
|
|
138
|
+
ple.meta_id = meta_id
|
|
139
|
+
ple.save!
|
|
140
|
+
end
|
|
141
|
+
else # A PacketLogEntry was found so this packet is skipped
|
|
142
|
+
# If the packet is a SYSTEM META packet we keep track of the meta_id
|
|
143
|
+
# for use in subsequent packets that aren't already in the database.
|
|
144
|
+
if target_name == 'SYSTEM'.freeze and packet_name == 'META'.freeze
|
|
145
|
+
# Need to update meta_id for subsequent packets
|
|
146
|
+
meta_id = ple.id
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
data_offset = plr.bytes_read
|
|
150
|
+
end
|
|
151
|
+
Cosmos::Logger.info("Added #{count} packet log entries to database")
|
|
152
|
+
return 0 # Success code
|
|
153
|
+
end
|
|
154
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# encoding: ascii-8bit
|
|
2
|
+
|
|
3
|
+
# Copyright 2018 Ball Aerospace & Technologies Corp.
|
|
4
|
+
# All Rights Reserved.
|
|
5
|
+
#
|
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
|
7
|
+
# under the terms of the GNU General Public License
|
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
|
10
|
+
|
|
11
|
+
require 'cosmos'
|
|
12
|
+
require 'stringio'
|
|
13
|
+
|
|
14
|
+
# Creates a MessageLog in the DART_LOGS System path for DART logging
|
|
15
|
+
class DartLogging
|
|
16
|
+
def initialize(message_log_name)
|
|
17
|
+
@output_sleeper = Cosmos::Sleeper.new
|
|
18
|
+
@string_output = StringIO.new("", "r+")
|
|
19
|
+
$stdout = @string_output
|
|
20
|
+
@message_log = Cosmos::MessageLog.new(message_log_name, Cosmos::System.paths['DART_LOGS'])
|
|
21
|
+
|
|
22
|
+
@output_thread = Thread.new do
|
|
23
|
+
while true
|
|
24
|
+
handle_string_output()
|
|
25
|
+
break if @output_sleeper.sleep(1)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def handle_string_output
|
|
31
|
+
if @string_output.string[-1..-1] == "\n"
|
|
32
|
+
string = @string_output.string.clone
|
|
33
|
+
@string_output.string = @string_output.string[string.length..-1]
|
|
34
|
+
@message_log.write(string, true)
|
|
35
|
+
STDOUT.print string if STDIN.isatty # Have a console
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def graceful_kill
|
|
40
|
+
# Do Nothing
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def stop
|
|
44
|
+
handle_string_output()
|
|
45
|
+
@output_sleeper.cancel
|
|
46
|
+
Cosmos.kill_thread(self, @output_thread)
|
|
47
|
+
handle_string_output()
|
|
48
|
+
@message_log.stop
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# encoding: ascii-8bit
|
|
2
|
+
|
|
3
|
+
# Copyright 2018 Ball Aerospace & Technologies Corp.
|
|
4
|
+
# All Rights Reserved.
|
|
5
|
+
#
|
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
|
7
|
+
# under the terms of the GNU General Public License
|
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
|
10
|
+
|
|
11
|
+
require 'dart_common'
|
|
12
|
+
|
|
13
|
+
# Writes all packets to a log file for use by the DART database.
|
|
14
|
+
# The PacketLog table hold the binary file name.
|
|
15
|
+
# As each packet is written to disk the location of the packet
|
|
16
|
+
# is recorded in the PacketLogEntry table for quick access.
|
|
17
|
+
class DartPacketLogWriter < Cosmos::PacketLogWriter
|
|
18
|
+
include DartCommon
|
|
19
|
+
|
|
20
|
+
DEFAULT_SYNC_COUNT_LIMIT = 100
|
|
21
|
+
|
|
22
|
+
# Initialize the database by synchronizing all known targets and
|
|
23
|
+
# packet names to the Target and Packet tables. Start the thread
|
|
24
|
+
# which updates the PacketLogEntry table when new packets arrive.
|
|
25
|
+
def initialize(*args)
|
|
26
|
+
super(*args)
|
|
27
|
+
@packet_log_id = nil
|
|
28
|
+
@meta_id = nil
|
|
29
|
+
@db_queue = Queue.new
|
|
30
|
+
@sync_count = 0
|
|
31
|
+
@sync_count_limit = DEFAULT_SYNC_COUNT_LIMIT
|
|
32
|
+
@not_ready_ple_ids = []
|
|
33
|
+
|
|
34
|
+
sync_targets_and_packets()
|
|
35
|
+
|
|
36
|
+
@db_thread = Cosmos.safe_thread("Database packet log entries") do
|
|
37
|
+
db_thread_body()
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Kill the database update thread
|
|
42
|
+
def shutdown
|
|
43
|
+
super()
|
|
44
|
+
Cosmos.kill_thread(self, @db_thread)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Kick the database update thread to allow it to quit
|
|
48
|
+
def graceful_kill
|
|
49
|
+
super()
|
|
50
|
+
@db_queue << nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
protected
|
|
54
|
+
|
|
55
|
+
# Override the default new file hook to create a PacketLog entry in the database
|
|
56
|
+
def start_new_file_hook(packet)
|
|
57
|
+
# When we create a new file we mark any existing PLEs ready
|
|
58
|
+
PacketLogEntry.where("id" => @not_ready_ple_ids).update_all(ready: true)
|
|
59
|
+
@not_ready_ple_ids.clear
|
|
60
|
+
@sync_count = 0
|
|
61
|
+
|
|
62
|
+
packet_log = PacketLog.new
|
|
63
|
+
packet_log.filename = @filename.clone
|
|
64
|
+
if @log_type == :TLM
|
|
65
|
+
packet_log.is_tlm = true
|
|
66
|
+
else
|
|
67
|
+
packet_log.is_tlm = false
|
|
68
|
+
end
|
|
69
|
+
packet_log.save!
|
|
70
|
+
@packet_log_id = packet_log.id
|
|
71
|
+
super(packet)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Override the default pre write hook to pop a message on the queue which
|
|
75
|
+
# will be processed by the database thread. This also writes out the log
|
|
76
|
+
# files to disk periodically for use by other DART processes.
|
|
77
|
+
def pre_write_entry_hook(packet)
|
|
78
|
+
@sync_count += 1
|
|
79
|
+
if @sync_count > @sync_count_limit
|
|
80
|
+
@file.fsync
|
|
81
|
+
@sync_count = 0
|
|
82
|
+
end
|
|
83
|
+
@db_queue << [packet.target_name, packet.packet_name, packet.received_time, @file_size, @packet_log_id, @sync_count]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Build the target / packet table lookup table and then wait on the queue
|
|
87
|
+
# being populated by the pre_write_entry_hook thread to add rows to the
|
|
88
|
+
# PacketLogEntry table. Each entry identifies a packet in the log file by
|
|
89
|
+
# its target, packet, time, and data offset (among other things).
|
|
90
|
+
def db_thread_body
|
|
91
|
+
if @log_type == :TLM
|
|
92
|
+
is_tlm = true
|
|
93
|
+
else
|
|
94
|
+
is_tlm = false
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
while true
|
|
98
|
+
begin
|
|
99
|
+
target_name, packet_name, time, data_offset, packet_log_id, sync_count = @db_queue.pop
|
|
100
|
+
# Every time the sync_count resets by the pre_write_entry_hook the file
|
|
101
|
+
# is written out to disk. Thus we mark all the PacketLogEntrys to ready
|
|
102
|
+
# since we know the packets have been written to disk.
|
|
103
|
+
if sync_count == 0 or sync_count.nil?
|
|
104
|
+
PacketLogEntry.where("id" => @not_ready_ple_ids).update_all(ready: true)
|
|
105
|
+
@not_ready_ple_ids.clear
|
|
106
|
+
end
|
|
107
|
+
return if @cancel_threads or sync_count.nil?
|
|
108
|
+
rescue ThreadError
|
|
109
|
+
# This can happen when the thread is killed
|
|
110
|
+
return
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
target_id, packet_id = lookup_target_and_packet_id(target_name, packet_name, is_tlm)
|
|
114
|
+
|
|
115
|
+
ple = PacketLogEntry.new
|
|
116
|
+
ple.target_id = target_id
|
|
117
|
+
ple.packet_id = packet_id
|
|
118
|
+
ple.time = time
|
|
119
|
+
ple.packet_log_id = packet_log_id
|
|
120
|
+
ple.data_offset = data_offset
|
|
121
|
+
ple.meta_id = @meta_id
|
|
122
|
+
ple.is_tlm = is_tlm
|
|
123
|
+
ple.ready = false
|
|
124
|
+
ple.save!
|
|
125
|
+
|
|
126
|
+
# SYSTEM META packets are special in that their meta_id is their own
|
|
127
|
+
# PacketLogEntry ID from the database. All other packets have meta_id
|
|
128
|
+
# values which point back to the last SYSTEM META PacketLogEntry ID.
|
|
129
|
+
if target_name == 'SYSTEM'.freeze and packet_name == 'META'.freeze
|
|
130
|
+
# Need to update meta_id for this and all subsequent packets
|
|
131
|
+
@meta_id = ple.id
|
|
132
|
+
ple.meta_id = @meta_id
|
|
133
|
+
ple.save!
|
|
134
|
+
end
|
|
135
|
+
# Remember this new PacketLogEntry so we can mark it ready later
|
|
136
|
+
@not_ready_ple_ids << ple.id
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# encoding: ascii-8bit
|
|
2
|
+
|
|
3
|
+
# Copyright 2018 Ball Aerospace & Technologies Corp.
|
|
4
|
+
# All Rights Reserved.
|
|
5
|
+
#
|
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
|
7
|
+
# under the terms of the GNU General Public License
|
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
|
10
|
+
|
|
11
|
+
require 'dart_reducer_worker_thread'
|
|
12
|
+
|
|
13
|
+
# Reduce the decommutated data into the database. It creates a number of
|
|
14
|
+
# threads to perform the actual data reduction. Then it queries the database
|
|
15
|
+
# for all the decommutation tables and determines which need to be reduced
|
|
16
|
+
# by minute, hour, and day.
|
|
17
|
+
class DartReducerManager
|
|
18
|
+
include DartCommon
|
|
19
|
+
|
|
20
|
+
# Create worker threads to perform the data reduction
|
|
21
|
+
#
|
|
22
|
+
# @param num_threads [Integer] The number of worker threads to create
|
|
23
|
+
def initialize(num_threads = 5)
|
|
24
|
+
Cosmos::Logger.info("Dart Reducer Starting with #{num_threads} threads...")
|
|
25
|
+
@master_queue = Queue.new
|
|
26
|
+
@locked_tables = []
|
|
27
|
+
@mutex = Mutex.new
|
|
28
|
+
@threads = []
|
|
29
|
+
num_threads.times do |index|
|
|
30
|
+
@threads << DartReducerWorkerThread.new(@master_queue, @locked_tables, @mutex, index + 1)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Shutdown each of the worker threads
|
|
35
|
+
def shutdown
|
|
36
|
+
@threads.each {|thread| thread.shutdown}
|
|
37
|
+
@threads.each {|thread| thread.join}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Search through all the tables in the database looking for decommutation tables
|
|
41
|
+
# and reduction tables. Then push all found tables onto one of the worker
|
|
42
|
+
# thread queues for processing.
|
|
43
|
+
def run
|
|
44
|
+
begin
|
|
45
|
+
while true
|
|
46
|
+
time_start = Time.now
|
|
47
|
+
# Find base tables that need to be reduced
|
|
48
|
+
base_tables = []
|
|
49
|
+
each_decom_and_reduced_table() do |packet_config_id, table_index, decom_model, minute_model, hour_model, day_model|
|
|
50
|
+
queue_worker(:MINUTE, packet_config_id, table_index, decom_model, minute_model)
|
|
51
|
+
queue_worker(:HOUR, packet_config_id, table_index, minute_model, hour_model)
|
|
52
|
+
queue_worker(:DAY, packet_config_id, table_index, hour_model, day_model)
|
|
53
|
+
end
|
|
54
|
+
# Throttle to no faster than once every 60 seconds
|
|
55
|
+
delta = Time.now - time_start
|
|
56
|
+
if delta < 60 and delta > 0
|
|
57
|
+
sleep(60 - delta)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
rescue Interrupt
|
|
61
|
+
Cosmos::Logger.info("Dart Reducer Shutting Down...")
|
|
62
|
+
shutdown()
|
|
63
|
+
exit(0)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
protected
|
|
68
|
+
|
|
69
|
+
# Add a task to a worker thread queue
|
|
70
|
+
#
|
|
71
|
+
# @param type [Symbol] One of :MINUTE, :HOUR, :DAY
|
|
72
|
+
# @param packet_config_id [Integer] PacketConfig ID from the database
|
|
73
|
+
# @param table_index [Integer] Table index used in table names
|
|
74
|
+
# @param base_model [ActiveRecord] Database model of the table to be reduced
|
|
75
|
+
# @param reduction_model [ActiveRecord] Database model of the reduction table
|
|
76
|
+
def queue_worker(type, packet_config_id, table_index, base_model, reduction_model)
|
|
77
|
+
thread_queue = @master_queue.pop
|
|
78
|
+
unless @locked_tables.include?([type, packet_config_id, table_index])
|
|
79
|
+
@mutex.synchronize do
|
|
80
|
+
@locked_tables << ([type, packet_config_id, table_index])
|
|
81
|
+
end
|
|
82
|
+
thread_queue << [type, packet_config_id, table_index, base_model, reduction_model]
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# encoding: ascii-8bit
|
|
2
|
+
|
|
3
|
+
# Copyright 2018 Ball Aerospace & Technologies Corp.
|
|
4
|
+
# All Rights Reserved.
|
|
5
|
+
#
|
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
|
7
|
+
# under the terms of the GNU General Public License
|
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
|
10
|
+
|
|
11
|
+
require 'dart_common'
|
|
12
|
+
|
|
13
|
+
ItemToDecomTableMapping
|
|
14
|
+
|
|
15
|
+
# Thread which performs data reduction in the DART database.
|
|
16
|
+
class DartReducerWorkerThread
|
|
17
|
+
# Create a new thread and start it
|
|
18
|
+
#
|
|
19
|
+
# @param master_queue [Queue] Queue which the new thread will be added to
|
|
20
|
+
# @param locked_tables [Array<Array<Symbol, Integer, Integer>>] Array of
|
|
21
|
+
# all the tables which are currently being processed. The first parameter
|
|
22
|
+
# is the table type and must be :MINUTE, :HOUR or :DAY. The second and
|
|
23
|
+
# third values are the PacketConfig ID and table index.
|
|
24
|
+
# @param mutex [Mutex] Mutex used to synchronize access to the locked_tables
|
|
25
|
+
# @param instance_num [Integer] Simple counter to trace the thread instance
|
|
26
|
+
def initialize(master_queue, locked_tables, mutex, instance_num)
|
|
27
|
+
@instance_num = instance_num
|
|
28
|
+
@running = true
|
|
29
|
+
@master_queue = master_queue
|
|
30
|
+
@locked_tables = locked_tables
|
|
31
|
+
@mutex = mutex
|
|
32
|
+
@thread_queue = Queue.new
|
|
33
|
+
# Start the thread which will wait on @thread_queue.pop
|
|
34
|
+
@thread = Thread.new { work() }
|
|
35
|
+
# Add the local @thread_queue to the @master_queue so jobs can be added
|
|
36
|
+
@master_queue << @thread_queue
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Pop a job off the queue and find items which are able to be reduced.
|
|
40
|
+
# Calculate the min, max, and average value over the reduction period
|
|
41
|
+
# (min, hour, or day) and save to the reduction table tXXX_YYY_Z where
|
|
42
|
+
# XXX is the PacketConfig ID, YYY is the table index, and Z is 'm', 'h', or 'd'
|
|
43
|
+
# (minute, hour, day).
|
|
44
|
+
def work
|
|
45
|
+
while @running # Set to false in shutdown()
|
|
46
|
+
job_type, packet_config_id, table_index, base_model, reduction_model = @thread_queue.pop
|
|
47
|
+
break unless job_type # shutdown was called
|
|
48
|
+
|
|
49
|
+
# Find all the items which are able to be reduced (reduced = true)
|
|
50
|
+
mappings = ItemToDecomTableMapping.where("packet_config_id = ? and table_index = ? and reduced = true",
|
|
51
|
+
packet_config_id, table_index)
|
|
52
|
+
# The only way to not have any mappings is if the packet contains no items
|
|
53
|
+
# which can be reduced (no integer or float values). This would be extremely rare.
|
|
54
|
+
if mappings.length == 0
|
|
55
|
+
Cosmos::Logger.debug("No Mappings for JobType #{job_type}: #{packet_config_id}: #{table_index}")
|
|
56
|
+
complete_job(job_type, packet_config_id, table_index)
|
|
57
|
+
next
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
time_delta, base_model_time_column, time_method = job_attributes(job_type)
|
|
61
|
+
rows = []
|
|
62
|
+
# Find all the rows in the decommutation table which are ready to reduce
|
|
63
|
+
base_model.where("reduced_state = #{DartCommon::READY_TO_REDUCE}").order("meta_id ASC, #{base_model_time_column} ASC").find_each do |row|
|
|
64
|
+
rows << row
|
|
65
|
+
first_row_time = rows[0].send(base_model_time_column)
|
|
66
|
+
last_row_time = rows[-1].send(base_model_time_column)
|
|
67
|
+
# Ensure we have conditions to process the reduction data
|
|
68
|
+
next unless (last_row_time - first_row_time) > time_delta || # Enough samples or
|
|
69
|
+
# The time attribute (min, hour, day) has changed or
|
|
70
|
+
first_row_time.send(time_method) != last_row_time.send(time_method) ||
|
|
71
|
+
rows[0].meta_id != rows[-1].meta_id # New meta data
|
|
72
|
+
|
|
73
|
+
# Sample from the start to the second to last row because the last row
|
|
74
|
+
# is where we detected a change. The last row will be part of a new sample set.
|
|
75
|
+
sample_rows = rows[0..-2]
|
|
76
|
+
new_row = reduction_model.new
|
|
77
|
+
new_row.start_time = first_row_time
|
|
78
|
+
new_row.num_samples = sample_rows.length
|
|
79
|
+
new_row.meta_id = sample_rows[0].meta_id
|
|
80
|
+
# Process each of the ItemToDecomTableMapping to get the item to be reduced
|
|
81
|
+
mappings.each do |mapping|
|
|
82
|
+
item_name = "i#{mapping.item_index}"
|
|
83
|
+
min_item_name = "i#{mapping.item_index}min"
|
|
84
|
+
max_item_name = "i#{mapping.item_index}max"
|
|
85
|
+
avg_item_name = "i#{mapping.item_index}avg"
|
|
86
|
+
stddev_item_name = "i#{mapping.item_index}stddev"
|
|
87
|
+
min_value = nil
|
|
88
|
+
max_value = nil
|
|
89
|
+
total_samples = 0 # s0
|
|
90
|
+
avg_value = 0.0 # s1
|
|
91
|
+
s2 = 0.0
|
|
92
|
+
stddev_value = 0.0
|
|
93
|
+
min_nan_found = false
|
|
94
|
+
max_nan_found = false
|
|
95
|
+
avg_nan_found = false
|
|
96
|
+
stddev_nan_found = false
|
|
97
|
+
# Process each of the rows in the base model which is the decommutation table
|
|
98
|
+
# or a lesser reduction table (the minute or hour table).
|
|
99
|
+
sample_rows.each do |row_to_reduce|
|
|
100
|
+
# If we processing minute data we're reading from the base decommutation table
|
|
101
|
+
# thus there is only raw values to read
|
|
102
|
+
if job_type == :MINUTE
|
|
103
|
+
value = row_to_reduce.read_attribute(item_name)
|
|
104
|
+
min_sample = value
|
|
105
|
+
max_sample = value
|
|
106
|
+
avg_sample = value
|
|
107
|
+
if value.nil?
|
|
108
|
+
Cosmos::Logger.error("#{item_name} is nil in #{row_to_reduce.class}:#{row_to_reduce.id}")
|
|
109
|
+
next
|
|
110
|
+
end
|
|
111
|
+
else # :HOUR or :DAY
|
|
112
|
+
# We're processing hour or day data so we're reducing previously reduced data
|
|
113
|
+
# thus there are min, max, and average values to read
|
|
114
|
+
min_sample = row_to_reduce.read_attribute(min_item_name)
|
|
115
|
+
max_sample = row_to_reduce.read_attribute(max_item_name)
|
|
116
|
+
avg_sample = row_to_reduce.read_attribute(avg_item_name)
|
|
117
|
+
stddev_sample = row_to_reduce.read_attribute(stddev_item_name)
|
|
118
|
+
if min_sample.nil?
|
|
119
|
+
Cosmos::Logger.error("#{min_item_name} is nil in #{row_to_reduce.class}:#{row_to_reduce.id}")
|
|
120
|
+
next
|
|
121
|
+
end
|
|
122
|
+
if max_sample.nil?
|
|
123
|
+
Cosmos::Logger.error("#{max_item_name} is nil in #{row_to_reduce.class}:#{row_to_reduce.id}")
|
|
124
|
+
next
|
|
125
|
+
end
|
|
126
|
+
if avg_sample.nil?
|
|
127
|
+
Cosmos::Logger.error("#{avg_item_name} is nil in #{row_to_reduce.class}:#{row_to_reduce.id}")
|
|
128
|
+
next
|
|
129
|
+
end
|
|
130
|
+
if stddev_sample.nil?
|
|
131
|
+
Cosmos::Logger.error("#{stddev_item_name} is nil in #{row_to_reduce.class}:#{row_to_reduce.id}")
|
|
132
|
+
next
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
if nan_value?(min_sample)
|
|
137
|
+
min_nan_found = true
|
|
138
|
+
else
|
|
139
|
+
if !min_value or min_sample < min_value
|
|
140
|
+
min_value = min_sample
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
if nan_value?(max_sample)
|
|
145
|
+
max_nan_found = true
|
|
146
|
+
else
|
|
147
|
+
if !max_value or max_sample > max_value
|
|
148
|
+
max_value = max_sample
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
if nan_value?(avg_sample)
|
|
153
|
+
avg_nan_found = true
|
|
154
|
+
else
|
|
155
|
+
# MINUTE data is reducing the decommutated values
|
|
156
|
+
if job_type == :MINUTE
|
|
157
|
+
total_samples += 1 # s0
|
|
158
|
+
avg_value += avg_sample # s1
|
|
159
|
+
s2 += (avg_sample * avg_sample)
|
|
160
|
+
else # :HOUR or :DAY
|
|
161
|
+
# Aggregated Stddev
|
|
162
|
+
# See https://math.stackexchange.com/questions/1547141/aggregating-standard-deviation-to-a-summary-point
|
|
163
|
+
total_samples += row_to_reduce.num_samples # s0
|
|
164
|
+
avg_value += (avg_sample * row_to_reduce.num_samples) # s1
|
|
165
|
+
s2 += row_to_reduce.num_samples * (avg_sample * avg_sample + stddev_sample * stddev_sample)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
if total_samples != 0
|
|
170
|
+
# Aggregated Stddev
|
|
171
|
+
# See https://math.stackexchange.com/questions/1547141/aggregating-standard-deviation-to-a-summary-point
|
|
172
|
+
avg_value = avg_value.to_f / total_samples
|
|
173
|
+
# Note: For very large numbers with very small deviations this sqrt can fail. If so then just set the stddev to 0.
|
|
174
|
+
begin
|
|
175
|
+
stddev_value = sqrt((s2 / total_samples) - (avg_value * avg_value))
|
|
176
|
+
rescue Exception
|
|
177
|
+
stddev_value = 0.0
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
min_value = Float::NAN if min_nan_found and !min_value
|
|
181
|
+
max_value = Float::NAN if max_nan_found and !max_value
|
|
182
|
+
if avg_nan_found and total_samples == 0
|
|
183
|
+
avg_value = Float::NAN
|
|
184
|
+
stddev_value = Float::NAN
|
|
185
|
+
end
|
|
186
|
+
new_row.write_attribute(min_item_name, min_value)
|
|
187
|
+
new_row.write_attribute(max_item_name, max_value)
|
|
188
|
+
new_row.write_attribute(avg_item_name, avg_value)
|
|
189
|
+
new_row.write_attribute(stddev_item_name, stddev_value)
|
|
190
|
+
end
|
|
191
|
+
base_model.where(id: sample_rows.map(&:id)).update_all(:reduced_state => DartCommon::REDUCED)
|
|
192
|
+
new_row.save! # Create the reduced data row in the database
|
|
193
|
+
base_model.where(id: sample_rows.map(&:id)).update_all(:reduced_id => new_row.id)
|
|
194
|
+
new_row.reduced_state = DartCommon::READY_TO_REDUCE
|
|
195
|
+
new_row.save!
|
|
196
|
+
|
|
197
|
+
rows = rows[-1..-1] # Start a new sample with the last item in the previous sample
|
|
198
|
+
Cosmos::Logger.debug("Created #{new_row.class}:#{new_row.id} with #{mappings.length} items from #{new_row.num_samples} samples")
|
|
199
|
+
end
|
|
200
|
+
complete_job(job_type, packet_config_id, table_index)
|
|
201
|
+
end # while @running
|
|
202
|
+
Cosmos::Logger.info("Reducer Thread #{@instance_num} Shutdown")
|
|
203
|
+
rescue Exception => error
|
|
204
|
+
Cosmos::Logger.error("Reducer Thread Unexpectedly Died: #{error.formatted}")
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Shutdown the worker thread
|
|
208
|
+
def shutdown
|
|
209
|
+
@running = false
|
|
210
|
+
# Push the queue to allow the thread to run and shutdown
|
|
211
|
+
@thread_queue << nil
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Kill the worker thread
|
|
215
|
+
def join
|
|
216
|
+
Cosmos.kill_thread(self, @thread)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# Call shutdown to gracefully shutdown the worker thread
|
|
220
|
+
def graceful_kill
|
|
221
|
+
shutdown()
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
protected
|
|
225
|
+
|
|
226
|
+
# @return [Boolean] Whether the value is Not A Number (nan)
|
|
227
|
+
def nan_value?(value)
|
|
228
|
+
value.is_a?(Float) && (value.nan? || !value.finite?)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Remove the job from the @locked_tables and add the worker thread back
|
|
232
|
+
# to the @master_queue so additional jobs can be scheduled
|
|
233
|
+
#
|
|
234
|
+
# @param job_type [Symbol] One of :MINUTE, :HOUR, or :DAY
|
|
235
|
+
# @param packet_config_id [Integer] PacketConfig ID from the database
|
|
236
|
+
# @param table_index [Integer] Table index used in table names
|
|
237
|
+
def complete_job(job_type, packet_config_id, table_index)
|
|
238
|
+
@mutex.synchronize do
|
|
239
|
+
@locked_tables.delete([job_type, packet_config_id, table_index])
|
|
240
|
+
end
|
|
241
|
+
@master_queue << @thread_queue
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# Get various attributes associated with a job type
|
|
245
|
+
#
|
|
246
|
+
# @param job_type [Symbol] One of :MINUTE, :HOUR, or :DAY
|
|
247
|
+
# @return [Array<Float, String, Symbol>] Array of three items: Float time delta
|
|
248
|
+
# which is the number of seconds in the time period, String database model time
|
|
249
|
+
# column name, and Symbol method to call on the resulting Ruby Time object to
|
|
250
|
+
# get the minute, hour, or day.
|
|
251
|
+
def job_attributes(job_type)
|
|
252
|
+
case job_type
|
|
253
|
+
when :MINUTE
|
|
254
|
+
return 60.0, "time", :min
|
|
255
|
+
when :HOUR
|
|
256
|
+
return 3600.0, "start_time", :hour
|
|
257
|
+
when :DAY
|
|
258
|
+
return 86400.0, "start_time", :yday
|
|
259
|
+
else # Should never get this since we control the jobs so raise
|
|
260
|
+
raise "Reducer Thread Unexpected Job Type: #{job_type}"
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
end
|