cosmos 4.1.1-java → 4.2.0-java
Sign up to get free protection for your applications and to get access to all the features.
- 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
|