Initial commit with BSL
This commit is contained in:
28
client/controller/.gitignore
vendored
Normal file
28
client/controller/.gitignore
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
# Mac OS X hidden file
|
||||
.DS_Store
|
||||
|
||||
# workspace configuration files
|
||||
.settings/
|
||||
.metadata/
|
||||
|
||||
# Gradle
|
||||
.gradle/
|
||||
/gradlew.bat
|
||||
/gradlew
|
||||
/settings.gradle
|
||||
|
||||
# Intellij
|
||||
.idea
|
||||
/dbcollector.iml
|
||||
|
||||
# generated files
|
||||
bin/
|
||||
build/
|
||||
out/
|
||||
output/
|
||||
|
||||
# lib
|
||||
lib/
|
||||
|
||||
# log file
|
||||
*.log
|
||||
12
client/controller/README.md
Normal file
12
client/controller/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
## OtterTune Controller
|
||||
The controller is responsible for collecting database metrics and knobs information during an experiment.</br>
|
||||
#### Usage:
|
||||
To build the project, run `gradle build`.</br>
|
||||
To run the controller, you need to provide a configuration file and provide command line arguments (command line arguments are optional). Then run `gradle run`.
|
||||
|
||||
* Command line arguments:
|
||||
* time (flag : `-t`) </br>
|
||||
The duration of the experiment in `seconds`. The default time is set to 300 seconds.
|
||||
* configuration file path (flag : `-c`) </br>
|
||||
The path of the input configuration file (required). Sample config files are under the directory `config`.
|
||||
|
||||
90
client/controller/build.gradle
Normal file
90
client/controller/build.gradle
Normal file
@@ -0,0 +1,90 @@
|
||||
plugins {
|
||||
id "de.undercouch.download" version "3.3.0"
|
||||
id "com.github.spotbugs" version "2.0.0"
|
||||
}
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'maven'
|
||||
apply plugin: 'application'
|
||||
apply plugin: 'project-report'
|
||||
|
||||
mainClassName = "com.controller.Main"
|
||||
|
||||
test.testLogging { exceptionFormat "full"; events "failed", "passed", "skipped" }
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testCompile group: 'junit', name: 'junit', version: '4.11'
|
||||
runtime fileTree(dir: 'lib', include: '*.jar')
|
||||
compile group: 'net.sourceforge.collections', name: 'collections-generic', version: '4.01'
|
||||
compile group: 'commons-lang', name: 'commons-lang', version: '2.6'
|
||||
compile group: 'log4j', name: 'log4j', version: '1.2.17'
|
||||
compile group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1.1'
|
||||
compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.3'
|
||||
compile group: 'org.apache.httpcomponents', name: 'httpmime', version: '4.5.3'
|
||||
|
||||
// https://mvnrepository.com/artifact/com.github.fge/json-schema-validator
|
||||
compile group: 'com.github.fge', name: 'json-schema-validator', version: '2.2.6'
|
||||
// https://mvnrepository.com/artifact/com.github.fge/jackson-coreutils
|
||||
compile group: 'com.github.fge', name: 'jackson-coreutils', version: '1.8'
|
||||
// https://mvnrepository.com/artifact/com.github.fge/json-schema-core
|
||||
compile group: 'com.github.fge', name: 'json-schema-core', version: '1.2.5'
|
||||
|
||||
// https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations
|
||||
compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.9.0'
|
||||
// https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
|
||||
compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.8.0'
|
||||
// https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
|
||||
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.8.0'
|
||||
compile(group: "com.github.java-json-tools", name: "json-schema-validator", version: "2.2.8");
|
||||
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.10.0'
|
||||
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.10.0'
|
||||
// https://mvnrepository.com/artifact/commons-cli/commons-cli
|
||||
compile group: 'commons-cli', name: 'commons-cli', version: '1.2'
|
||||
|
||||
// https://mvnrepository.com/artifact/mysql/mysql-connector-java
|
||||
compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.6'
|
||||
|
||||
// https://mvnrepository.com/artifact/org.postgresql/postgresql
|
||||
compile group: 'org.postgresql', name: 'postgresql', version: '9.4-1201-jdbc41'
|
||||
|
||||
// This lib has to be manually downloaded from Oracle
|
||||
dependencies {compile files('lib/ojdbc8.jar')}
|
||||
}
|
||||
|
||||
run {
|
||||
if (project.hasProperty("appArgs")) {
|
||||
args(appArgs.split(' '))
|
||||
}
|
||||
// Below is another way to add args but this causes gradle to
|
||||
// always invoke the run application task
|
||||
// args = ["-c","$config","-t","$time","-d","$dir"]
|
||||
}
|
||||
|
||||
spotbugs {
|
||||
toolVersion = '4.0.0-beta3'
|
||||
ignoreFailures = true
|
||||
}
|
||||
|
||||
// Note (07-29-2019): the HTML report for spotbugs is currently broken
|
||||
tasks.withType(com.github.spotbugs.SpotBugsTask) {
|
||||
reports {
|
||||
xml.enabled true
|
||||
html.enabled false
|
||||
}
|
||||
}
|
||||
|
||||
import de.undercouch.gradle.tasks.download.Download
|
||||
task downloadJars(type: Download) {
|
||||
src ([
|
||||
'https://github.com/google/google-java-format/releases/download/google-java-format-1.5/google-java-format-1.5-all-deps.jar',
|
||||
'https://github.com/checkstyle/checkstyle/releases/download/checkstyle-8.8/checkstyle-8.8-all.jar'
|
||||
])
|
||||
dest libsDir
|
||||
overwrite false
|
||||
}
|
||||
|
||||
build.finalizedBy(downloadJars)
|
||||
9
client/controller/config/sample_mysql_config.json
Normal file
9
client/controller/config/sample_mysql_config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"database_type" : "mysql",
|
||||
"database_url" : "jdbc:mysql://localhost:3306/mysqldb",
|
||||
"username" : "MY_DATABASE_USERNAME",
|
||||
"password" : "MY_DATABASE_PASSWORD",
|
||||
"upload_code" : "DEPRECATED",
|
||||
"upload_url" : "DEPRECATED",
|
||||
"workload_name" : "workload_name"
|
||||
}
|
||||
9
client/controller/config/sample_oracle_config.json
Normal file
9
client/controller/config/sample_oracle_config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"database_type" : "oracle",
|
||||
"database_url" : "jdbc:oracle:thin:@localhost:1521:orcldb",
|
||||
"username" : "sys as sysdba",
|
||||
"password" : "oracle",
|
||||
"upload_code" : "DEPRECATED",
|
||||
"upload_url" : "DEPRECATED",
|
||||
"workload_name" : "tpcc"
|
||||
}
|
||||
9
client/controller/config/sample_postgres_config.json
Normal file
9
client/controller/config/sample_postgres_config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"database_type" : "postgres",
|
||||
"database_url" : "jdbc:postgresql://localhost:5432/postgres",
|
||||
"username" : "MY_DATABASE_USERNAME",
|
||||
"password" : "MY_DATABASE_PASSWORD",
|
||||
"upload_code" : "DEPRECATED",
|
||||
"upload_url" : "DEPRECATED",
|
||||
"workload_name" : "workload_name"
|
||||
}
|
||||
9
client/controller/config/sample_saphana_config.json
Normal file
9
client/controller/config/sample_saphana_config.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"database_type" : "saphana",
|
||||
"database_url" : "jdbc:sap://localhost:39015",
|
||||
"username" : "MY_DATABASE_USERNAME",
|
||||
"password" : "MY_DATABASE_PASSWORD",
|
||||
"upload_code" : "DEPRECATED",
|
||||
"upload_url" : "DEPRECATED",
|
||||
"workload_name" : "workload_name"
|
||||
}
|
||||
6
client/controller/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
client/controller/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Thu Nov 30 15:45:05 EST 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.1-bin.zip
|
||||
28
client/controller/log4j.properties
Normal file
28
client/controller/log4j.properties
Normal file
@@ -0,0 +1,28 @@
|
||||
# Set root logger level to DEBUG and its only appender to A1.
|
||||
log4j.rootLogger=INFO, A1, FILE
|
||||
log4j.rootLogger.layout=org.apache.log4j.PatternLayout
|
||||
|
||||
# A1 is set to be a ConsoleAppender.
|
||||
log4j.appender.A1=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.A1.layout.ConversionPattern=%d{ABSOLUTE} (%F:%L) %-5p - %m%n
|
||||
|
||||
# Redirect log messages to a log file, support file rolling.
|
||||
# Define the file appender
|
||||
log4j.appender.FILE=org.apache.log4j.FileAppender
|
||||
|
||||
# Set the name of the file
|
||||
log4j.appender.FILE.file=controller.log
|
||||
|
||||
# Set the immediate flush to true (default)
|
||||
log4j.appender.FILE.immediateFlush=true
|
||||
|
||||
# Set the threshold to debug mode
|
||||
log4j.appender.FILE.Threshold=debug
|
||||
|
||||
# Set the append to false, overwrite
|
||||
log4j.appender.FILE.append=true
|
||||
|
||||
# Define the layout for file appender
|
||||
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.A1.layout.ConversionPattern=%d{ABSOLUTE} (%F:%L) %-5p - %m%n
|
||||
517
client/controller/sample_output/mysql/knobs.json
Normal file
517
client/controller/sample_output/mysql/knobs.json
Normal file
@@ -0,0 +1,517 @@
|
||||
{
|
||||
"global": {"global": {
|
||||
"auto_generate_certs": "ON",
|
||||
"auto_increment_increment": "1",
|
||||
"auto_increment_offset": "1",
|
||||
"autocommit": "ON",
|
||||
"automatic_sp_privileges": "ON",
|
||||
"avoid_temporal_upgrade": "OFF",
|
||||
"back_log": "80",
|
||||
"basedir": "/usr/local/Cellar/mysql/5.7.20/",
|
||||
"big_tables": "OFF",
|
||||
"bind_address": "127.0.0.1",
|
||||
"binlog_cache_size": "32768",
|
||||
"binlog_checksum": "CRC32",
|
||||
"binlog_direct_non_transactional_updates": "OFF",
|
||||
"binlog_error_action": "ABORT_SERVER",
|
||||
"binlog_format": "ROW",
|
||||
"binlog_group_commit_sync_delay": "0",
|
||||
"binlog_group_commit_sync_no_delay_count": "0",
|
||||
"binlog_gtid_simple_recovery": "ON",
|
||||
"binlog_max_flush_queue_time": "0",
|
||||
"binlog_order_commits": "ON",
|
||||
"binlog_row_image": "FULL",
|
||||
"binlog_rows_query_log_events": "OFF",
|
||||
"binlog_stmt_cache_size": "32768",
|
||||
"block_encryption_mode": "aes-128-ecb",
|
||||
"bulk_insert_buffer_size": "8388608",
|
||||
"character_set_client": "utf8",
|
||||
"character_set_connection": "utf8",
|
||||
"character_set_database": "utf8",
|
||||
"character_set_filesystem": "binary",
|
||||
"character_set_results": "",
|
||||
"character_set_server": "utf8",
|
||||
"character_set_system": "utf8",
|
||||
"character_sets_dir": "/usr/local/Cellar/mysql/5.7.20/share/mysql/charsets/",
|
||||
"check_proxy_users": "OFF",
|
||||
"collation_connection": "utf8_general_ci",
|
||||
"collation_database": "utf8_general_ci",
|
||||
"collation_server": "utf8_general_ci",
|
||||
"completion_type": "NO_CHAIN",
|
||||
"concurrent_insert": "AUTO",
|
||||
"connect_timeout": "10",
|
||||
"core_file": "OFF",
|
||||
"datadir": "/usr/local/var/mysql/",
|
||||
"date_format": "%Y-%m-%d",
|
||||
"datetime_format": "%Y-%m-%d %H:%i:%s",
|
||||
"default_authentication_plugin": "mysql_native_password",
|
||||
"default_password_lifetime": "0",
|
||||
"default_storage_engine": "InnoDB",
|
||||
"default_tmp_storage_engine": "InnoDB",
|
||||
"default_week_format": "0",
|
||||
"delay_key_write": "ON",
|
||||
"delayed_insert_limit": "100",
|
||||
"delayed_insert_timeout": "300",
|
||||
"delayed_queue_size": "1000",
|
||||
"disabled_storage_engines": "",
|
||||
"disconnect_on_expired_password": "ON",
|
||||
"div_precision_increment": "4",
|
||||
"end_markers_in_json": "OFF",
|
||||
"enforce_gtid_consistency": "OFF",
|
||||
"eq_range_index_dive_limit": "200",
|
||||
"error_count": "0",
|
||||
"event_scheduler": "OFF",
|
||||
"expire_logs_days": "0",
|
||||
"explicit_defaults_for_timestamp": "OFF",
|
||||
"external_user": "",
|
||||
"flush": "OFF",
|
||||
"flush_time": "0",
|
||||
"foreign_key_checks": "ON",
|
||||
"ft_boolean_syntax": "+ -><()~*:\"\"&|",
|
||||
"ft_max_word_len": "84",
|
||||
"ft_min_word_len": "4",
|
||||
"ft_query_expansion_limit": "20",
|
||||
"ft_stopword_file": "(built-in)",
|
||||
"general_log": "OFF",
|
||||
"general_log_file": "/usr/local/var/mysql/JiangShuli.log",
|
||||
"group_concat_max_len": "1024",
|
||||
"gtid_executed_compression_period": "1000",
|
||||
"gtid_mode": "OFF",
|
||||
"gtid_next": "AUTOMATIC",
|
||||
"gtid_owned": "",
|
||||
"gtid_purged": "",
|
||||
"have_compress": "YES",
|
||||
"have_crypt": "YES",
|
||||
"have_dynamic_loading": "YES",
|
||||
"have_geometry": "YES",
|
||||
"have_openssl": "YES",
|
||||
"have_profiling": "YES",
|
||||
"have_query_cache": "YES",
|
||||
"have_rtree_keys": "YES",
|
||||
"have_ssl": "YES",
|
||||
"have_statement_timeout": "YES",
|
||||
"have_symlink": "YES",
|
||||
"host_cache_size": "279",
|
||||
"hostname": "JiangShuli.local",
|
||||
"identity": "0",
|
||||
"ignore_builtin_innodb": "OFF",
|
||||
"ignore_db_dirs": "",
|
||||
"init_connect": "",
|
||||
"init_file": "",
|
||||
"init_slave": "",
|
||||
"innodb_adaptive_flushing": "ON",
|
||||
"innodb_adaptive_flushing_lwm": "10",
|
||||
"innodb_adaptive_hash_index": "ON",
|
||||
"innodb_adaptive_hash_index_parts": "8",
|
||||
"innodb_adaptive_max_sleep_delay": "150000",
|
||||
"innodb_api_bk_commit_interval": "5",
|
||||
"innodb_api_disable_rowlock": "OFF",
|
||||
"innodb_api_enable_binlog": "OFF",
|
||||
"innodb_api_enable_mdl": "OFF",
|
||||
"innodb_api_trx_level": "0",
|
||||
"innodb_autoextend_increment": "64",
|
||||
"innodb_autoinc_lock_mode": "1",
|
||||
"innodb_buffer_pool_chunk_size": "134217728",
|
||||
"innodb_buffer_pool_dump_at_shutdown": "ON",
|
||||
"innodb_buffer_pool_dump_now": "OFF",
|
||||
"innodb_buffer_pool_dump_pct": "25",
|
||||
"innodb_buffer_pool_filename": "ib_buffer_pool",
|
||||
"innodb_buffer_pool_instances": "1",
|
||||
"innodb_buffer_pool_load_abort": "OFF",
|
||||
"innodb_buffer_pool_load_at_startup": "ON",
|
||||
"innodb_buffer_pool_load_now": "OFF",
|
||||
"innodb_buffer_pool_size": "134217728",
|
||||
"innodb_change_buffer_max_size": "25",
|
||||
"innodb_change_buffering": "all",
|
||||
"innodb_checksum_algorithm": "crc32",
|
||||
"innodb_checksums": "ON",
|
||||
"innodb_cmp_per_index_enabled": "OFF",
|
||||
"innodb_commit_concurrency": "0",
|
||||
"innodb_compression_failure_threshold_pct": "5",
|
||||
"innodb_compression_level": "6",
|
||||
"innodb_compression_pad_pct_max": "50",
|
||||
"innodb_concurrency_tickets": "5000",
|
||||
"innodb_data_file_path": "ibdata1:12M:autoextend",
|
||||
"innodb_data_home_dir": "",
|
||||
"innodb_deadlock_detect": "ON",
|
||||
"innodb_default_row_format": "dynamic",
|
||||
"innodb_disable_sort_file_cache": "OFF",
|
||||
"innodb_doublewrite": "ON",
|
||||
"innodb_fast_shutdown": "1",
|
||||
"innodb_file_format": "Barracuda",
|
||||
"innodb_file_format_check": "ON",
|
||||
"innodb_file_format_max": "Barracuda",
|
||||
"innodb_file_per_table": "ON",
|
||||
"innodb_fill_factor": "100",
|
||||
"innodb_flush_log_at_timeout": "1",
|
||||
"innodb_flush_log_at_trx_commit": "1",
|
||||
"innodb_flush_method": "",
|
||||
"innodb_flush_neighbors": "1",
|
||||
"innodb_flush_sync": "ON",
|
||||
"innodb_flushing_avg_loops": "30",
|
||||
"innodb_force_load_corrupted": "OFF",
|
||||
"innodb_force_recovery": "0",
|
||||
"innodb_ft_aux_table": "",
|
||||
"innodb_ft_cache_size": "8000000",
|
||||
"innodb_ft_enable_diag_print": "OFF",
|
||||
"innodb_ft_enable_stopword": "ON",
|
||||
"innodb_ft_max_token_size": "84",
|
||||
"innodb_ft_min_token_size": "3",
|
||||
"innodb_ft_num_word_optimize": "2000",
|
||||
"innodb_ft_result_cache_limit": "2000000000",
|
||||
"innodb_ft_server_stopword_table": "",
|
||||
"innodb_ft_sort_pll_degree": "2",
|
||||
"innodb_ft_total_cache_size": "640000000",
|
||||
"innodb_ft_user_stopword_table": "",
|
||||
"innodb_io_capacity": "200",
|
||||
"innodb_io_capacity_max": "2000",
|
||||
"innodb_large_prefix": "ON",
|
||||
"innodb_lock_wait_timeout": "50",
|
||||
"innodb_locks_unsafe_for_binlog": "OFF",
|
||||
"innodb_log_buffer_size": "16777216",
|
||||
"innodb_log_checksums": "ON",
|
||||
"innodb_log_compressed_pages": "ON",
|
||||
"innodb_log_file_size": "50331648",
|
||||
"innodb_log_files_in_group": "2",
|
||||
"innodb_log_group_home_dir": "./",
|
||||
"innodb_log_write_ahead_size": "8192",
|
||||
"innodb_lru_scan_depth": "1024",
|
||||
"innodb_max_dirty_pages_pct": "75.000000",
|
||||
"innodb_max_dirty_pages_pct_lwm": "0.000000",
|
||||
"innodb_max_purge_lag": "0",
|
||||
"innodb_max_purge_lag_delay": "0",
|
||||
"innodb_max_undo_log_size": "1073741824",
|
||||
"innodb_monitor_disable": "",
|
||||
"innodb_monitor_enable": "",
|
||||
"innodb_monitor_reset": "",
|
||||
"innodb_monitor_reset_all": "",
|
||||
"innodb_old_blocks_pct": "37",
|
||||
"innodb_old_blocks_time": "1000",
|
||||
"innodb_online_alter_log_max_size": "134217728",
|
||||
"innodb_open_files": "2000",
|
||||
"innodb_optimize_fulltext_only": "OFF",
|
||||
"innodb_page_cleaners": "1",
|
||||
"innodb_page_size": "16384",
|
||||
"innodb_print_all_deadlocks": "OFF",
|
||||
"innodb_purge_batch_size": "300",
|
||||
"innodb_purge_rseg_truncate_frequency": "128",
|
||||
"innodb_purge_threads": "4",
|
||||
"innodb_random_read_ahead": "OFF",
|
||||
"innodb_read_ahead_threshold": "56",
|
||||
"innodb_read_io_threads": "4",
|
||||
"innodb_read_only": "OFF",
|
||||
"innodb_replication_delay": "0",
|
||||
"innodb_rollback_on_timeout": "OFF",
|
||||
"innodb_rollback_segments": "128",
|
||||
"innodb_sort_buffer_size": "1048576",
|
||||
"innodb_spin_wait_delay": "6",
|
||||
"innodb_stats_auto_recalc": "ON",
|
||||
"innodb_stats_include_delete_marked": "OFF",
|
||||
"innodb_stats_method": "nulls_equal",
|
||||
"innodb_stats_on_metadata": "OFF",
|
||||
"innodb_stats_persistent": "ON",
|
||||
"innodb_stats_persistent_sample_pages": "20",
|
||||
"innodb_stats_sample_pages": "8",
|
||||
"innodb_stats_transient_sample_pages": "8",
|
||||
"innodb_status_output": "OFF",
|
||||
"innodb_status_output_locks": "OFF",
|
||||
"innodb_strict_mode": "ON",
|
||||
"innodb_support_xa": "ON",
|
||||
"innodb_sync_array_size": "1",
|
||||
"innodb_sync_spin_loops": "30",
|
||||
"innodb_table_locks": "ON",
|
||||
"innodb_temp_data_file_path": "ibtmp1:12M:autoextend",
|
||||
"innodb_thread_concurrency": "0",
|
||||
"innodb_thread_sleep_delay": "10000",
|
||||
"innodb_tmpdir": "",
|
||||
"innodb_undo_directory": "./",
|
||||
"innodb_undo_log_truncate": "OFF",
|
||||
"innodb_undo_logs": "128",
|
||||
"innodb_undo_tablespaces": "0",
|
||||
"innodb_use_native_aio": "OFF",
|
||||
"innodb_version": "5.7.20",
|
||||
"innodb_write_io_threads": "4",
|
||||
"insert_id": "0",
|
||||
"interactive_timeout": "28800",
|
||||
"internal_tmp_disk_storage_engine": "InnoDB",
|
||||
"join_buffer_size": "262144",
|
||||
"keep_files_on_create": "OFF",
|
||||
"key_buffer_size": "8388608",
|
||||
"key_cache_age_threshold": "300",
|
||||
"key_cache_block_size": "1024",
|
||||
"key_cache_division_limit": "100",
|
||||
"large_files_support": "ON",
|
||||
"large_page_size": "0",
|
||||
"large_pages": "OFF",
|
||||
"last_insert_id": "0",
|
||||
"lc_messages": "en_US",
|
||||
"lc_messages_dir": "/usr/local/Cellar/mysql/5.7.20/share/mysql/",
|
||||
"lc_time_names": "en_US",
|
||||
"license": "GPL",
|
||||
"local_infile": "ON",
|
||||
"lock_wait_timeout": "31536000",
|
||||
"locked_in_memory": "OFF",
|
||||
"log_bin": "OFF",
|
||||
"log_bin_basename": "",
|
||||
"log_bin_index": "",
|
||||
"log_bin_trust_function_creators": "OFF",
|
||||
"log_bin_use_v1_row_events": "OFF",
|
||||
"log_builtin_as_identified_by_password": "OFF",
|
||||
"log_error": "./JiangShuli.local.err",
|
||||
"log_error_verbosity": "3",
|
||||
"log_output": "FILE",
|
||||
"log_queries_not_using_indexes": "OFF",
|
||||
"log_slave_updates": "OFF",
|
||||
"log_slow_admin_statements": "OFF",
|
||||
"log_slow_slave_statements": "OFF",
|
||||
"log_statements_unsafe_for_binlog": "ON",
|
||||
"log_syslog": "OFF",
|
||||
"log_syslog_facility": "daemon",
|
||||
"log_syslog_include_pid": "ON",
|
||||
"log_syslog_tag": "",
|
||||
"log_throttle_queries_not_using_indexes": "0",
|
||||
"log_timestamps": "UTC",
|
||||
"log_warnings": "2",
|
||||
"long_query_time": "10.000000",
|
||||
"low_priority_updates": "OFF",
|
||||
"lower_case_file_system": "ON",
|
||||
"lower_case_table_names": "2",
|
||||
"master_info_repository": "FILE",
|
||||
"master_verify_checksum": "OFF",
|
||||
"max_allowed_packet": "4194304",
|
||||
"max_binlog_cache_size": "18446744073709547520",
|
||||
"max_binlog_size": "1073741824",
|
||||
"max_binlog_stmt_cache_size": "18446744073709547520",
|
||||
"max_connect_errors": "100",
|
||||
"max_connections": "151",
|
||||
"max_delayed_threads": "20",
|
||||
"max_digest_length": "1024",
|
||||
"max_error_count": "64",
|
||||
"max_execution_time": "0",
|
||||
"max_heap_table_size": "16777216",
|
||||
"max_insert_delayed_threads": "20",
|
||||
"max_join_size": "18446744073709551615",
|
||||
"max_length_for_sort_data": "1024",
|
||||
"max_points_in_geometry": "65536",
|
||||
"max_prepared_stmt_count": "16382",
|
||||
"max_relay_log_size": "0",
|
||||
"max_seeks_for_key": "18446744073709551615",
|
||||
"max_sort_length": "1024",
|
||||
"max_sp_recursion_depth": "0",
|
||||
"max_tmp_tables": "32",
|
||||
"max_user_connections": "0",
|
||||
"max_write_lock_count": "18446744073709551615",
|
||||
"metadata_locks_cache_size": "1024",
|
||||
"metadata_locks_hash_instances": "8",
|
||||
"min_examined_row_limit": "0",
|
||||
"multi_range_count": "256",
|
||||
"myisam_data_pointer_size": "6",
|
||||
"myisam_max_sort_file_size": "9223372036853727232",
|
||||
"myisam_mmap_size": "18446744073709551615",
|
||||
"myisam_recover_options": "OFF",
|
||||
"myisam_repair_threads": "1",
|
||||
"myisam_sort_buffer_size": "8388608",
|
||||
"myisam_stats_method": "nulls_unequal",
|
||||
"myisam_use_mmap": "OFF",
|
||||
"mysql_native_password_proxy_users": "OFF",
|
||||
"net_buffer_length": "16384",
|
||||
"net_read_timeout": "30",
|
||||
"net_retry_count": "10",
|
||||
"net_write_timeout": "60",
|
||||
"new": "OFF",
|
||||
"ngram_token_size": "2",
|
||||
"offline_mode": "OFF",
|
||||
"old": "OFF",
|
||||
"old_alter_table": "OFF",
|
||||
"old_passwords": "0",
|
||||
"open_files_limit": "5000",
|
||||
"optimizer_prune_level": "1",
|
||||
"optimizer_search_depth": "62",
|
||||
"optimizer_switch": "index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on",
|
||||
"optimizer_trace": "enabled=off,one_line=off",
|
||||
"optimizer_trace_features": "greedy_search=on,range_optimizer=on,dynamic_range=on,repeated_subselect=on",
|
||||
"optimizer_trace_limit": "1",
|
||||
"optimizer_trace_max_mem_size": "16384",
|
||||
"optimizer_trace_offset": "-1",
|
||||
"parser_max_mem_size": "18446744073709551615",
|
||||
"performance_schema": "ON",
|
||||
"performance_schema_accounts_size": "-1",
|
||||
"performance_schema_digests_size": "10000",
|
||||
"performance_schema_events_stages_history_long_size": "10000",
|
||||
"performance_schema_events_stages_history_size": "10",
|
||||
"performance_schema_events_statements_history_long_size": "10000",
|
||||
"performance_schema_events_statements_history_size": "10",
|
||||
"performance_schema_events_transactions_history_long_size": "10000",
|
||||
"performance_schema_events_transactions_history_size": "10",
|
||||
"performance_schema_events_waits_history_long_size": "10000",
|
||||
"performance_schema_events_waits_history_size": "10",
|
||||
"performance_schema_hosts_size": "-1",
|
||||
"performance_schema_max_cond_classes": "80",
|
||||
"performance_schema_max_cond_instances": "-1",
|
||||
"performance_schema_max_digest_length": "1024",
|
||||
"performance_schema_max_file_classes": "80",
|
||||
"performance_schema_max_file_handles": "32768",
|
||||
"performance_schema_max_file_instances": "-1",
|
||||
"performance_schema_max_index_stat": "-1",
|
||||
"performance_schema_max_memory_classes": "320",
|
||||
"performance_schema_max_metadata_locks": "-1",
|
||||
"performance_schema_max_mutex_classes": "210",
|
||||
"performance_schema_max_mutex_instances": "-1",
|
||||
"performance_schema_max_prepared_statements_instances": "-1",
|
||||
"performance_schema_max_program_instances": "-1",
|
||||
"performance_schema_max_rwlock_classes": "40",
|
||||
"performance_schema_max_rwlock_instances": "-1",
|
||||
"performance_schema_max_socket_classes": "10",
|
||||
"performance_schema_max_socket_instances": "-1",
|
||||
"performance_schema_max_sql_text_length": "1024",
|
||||
"performance_schema_max_stage_classes": "150",
|
||||
"performance_schema_max_statement_classes": "193",
|
||||
"performance_schema_max_statement_stack": "10",
|
||||
"performance_schema_max_table_handles": "-1",
|
||||
"performance_schema_max_table_instances": "-1",
|
||||
"performance_schema_max_table_lock_stat": "-1",
|
||||
"performance_schema_max_thread_classes": "50",
|
||||
"performance_schema_max_thread_instances": "-1",
|
||||
"performance_schema_session_connect_attrs_size": "512",
|
||||
"performance_schema_setup_actors_size": "-1",
|
||||
"performance_schema_setup_objects_size": "-1",
|
||||
"performance_schema_users_size": "-1",
|
||||
"pid_file": "/usr/local/var/mysql/JiangShuli.local.pid",
|
||||
"plugin_dir": "/usr/local/Cellar/mysql/5.7.20/lib/plugin/",
|
||||
"port": "3306",
|
||||
"preload_buffer_size": "32768",
|
||||
"profiling": "OFF",
|
||||
"profiling_history_size": "15",
|
||||
"protocol_version": "10",
|
||||
"proxy_user": "",
|
||||
"pseudo_slave_mode": "OFF",
|
||||
"pseudo_thread_id": "3",
|
||||
"query_alloc_block_size": "8192",
|
||||
"query_cache_limit": "1048576",
|
||||
"query_cache_min_res_unit": "4096",
|
||||
"query_cache_size": "1048576",
|
||||
"query_cache_type": "OFF",
|
||||
"query_cache_wlock_invalidate": "OFF",
|
||||
"query_prealloc_size": "8192",
|
||||
"rand_seed1": "0",
|
||||
"rand_seed2": "0",
|
||||
"range_alloc_block_size": "4096",
|
||||
"range_optimizer_max_mem_size": "8388608",
|
||||
"rbr_exec_mode": "STRICT",
|
||||
"read_buffer_size": "131072",
|
||||
"read_only": "OFF",
|
||||
"read_rnd_buffer_size": "262144",
|
||||
"relay_log": "",
|
||||
"relay_log_basename": "/usr/local/var/mysql/JiangShuli-relay-bin",
|
||||
"relay_log_index": "/usr/local/var/mysql/JiangShuli-relay-bin.index",
|
||||
"relay_log_info_file": "relay-log.info",
|
||||
"relay_log_info_repository": "FILE",
|
||||
"relay_log_purge": "ON",
|
||||
"relay_log_recovery": "OFF",
|
||||
"relay_log_space_limit": "0",
|
||||
"report_host": "",
|
||||
"report_password": "",
|
||||
"report_port": "3306",
|
||||
"report_user": "",
|
||||
"require_secure_transport": "OFF",
|
||||
"rpl_stop_slave_timeout": "31536000",
|
||||
"secure_auth": "ON",
|
||||
"secure_file_priv": "NULL",
|
||||
"server_id": "0",
|
||||
"server_id_bits": "32",
|
||||
"server_uuid": "89286c98-d4ae-11e7-bb02-defe5cd105a2",
|
||||
"session_track_gtids": "OFF",
|
||||
"session_track_schema": "ON",
|
||||
"session_track_state_change": "OFF",
|
||||
"session_track_system_variables": "time_zone,autocommit,character_set_client,character_set_results,character_set_connection",
|
||||
"session_track_transaction_info": "OFF",
|
||||
"sha256_password_auto_generate_rsa_keys": "ON",
|
||||
"sha256_password_private_key_path": "private_key.pem",
|
||||
"sha256_password_proxy_users": "OFF",
|
||||
"sha256_password_public_key_path": "public_key.pem",
|
||||
"show_compatibility_56": "OFF",
|
||||
"show_old_temporals": "OFF",
|
||||
"skip_external_locking": "ON",
|
||||
"skip_name_resolve": "OFF",
|
||||
"skip_networking": "OFF",
|
||||
"skip_show_database": "OFF",
|
||||
"slave_allow_batching": "OFF",
|
||||
"slave_checkpoint_group": "512",
|
||||
"slave_checkpoint_period": "300",
|
||||
"slave_compressed_protocol": "OFF",
|
||||
"slave_exec_mode": "STRICT",
|
||||
"slave_load_tmpdir": "/var/folders/hd/lw_b86v52pdfg323g_jn76k80000gn/T/",
|
||||
"slave_max_allowed_packet": "1073741824",
|
||||
"slave_net_timeout": "60",
|
||||
"slave_parallel_type": "DATABASE",
|
||||
"slave_parallel_workers": "0",
|
||||
"slave_pending_jobs_size_max": "16777216",
|
||||
"slave_preserve_commit_order": "OFF",
|
||||
"slave_rows_search_algorithms": "TABLE_SCAN,INDEX_SCAN",
|
||||
"slave_skip_errors": "OFF",
|
||||
"slave_sql_verify_checksum": "ON",
|
||||
"slave_transaction_retries": "10",
|
||||
"slave_type_conversions": "",
|
||||
"slow_launch_time": "2",
|
||||
"slow_query_log": "OFF",
|
||||
"slow_query_log_file": "/usr/local/var/mysql/JiangShuli-slow.log",
|
||||
"socket": "/tmp/mysql.sock",
|
||||
"sort_buffer_size": "262144",
|
||||
"sql_auto_is_null": "OFF",
|
||||
"sql_big_selects": "ON",
|
||||
"sql_buffer_result": "OFF",
|
||||
"sql_log_bin": "ON",
|
||||
"sql_log_off": "OFF",
|
||||
"sql_mode": "ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION",
|
||||
"sql_notes": "ON",
|
||||
"sql_quote_show_create": "ON",
|
||||
"sql_safe_updates": "OFF",
|
||||
"sql_select_limit": "18446744073709551615",
|
||||
"sql_slave_skip_counter": "0",
|
||||
"sql_warnings": "OFF",
|
||||
"ssl_ca": "ca.pem",
|
||||
"ssl_capath": "",
|
||||
"ssl_cert": "server-cert.pem",
|
||||
"ssl_cipher": "",
|
||||
"ssl_crl": "",
|
||||
"ssl_crlpath": "",
|
||||
"ssl_key": "server-key.pem",
|
||||
"stored_program_cache": "256",
|
||||
"super_read_only": "OFF",
|
||||
"sync_binlog": "1",
|
||||
"sync_frm": "ON",
|
||||
"sync_master_info": "10000",
|
||||
"sync_relay_log": "10000",
|
||||
"sync_relay_log_info": "10000",
|
||||
"system_time_zone": "EST",
|
||||
"table_definition_cache": "1400",
|
||||
"table_open_cache": "2000",
|
||||
"table_open_cache_instances": "16",
|
||||
"thread_cache_size": "9",
|
||||
"thread_handling": "one-thread-per-connection",
|
||||
"thread_stack": "262144",
|
||||
"time_format": "%H:%i:%s",
|
||||
"time_zone": "SYSTEM",
|
||||
"timestamp": "1512532880.980241",
|
||||
"tls_version": "TLSv1,TLSv1.1,TLSv1.2",
|
||||
"tmp_table_size": "16777216",
|
||||
"tmpdir": "/var/folders/hd/lw_b86v52pdfg323g_jn76k80000gn/T/",
|
||||
"transaction_alloc_block_size": "8192",
|
||||
"transaction_allow_batching": "OFF",
|
||||
"transaction_isolation": "REPEATABLE-READ",
|
||||
"transaction_prealloc_size": "4096",
|
||||
"transaction_read_only": "OFF",
|
||||
"transaction_write_set_extraction": "OFF",
|
||||
"tx_isolation": "REPEATABLE-READ",
|
||||
"tx_read_only": "OFF",
|
||||
"unique_checks": "ON",
|
||||
"updatable_views_with_limit": "YES",
|
||||
"version": "5.7.20",
|
||||
"version_comment": "Homebrew",
|
||||
"version_compile_machine": "x86_64",
|
||||
"version_compile_os": "osx10.12",
|
||||
"wait_timeout": "28800",
|
||||
"warning_count": "0"
|
||||
}},
|
||||
"local": null
|
||||
}
|
||||
362
client/controller/sample_output/mysql/metrics_after.json
Normal file
362
client/controller/sample_output/mysql/metrics_after.json
Normal file
@@ -0,0 +1,362 @@
|
||||
{
|
||||
"global": {"global": {
|
||||
"aborted_clients": "0",
|
||||
"aborted_connects": "0",
|
||||
"binlog_cache_disk_use": "0",
|
||||
"binlog_cache_use": "0",
|
||||
"binlog_stmt_cache_disk_use": "0",
|
||||
"binlog_stmt_cache_use": "0",
|
||||
"bytes_received": "1227",
|
||||
"bytes_sent": "29713",
|
||||
"com_admin_commands": "0",
|
||||
"com_alter_db": "0",
|
||||
"com_alter_db_upgrade": "0",
|
||||
"com_alter_event": "0",
|
||||
"com_alter_function": "0",
|
||||
"com_alter_instance": "0",
|
||||
"com_alter_procedure": "0",
|
||||
"com_alter_server": "0",
|
||||
"com_alter_table": "0",
|
||||
"com_alter_tablespace": "0",
|
||||
"com_alter_user": "0",
|
||||
"com_analyze": "0",
|
||||
"com_assign_to_keycache": "0",
|
||||
"com_begin": "0",
|
||||
"com_binlog": "0",
|
||||
"com_call_procedure": "0",
|
||||
"com_change_db": "0",
|
||||
"com_change_master": "0",
|
||||
"com_change_repl_filter": "0",
|
||||
"com_check": "0",
|
||||
"com_checksum": "0",
|
||||
"com_commit": "0",
|
||||
"com_create_db": "0",
|
||||
"com_create_event": "0",
|
||||
"com_create_function": "0",
|
||||
"com_create_index": "0",
|
||||
"com_create_procedure": "0",
|
||||
"com_create_server": "0",
|
||||
"com_create_table": "0",
|
||||
"com_create_trigger": "0",
|
||||
"com_create_udf": "0",
|
||||
"com_create_user": "0",
|
||||
"com_create_view": "0",
|
||||
"com_dealloc_sql": "0",
|
||||
"com_delete": "0",
|
||||
"com_delete_multi": "0",
|
||||
"com_do": "0",
|
||||
"com_drop_db": "0",
|
||||
"com_drop_event": "0",
|
||||
"com_drop_function": "0",
|
||||
"com_drop_index": "0",
|
||||
"com_drop_procedure": "0",
|
||||
"com_drop_server": "0",
|
||||
"com_drop_table": "0",
|
||||
"com_drop_trigger": "0",
|
||||
"com_drop_user": "0",
|
||||
"com_drop_view": "0",
|
||||
"com_empty_query": "0",
|
||||
"com_execute_sql": "0",
|
||||
"com_explain_other": "0",
|
||||
"com_flush": "0",
|
||||
"com_get_diagnostics": "0",
|
||||
"com_grant": "0",
|
||||
"com_group_replication_start": "0",
|
||||
"com_group_replication_stop": "0",
|
||||
"com_ha_close": "0",
|
||||
"com_ha_open": "0",
|
||||
"com_ha_read": "0",
|
||||
"com_help": "0",
|
||||
"com_insert": "0",
|
||||
"com_insert_select": "0",
|
||||
"com_install_plugin": "0",
|
||||
"com_kill": "0",
|
||||
"com_load": "0",
|
||||
"com_lock_tables": "0",
|
||||
"com_optimize": "0",
|
||||
"com_preload_keys": "0",
|
||||
"com_prepare_sql": "0",
|
||||
"com_purge": "0",
|
||||
"com_purge_before_date": "0",
|
||||
"com_release_savepoint": "0",
|
||||
"com_rename_table": "0",
|
||||
"com_rename_user": "0",
|
||||
"com_repair": "0",
|
||||
"com_replace": "0",
|
||||
"com_replace_select": "0",
|
||||
"com_reset": "0",
|
||||
"com_resignal": "0",
|
||||
"com_revoke": "0",
|
||||
"com_revoke_all": "0",
|
||||
"com_rollback": "0",
|
||||
"com_rollback_to_savepoint": "0",
|
||||
"com_savepoint": "0",
|
||||
"com_select": "2",
|
||||
"com_set_option": "2",
|
||||
"com_show_binlog_events": "0",
|
||||
"com_show_binlogs": "0",
|
||||
"com_show_charsets": "1",
|
||||
"com_show_collations": "1",
|
||||
"com_show_create_db": "0",
|
||||
"com_show_create_event": "0",
|
||||
"com_show_create_func": "0",
|
||||
"com_show_create_proc": "0",
|
||||
"com_show_create_table": "0",
|
||||
"com_show_create_trigger": "0",
|
||||
"com_show_create_user": "0",
|
||||
"com_show_databases": "0",
|
||||
"com_show_engine_logs": "0",
|
||||
"com_show_engine_mutex": "0",
|
||||
"com_show_engine_status": "0",
|
||||
"com_show_errors": "0",
|
||||
"com_show_events": "0",
|
||||
"com_show_fields": "0",
|
||||
"com_show_function_code": "0",
|
||||
"com_show_function_status": "0",
|
||||
"com_show_grants": "0",
|
||||
"com_show_keys": "0",
|
||||
"com_show_master_status": "0",
|
||||
"com_show_open_tables": "0",
|
||||
"com_show_plugins": "0",
|
||||
"com_show_privileges": "0",
|
||||
"com_show_procedure_code": "0",
|
||||
"com_show_procedure_status": "0",
|
||||
"com_show_processlist": "0",
|
||||
"com_show_profile": "0",
|
||||
"com_show_profiles": "0",
|
||||
"com_show_relaylog_events": "0",
|
||||
"com_show_slave_hosts": "0",
|
||||
"com_show_slave_status": "0",
|
||||
"com_show_status": "1",
|
||||
"com_show_storage_engines": "0",
|
||||
"com_show_table_status": "0",
|
||||
"com_show_tables": "0",
|
||||
"com_show_triggers": "0",
|
||||
"com_show_variables": "2",
|
||||
"com_show_warnings": "0",
|
||||
"com_shutdown": "0",
|
||||
"com_signal": "0",
|
||||
"com_slave_start": "0",
|
||||
"com_slave_stop": "0",
|
||||
"com_stmt_close": "0",
|
||||
"com_stmt_execute": "0",
|
||||
"com_stmt_fetch": "0",
|
||||
"com_stmt_prepare": "0",
|
||||
"com_stmt_reprepare": "0",
|
||||
"com_stmt_reset": "0",
|
||||
"com_stmt_send_long_data": "0",
|
||||
"com_truncate": "0",
|
||||
"com_uninstall_plugin": "0",
|
||||
"com_unlock_tables": "0",
|
||||
"com_update": "0",
|
||||
"com_update_multi": "0",
|
||||
"com_xa_commit": "0",
|
||||
"com_xa_end": "0",
|
||||
"com_xa_prepare": "0",
|
||||
"com_xa_recover": "0",
|
||||
"com_xa_rollback": "0",
|
||||
"com_xa_start": "0",
|
||||
"compression": "OFF",
|
||||
"connection_errors_accept": "0",
|
||||
"connection_errors_internal": "0",
|
||||
"connection_errors_max_connections": "0",
|
||||
"connection_errors_peer_address": "0",
|
||||
"connection_errors_select": "0",
|
||||
"connection_errors_tcpwrap": "0",
|
||||
"connections": "4",
|
||||
"created_tmp_disk_tables": "0",
|
||||
"created_tmp_files": "5",
|
||||
"created_tmp_tables": "4",
|
||||
"delayed_errors": "0",
|
||||
"delayed_insert_threads": "0",
|
||||
"delayed_writes": "0",
|
||||
"flush_commands": "1",
|
||||
"handler_commit": "0",
|
||||
"handler_delete": "0",
|
||||
"handler_discover": "0",
|
||||
"handler_external_lock": "4",
|
||||
"handler_mrr_init": "0",
|
||||
"handler_prepare": "0",
|
||||
"handler_read_first": "0",
|
||||
"handler_read_key": "0",
|
||||
"handler_read_last": "0",
|
||||
"handler_read_next": "0",
|
||||
"handler_read_prev": "0",
|
||||
"handler_read_rnd": "0",
|
||||
"handler_read_rnd_next": "2317",
|
||||
"handler_rollback": "0",
|
||||
"handler_savepoint": "0",
|
||||
"handler_savepoint_rollback": "0",
|
||||
"handler_update": "0",
|
||||
"handler_write": "1287",
|
||||
"innodb_available_undo_logs": "128",
|
||||
"innodb_buffer_pool_bytes_data": "11288576",
|
||||
"innodb_buffer_pool_bytes_dirty": "0",
|
||||
"innodb_buffer_pool_dump_status": "Dumping of buffer pool not started",
|
||||
"innodb_buffer_pool_load_status": "Buffer pool(s) load completed at 171205 23:01:14",
|
||||
"innodb_buffer_pool_pages_data": "689",
|
||||
"innodb_buffer_pool_pages_dirty": "0",
|
||||
"innodb_buffer_pool_pages_flushed": "37",
|
||||
"innodb_buffer_pool_pages_free": "7502",
|
||||
"innodb_buffer_pool_pages_misc": "0",
|
||||
"innodb_buffer_pool_pages_total": "8191",
|
||||
"innodb_buffer_pool_read_ahead": "0",
|
||||
"innodb_buffer_pool_read_ahead_evicted": "0",
|
||||
"innodb_buffer_pool_read_ahead_rnd": "0",
|
||||
"innodb_buffer_pool_read_requests": "1833",
|
||||
"innodb_buffer_pool_reads": "655",
|
||||
"innodb_buffer_pool_resize_status": "",
|
||||
"innodb_buffer_pool_wait_free": "0",
|
||||
"innodb_buffer_pool_write_requests": "515",
|
||||
"innodb_data_fsyncs": "7",
|
||||
"innodb_data_pending_fsyncs": "0",
|
||||
"innodb_data_pending_reads": "0",
|
||||
"innodb_data_pending_writes": "0",
|
||||
"innodb_data_read": "10801664",
|
||||
"innodb_data_reads": "683",
|
||||
"innodb_data_writes": "54",
|
||||
"innodb_data_written": "641024",
|
||||
"innodb_dblwr_pages_written": "2",
|
||||
"innodb_dblwr_writes": "1",
|
||||
"innodb_log_waits": "0",
|
||||
"innodb_log_write_requests": "0",
|
||||
"innodb_log_writes": "2",
|
||||
"innodb_num_open_files": "20",
|
||||
"innodb_os_log_fsyncs": "4",
|
||||
"innodb_os_log_pending_fsyncs": "0",
|
||||
"innodb_os_log_pending_writes": "0",
|
||||
"innodb_os_log_written": "1024",
|
||||
"innodb_page_size": "16384",
|
||||
"innodb_pages_created": "35",
|
||||
"innodb_pages_read": "654",
|
||||
"innodb_pages_written": "37",
|
||||
"innodb_row_lock_current_waits": "0",
|
||||
"innodb_row_lock_time": "0",
|
||||
"innodb_row_lock_time_avg": "0",
|
||||
"innodb_row_lock_time_max": "0",
|
||||
"innodb_row_lock_waits": "0",
|
||||
"innodb_rows_deleted": "0",
|
||||
"innodb_rows_inserted": "0",
|
||||
"innodb_rows_read": "8",
|
||||
"innodb_rows_updated": "0",
|
||||
"innodb_truncated_status_writes": "0",
|
||||
"key_blocks_not_flushed": "0",
|
||||
"key_blocks_unused": "6695",
|
||||
"key_blocks_used": "3",
|
||||
"key_read_requests": "6",
|
||||
"key_reads": "3",
|
||||
"key_write_requests": "0",
|
||||
"key_writes": "0",
|
||||
"last_query_cost": "0.000000",
|
||||
"last_query_partial_plans": "2",
|
||||
"locked_connects": "0",
|
||||
"max_execution_time_exceeded": "0",
|
||||
"max_execution_time_set": "0",
|
||||
"max_execution_time_set_failed": "0",
|
||||
"max_used_connections": "1",
|
||||
"max_used_connections_time": "2017-12-05 23:01:20",
|
||||
"not_flushed_delayed_rows": "0",
|
||||
"ongoing_anonymous_transaction_count": "0",
|
||||
"open_files": "14",
|
||||
"open_streams": "0",
|
||||
"open_table_definitions": "228",
|
||||
"open_tables": "100",
|
||||
"opened_files": "357",
|
||||
"opened_table_definitions": "0",
|
||||
"opened_tables": "1",
|
||||
"performance_schema_accounts_lost": "0",
|
||||
"performance_schema_cond_classes_lost": "0",
|
||||
"performance_schema_cond_instances_lost": "0",
|
||||
"performance_schema_digest_lost": "0",
|
||||
"performance_schema_file_classes_lost": "0",
|
||||
"performance_schema_file_handles_lost": "0",
|
||||
"performance_schema_file_instances_lost": "0",
|
||||
"performance_schema_hosts_lost": "0",
|
||||
"performance_schema_index_stat_lost": "0",
|
||||
"performance_schema_locker_lost": "0",
|
||||
"performance_schema_memory_classes_lost": "0",
|
||||
"performance_schema_metadata_lock_lost": "0",
|
||||
"performance_schema_mutex_classes_lost": "0",
|
||||
"performance_schema_mutex_instances_lost": "0",
|
||||
"performance_schema_nested_statement_lost": "0",
|
||||
"performance_schema_prepared_statements_lost": "0",
|
||||
"performance_schema_program_lost": "0",
|
||||
"performance_schema_rwlock_classes_lost": "0",
|
||||
"performance_schema_rwlock_instances_lost": "0",
|
||||
"performance_schema_session_connect_attrs_lost": "0",
|
||||
"performance_schema_socket_classes_lost": "0",
|
||||
"performance_schema_socket_instances_lost": "0",
|
||||
"performance_schema_stage_classes_lost": "0",
|
||||
"performance_schema_statement_classes_lost": "0",
|
||||
"performance_schema_table_handles_lost": "0",
|
||||
"performance_schema_table_instances_lost": "0",
|
||||
"performance_schema_table_lock_stat_lost": "0",
|
||||
"performance_schema_thread_classes_lost": "0",
|
||||
"performance_schema_thread_instances_lost": "0",
|
||||
"performance_schema_users_lost": "0",
|
||||
"prepared_stmt_count": "0",
|
||||
"qcache_free_blocks": "1",
|
||||
"qcache_free_memory": "1031832",
|
||||
"qcache_hits": "0",
|
||||
"qcache_inserts": "0",
|
||||
"qcache_lowmem_prunes": "0",
|
||||
"qcache_not_cached": "2",
|
||||
"qcache_queries_in_cache": "0",
|
||||
"qcache_total_blocks": "1",
|
||||
"queries": "11",
|
||||
"questions": "9",
|
||||
"rsa_public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApBHbP3hArKih5/R7ffR9\n8ZUpK1VCGmD/7PCjOMQiChcb+KYr7PdgokSw/D95Ua84u36bvRHiB+7a6uGSYHZv\nOMB/h+zP0pSdmucCF5CNRuFgA6D0SHP7lql8O1t4x0dBYGkI0bkUgCxZeeRZshLm\nG6rGMXh79j3WlZP2Ny87TbCcgpbvW0tYxM9/pc1em/8y3+hDd3V0tVSBk36TEuJd\nJRr8Of09H0paSNjPdnvaZYdpXyhZUD0frhLSfnCj52OqFcypeelArR/ntEQffqif\n7CQvVm06mD5a5BlflgIVvnCLSH5pTBcn5tnPACFwbxBMYeRzfmRu+TFqFMBaxEhl\nVQIDAQAB\n-----END PUBLIC KEY-----\n",
|
||||
"select_full_join": "0",
|
||||
"select_full_range_join": "0",
|
||||
"select_range": "0",
|
||||
"select_range_check": "0",
|
||||
"select_scan": "6",
|
||||
"slave_open_temp_tables": "0",
|
||||
"slow_launch_threads": "0",
|
||||
"slow_queries": "0",
|
||||
"sort_merge_passes": "0",
|
||||
"sort_range": "0",
|
||||
"sort_rows": "0",
|
||||
"sort_scan": "0",
|
||||
"ssl_accept_renegotiates": "0",
|
||||
"ssl_accepts": "0",
|
||||
"ssl_callback_cache_hits": "0",
|
||||
"ssl_cipher": "",
|
||||
"ssl_cipher_list": "",
|
||||
"ssl_client_connects": "0",
|
||||
"ssl_connect_renegotiates": "0",
|
||||
"ssl_ctx_verify_depth": "18446744073709551615",
|
||||
"ssl_ctx_verify_mode": "5",
|
||||
"ssl_default_timeout": "0",
|
||||
"ssl_finished_accepts": "0",
|
||||
"ssl_finished_connects": "0",
|
||||
"ssl_server_not_after": "Nov 27 02:39:35 2027 GMT",
|
||||
"ssl_server_not_before": "Nov 29 02:39:35 2017 GMT",
|
||||
"ssl_session_cache_hits": "0",
|
||||
"ssl_session_cache_misses": "0",
|
||||
"ssl_session_cache_mode": "SERVER",
|
||||
"ssl_session_cache_overflows": "0",
|
||||
"ssl_session_cache_size": "128",
|
||||
"ssl_session_cache_timeouts": "0",
|
||||
"ssl_sessions_reused": "0",
|
||||
"ssl_used_session_cache_entries": "0",
|
||||
"ssl_verify_depth": "0",
|
||||
"ssl_verify_mode": "0",
|
||||
"ssl_version": "",
|
||||
"table_locks_immediate": "101",
|
||||
"table_locks_waited": "0",
|
||||
"table_open_cache_hits": "1",
|
||||
"table_open_cache_misses": "1",
|
||||
"table_open_cache_overflows": "0",
|
||||
"tc_log_max_pages_used": "0",
|
||||
"tc_log_page_size": "0",
|
||||
"tc_log_page_waits": "0",
|
||||
"threads_cached": "0",
|
||||
"threads_connected": "1",
|
||||
"threads_created": "1",
|
||||
"threads_running": "1",
|
||||
"uptime": "8",
|
||||
"uptime_since_flush_status": "8"
|
||||
}},
|
||||
"local": null
|
||||
}
|
||||
362
client/controller/sample_output/mysql/metrics_before.json
Normal file
362
client/controller/sample_output/mysql/metrics_before.json
Normal file
@@ -0,0 +1,362 @@
|
||||
{
|
||||
"global": {"global": {
|
||||
"aborted_clients": "0",
|
||||
"aborted_connects": "0",
|
||||
"binlog_cache_disk_use": "0",
|
||||
"binlog_cache_use": "0",
|
||||
"binlog_stmt_cache_disk_use": "0",
|
||||
"binlog_stmt_cache_use": "0",
|
||||
"bytes_received": "1227",
|
||||
"bytes_sent": "29713",
|
||||
"com_admin_commands": "0",
|
||||
"com_alter_db": "0",
|
||||
"com_alter_db_upgrade": "0",
|
||||
"com_alter_event": "0",
|
||||
"com_alter_function": "0",
|
||||
"com_alter_instance": "0",
|
||||
"com_alter_procedure": "0",
|
||||
"com_alter_server": "0",
|
||||
"com_alter_table": "0",
|
||||
"com_alter_tablespace": "0",
|
||||
"com_alter_user": "0",
|
||||
"com_analyze": "0",
|
||||
"com_assign_to_keycache": "0",
|
||||
"com_begin": "0",
|
||||
"com_binlog": "0",
|
||||
"com_call_procedure": "0",
|
||||
"com_change_db": "0",
|
||||
"com_change_master": "0",
|
||||
"com_change_repl_filter": "0",
|
||||
"com_check": "0",
|
||||
"com_checksum": "0",
|
||||
"com_commit": "0",
|
||||
"com_create_db": "0",
|
||||
"com_create_event": "0",
|
||||
"com_create_function": "0",
|
||||
"com_create_index": "0",
|
||||
"com_create_procedure": "0",
|
||||
"com_create_server": "0",
|
||||
"com_create_table": "0",
|
||||
"com_create_trigger": "0",
|
||||
"com_create_udf": "0",
|
||||
"com_create_user": "0",
|
||||
"com_create_view": "0",
|
||||
"com_dealloc_sql": "0",
|
||||
"com_delete": "0",
|
||||
"com_delete_multi": "0",
|
||||
"com_do": "0",
|
||||
"com_drop_db": "0",
|
||||
"com_drop_event": "0",
|
||||
"com_drop_function": "0",
|
||||
"com_drop_index": "0",
|
||||
"com_drop_procedure": "0",
|
||||
"com_drop_server": "0",
|
||||
"com_drop_table": "0",
|
||||
"com_drop_trigger": "0",
|
||||
"com_drop_user": "0",
|
||||
"com_drop_view": "0",
|
||||
"com_empty_query": "0",
|
||||
"com_execute_sql": "0",
|
||||
"com_explain_other": "0",
|
||||
"com_flush": "0",
|
||||
"com_get_diagnostics": "0",
|
||||
"com_grant": "0",
|
||||
"com_group_replication_start": "0",
|
||||
"com_group_replication_stop": "0",
|
||||
"com_ha_close": "0",
|
||||
"com_ha_open": "0",
|
||||
"com_ha_read": "0",
|
||||
"com_help": "0",
|
||||
"com_insert": "0",
|
||||
"com_insert_select": "0",
|
||||
"com_install_plugin": "0",
|
||||
"com_kill": "0",
|
||||
"com_load": "0",
|
||||
"com_lock_tables": "0",
|
||||
"com_optimize": "0",
|
||||
"com_preload_keys": "0",
|
||||
"com_prepare_sql": "0",
|
||||
"com_purge": "0",
|
||||
"com_purge_before_date": "0",
|
||||
"com_release_savepoint": "0",
|
||||
"com_rename_table": "0",
|
||||
"com_rename_user": "0",
|
||||
"com_repair": "0",
|
||||
"com_replace": "0",
|
||||
"com_replace_select": "0",
|
||||
"com_reset": "0",
|
||||
"com_resignal": "0",
|
||||
"com_revoke": "0",
|
||||
"com_revoke_all": "0",
|
||||
"com_rollback": "0",
|
||||
"com_rollback_to_savepoint": "0",
|
||||
"com_savepoint": "0",
|
||||
"com_select": "2",
|
||||
"com_set_option": "2",
|
||||
"com_show_binlog_events": "0",
|
||||
"com_show_binlogs": "0",
|
||||
"com_show_charsets": "1",
|
||||
"com_show_collations": "1",
|
||||
"com_show_create_db": "0",
|
||||
"com_show_create_event": "0",
|
||||
"com_show_create_func": "0",
|
||||
"com_show_create_proc": "0",
|
||||
"com_show_create_table": "0",
|
||||
"com_show_create_trigger": "0",
|
||||
"com_show_create_user": "0",
|
||||
"com_show_databases": "0",
|
||||
"com_show_engine_logs": "0",
|
||||
"com_show_engine_mutex": "0",
|
||||
"com_show_engine_status": "0",
|
||||
"com_show_errors": "0",
|
||||
"com_show_events": "0",
|
||||
"com_show_fields": "0",
|
||||
"com_show_function_code": "0",
|
||||
"com_show_function_status": "0",
|
||||
"com_show_grants": "0",
|
||||
"com_show_keys": "0",
|
||||
"com_show_master_status": "0",
|
||||
"com_show_open_tables": "0",
|
||||
"com_show_plugins": "0",
|
||||
"com_show_privileges": "0",
|
||||
"com_show_procedure_code": "0",
|
||||
"com_show_procedure_status": "0",
|
||||
"com_show_processlist": "0",
|
||||
"com_show_profile": "0",
|
||||
"com_show_profiles": "0",
|
||||
"com_show_relaylog_events": "0",
|
||||
"com_show_slave_hosts": "0",
|
||||
"com_show_slave_status": "0",
|
||||
"com_show_status": "1",
|
||||
"com_show_storage_engines": "0",
|
||||
"com_show_table_status": "0",
|
||||
"com_show_tables": "0",
|
||||
"com_show_triggers": "0",
|
||||
"com_show_variables": "2",
|
||||
"com_show_warnings": "0",
|
||||
"com_shutdown": "0",
|
||||
"com_signal": "0",
|
||||
"com_slave_start": "0",
|
||||
"com_slave_stop": "0",
|
||||
"com_stmt_close": "0",
|
||||
"com_stmt_execute": "0",
|
||||
"com_stmt_fetch": "0",
|
||||
"com_stmt_prepare": "0",
|
||||
"com_stmt_reprepare": "0",
|
||||
"com_stmt_reset": "0",
|
||||
"com_stmt_send_long_data": "0",
|
||||
"com_truncate": "0",
|
||||
"com_uninstall_plugin": "0",
|
||||
"com_unlock_tables": "0",
|
||||
"com_update": "0",
|
||||
"com_update_multi": "0",
|
||||
"com_xa_commit": "0",
|
||||
"com_xa_end": "0",
|
||||
"com_xa_prepare": "0",
|
||||
"com_xa_recover": "0",
|
||||
"com_xa_rollback": "0",
|
||||
"com_xa_start": "0",
|
||||
"compression": "OFF",
|
||||
"connection_errors_accept": "0",
|
||||
"connection_errors_internal": "0",
|
||||
"connection_errors_max_connections": "0",
|
||||
"connection_errors_peer_address": "0",
|
||||
"connection_errors_select": "0",
|
||||
"connection_errors_tcpwrap": "0",
|
||||
"connections": "4",
|
||||
"created_tmp_disk_tables": "0",
|
||||
"created_tmp_files": "5",
|
||||
"created_tmp_tables": "4",
|
||||
"delayed_errors": "0",
|
||||
"delayed_insert_threads": "0",
|
||||
"delayed_writes": "0",
|
||||
"flush_commands": "1",
|
||||
"handler_commit": "0",
|
||||
"handler_delete": "0",
|
||||
"handler_discover": "0",
|
||||
"handler_external_lock": "4",
|
||||
"handler_mrr_init": "0",
|
||||
"handler_prepare": "0",
|
||||
"handler_read_first": "0",
|
||||
"handler_read_key": "0",
|
||||
"handler_read_last": "0",
|
||||
"handler_read_next": "0",
|
||||
"handler_read_prev": "0",
|
||||
"handler_read_rnd": "0",
|
||||
"handler_read_rnd_next": "2317",
|
||||
"handler_rollback": "0",
|
||||
"handler_savepoint": "0",
|
||||
"handler_savepoint_rollback": "0",
|
||||
"handler_update": "0",
|
||||
"handler_write": "1287",
|
||||
"innodb_available_undo_logs": "128",
|
||||
"innodb_buffer_pool_bytes_data": "11288576",
|
||||
"innodb_buffer_pool_bytes_dirty": "0",
|
||||
"innodb_buffer_pool_dump_status": "Dumping of buffer pool not started",
|
||||
"innodb_buffer_pool_load_status": "Buffer pool(s) load completed at 171205 23:01:14",
|
||||
"innodb_buffer_pool_pages_data": "689",
|
||||
"innodb_buffer_pool_pages_dirty": "0",
|
||||
"innodb_buffer_pool_pages_flushed": "37",
|
||||
"innodb_buffer_pool_pages_free": "7502",
|
||||
"innodb_buffer_pool_pages_misc": "0",
|
||||
"innodb_buffer_pool_pages_total": "8191",
|
||||
"innodb_buffer_pool_read_ahead": "0",
|
||||
"innodb_buffer_pool_read_ahead_evicted": "0",
|
||||
"innodb_buffer_pool_read_ahead_rnd": "0",
|
||||
"innodb_buffer_pool_read_requests": "1833",
|
||||
"innodb_buffer_pool_reads": "655",
|
||||
"innodb_buffer_pool_resize_status": "",
|
||||
"innodb_buffer_pool_wait_free": "0",
|
||||
"innodb_buffer_pool_write_requests": "515",
|
||||
"innodb_data_fsyncs": "7",
|
||||
"innodb_data_pending_fsyncs": "0",
|
||||
"innodb_data_pending_reads": "0",
|
||||
"innodb_data_pending_writes": "0",
|
||||
"innodb_data_read": "10801664",
|
||||
"innodb_data_reads": "683",
|
||||
"innodb_data_writes": "54",
|
||||
"innodb_data_written": "641024",
|
||||
"innodb_dblwr_pages_written": "2",
|
||||
"innodb_dblwr_writes": "1",
|
||||
"innodb_log_waits": "0",
|
||||
"innodb_log_write_requests": "0",
|
||||
"innodb_log_writes": "2",
|
||||
"innodb_num_open_files": "20",
|
||||
"innodb_os_log_fsyncs": "4",
|
||||
"innodb_os_log_pending_fsyncs": "0",
|
||||
"innodb_os_log_pending_writes": "0",
|
||||
"innodb_os_log_written": "1024",
|
||||
"innodb_page_size": "16384",
|
||||
"innodb_pages_created": "35",
|
||||
"innodb_pages_read": "654",
|
||||
"innodb_pages_written": "37",
|
||||
"innodb_row_lock_current_waits": "0",
|
||||
"innodb_row_lock_time": "0",
|
||||
"innodb_row_lock_time_avg": "0",
|
||||
"innodb_row_lock_time_max": "0",
|
||||
"innodb_row_lock_waits": "0",
|
||||
"innodb_rows_deleted": "0",
|
||||
"innodb_rows_inserted": "0",
|
||||
"innodb_rows_read": "8",
|
||||
"innodb_rows_updated": "0",
|
||||
"innodb_truncated_status_writes": "0",
|
||||
"key_blocks_not_flushed": "0",
|
||||
"key_blocks_unused": "6695",
|
||||
"key_blocks_used": "3",
|
||||
"key_read_requests": "6",
|
||||
"key_reads": "3",
|
||||
"key_write_requests": "0",
|
||||
"key_writes": "0",
|
||||
"last_query_cost": "0.000000",
|
||||
"last_query_partial_plans": "2",
|
||||
"locked_connects": "0",
|
||||
"max_execution_time_exceeded": "0",
|
||||
"max_execution_time_set": "0",
|
||||
"max_execution_time_set_failed": "0",
|
||||
"max_used_connections": "1",
|
||||
"max_used_connections_time": "2017-12-05 23:01:20",
|
||||
"not_flushed_delayed_rows": "0",
|
||||
"ongoing_anonymous_transaction_count": "0",
|
||||
"open_files": "14",
|
||||
"open_streams": "0",
|
||||
"open_table_definitions": "228",
|
||||
"open_tables": "100",
|
||||
"opened_files": "357",
|
||||
"opened_table_definitions": "0",
|
||||
"opened_tables": "1",
|
||||
"performance_schema_accounts_lost": "0",
|
||||
"performance_schema_cond_classes_lost": "0",
|
||||
"performance_schema_cond_instances_lost": "0",
|
||||
"performance_schema_digest_lost": "0",
|
||||
"performance_schema_file_classes_lost": "0",
|
||||
"performance_schema_file_handles_lost": "0",
|
||||
"performance_schema_file_instances_lost": "0",
|
||||
"performance_schema_hosts_lost": "0",
|
||||
"performance_schema_index_stat_lost": "0",
|
||||
"performance_schema_locker_lost": "0",
|
||||
"performance_schema_memory_classes_lost": "0",
|
||||
"performance_schema_metadata_lock_lost": "0",
|
||||
"performance_schema_mutex_classes_lost": "0",
|
||||
"performance_schema_mutex_instances_lost": "0",
|
||||
"performance_schema_nested_statement_lost": "0",
|
||||
"performance_schema_prepared_statements_lost": "0",
|
||||
"performance_schema_program_lost": "0",
|
||||
"performance_schema_rwlock_classes_lost": "0",
|
||||
"performance_schema_rwlock_instances_lost": "0",
|
||||
"performance_schema_session_connect_attrs_lost": "0",
|
||||
"performance_schema_socket_classes_lost": "0",
|
||||
"performance_schema_socket_instances_lost": "0",
|
||||
"performance_schema_stage_classes_lost": "0",
|
||||
"performance_schema_statement_classes_lost": "0",
|
||||
"performance_schema_table_handles_lost": "0",
|
||||
"performance_schema_table_instances_lost": "0",
|
||||
"performance_schema_table_lock_stat_lost": "0",
|
||||
"performance_schema_thread_classes_lost": "0",
|
||||
"performance_schema_thread_instances_lost": "0",
|
||||
"performance_schema_users_lost": "0",
|
||||
"prepared_stmt_count": "0",
|
||||
"qcache_free_blocks": "1",
|
||||
"qcache_free_memory": "1031832",
|
||||
"qcache_hits": "0",
|
||||
"qcache_inserts": "0",
|
||||
"qcache_lowmem_prunes": "0",
|
||||
"qcache_not_cached": "2",
|
||||
"qcache_queries_in_cache": "0",
|
||||
"qcache_total_blocks": "1",
|
||||
"queries": "11",
|
||||
"questions": "9",
|
||||
"rsa_public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApBHbP3hArKih5/R7ffR9\n8ZUpK1VCGmD/7PCjOMQiChcb+KYr7PdgokSw/D95Ua84u36bvRHiB+7a6uGSYHZv\nOMB/h+zP0pSdmucCF5CNRuFgA6D0SHP7lql8O1t4x0dBYGkI0bkUgCxZeeRZshLm\nG6rGMXh79j3WlZP2Ny87TbCcgpbvW0tYxM9/pc1em/8y3+hDd3V0tVSBk36TEuJd\nJRr8Of09H0paSNjPdnvaZYdpXyhZUD0frhLSfnCj52OqFcypeelArR/ntEQffqif\n7CQvVm06mD5a5BlflgIVvnCLSH5pTBcn5tnPACFwbxBMYeRzfmRu+TFqFMBaxEhl\nVQIDAQAB\n-----END PUBLIC KEY-----\n",
|
||||
"select_full_join": "0",
|
||||
"select_full_range_join": "0",
|
||||
"select_range": "0",
|
||||
"select_range_check": "0",
|
||||
"select_scan": "6",
|
||||
"slave_open_temp_tables": "0",
|
||||
"slow_launch_threads": "0",
|
||||
"slow_queries": "0",
|
||||
"sort_merge_passes": "0",
|
||||
"sort_range": "0",
|
||||
"sort_rows": "0",
|
||||
"sort_scan": "0",
|
||||
"ssl_accept_renegotiates": "0",
|
||||
"ssl_accepts": "0",
|
||||
"ssl_callback_cache_hits": "0",
|
||||
"ssl_cipher": "",
|
||||
"ssl_cipher_list": "",
|
||||
"ssl_client_connects": "0",
|
||||
"ssl_connect_renegotiates": "0",
|
||||
"ssl_ctx_verify_depth": "18446744073709551615",
|
||||
"ssl_ctx_verify_mode": "5",
|
||||
"ssl_default_timeout": "0",
|
||||
"ssl_finished_accepts": "0",
|
||||
"ssl_finished_connects": "0",
|
||||
"ssl_server_not_after": "Nov 27 02:39:35 2027 GMT",
|
||||
"ssl_server_not_before": "Nov 29 02:39:35 2017 GMT",
|
||||
"ssl_session_cache_hits": "0",
|
||||
"ssl_session_cache_misses": "0",
|
||||
"ssl_session_cache_mode": "SERVER",
|
||||
"ssl_session_cache_overflows": "0",
|
||||
"ssl_session_cache_size": "128",
|
||||
"ssl_session_cache_timeouts": "0",
|
||||
"ssl_sessions_reused": "0",
|
||||
"ssl_used_session_cache_entries": "0",
|
||||
"ssl_verify_depth": "0",
|
||||
"ssl_verify_mode": "0",
|
||||
"ssl_version": "",
|
||||
"table_locks_immediate": "101",
|
||||
"table_locks_waited": "0",
|
||||
"table_open_cache_hits": "1",
|
||||
"table_open_cache_misses": "1",
|
||||
"table_open_cache_overflows": "0",
|
||||
"tc_log_max_pages_used": "0",
|
||||
"tc_log_page_size": "0",
|
||||
"tc_log_page_waits": "0",
|
||||
"threads_cached": "0",
|
||||
"threads_connected": "1",
|
||||
"threads_created": "1",
|
||||
"threads_running": "1",
|
||||
"uptime": "8",
|
||||
"uptime_since_flush_status": "8"
|
||||
}},
|
||||
"local": null
|
||||
}
|
||||
8
client/controller/sample_output/mysql/summary.json
Normal file
8
client/controller/sample_output/mysql/summary.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"start_time": 1535653369274,
|
||||
"end_time": 1535653559607,
|
||||
"observation_time": 190,
|
||||
"database_type": "mysql",
|
||||
"database_version": "5.7.20",
|
||||
"workload_name": "workload_name"
|
||||
}
|
||||
4902
client/controller/sample_output/oracle/knobs.json
Normal file
4902
client/controller/sample_output/oracle/knobs.json
Normal file
File diff suppressed because it is too large
Load Diff
2041
client/controller/sample_output/oracle/metrics_after.json
Normal file
2041
client/controller/sample_output/oracle/metrics_after.json
Normal file
File diff suppressed because it is too large
Load Diff
2041
client/controller/sample_output/oracle/metrics_before.json
Normal file
2041
client/controller/sample_output/oracle/metrics_before.json
Normal file
File diff suppressed because it is too large
Load Diff
8
client/controller/sample_output/oracle/summary.json
Normal file
8
client/controller/sample_output/oracle/summary.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"start_time": 1563264802685,
|
||||
"end_time": 1563265002918,
|
||||
"observation_time": 200,
|
||||
"database_type": "oracle",
|
||||
"database_version": "19.0.0.0.0",
|
||||
"workload_name": "tpcc"
|
||||
}
|
||||
274
client/controller/sample_output/postgres/knobs.json
Normal file
274
client/controller/sample_output/postgres/knobs.json
Normal file
@@ -0,0 +1,274 @@
|
||||
{
|
||||
"global": {"global": {
|
||||
"DateStyle": "ISO, MDY",
|
||||
"IntervalStyle": "postgres",
|
||||
"TimeZone": "America/New_York",
|
||||
"allow_system_table_mods": "off",
|
||||
"application_name": "",
|
||||
"archive_command": "(disabled)",
|
||||
"archive_mode": "off",
|
||||
"archive_timeout": "0",
|
||||
"array_nulls": "on",
|
||||
"authentication_timeout": "1min",
|
||||
"autovacuum": "on",
|
||||
"autovacuum_analyze_scale_factor": "0.1",
|
||||
"autovacuum_analyze_threshold": "50",
|
||||
"autovacuum_freeze_max_age": "200000000",
|
||||
"autovacuum_max_workers": "3",
|
||||
"autovacuum_multixact_freeze_max_age": "400000000",
|
||||
"autovacuum_naptime": "1min",
|
||||
"autovacuum_vacuum_cost_delay": "20ms",
|
||||
"autovacuum_vacuum_cost_limit": "-1",
|
||||
"autovacuum_vacuum_scale_factor": "0.2",
|
||||
"autovacuum_vacuum_threshold": "50",
|
||||
"autovacuum_work_mem": "-1",
|
||||
"backend_flush_after": "0",
|
||||
"backslash_quote": "safe_encoding",
|
||||
"bgwriter_delay": "200ms",
|
||||
"bgwriter_flush_after": "0",
|
||||
"bgwriter_lru_maxpages": "100",
|
||||
"bgwriter_lru_multiplier": "2",
|
||||
"block_size": "8192",
|
||||
"bonjour": "off",
|
||||
"bonjour_name": "",
|
||||
"bytea_output": "hex",
|
||||
"check_function_bodies": "on",
|
||||
"checkpoint_completion_target": "0.5",
|
||||
"checkpoint_flush_after": "0",
|
||||
"checkpoint_timeout": "5min",
|
||||
"checkpoint_warning": "30s",
|
||||
"client_encoding": "UTF8",
|
||||
"client_min_messages": "notice",
|
||||
"cluster_name": "",
|
||||
"commit_delay": "0",
|
||||
"commit_siblings": "5",
|
||||
"config_file": "/Users/MacadamiaKitten/Desktop/psql_db/postgresql.conf",
|
||||
"constraint_exclusion": "partition",
|
||||
"cpu_index_tuple_cost": "0.005",
|
||||
"cpu_operator_cost": "0.0025",
|
||||
"cpu_tuple_cost": "0.01",
|
||||
"cursor_tuple_fraction": "0.1",
|
||||
"data_checksums": "off",
|
||||
"data_directory": "/Users/MacadamiaKitten/Desktop/psql_db",
|
||||
"db_user_namespace": "off",
|
||||
"deadlock_timeout": "1s",
|
||||
"debug_assertions": "off",
|
||||
"debug_pretty_print": "on",
|
||||
"debug_print_parse": "off",
|
||||
"debug_print_plan": "off",
|
||||
"debug_print_rewritten": "off",
|
||||
"default_statistics_target": "100",
|
||||
"default_tablespace": "",
|
||||
"default_text_search_config": "pg_catalog.english",
|
||||
"default_transaction_deferrable": "off",
|
||||
"default_transaction_isolation": "read committed",
|
||||
"default_transaction_read_only": "off",
|
||||
"default_with_oids": "off",
|
||||
"dynamic_library_path": "$libdir",
|
||||
"dynamic_shared_memory_type": "posix",
|
||||
"effective_cache_size": "4GB",
|
||||
"effective_io_concurrency": "0",
|
||||
"enable_bitmapscan": "on",
|
||||
"enable_gathermerge": "on",
|
||||
"enable_hashagg": "on",
|
||||
"enable_hashjoin": "on",
|
||||
"enable_indexonlyscan": "on",
|
||||
"enable_indexscan": "on",
|
||||
"enable_material": "on",
|
||||
"enable_mergejoin": "on",
|
||||
"enable_nestloop": "on",
|
||||
"enable_seqscan": "on",
|
||||
"enable_sort": "on",
|
||||
"enable_tidscan": "on",
|
||||
"escape_string_warning": "on",
|
||||
"event_source": "PostgreSQL",
|
||||
"exit_on_error": "off",
|
||||
"external_pid_file": "",
|
||||
"extra_float_digits": "3",
|
||||
"force_parallel_mode": "off",
|
||||
"from_collapse_limit": "8",
|
||||
"fsync": "on",
|
||||
"full_page_writes": "on",
|
||||
"geqo": "on",
|
||||
"geqo_effort": "5",
|
||||
"geqo_generations": "0",
|
||||
"geqo_pool_size": "0",
|
||||
"geqo_seed": "0",
|
||||
"geqo_selection_bias": "2",
|
||||
"geqo_threshold": "12",
|
||||
"gin_fuzzy_search_limit": "0",
|
||||
"gin_pending_list_limit": "4MB",
|
||||
"hba_file": "/Users/MacadamiaKitten/Desktop/psql_db/pg_hba.conf",
|
||||
"hot_standby": "on",
|
||||
"hot_standby_feedback": "off",
|
||||
"huge_pages": "try",
|
||||
"ident_file": "/Users/MacadamiaKitten/Desktop/psql_db/pg_ident.conf",
|
||||
"idle_in_transaction_session_timeout": "0",
|
||||
"ignore_checksum_failure": "off",
|
||||
"ignore_system_indexes": "off",
|
||||
"integer_datetimes": "on",
|
||||
"join_collapse_limit": "8",
|
||||
"krb_caseins_users": "off",
|
||||
"krb_server_keyfile": "FILE:/usr/local/etc/postgresql/krb5.keytab",
|
||||
"lc_collate": "en_US.UTF-8",
|
||||
"lc_ctype": "en_US.UTF-8",
|
||||
"lc_messages": "en_US.UTF-8",
|
||||
"lc_monetary": "en_US.UTF-8",
|
||||
"lc_numeric": "en_US.UTF-8",
|
||||
"lc_time": "en_US.UTF-8",
|
||||
"listen_addresses": "localhost",
|
||||
"lo_compat_privileges": "off",
|
||||
"local_preload_libraries": "",
|
||||
"lock_timeout": "0",
|
||||
"log_autovacuum_min_duration": "-1",
|
||||
"log_checkpoints": "off",
|
||||
"log_connections": "off",
|
||||
"log_destination": "stderr",
|
||||
"log_directory": "log",
|
||||
"log_disconnections": "off",
|
||||
"log_duration": "off",
|
||||
"log_error_verbosity": "default",
|
||||
"log_executor_stats": "off",
|
||||
"log_file_mode": "0600",
|
||||
"log_filename": "postgresql-%Y-%m-%d_%H%M%S.log",
|
||||
"log_hostname": "off",
|
||||
"log_line_prefix": "%m [%p] ",
|
||||
"log_lock_waits": "off",
|
||||
"log_min_duration_statement": "-1",
|
||||
"log_min_error_statement": "error",
|
||||
"log_min_messages": "warning",
|
||||
"log_parser_stats": "off",
|
||||
"log_planner_stats": "off",
|
||||
"log_replication_commands": "off",
|
||||
"log_rotation_age": "1d",
|
||||
"log_rotation_size": "10MB",
|
||||
"log_statement": "none",
|
||||
"log_statement_stats": "off",
|
||||
"log_temp_files": "-1",
|
||||
"log_timezone": "US/Eastern",
|
||||
"log_truncate_on_rotation": "off",
|
||||
"logging_collector": "off",
|
||||
"maintenance_work_mem": "64MB",
|
||||
"max_connections": "100",
|
||||
"max_files_per_process": "1000",
|
||||
"max_function_args": "100",
|
||||
"max_identifier_length": "63",
|
||||
"max_index_keys": "32",
|
||||
"max_locks_per_transaction": "64",
|
||||
"max_logical_replication_workers": "4",
|
||||
"max_parallel_workers": "8",
|
||||
"max_parallel_workers_per_gather": "2",
|
||||
"max_pred_locks_per_page": "2",
|
||||
"max_pred_locks_per_relation": "-2",
|
||||
"max_pred_locks_per_transaction": "64",
|
||||
"max_prepared_transactions": "0",
|
||||
"max_replication_slots": "10",
|
||||
"max_stack_depth": "2MB",
|
||||
"max_standby_archive_delay": "30s",
|
||||
"max_standby_streaming_delay": "30s",
|
||||
"max_sync_workers_per_subscription": "2",
|
||||
"max_wal_senders": "10",
|
||||
"max_wal_size": "1GB",
|
||||
"max_worker_processes": "8",
|
||||
"min_parallel_index_scan_size": "512kB",
|
||||
"min_parallel_table_scan_size": "8MB",
|
||||
"min_wal_size": "80MB",
|
||||
"old_snapshot_threshold": "-1",
|
||||
"operator_precedence_warning": "off",
|
||||
"parallel_setup_cost": "1000",
|
||||
"parallel_tuple_cost": "0.1",
|
||||
"password_encryption": "md5",
|
||||
"port": "5432",
|
||||
"post_auth_delay": "0",
|
||||
"pre_auth_delay": "0",
|
||||
"quote_all_identifiers": "off",
|
||||
"random_page_cost": "4",
|
||||
"replacement_sort_tuples": "150000",
|
||||
"restart_after_crash": "on",
|
||||
"row_security": "on",
|
||||
"search_path": "\"$user\", public",
|
||||
"segment_size": "1GB",
|
||||
"seq_page_cost": "1",
|
||||
"server_encoding": "UTF8",
|
||||
"server_version": "10.1",
|
||||
"server_version_num": "100001",
|
||||
"session_preload_libraries": "",
|
||||
"session_replication_role": "origin",
|
||||
"shared_buffers": "128MB",
|
||||
"shared_preload_libraries": "",
|
||||
"ssl": "off",
|
||||
"ssl_ca_file": "",
|
||||
"ssl_cert_file": "server.crt",
|
||||
"ssl_ciphers": "HIGH:MEDIUM:+3DES:!aNULL",
|
||||
"ssl_crl_file": "",
|
||||
"ssl_dh_params_file": "",
|
||||
"ssl_ecdh_curve": "prime256v1",
|
||||
"ssl_key_file": "server.key",
|
||||
"ssl_prefer_server_ciphers": "on",
|
||||
"standard_conforming_strings": "on",
|
||||
"statement_timeout": "0",
|
||||
"stats_temp_directory": "pg_stat_tmp",
|
||||
"superuser_reserved_connections": "3",
|
||||
"synchronize_seqscans": "on",
|
||||
"synchronous_commit": "on",
|
||||
"synchronous_standby_names": "",
|
||||
"syslog_facility": "local0",
|
||||
"syslog_ident": "postgres",
|
||||
"syslog_sequence_numbers": "on",
|
||||
"syslog_split_messages": "on",
|
||||
"tcp_keepalives_count": "8",
|
||||
"tcp_keepalives_idle": "7200",
|
||||
"tcp_keepalives_interval": "75",
|
||||
"temp_buffers": "8MB",
|
||||
"temp_file_limit": "-1",
|
||||
"temp_tablespaces": "",
|
||||
"timezone_abbreviations": "Default",
|
||||
"trace_notify": "off",
|
||||
"trace_recovery_messages": "log",
|
||||
"trace_sort": "off",
|
||||
"track_activities": "on",
|
||||
"track_activity_query_size": "1024",
|
||||
"track_commit_timestamp": "off",
|
||||
"track_counts": "on",
|
||||
"track_functions": "none",
|
||||
"track_io_timing": "off",
|
||||
"transaction_deferrable": "off",
|
||||
"transaction_isolation": "read committed",
|
||||
"transaction_read_only": "off",
|
||||
"transform_null_equals": "off",
|
||||
"unix_socket_directories": "/tmp",
|
||||
"unix_socket_group": "",
|
||||
"unix_socket_permissions": "0777",
|
||||
"update_process_title": "on",
|
||||
"vacuum_cost_delay": "0",
|
||||
"vacuum_cost_limit": "200",
|
||||
"vacuum_cost_page_dirty": "20",
|
||||
"vacuum_cost_page_hit": "1",
|
||||
"vacuum_cost_page_miss": "10",
|
||||
"vacuum_defer_cleanup_age": "0",
|
||||
"vacuum_freeze_min_age": "50000000",
|
||||
"vacuum_freeze_table_age": "150000000",
|
||||
"vacuum_multixact_freeze_min_age": "5000000",
|
||||
"vacuum_multixact_freeze_table_age": "150000000",
|
||||
"wal_block_size": "8192",
|
||||
"wal_buffers": "4MB",
|
||||
"wal_compression": "off",
|
||||
"wal_consistency_checking": "",
|
||||
"wal_keep_segments": "0",
|
||||
"wal_level": "replica",
|
||||
"wal_log_hints": "off",
|
||||
"wal_receiver_status_interval": "10s",
|
||||
"wal_receiver_timeout": "1min",
|
||||
"wal_retrieve_retry_interval": "5s",
|
||||
"wal_segment_size": "16MB",
|
||||
"wal_sender_timeout": "1min",
|
||||
"wal_sync_method": "open_datasync",
|
||||
"wal_writer_delay": "200ms",
|
||||
"wal_writer_flush_after": "1MB",
|
||||
"work_mem": "4MB",
|
||||
"xmlbinary": "base64",
|
||||
"xmloption": "content",
|
||||
"zero_damaged_pages": "off"
|
||||
}},
|
||||
"local": null
|
||||
}
|
||||
582
client/controller/sample_output/postgres/metrics_after.json
Normal file
582
client/controller/sample_output/postgres/metrics_after.json
Normal file
@@ -0,0 +1,582 @@
|
||||
{
|
||||
"global": {
|
||||
"pg_stat_archiver": {
|
||||
"archived_count": "0",
|
||||
"failed_count": "0",
|
||||
"stats_reset": "2017-11-10 10:59:47.397075-05"
|
||||
},
|
||||
"pg_stat_bgwriter": {
|
||||
"buffers_alloc": "87670",
|
||||
"buffers_backend": "81032",
|
||||
"buffers_backend_fsync": "0",
|
||||
"buffers_checkpoint": "33250",
|
||||
"buffers_clean": "49590",
|
||||
"checkpoint_sync_time": "19",
|
||||
"checkpoint_write_time": "597851",
|
||||
"checkpoints_req": "2",
|
||||
"checkpoints_timed": "1277",
|
||||
"maxwritten_clean": "325",
|
||||
"stats_reset": "2017-11-10 10:59:47.397075-05"
|
||||
}
|
||||
},
|
||||
"local": {
|
||||
"table": {
|
||||
"pg_stat_user_tables": {
|
||||
"history": {
|
||||
"analyze_count": "0",
|
||||
"autoanalyze_count": "1",
|
||||
"autovacuum_count": "0",
|
||||
"last_autoanalyze": "2017-11-20 15:59:02.567618-05",
|
||||
"n_dead_tup": "0",
|
||||
"n_live_tup": "60854",
|
||||
"n_mod_since_analyze": "854",
|
||||
"n_tup_del": "0",
|
||||
"n_tup_hot_upd": "0",
|
||||
"n_tup_ins": "60854",
|
||||
"n_tup_upd": "0",
|
||||
"relid": "16536",
|
||||
"relname": "history",
|
||||
"schemaname": "public",
|
||||
"seq_scan": "2",
|
||||
"seq_tup_read": "0",
|
||||
"vacuum_count": "0"
|
||||
},
|
||||
"warehouse": {
|
||||
"analyze_count": "0",
|
||||
"autoanalyze_count": "2",
|
||||
"autovacuum_count": "2",
|
||||
"idx_scan": "202634",
|
||||
"idx_tup_fetch": "202634",
|
||||
"last_autoanalyze": "2017-11-20 19:23:34.236294-05",
|
||||
"last_autovacuum": "2017-11-20 19:23:34.235793-05",
|
||||
"n_dead_tup": "0",
|
||||
"n_live_tup": "2",
|
||||
"n_mod_since_analyze": "0",
|
||||
"n_tup_del": "0",
|
||||
"n_tup_hot_upd": "854",
|
||||
"n_tup_ins": "2",
|
||||
"n_tup_upd": "854",
|
||||
"relid": "16559",
|
||||
"relname": "warehouse",
|
||||
"schemaname": "public",
|
||||
"seq_scan": "1",
|
||||
"seq_tup_read": "0",
|
||||
"vacuum_count": "0"
|
||||
},
|
||||
"stock": {
|
||||
"analyze_count": "0",
|
||||
"autoanalyze_count": "1",
|
||||
"autovacuum_count": "0",
|
||||
"idx_scan": "644561",
|
||||
"idx_tup_fetch": "644561",
|
||||
"last_autoanalyze": "2017-11-20 15:59:01.368483-05",
|
||||
"n_dead_tup": "4364",
|
||||
"n_live_tup": "200000",
|
||||
"n_mod_since_analyze": "8901",
|
||||
"n_tup_del": "0",
|
||||
"n_tup_hot_upd": "5305",
|
||||
"n_tup_ins": "200000",
|
||||
"n_tup_upd": "8901",
|
||||
"relid": "16523",
|
||||
"relname": "stock",
|
||||
"schemaname": "public",
|
||||
"seq_scan": "3",
|
||||
"seq_tup_read": "0",
|
||||
"vacuum_count": "0"
|
||||
},
|
||||
"customer": {
|
||||
"analyze_count": "0",
|
||||
"autoanalyze_count": "1",
|
||||
"autovacuum_count": "0",
|
||||
"idx_scan": "125261",
|
||||
"idx_tup_fetch": "85299628",
|
||||
"last_autoanalyze": "2017-11-20 15:59:18.824212-05",
|
||||
"n_dead_tup": "1510",
|
||||
"n_live_tup": "60000",
|
||||
"n_mod_since_analyze": "1594",
|
||||
"n_tup_del": "0",
|
||||
"n_tup_hot_upd": "262",
|
||||
"n_tup_ins": "60000",
|
||||
"n_tup_upd": "1594",
|
||||
"relid": "16540",
|
||||
"relname": "customer",
|
||||
"schemaname": "public",
|
||||
"seq_scan": "3",
|
||||
"seq_tup_read": "0",
|
||||
"vacuum_count": "0"
|
||||
},
|
||||
"order_line": {
|
||||
"analyze_count": "0",
|
||||
"autoanalyze_count": "1",
|
||||
"autovacuum_count": "0",
|
||||
"idx_scan": "1655",
|
||||
"idx_tup_fetch": "33762",
|
||||
"last_autoanalyze": "2017-11-20 16:00:11.017507-05",
|
||||
"n_dead_tup": "2550",
|
||||
"n_live_tup": "608373",
|
||||
"n_mod_since_analyze": "16230",
|
||||
"n_tup_del": "0",
|
||||
"n_tup_hot_upd": "5393",
|
||||
"n_tup_ins": "608373",
|
||||
"n_tup_upd": "7329",
|
||||
"relid": "16513",
|
||||
"relname": "order_line",
|
||||
"schemaname": "public",
|
||||
"seq_scan": "3",
|
||||
"seq_tup_read": "0",
|
||||
"vacuum_count": "0"
|
||||
},
|
||||
"oorder": {
|
||||
"analyze_count": "0",
|
||||
"autoanalyze_count": "1",
|
||||
"autovacuum_count": "0",
|
||||
"idx_scan": "627652",
|
||||
"idx_tup_fetch": "627652",
|
||||
"last_autoanalyze": "2017-11-20 15:59:54.690984-05",
|
||||
"n_dead_tup": "117",
|
||||
"n_live_tup": "60889",
|
||||
"n_mod_since_analyze": "1629",
|
||||
"n_tup_del": "0",
|
||||
"n_tup_hot_upd": "662",
|
||||
"n_tup_ins": "60900",
|
||||
"n_tup_upd": "740",
|
||||
"relid": "16528",
|
||||
"relname": "oorder",
|
||||
"schemaname": "public",
|
||||
"seq_scan": "4",
|
||||
"seq_tup_read": "0",
|
||||
"vacuum_count": "0"
|
||||
},
|
||||
"new_order": {
|
||||
"analyze_count": "0",
|
||||
"autoanalyze_count": "1",
|
||||
"autovacuum_count": "0",
|
||||
"idx_scan": "1481",
|
||||
"idx_tup_fetch": "1480",
|
||||
"last_autoanalyze": "2017-11-20 16:00:11.217111-05",
|
||||
"n_dead_tup": "751",
|
||||
"n_live_tup": "16964",
|
||||
"n_mod_since_analyze": "1629",
|
||||
"n_tup_del": "740",
|
||||
"n_tup_hot_upd": "0",
|
||||
"n_tup_ins": "17715",
|
||||
"n_tup_upd": "0",
|
||||
"relid": "16518",
|
||||
"relname": "new_order",
|
||||
"schemaname": "public",
|
||||
"seq_scan": "1",
|
||||
"seq_tup_read": "0",
|
||||
"vacuum_count": "0"
|
||||
},
|
||||
"district": {
|
||||
"analyze_count": "0",
|
||||
"autoanalyze_count": "2",
|
||||
"autovacuum_count": "0",
|
||||
"idx_scan": "122234",
|
||||
"idx_tup_fetch": "122234",
|
||||
"last_autoanalyze": "2017-11-20 19:23:34.201509-05",
|
||||
"n_dead_tup": "33",
|
||||
"n_live_tup": "20",
|
||||
"n_mod_since_analyze": "0",
|
||||
"n_tup_del": "0",
|
||||
"n_tup_hot_upd": "1754",
|
||||
"n_tup_ins": "20",
|
||||
"n_tup_upd": "1754",
|
||||
"relid": "16549",
|
||||
"relname": "district",
|
||||
"schemaname": "public",
|
||||
"seq_scan": "2221",
|
||||
"seq_tup_read": "41522",
|
||||
"vacuum_count": "0"
|
||||
},
|
||||
"item": {
|
||||
"analyze_count": "0",
|
||||
"autoanalyze_count": "1",
|
||||
"autovacuum_count": "0",
|
||||
"idx_scan": "209020",
|
||||
"idx_tup_fetch": "209009",
|
||||
"last_autoanalyze": "2017-11-20 15:59:26.613728-05",
|
||||
"n_dead_tup": "0",
|
||||
"n_live_tup": "102000",
|
||||
"n_mod_since_analyze": "2000",
|
||||
"n_tup_del": "0",
|
||||
"n_tup_hot_upd": "0",
|
||||
"n_tup_ins": "100000",
|
||||
"n_tup_upd": "0",
|
||||
"relid": "16554",
|
||||
"relname": "item",
|
||||
"schemaname": "public",
|
||||
"seq_scan": "1",
|
||||
"seq_tup_read": "0",
|
||||
"vacuum_count": "0"
|
||||
}
|
||||
},
|
||||
"pg_statio_user_tables": {
|
||||
"history": {
|
||||
"heap_blks_hit": "184380",
|
||||
"heap_blks_read": "746",
|
||||
"relid": "16536",
|
||||
"relname": "history",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"order_line": {
|
||||
"heap_blks_hit": "1869417",
|
||||
"heap_blks_read": "12419",
|
||||
"idx_blks_hit": "1788651",
|
||||
"idx_blks_read": "3708",
|
||||
"relid": "16513",
|
||||
"relname": "order_line",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"warehouse": {
|
||||
"heap_blks_hit": "404486",
|
||||
"heap_blks_read": "80",
|
||||
"idx_blks_hit": "202643",
|
||||
"idx_blks_read": "6",
|
||||
"relid": "16559",
|
||||
"relname": "warehouse",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"new_order": {
|
||||
"heap_blks_hit": "37856",
|
||||
"heap_blks_read": "192",
|
||||
"idx_blks_hit": "38225",
|
||||
"idx_blks_read": "134",
|
||||
"relid": "16518",
|
||||
"relname": "new_order",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"stock": {
|
||||
"heap_blks_hit": "1920817",
|
||||
"heap_blks_read": "11757",
|
||||
"idx_blks_hit": "2447522",
|
||||
"idx_blks_read": "1530",
|
||||
"relid": "16523",
|
||||
"relname": "stock",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"oorder": {
|
||||
"heap_blks_hit": "1378399",
|
||||
"heap_blks_read": "928",
|
||||
"idx_blks_hit": "3979052",
|
||||
"idx_blks_read": "1881",
|
||||
"relid": "16528",
|
||||
"relname": "oorder",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"district": {
|
||||
"heap_blks_hit": "249754",
|
||||
"heap_blks_read": "3",
|
||||
"idx_blks_hit": "122259",
|
||||
"idx_blks_read": "5",
|
||||
"relid": "16549",
|
||||
"relname": "district",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"item": {
|
||||
"heap_blks_hit": "509702",
|
||||
"heap_blks_read": "4542",
|
||||
"idx_blks_hit": "617914",
|
||||
"idx_blks_read": "877",
|
||||
"relid": "16554",
|
||||
"relname": "item",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"customer": {
|
||||
"heap_blks_hit": "70136669",
|
||||
"heap_blks_read": "13826",
|
||||
"idx_blks_hit": "1411491",
|
||||
"idx_blks_read": "2716",
|
||||
"relid": "16540",
|
||||
"relname": "customer",
|
||||
"schemaname": "public",
|
||||
"tidx_blks_hit": "0",
|
||||
"tidx_blks_read": "0",
|
||||
"toast_blks_hit": "0",
|
||||
"toast_blks_read": "0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"database": {
|
||||
"pg_stat_database": {
|
||||
"postgres": {
|
||||
"blk_read_time": "0",
|
||||
"blk_write_time": "0",
|
||||
"blks_hit": "115229324",
|
||||
"blks_read": "104188",
|
||||
"conflicts": "0",
|
||||
"datid": "12558",
|
||||
"datname": "postgres",
|
||||
"deadlocks": "0",
|
||||
"numbackends": "1",
|
||||
"stats_reset": "2017-11-10 11:14:57.116228-05",
|
||||
"temp_bytes": "0",
|
||||
"temp_files": "0",
|
||||
"tup_deleted": "1818",
|
||||
"tup_fetched": "103355344",
|
||||
"tup_inserted": "2210752",
|
||||
"tup_returned": "110741743",
|
||||
"tup_updated": "32675",
|
||||
"xact_commit": "19082",
|
||||
"xact_rollback": "17"
|
||||
},
|
||||
"tpcc": {
|
||||
"blk_read_time": "0",
|
||||
"blk_write_time": "0",
|
||||
"blks_hit": "0",
|
||||
"blks_read": "0",
|
||||
"conflicts": "0",
|
||||
"datid": "16384",
|
||||
"datname": "tpcc",
|
||||
"deadlocks": "0",
|
||||
"numbackends": "0",
|
||||
"temp_bytes": "0",
|
||||
"temp_files": "0",
|
||||
"tup_deleted": "0",
|
||||
"tup_fetched": "0",
|
||||
"tup_inserted": "0",
|
||||
"tup_returned": "0",
|
||||
"tup_updated": "0",
|
||||
"xact_commit": "0",
|
||||
"xact_rollback": "0"
|
||||
},
|
||||
"template1": {
|
||||
"blk_read_time": "0",
|
||||
"blk_write_time": "0",
|
||||
"blks_hit": "0",
|
||||
"blks_read": "0",
|
||||
"conflicts": "0",
|
||||
"datid": "1",
|
||||
"datname": "template1",
|
||||
"deadlocks": "0",
|
||||
"numbackends": "0",
|
||||
"temp_bytes": "0",
|
||||
"temp_files": "0",
|
||||
"tup_deleted": "0",
|
||||
"tup_fetched": "0",
|
||||
"tup_inserted": "0",
|
||||
"tup_returned": "0",
|
||||
"tup_updated": "0",
|
||||
"xact_commit": "0",
|
||||
"xact_rollback": "0"
|
||||
},
|
||||
"template0": {
|
||||
"blk_read_time": "0",
|
||||
"blk_write_time": "0",
|
||||
"blks_hit": "0",
|
||||
"blks_read": "0",
|
||||
"conflicts": "0",
|
||||
"datid": "12557",
|
||||
"datname": "template0",
|
||||
"deadlocks": "0",
|
||||
"numbackends": "0",
|
||||
"temp_bytes": "0",
|
||||
"temp_files": "0",
|
||||
"tup_deleted": "0",
|
||||
"tup_fetched": "0",
|
||||
"tup_inserted": "0",
|
||||
"tup_returned": "0",
|
||||
"tup_updated": "0",
|
||||
"xact_commit": "0",
|
||||
"xact_rollback": "0"
|
||||
}
|
||||
},
|
||||
"pg_stat_database_conflicts": {
|
||||
"postgres": {
|
||||
"confl_bufferpin": "0",
|
||||
"confl_deadlock": "0",
|
||||
"confl_lock": "0",
|
||||
"confl_snapshot": "0",
|
||||
"confl_tablespace": "0",
|
||||
"datid": "12558",
|
||||
"datname": "postgres"
|
||||
},
|
||||
"tpcc": {
|
||||
"confl_bufferpin": "0",
|
||||
"confl_deadlock": "0",
|
||||
"confl_lock": "0",
|
||||
"confl_snapshot": "0",
|
||||
"confl_tablespace": "0",
|
||||
"datid": "16384",
|
||||
"datname": "tpcc"
|
||||
},
|
||||
"template1": {
|
||||
"confl_bufferpin": "0",
|
||||
"confl_deadlock": "0",
|
||||
"confl_lock": "0",
|
||||
"confl_snapshot": "0",
|
||||
"confl_tablespace": "0",
|
||||
"datid": "1",
|
||||
"datname": "template1"
|
||||
},
|
||||
"template0": {
|
||||
"confl_bufferpin": "0",
|
||||
"confl_deadlock": "0",
|
||||
"confl_lock": "0",
|
||||
"confl_snapshot": "0",
|
||||
"confl_tablespace": "0",
|
||||
"datid": "12557",
|
||||
"datname": "template0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"pg_stat_user_indexes": {
|
||||
"order_line": {
|
||||
"idx_scan": "1655",
|
||||
"idx_tup_fetch": "33762",
|
||||
"idx_tup_read": "35698",
|
||||
"indexrelid": "16516",
|
||||
"indexrelname": "order_line_pkey",
|
||||
"relid": "16513",
|
||||
"relname": "order_line",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"new_order": {
|
||||
"idx_scan": "1481",
|
||||
"idx_tup_fetch": "1480",
|
||||
"idx_tup_read": "2200",
|
||||
"indexrelid": "16521",
|
||||
"indexrelname": "new_order_pkey",
|
||||
"relid": "16518",
|
||||
"relname": "new_order",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"stock": {
|
||||
"idx_scan": "644561",
|
||||
"idx_tup_fetch": "644561",
|
||||
"idx_tup_read": "647319",
|
||||
"indexrelid": "16526",
|
||||
"indexrelname": "stock_pkey",
|
||||
"relid": "16523",
|
||||
"relname": "stock",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"oorder": {
|
||||
"idx_scan": "616371",
|
||||
"idx_tup_fetch": "616371",
|
||||
"idx_tup_read": "616371",
|
||||
"indexrelid": "16565",
|
||||
"indexrelname": "idx_order",
|
||||
"relid": "16528",
|
||||
"relname": "oorder",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"customer": {
|
||||
"idx_scan": "82442",
|
||||
"idx_tup_fetch": "85256809",
|
||||
"idx_tup_read": "85256841",
|
||||
"indexrelid": "16564",
|
||||
"indexrelname": "idx_customer_name",
|
||||
"relid": "16540",
|
||||
"relname": "customer",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"district": {
|
||||
"idx_scan": "122234",
|
||||
"idx_tup_fetch": "122234",
|
||||
"idx_tup_read": "122234",
|
||||
"indexrelid": "16552",
|
||||
"indexrelname": "district_pkey",
|
||||
"relid": "16549",
|
||||
"relname": "district",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"item": {
|
||||
"idx_scan": "209020",
|
||||
"idx_tup_fetch": "209009",
|
||||
"idx_tup_read": "209009",
|
||||
"indexrelid": "16557",
|
||||
"indexrelname": "item_pkey",
|
||||
"relid": "16554",
|
||||
"relname": "item",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"warehouse": {
|
||||
"idx_scan": "202634",
|
||||
"idx_tup_fetch": "201331",
|
||||
"idx_tup_read": "202634",
|
||||
"indexrelid": "16562",
|
||||
"indexrelname": "warehouse_pkey",
|
||||
"relid": "16559",
|
||||
"relname": "warehouse",
|
||||
"schemaname": "public"
|
||||
}
|
||||
},
|
||||
"pg_statio_user_indexes": {
|
||||
"order_line": {
|
||||
"idx_blks_hit": "1788651",
|
||||
"idx_blks_read": "3708",
|
||||
"indexrelid": "16516",
|
||||
"indexrelname": "order_line_pkey",
|
||||
"relid": "16513",
|
||||
"relname": "order_line",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"new_order": {
|
||||
"idx_blks_hit": "38225",
|
||||
"idx_blks_read": "134",
|
||||
"indexrelid": "16521",
|
||||
"indexrelname": "new_order_pkey",
|
||||
"relid": "16518",
|
||||
"relname": "new_order",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"stock": {
|
||||
"idx_blks_hit": "2447522",
|
||||
"idx_blks_read": "1530",
|
||||
"indexrelid": "16526",
|
||||
"indexrelname": "stock_pkey",
|
||||
"relid": "16523",
|
||||
"relname": "stock",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"oorder": {
|
||||
"idx_blks_hit": "3689479",
|
||||
"idx_blks_read": "733",
|
||||
"indexrelid": "16565",
|
||||
"indexrelname": "idx_order",
|
||||
"relid": "16528",
|
||||
"relname": "oorder",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"customer": {
|
||||
"idx_blks_hit": "1151523",
|
||||
"idx_blks_read": "1589",
|
||||
"indexrelid": "16564",
|
||||
"indexrelname": "idx_customer_name",
|
||||
"relid": "16540",
|
||||
"relname": "customer",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"district": {
|
||||
"idx_blks_hit": "122259",
|
||||
"idx_blks_read": "5",
|
||||
"indexrelid": "16552",
|
||||
"indexrelname": "district_pkey",
|
||||
"relid": "16549",
|
||||
"relname": "district",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"item": {
|
||||
"idx_blks_hit": "617914",
|
||||
"idx_blks_read": "877",
|
||||
"indexrelid": "16557",
|
||||
"indexrelname": "item_pkey",
|
||||
"relid": "16554",
|
||||
"relname": "item",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"warehouse": {
|
||||
"idx_blks_hit": "202643",
|
||||
"idx_blks_read": "6",
|
||||
"indexrelid": "16562",
|
||||
"indexrelname": "warehouse_pkey",
|
||||
"relid": "16559",
|
||||
"relname": "warehouse",
|
||||
"schemaname": "public"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
582
client/controller/sample_output/postgres/metrics_before.json
Normal file
582
client/controller/sample_output/postgres/metrics_before.json
Normal file
@@ -0,0 +1,582 @@
|
||||
{
|
||||
"global": {
|
||||
"pg_stat_archiver": {
|
||||
"archived_count": "0",
|
||||
"failed_count": "0",
|
||||
"stats_reset": "2017-11-10 10:59:47.397075-05"
|
||||
},
|
||||
"pg_stat_bgwriter": {
|
||||
"buffers_alloc": "87670",
|
||||
"buffers_backend": "81032",
|
||||
"buffers_backend_fsync": "0",
|
||||
"buffers_checkpoint": "33250",
|
||||
"buffers_clean": "49590",
|
||||
"checkpoint_sync_time": "19",
|
||||
"checkpoint_write_time": "597851",
|
||||
"checkpoints_req": "2",
|
||||
"checkpoints_timed": "1277",
|
||||
"maxwritten_clean": "325",
|
||||
"stats_reset": "2017-11-10 10:59:47.397075-05"
|
||||
}
|
||||
},
|
||||
"local": {
|
||||
"table": {
|
||||
"pg_stat_user_tables": {
|
||||
"history": {
|
||||
"analyze_count": "0",
|
||||
"autoanalyze_count": "1",
|
||||
"autovacuum_count": "0",
|
||||
"last_autoanalyze": "2017-11-20 15:59:02.567618-05",
|
||||
"n_dead_tup": "0",
|
||||
"n_live_tup": "60854",
|
||||
"n_mod_since_analyze": "854",
|
||||
"n_tup_del": "0",
|
||||
"n_tup_hot_upd": "0",
|
||||
"n_tup_ins": "60854",
|
||||
"n_tup_upd": "0",
|
||||
"relid": "16536",
|
||||
"relname": "history",
|
||||
"schemaname": "public",
|
||||
"seq_scan": "2",
|
||||
"seq_tup_read": "0",
|
||||
"vacuum_count": "0"
|
||||
},
|
||||
"warehouse": {
|
||||
"analyze_count": "0",
|
||||
"autoanalyze_count": "2",
|
||||
"autovacuum_count": "2",
|
||||
"idx_scan": "202634",
|
||||
"idx_tup_fetch": "202634",
|
||||
"last_autoanalyze": "2017-11-20 19:23:34.236294-05",
|
||||
"last_autovacuum": "2017-11-20 19:23:34.235793-05",
|
||||
"n_dead_tup": "0",
|
||||
"n_live_tup": "2",
|
||||
"n_mod_since_analyze": "0",
|
||||
"n_tup_del": "0",
|
||||
"n_tup_hot_upd": "854",
|
||||
"n_tup_ins": "2",
|
||||
"n_tup_upd": "854",
|
||||
"relid": "16559",
|
||||
"relname": "warehouse",
|
||||
"schemaname": "public",
|
||||
"seq_scan": "1",
|
||||
"seq_tup_read": "0",
|
||||
"vacuum_count": "0"
|
||||
},
|
||||
"stock": {
|
||||
"analyze_count": "0",
|
||||
"autoanalyze_count": "1",
|
||||
"autovacuum_count": "0",
|
||||
"idx_scan": "644561",
|
||||
"idx_tup_fetch": "644561",
|
||||
"last_autoanalyze": "2017-11-20 15:59:01.368483-05",
|
||||
"n_dead_tup": "4364",
|
||||
"n_live_tup": "200000",
|
||||
"n_mod_since_analyze": "8901",
|
||||
"n_tup_del": "0",
|
||||
"n_tup_hot_upd": "5305",
|
||||
"n_tup_ins": "200000",
|
||||
"n_tup_upd": "8901",
|
||||
"relid": "16523",
|
||||
"relname": "stock",
|
||||
"schemaname": "public",
|
||||
"seq_scan": "3",
|
||||
"seq_tup_read": "0",
|
||||
"vacuum_count": "0"
|
||||
},
|
||||
"customer": {
|
||||
"analyze_count": "0",
|
||||
"autoanalyze_count": "1",
|
||||
"autovacuum_count": "0",
|
||||
"idx_scan": "125261",
|
||||
"idx_tup_fetch": "85299628",
|
||||
"last_autoanalyze": "2017-11-20 15:59:18.824212-05",
|
||||
"n_dead_tup": "1510",
|
||||
"n_live_tup": "60000",
|
||||
"n_mod_since_analyze": "1594",
|
||||
"n_tup_del": "0",
|
||||
"n_tup_hot_upd": "262",
|
||||
"n_tup_ins": "60000",
|
||||
"n_tup_upd": "1594",
|
||||
"relid": "16540",
|
||||
"relname": "customer",
|
||||
"schemaname": "public",
|
||||
"seq_scan": "3",
|
||||
"seq_tup_read": "0",
|
||||
"vacuum_count": "0"
|
||||
},
|
||||
"order_line": {
|
||||
"analyze_count": "0",
|
||||
"autoanalyze_count": "1",
|
||||
"autovacuum_count": "0",
|
||||
"idx_scan": "1655",
|
||||
"idx_tup_fetch": "33762",
|
||||
"last_autoanalyze": "2017-11-20 16:00:11.017507-05",
|
||||
"n_dead_tup": "2550",
|
||||
"n_live_tup": "608373",
|
||||
"n_mod_since_analyze": "16230",
|
||||
"n_tup_del": "0",
|
||||
"n_tup_hot_upd": "5393",
|
||||
"n_tup_ins": "608373",
|
||||
"n_tup_upd": "7329",
|
||||
"relid": "16513",
|
||||
"relname": "order_line",
|
||||
"schemaname": "public",
|
||||
"seq_scan": "3",
|
||||
"seq_tup_read": "0",
|
||||
"vacuum_count": "0"
|
||||
},
|
||||
"oorder": {
|
||||
"analyze_count": "0",
|
||||
"autoanalyze_count": "1",
|
||||
"autovacuum_count": "0",
|
||||
"idx_scan": "627652",
|
||||
"idx_tup_fetch": "627652",
|
||||
"last_autoanalyze": "2017-11-20 15:59:54.690984-05",
|
||||
"n_dead_tup": "117",
|
||||
"n_live_tup": "60889",
|
||||
"n_mod_since_analyze": "1629",
|
||||
"n_tup_del": "0",
|
||||
"n_tup_hot_upd": "662",
|
||||
"n_tup_ins": "60900",
|
||||
"n_tup_upd": "740",
|
||||
"relid": "16528",
|
||||
"relname": "oorder",
|
||||
"schemaname": "public",
|
||||
"seq_scan": "4",
|
||||
"seq_tup_read": "0",
|
||||
"vacuum_count": "0"
|
||||
},
|
||||
"new_order": {
|
||||
"analyze_count": "0",
|
||||
"autoanalyze_count": "1",
|
||||
"autovacuum_count": "0",
|
||||
"idx_scan": "1481",
|
||||
"idx_tup_fetch": "1480",
|
||||
"last_autoanalyze": "2017-11-20 16:00:11.217111-05",
|
||||
"n_dead_tup": "751",
|
||||
"n_live_tup": "16964",
|
||||
"n_mod_since_analyze": "1629",
|
||||
"n_tup_del": "740",
|
||||
"n_tup_hot_upd": "0",
|
||||
"n_tup_ins": "17715",
|
||||
"n_tup_upd": "0",
|
||||
"relid": "16518",
|
||||
"relname": "new_order",
|
||||
"schemaname": "public",
|
||||
"seq_scan": "1",
|
||||
"seq_tup_read": "0",
|
||||
"vacuum_count": "0"
|
||||
},
|
||||
"district": {
|
||||
"analyze_count": "0",
|
||||
"autoanalyze_count": "2",
|
||||
"autovacuum_count": "0",
|
||||
"idx_scan": "122234",
|
||||
"idx_tup_fetch": "122234",
|
||||
"last_autoanalyze": "2017-11-20 19:23:34.201509-05",
|
||||
"n_dead_tup": "33",
|
||||
"n_live_tup": "20",
|
||||
"n_mod_since_analyze": "0",
|
||||
"n_tup_del": "0",
|
||||
"n_tup_hot_upd": "1754",
|
||||
"n_tup_ins": "20",
|
||||
"n_tup_upd": "1754",
|
||||
"relid": "16549",
|
||||
"relname": "district",
|
||||
"schemaname": "public",
|
||||
"seq_scan": "2221",
|
||||
"seq_tup_read": "41522",
|
||||
"vacuum_count": "0"
|
||||
},
|
||||
"item": {
|
||||
"analyze_count": "0",
|
||||
"autoanalyze_count": "1",
|
||||
"autovacuum_count": "0",
|
||||
"idx_scan": "209020",
|
||||
"idx_tup_fetch": "209009",
|
||||
"last_autoanalyze": "2017-11-20 15:59:26.613728-05",
|
||||
"n_dead_tup": "0",
|
||||
"n_live_tup": "102000",
|
||||
"n_mod_since_analyze": "2000",
|
||||
"n_tup_del": "0",
|
||||
"n_tup_hot_upd": "0",
|
||||
"n_tup_ins": "100000",
|
||||
"n_tup_upd": "0",
|
||||
"relid": "16554",
|
||||
"relname": "item",
|
||||
"schemaname": "public",
|
||||
"seq_scan": "1",
|
||||
"seq_tup_read": "0",
|
||||
"vacuum_count": "0"
|
||||
}
|
||||
},
|
||||
"pg_statio_user_tables": {
|
||||
"history": {
|
||||
"heap_blks_hit": "184380",
|
||||
"heap_blks_read": "746",
|
||||
"relid": "16536",
|
||||
"relname": "history",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"order_line": {
|
||||
"heap_blks_hit": "1869417",
|
||||
"heap_blks_read": "12419",
|
||||
"idx_blks_hit": "1788651",
|
||||
"idx_blks_read": "3708",
|
||||
"relid": "16513",
|
||||
"relname": "order_line",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"warehouse": {
|
||||
"heap_blks_hit": "404486",
|
||||
"heap_blks_read": "80",
|
||||
"idx_blks_hit": "202643",
|
||||
"idx_blks_read": "6",
|
||||
"relid": "16559",
|
||||
"relname": "warehouse",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"new_order": {
|
||||
"heap_blks_hit": "37856",
|
||||
"heap_blks_read": "192",
|
||||
"idx_blks_hit": "38225",
|
||||
"idx_blks_read": "134",
|
||||
"relid": "16518",
|
||||
"relname": "new_order",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"stock": {
|
||||
"heap_blks_hit": "1920817",
|
||||
"heap_blks_read": "11757",
|
||||
"idx_blks_hit": "2447522",
|
||||
"idx_blks_read": "1530",
|
||||
"relid": "16523",
|
||||
"relname": "stock",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"oorder": {
|
||||
"heap_blks_hit": "1378399",
|
||||
"heap_blks_read": "928",
|
||||
"idx_blks_hit": "3979052",
|
||||
"idx_blks_read": "1881",
|
||||
"relid": "16528",
|
||||
"relname": "oorder",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"district": {
|
||||
"heap_blks_hit": "249754",
|
||||
"heap_blks_read": "3",
|
||||
"idx_blks_hit": "122259",
|
||||
"idx_blks_read": "5",
|
||||
"relid": "16549",
|
||||
"relname": "district",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"item": {
|
||||
"heap_blks_hit": "509702",
|
||||
"heap_blks_read": "4542",
|
||||
"idx_blks_hit": "617914",
|
||||
"idx_blks_read": "877",
|
||||
"relid": "16554",
|
||||
"relname": "item",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"customer": {
|
||||
"heap_blks_hit": "70136669",
|
||||
"heap_blks_read": "13826",
|
||||
"idx_blks_hit": "1411491",
|
||||
"idx_blks_read": "2716",
|
||||
"relid": "16540",
|
||||
"relname": "customer",
|
||||
"schemaname": "public",
|
||||
"tidx_blks_hit": "0",
|
||||
"tidx_blks_read": "0",
|
||||
"toast_blks_hit": "0",
|
||||
"toast_blks_read": "0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"database": {
|
||||
"pg_stat_database": {
|
||||
"postgres": {
|
||||
"blk_read_time": "0",
|
||||
"blk_write_time": "0",
|
||||
"blks_hit": "115229324",
|
||||
"blks_read": "104188",
|
||||
"conflicts": "0",
|
||||
"datid": "12558",
|
||||
"datname": "postgres",
|
||||
"deadlocks": "0",
|
||||
"numbackends": "1",
|
||||
"stats_reset": "2017-11-10 11:14:57.116228-05",
|
||||
"temp_bytes": "0",
|
||||
"temp_files": "0",
|
||||
"tup_deleted": "1818",
|
||||
"tup_fetched": "103355344",
|
||||
"tup_inserted": "2210752",
|
||||
"tup_returned": "110741743",
|
||||
"tup_updated": "32675",
|
||||
"xact_commit": "19082",
|
||||
"xact_rollback": "17"
|
||||
},
|
||||
"tpcc": {
|
||||
"blk_read_time": "0",
|
||||
"blk_write_time": "0",
|
||||
"blks_hit": "0",
|
||||
"blks_read": "0",
|
||||
"conflicts": "0",
|
||||
"datid": "16384",
|
||||
"datname": "tpcc",
|
||||
"deadlocks": "0",
|
||||
"numbackends": "0",
|
||||
"temp_bytes": "0",
|
||||
"temp_files": "0",
|
||||
"tup_deleted": "0",
|
||||
"tup_fetched": "0",
|
||||
"tup_inserted": "0",
|
||||
"tup_returned": "0",
|
||||
"tup_updated": "0",
|
||||
"xact_commit": "0",
|
||||
"xact_rollback": "0"
|
||||
},
|
||||
"template1": {
|
||||
"blk_read_time": "0",
|
||||
"blk_write_time": "0",
|
||||
"blks_hit": "0",
|
||||
"blks_read": "0",
|
||||
"conflicts": "0",
|
||||
"datid": "1",
|
||||
"datname": "template1",
|
||||
"deadlocks": "0",
|
||||
"numbackends": "0",
|
||||
"temp_bytes": "0",
|
||||
"temp_files": "0",
|
||||
"tup_deleted": "0",
|
||||
"tup_fetched": "0",
|
||||
"tup_inserted": "0",
|
||||
"tup_returned": "0",
|
||||
"tup_updated": "0",
|
||||
"xact_commit": "0",
|
||||
"xact_rollback": "0"
|
||||
},
|
||||
"template0": {
|
||||
"blk_read_time": "0",
|
||||
"blk_write_time": "0",
|
||||
"blks_hit": "0",
|
||||
"blks_read": "0",
|
||||
"conflicts": "0",
|
||||
"datid": "12557",
|
||||
"datname": "template0",
|
||||
"deadlocks": "0",
|
||||
"numbackends": "0",
|
||||
"temp_bytes": "0",
|
||||
"temp_files": "0",
|
||||
"tup_deleted": "0",
|
||||
"tup_fetched": "0",
|
||||
"tup_inserted": "0",
|
||||
"tup_returned": "0",
|
||||
"tup_updated": "0",
|
||||
"xact_commit": "0",
|
||||
"xact_rollback": "0"
|
||||
}
|
||||
},
|
||||
"pg_stat_database_conflicts": {
|
||||
"postgres": {
|
||||
"confl_bufferpin": "0",
|
||||
"confl_deadlock": "0",
|
||||
"confl_lock": "0",
|
||||
"confl_snapshot": "0",
|
||||
"confl_tablespace": "0",
|
||||
"datid": "12558",
|
||||
"datname": "postgres"
|
||||
},
|
||||
"tpcc": {
|
||||
"confl_bufferpin": "0",
|
||||
"confl_deadlock": "0",
|
||||
"confl_lock": "0",
|
||||
"confl_snapshot": "0",
|
||||
"confl_tablespace": "0",
|
||||
"datid": "16384",
|
||||
"datname": "tpcc"
|
||||
},
|
||||
"template1": {
|
||||
"confl_bufferpin": "0",
|
||||
"confl_deadlock": "0",
|
||||
"confl_lock": "0",
|
||||
"confl_snapshot": "0",
|
||||
"confl_tablespace": "0",
|
||||
"datid": "1",
|
||||
"datname": "template1"
|
||||
},
|
||||
"template0": {
|
||||
"confl_bufferpin": "0",
|
||||
"confl_deadlock": "0",
|
||||
"confl_lock": "0",
|
||||
"confl_snapshot": "0",
|
||||
"confl_tablespace": "0",
|
||||
"datid": "12557",
|
||||
"datname": "template0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"pg_stat_user_indexes": {
|
||||
"order_line": {
|
||||
"idx_scan": "1655",
|
||||
"idx_tup_fetch": "33762",
|
||||
"idx_tup_read": "35698",
|
||||
"indexrelid": "16516",
|
||||
"indexrelname": "order_line_pkey",
|
||||
"relid": "16513",
|
||||
"relname": "order_line",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"new_order": {
|
||||
"idx_scan": "1481",
|
||||
"idx_tup_fetch": "1480",
|
||||
"idx_tup_read": "2200",
|
||||
"indexrelid": "16521",
|
||||
"indexrelname": "new_order_pkey",
|
||||
"relid": "16518",
|
||||
"relname": "new_order",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"stock": {
|
||||
"idx_scan": "644561",
|
||||
"idx_tup_fetch": "644561",
|
||||
"idx_tup_read": "647319",
|
||||
"indexrelid": "16526",
|
||||
"indexrelname": "stock_pkey",
|
||||
"relid": "16523",
|
||||
"relname": "stock",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"oorder": {
|
||||
"idx_scan": "616371",
|
||||
"idx_tup_fetch": "616371",
|
||||
"idx_tup_read": "616371",
|
||||
"indexrelid": "16565",
|
||||
"indexrelname": "idx_order",
|
||||
"relid": "16528",
|
||||
"relname": "oorder",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"customer": {
|
||||
"idx_scan": "82442",
|
||||
"idx_tup_fetch": "85256809",
|
||||
"idx_tup_read": "85256841",
|
||||
"indexrelid": "16564",
|
||||
"indexrelname": "idx_customer_name",
|
||||
"relid": "16540",
|
||||
"relname": "customer",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"district": {
|
||||
"idx_scan": "122234",
|
||||
"idx_tup_fetch": "122234",
|
||||
"idx_tup_read": "122234",
|
||||
"indexrelid": "16552",
|
||||
"indexrelname": "district_pkey",
|
||||
"relid": "16549",
|
||||
"relname": "district",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"item": {
|
||||
"idx_scan": "209020",
|
||||
"idx_tup_fetch": "209009",
|
||||
"idx_tup_read": "209009",
|
||||
"indexrelid": "16557",
|
||||
"indexrelname": "item_pkey",
|
||||
"relid": "16554",
|
||||
"relname": "item",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"warehouse": {
|
||||
"idx_scan": "202634",
|
||||
"idx_tup_fetch": "201331",
|
||||
"idx_tup_read": "202634",
|
||||
"indexrelid": "16562",
|
||||
"indexrelname": "warehouse_pkey",
|
||||
"relid": "16559",
|
||||
"relname": "warehouse",
|
||||
"schemaname": "public"
|
||||
}
|
||||
},
|
||||
"pg_statio_user_indexes": {
|
||||
"order_line": {
|
||||
"idx_blks_hit": "1788651",
|
||||
"idx_blks_read": "3708",
|
||||
"indexrelid": "16516",
|
||||
"indexrelname": "order_line_pkey",
|
||||
"relid": "16513",
|
||||
"relname": "order_line",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"new_order": {
|
||||
"idx_blks_hit": "38225",
|
||||
"idx_blks_read": "134",
|
||||
"indexrelid": "16521",
|
||||
"indexrelname": "new_order_pkey",
|
||||
"relid": "16518",
|
||||
"relname": "new_order",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"stock": {
|
||||
"idx_blks_hit": "2447522",
|
||||
"idx_blks_read": "1530",
|
||||
"indexrelid": "16526",
|
||||
"indexrelname": "stock_pkey",
|
||||
"relid": "16523",
|
||||
"relname": "stock",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"oorder": {
|
||||
"idx_blks_hit": "3689479",
|
||||
"idx_blks_read": "733",
|
||||
"indexrelid": "16565",
|
||||
"indexrelname": "idx_order",
|
||||
"relid": "16528",
|
||||
"relname": "oorder",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"customer": {
|
||||
"idx_blks_hit": "1151523",
|
||||
"idx_blks_read": "1589",
|
||||
"indexrelid": "16564",
|
||||
"indexrelname": "idx_customer_name",
|
||||
"relid": "16540",
|
||||
"relname": "customer",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"district": {
|
||||
"idx_blks_hit": "122259",
|
||||
"idx_blks_read": "5",
|
||||
"indexrelid": "16552",
|
||||
"indexrelname": "district_pkey",
|
||||
"relid": "16549",
|
||||
"relname": "district",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"item": {
|
||||
"idx_blks_hit": "617914",
|
||||
"idx_blks_read": "877",
|
||||
"indexrelid": "16557",
|
||||
"indexrelname": "item_pkey",
|
||||
"relid": "16554",
|
||||
"relname": "item",
|
||||
"schemaname": "public"
|
||||
},
|
||||
"warehouse": {
|
||||
"idx_blks_hit": "202643",
|
||||
"idx_blks_read": "6",
|
||||
"indexrelid": "16562",
|
||||
"indexrelname": "warehouse_pkey",
|
||||
"relid": "16559",
|
||||
"relname": "warehouse",
|
||||
"schemaname": "public"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
client/controller/sample_output/postgres/summary.json
Normal file
8
client/controller/sample_output/postgres/summary.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"start_time": 1535653369274,
|
||||
"end_time": 1535653559607,
|
||||
"observation_time": 190,
|
||||
"database_type": "postgres",
|
||||
"database_version": "9.3",
|
||||
"workload_name": "workload_name"
|
||||
}
|
||||
9440
client/controller/sample_output/saphana/knobs.json
Normal file
9440
client/controller/sample_output/saphana/knobs.json
Normal file
File diff suppressed because it is too large
Load Diff
8919
client/controller/sample_output/saphana/metrics_after.json
Normal file
8919
client/controller/sample_output/saphana/metrics_after.json
Normal file
File diff suppressed because it is too large
Load Diff
8919
client/controller/sample_output/saphana/metrics_before.json
Normal file
8919
client/controller/sample_output/saphana/metrics_before.json
Normal file
File diff suppressed because it is too large
Load Diff
8
client/controller/sample_output/saphana/summary.json
Normal file
8
client/controller/sample_output/saphana/summary.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"start_time": 1535653369274,
|
||||
"end_time": 1535653559607,
|
||||
"observation_time": 190,
|
||||
"database_type": "saphana",
|
||||
"database_version": "2.00.023.00.1513691289",
|
||||
"workload_name": "workload_name"
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* OtterTune - ControllerConfiguration.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller;
|
||||
|
||||
/** Controller Configuration. */
|
||||
public class ControllerConfiguration {
|
||||
private DatabaseType dbType;
|
||||
private String dbName;
|
||||
private String dbUsername;
|
||||
private String dbPassword;
|
||||
private String dbURL;
|
||||
private String uploadCode;
|
||||
private String uploadURL;
|
||||
private String workloadName;
|
||||
|
||||
public ControllerConfiguration() {}
|
||||
|
||||
public ControllerConfiguration(
|
||||
String dbName,
|
||||
String dbUsername,
|
||||
String dbPassword,
|
||||
String dbURL,
|
||||
String uploadCode,
|
||||
String uploadURL,
|
||||
String workloadName) {
|
||||
this.dbType = DatabaseType.get(dbName);
|
||||
this.dbName = dbName;
|
||||
this.dbUsername = dbUsername;
|
||||
this.dbPassword = dbPassword;
|
||||
this.dbURL = dbURL;
|
||||
this.uploadCode = uploadCode;
|
||||
this.uploadURL = uploadURL;
|
||||
this.workloadName = workloadName;
|
||||
}
|
||||
|
||||
/* Mutators */
|
||||
public void setDBType(DatabaseType dbType) {
|
||||
this.dbType = dbType;
|
||||
}
|
||||
|
||||
public void setDBName(String dbName) {
|
||||
this.dbName = dbName;
|
||||
}
|
||||
|
||||
public void setDBUsername(String dbUsername) {
|
||||
this.dbUsername = dbUsername;
|
||||
}
|
||||
|
||||
public void setPassword(String dbPassword) {
|
||||
this.dbPassword = dbPassword;
|
||||
}
|
||||
|
||||
public void setDBURL(String dbURL) {
|
||||
this.dbURL = dbURL;
|
||||
}
|
||||
|
||||
public void setUploadCode(String uploadCode) {
|
||||
this.uploadCode = uploadCode;
|
||||
}
|
||||
|
||||
public void setUploadURL(String uploadURL) {
|
||||
this.uploadURL = uploadURL;
|
||||
}
|
||||
|
||||
public void setWorkloadName(String workloadName) {
|
||||
this.workloadName = workloadName;
|
||||
}
|
||||
|
||||
/* Getters */
|
||||
public DatabaseType getDBType() {
|
||||
return this.dbType;
|
||||
}
|
||||
|
||||
public String getDBName() {
|
||||
return this.dbName;
|
||||
}
|
||||
|
||||
public String getDBUsername() {
|
||||
return this.dbUsername;
|
||||
}
|
||||
|
||||
public String getDBPassword() {
|
||||
return this.dbPassword;
|
||||
}
|
||||
|
||||
public String getDBURL() {
|
||||
return this.dbURL;
|
||||
}
|
||||
|
||||
public String getUploadCode() {
|
||||
return this.uploadCode;
|
||||
}
|
||||
|
||||
public String getUploadURL() {
|
||||
return this.uploadURL;
|
||||
}
|
||||
|
||||
public String getWorkloadName() {
|
||||
return this.workloadName;
|
||||
}
|
||||
}
|
||||
296
client/controller/src/main/java/com/controller/Main.java
Normal file
296
client/controller/src/main/java/com/controller/Main.java
Normal file
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* OtterTune - Main.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller;
|
||||
|
||||
import com.controller.collectors.DBCollector;
|
||||
import com.controller.collectors.MySQLCollector;
|
||||
import com.controller.collectors.OracleCollector;
|
||||
import com.controller.collectors.PostgresCollector;
|
||||
import com.controller.collectors.SAPHanaCollector;
|
||||
import com.controller.types.JSONSchemaType;
|
||||
import com.controller.util.FileUtil;
|
||||
import com.controller.util.JSONUtil;
|
||||
import com.controller.util.json.JSONException;
|
||||
import com.controller.util.json.JSONObject;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.CommandLineParser;
|
||||
import org.apache.commons.cli.HelpFormatter;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.cli.PosixParser;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.PropertyConfigurator;
|
||||
import sun.misc.Signal;
|
||||
|
||||
/**
|
||||
* Controller main.
|
||||
*
|
||||
* @author Shuli
|
||||
*/
|
||||
public class Main {
|
||||
static final Logger LOG = Logger.getLogger(Main.class);
|
||||
|
||||
// Default output directory name
|
||||
private static final String DEFAULT_DIRECTORY = "output";
|
||||
|
||||
// Default observation period time (5 minutes)
|
||||
private static final int DEFAULT_TIME_SECONDS = -1;
|
||||
|
||||
// Path to JSON schema directory
|
||||
private static final String SCHEMA_PATH = "src/main/java/com/controller/json_validation_schema";
|
||||
|
||||
private static final int TO_MILLISECONDS = 1000;
|
||||
|
||||
private static boolean keepRunning = true;
|
||||
private static boolean firstCollecting = false;
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
// Initialize log4j
|
||||
PropertyConfigurator.configure("log4j.properties");
|
||||
|
||||
// Initialize keepRunning
|
||||
keepRunning = true;
|
||||
|
||||
// Initialize firstCollecting
|
||||
firstCollecting = false;
|
||||
|
||||
// Create the command line parser
|
||||
CommandLineParser parser = new PosixParser();
|
||||
Options options = new Options();
|
||||
options.addOption("c", "config", true, "[required] Controller configuration file");
|
||||
options.addOption("t", "time", true, "The observation time in seconds, default is 300s");
|
||||
options.addOption(
|
||||
"d", "directory", true, "Base directory for the result files, default is 'output'");
|
||||
options.addOption("h", "help", true, "Print this help");
|
||||
String configFilePath = null;
|
||||
|
||||
// Parse the command line arguments
|
||||
CommandLine argsLine;
|
||||
try {
|
||||
argsLine = parser.parse(options, args);
|
||||
} catch (ParseException e) {
|
||||
LOG.error("Unable to Parse command line arguments");
|
||||
printUsage(options);
|
||||
return;
|
||||
}
|
||||
|
||||
if (argsLine.hasOption("h")) {
|
||||
printUsage(options);
|
||||
return;
|
||||
} else if (argsLine.hasOption("c") == false) {
|
||||
LOG.error("Missing configuration file");
|
||||
printUsage(options);
|
||||
return;
|
||||
}
|
||||
|
||||
int time = DEFAULT_TIME_SECONDS;
|
||||
if (argsLine.hasOption("t")) {
|
||||
time = Integer.parseInt(argsLine.getOptionValue("t"));
|
||||
}
|
||||
LOG.info("Experiment time is set to: " + time);
|
||||
|
||||
String outputDirectory = DEFAULT_DIRECTORY;
|
||||
if (argsLine.hasOption("d")) {
|
||||
outputDirectory = argsLine.getOptionValue("d");
|
||||
}
|
||||
LOG.info("Experiment output directory is set to: " + outputDirectory);
|
||||
FileUtil.makeDirIfNotExists(outputDirectory);
|
||||
|
||||
// Parse controller configuration file
|
||||
String configPath = argsLine.getOptionValue("c");
|
||||
File configFile = new File(configPath);
|
||||
|
||||
// Check config format
|
||||
if (!JSONSchemaType.isValidJson(JSONSchemaType.CONFIG, configFile)) {
|
||||
LOG.error("Invalid configuration JSON format");
|
||||
return;
|
||||
}
|
||||
|
||||
// Load configuration file
|
||||
ControllerConfiguration config = null;
|
||||
try {
|
||||
JSONObject input = new JSONObject(FileUtil.readFile(configFile));
|
||||
config =
|
||||
new ControllerConfiguration(
|
||||
input.getString("database_type"),
|
||||
input.getString("username"),
|
||||
input.getString("password"),
|
||||
input.getString("database_url"),
|
||||
input.getString("upload_code"),
|
||||
input.getString("upload_url"),
|
||||
input.getString("workload_name"));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
DBCollector collector = getCollector(config);
|
||||
try {
|
||||
// add a signal handler
|
||||
Signal.handle(new Signal("INT"), signal -> firstCollecting = true);
|
||||
File f = new File("pid.txt");
|
||||
|
||||
// get pid of this process and write the pid to a file before recording the start time
|
||||
if (time < 0) {
|
||||
String vmName = ManagementFactory.getRuntimeMXBean().getName();
|
||||
int p = vmName.indexOf("@");
|
||||
int pid = Integer.valueOf(vmName.substring(0, p));
|
||||
try {
|
||||
f.createNewFile();
|
||||
PrintWriter pidWriter = new PrintWriter(f);
|
||||
pidWriter.println(pid);
|
||||
pidWriter.flush();
|
||||
pidWriter.close();
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
}
|
||||
LOG.info("Output the process pid to pid.txt");
|
||||
|
||||
while (!firstCollecting) {
|
||||
Thread.sleep(1);
|
||||
}
|
||||
|
||||
// first collection (before queries)
|
||||
LOG.info("First collection of metrics before experiment");
|
||||
String metricsBefore = collector.collectMetrics();
|
||||
if (!JSONSchemaType.isValidJson(JSONSchemaType.OUTPUT, metricsBefore)) {
|
||||
LOG.error("Invalid output JSON format (metrics_before)");
|
||||
return;
|
||||
}
|
||||
PrintWriter metricsWriter =
|
||||
new PrintWriter(FileUtil.joinPath(outputDirectory, "metrics_before.json"), "UTF-8");
|
||||
metricsWriter.println(metricsBefore);
|
||||
metricsWriter.close();
|
||||
|
||||
String knobs = collector.collectParameters();
|
||||
if (!JSONSchemaType.isValidJson(JSONSchemaType.OUTPUT, knobs)) {
|
||||
LOG.error("Invalid output JSON format (knobs)");
|
||||
return;
|
||||
}
|
||||
PrintWriter knobsWriter =
|
||||
new PrintWriter(FileUtil.joinPath(outputDirectory, "knobs.json"), "UTF-8");
|
||||
knobsWriter.println(knobs);
|
||||
knobsWriter.close();
|
||||
|
||||
// add a signal handler
|
||||
Signal.handle(new Signal("INT"), signal -> keepRunning = false);
|
||||
|
||||
// record start time
|
||||
long startTime = System.currentTimeMillis();
|
||||
LOG.info("Starting the experiment ...");
|
||||
|
||||
// go to sleep
|
||||
if (time >= 0) {
|
||||
Thread.sleep(time * TO_MILLISECONDS);
|
||||
} else {
|
||||
while (keepRunning) {
|
||||
Thread.sleep(1);
|
||||
}
|
||||
f.delete();
|
||||
}
|
||||
|
||||
long endTime = System.currentTimeMillis();
|
||||
long observationTime = time >= 0 ? time : (endTime - startTime) / TO_MILLISECONDS;
|
||||
LOG.info("Done running the experiment");
|
||||
|
||||
// summary json obj
|
||||
JSONObject summary = null;
|
||||
try {
|
||||
summary = new JSONObject();
|
||||
summary.put("start_time", startTime);
|
||||
summary.put("end_time", endTime);
|
||||
summary.put("observation_time", observationTime);
|
||||
summary.put("database_type", config.getDBName());
|
||||
summary.put("database_version", collector.collectVersion());
|
||||
summary.put("workload_name", config.getWorkloadName());
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (!JSONSchemaType.isValidJson(JSONSchemaType.SUMMARY, summary.toString())) {
|
||||
LOG.error("Invalid summary JSON format");
|
||||
return;
|
||||
}
|
||||
|
||||
// write summary JSONObject into a JSON file
|
||||
PrintWriter summaryout =
|
||||
new PrintWriter(FileUtil.joinPath(outputDirectory, "summary.json"), "UTF-8");
|
||||
summaryout.println(JSONUtil.format(summary.toString()));
|
||||
summaryout.close();
|
||||
|
||||
// second collection (after workload execution)
|
||||
LOG.info("Second collection of metrics after experiment");
|
||||
collector = getCollector(config);
|
||||
String metricsAfter = collector.collectMetrics();
|
||||
if (!JSONSchemaType.isValidJson(JSONSchemaType.OUTPUT, metricsAfter)) {
|
||||
LOG.error("Invalid output JSON format (metrics_after)");
|
||||
return;
|
||||
}
|
||||
PrintWriter metricsWriterFinal =
|
||||
new PrintWriter(FileUtil.joinPath(outputDirectory, "metrics_after.json"), "UTF-8");
|
||||
metricsWriterFinal.println(metricsAfter);
|
||||
metricsWriterFinal.close();
|
||||
} catch (FileNotFoundException | UnsupportedEncodingException | InterruptedException e) {
|
||||
LOG.error("Failed to produce output files");
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (config.getUploadURL() != null && !config.getUploadURL().equals("")) {
|
||||
Map<String, String> outfiles = new HashMap<>();
|
||||
outfiles.put("knobs", FileUtil.joinPath(outputDirectory, "knobs.json"));
|
||||
outfiles.put("metrics_before", FileUtil.joinPath(outputDirectory, "metrics_before.json"));
|
||||
outfiles.put("metrics_after", FileUtil.joinPath(outputDirectory, "metrics_after.json"));
|
||||
outfiles.put("summary", FileUtil.joinPath(outputDirectory, "summary.json"));
|
||||
try {
|
||||
ResultUploader.upload(config.getUploadURL(), config.getUploadCode(), outfiles);
|
||||
} catch (IOException ioe) {
|
||||
LOG.warn("Failed to upload results from the controller");
|
||||
}
|
||||
} else {
|
||||
LOG.warn("Empty upload URL. Skipping upload...");
|
||||
}
|
||||
}
|
||||
|
||||
private static void printUsage(Options options) {
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
formatter.printHelp("controller", options);
|
||||
}
|
||||
|
||||
private static DBCollector getCollector(ControllerConfiguration config) {
|
||||
DBCollector collector = null;
|
||||
switch (config.getDBType()) {
|
||||
case POSTGRES:
|
||||
collector =
|
||||
new PostgresCollector(
|
||||
config.getDBURL(), config.getDBUsername(), config.getDBPassword());
|
||||
break;
|
||||
case MYSQL:
|
||||
collector =
|
||||
new MySQLCollector(config.getDBURL(), config.getDBUsername(), config.getDBPassword());
|
||||
break;
|
||||
case SAPHANA:
|
||||
collector =
|
||||
new SAPHanaCollector(config.getDBURL(), config.getDBUsername(), config.getDBPassword());
|
||||
break;
|
||||
case ORACLE:
|
||||
collector =
|
||||
new OracleCollector(config.getDBURL(), config.getDBUsername(), config.getDBPassword());
|
||||
break;
|
||||
default:
|
||||
LOG.error("Invalid database type");
|
||||
throw new RuntimeException("Invalid database type");
|
||||
}
|
||||
return collector;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* OtterTune - ResultUploader.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
||||
import org.apache.http.entity.mime.content.FileBody;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
/**
|
||||
* Uploading the result.
|
||||
*
|
||||
* @author Shuli
|
||||
*/
|
||||
public class ResultUploader {
|
||||
public static void upload(String uploadURL, String uploadCode,
|
||||
Map<String, String> files) throws IOException {
|
||||
|
||||
try {
|
||||
List<String> filesToSendNames = new ArrayList<>();
|
||||
List<File> filesToSend = new ArrayList<>();
|
||||
for (String fileName : files.keySet()) {
|
||||
String path = files.get(fileName);
|
||||
filesToSendNames.add(fileName);
|
||||
File f = new File(path);
|
||||
filesToSend.add(f);
|
||||
}
|
||||
CloseableHttpClient httpclient = HttpClients.createDefault();
|
||||
HttpPost httppost = new HttpPost(uploadURL);
|
||||
MultipartEntityBuilder mb =
|
||||
MultipartEntityBuilder.create().addTextBody("upload_code", uploadCode);
|
||||
for (int i = 0; i < filesToSendNames.size(); i++) {
|
||||
mb.addPart(filesToSendNames.get(i), new FileBody(filesToSend.get(i)));
|
||||
}
|
||||
|
||||
HttpEntity reqEntity = mb.build();
|
||||
httppost.setEntity(reqEntity);
|
||||
CloseableHttpResponse response = httpclient.execute(httppost);
|
||||
try {
|
||||
HttpEntity resEntity = response.getEntity();
|
||||
EntityUtils.consume(resEntity);
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* OtterTune - DBCollector.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller.collectors;
|
||||
|
||||
import com.controller.util.JSONUtil;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
public class DBCollector implements DBParameterCollector {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(DBCollector.class);
|
||||
|
||||
protected static final String JSON_GLOBAL_KEY = "global";
|
||||
protected static final String JSON_LOCAL_KEY = "local";
|
||||
|
||||
protected final Map<String, String> dbParameters = new TreeMap<String, String>();
|
||||
|
||||
protected final Map<String, String> dbMetrics = new TreeMap<String, String>();
|
||||
|
||||
protected final StringBuilder version = new StringBuilder();
|
||||
|
||||
@Override
|
||||
public boolean hasParameters() {
|
||||
return (dbParameters.isEmpty() == false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMetrics() {
|
||||
return (dbMetrics.isEmpty() == false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String collectParameters() {
|
||||
return JSONUtil.format(JSONUtil.toJSONString(dbParameters));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String collectMetrics() {
|
||||
return JSONUtil.format(JSONUtil.toJSONString(dbMetrics));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String collectVersion() {
|
||||
return version.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* OtterTune - DBParameterCollector.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller.collectors;
|
||||
|
||||
public interface DBParameterCollector {
|
||||
boolean hasParameters();
|
||||
|
||||
boolean hasMetrics();
|
||||
|
||||
String collectParameters();
|
||||
|
||||
String collectMetrics();
|
||||
|
||||
String collectVersion();
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* OtterTune - MySQLCollector.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller.collectors;
|
||||
|
||||
import com.controller.util.JSONUtil;
|
||||
import com.controller.util.json.JSONException;
|
||||
import com.controller.util.json.JSONObject;
|
||||
import com.controller.util.json.JSONStringer;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Map;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/** */
|
||||
public class MySQLCollector extends DBCollector {
|
||||
private static final Logger LOG = Logger.getLogger(MySQLCollector.class);
|
||||
|
||||
private static final String VERSION_SQL = "SELECT @@GLOBAL.version;";
|
||||
|
||||
private static final String PARAMETERS_SQL = "SHOW VARIABLES;";
|
||||
|
||||
private static final String METRICS_SQL = "SHOW STATUS";
|
||||
|
||||
public MySQLCollector(String oriDBUrl, String username, String password) {
|
||||
try {
|
||||
Connection conn = DriverManager.getConnection(oriDBUrl, username, password);
|
||||
Statement s = conn.createStatement();
|
||||
|
||||
// Collect DBMS version
|
||||
ResultSet out = s.executeQuery(VERSION_SQL);
|
||||
if (out.next()) {
|
||||
this.version.append(out.getString(1));
|
||||
}
|
||||
|
||||
// Collect DBMS parameters
|
||||
out = s.executeQuery(PARAMETERS_SQL);
|
||||
while (out.next()) {
|
||||
dbParameters.put(out.getString(1).toLowerCase(), out.getString(2));
|
||||
}
|
||||
|
||||
// Collect DBMS internal metrics
|
||||
out = s.executeQuery(METRICS_SQL);
|
||||
while (out.next()) {
|
||||
dbMetrics.put(out.getString(1).toLowerCase(), out.getString(2));
|
||||
}
|
||||
conn.close();
|
||||
} catch (SQLException e) {
|
||||
LOG.error("Error while collecting DB parameters: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String collectParameters() {
|
||||
JSONStringer stringer = new JSONStringer();
|
||||
try {
|
||||
stringer.object();
|
||||
stringer.key(JSON_GLOBAL_KEY);
|
||||
JSONObject jobLocal = new JSONObject();
|
||||
JSONObject job = new JSONObject();
|
||||
for (String k : dbParameters.keySet()) {
|
||||
job.put(k, dbParameters.get(k));
|
||||
}
|
||||
// "global is a fake view_name (a placeholder)"
|
||||
jobLocal.put("global", job);
|
||||
stringer.value(jobLocal);
|
||||
stringer.key(JSON_LOCAL_KEY);
|
||||
stringer.value(null);
|
||||
stringer.endObject();
|
||||
} catch (JSONException jsonexn) {
|
||||
jsonexn.printStackTrace();
|
||||
}
|
||||
return JSONUtil.format(stringer.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String collectMetrics() {
|
||||
JSONStringer stringer = new JSONStringer();
|
||||
try {
|
||||
stringer.object();
|
||||
stringer.key(JSON_GLOBAL_KEY);
|
||||
JSONObject jobGlobal = new JSONObject();
|
||||
JSONObject job = new JSONObject();
|
||||
for (Map.Entry<String, String> entry : dbMetrics.entrySet()) {
|
||||
job.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
// "global" is a a placeholder
|
||||
jobGlobal.put("global", job);
|
||||
stringer.value(jobGlobal);
|
||||
stringer.key(JSON_LOCAL_KEY);
|
||||
stringer.value(null);
|
||||
stringer.endObject();
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return JSONUtil.format(stringer.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* OtterTune - OracleCollector.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller.collectors;
|
||||
|
||||
import com.controller.util.JSONUtil;
|
||||
import com.controller.util.json.JSONException;
|
||||
import com.controller.util.json.JSONObject;
|
||||
import com.controller.util.json.JSONStringer;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Map;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/** */
|
||||
public class OracleCollector extends DBCollector {
|
||||
private static final Logger LOG = Logger.getLogger(MySQLCollector.class);
|
||||
|
||||
private static final String VERSION_SQL = "select VERSION from product_component_version";
|
||||
|
||||
private static final String PARAMETERS_SQL = "select name, value from v$parameter";
|
||||
|
||||
private static final String PARAMETERS_SQL_WITH_HIDDEN =
|
||||
"select x.ksppinm name, y.ksppstvl value from sys.x$ksppi x, sys.x$ksppcv y where"
|
||||
+ " x.inst_id = userenv('Instance') and y.inst_id = userenv('Instance') and x.indx = y.indx";
|
||||
|
||||
private static final String METRICS_SQL = "select name, value from v$sysstat";
|
||||
|
||||
public OracleCollector(String oriDBUrl, String username, String password) {
|
||||
try {
|
||||
Connection conn = DriverManager.getConnection(oriDBUrl, username, password);
|
||||
Statement statement = conn.createStatement();
|
||||
// Collect DBMS version
|
||||
ResultSet out = statement.executeQuery(VERSION_SQL);
|
||||
if (out.next()) {
|
||||
this.version.append(out.getString(1));
|
||||
}
|
||||
|
||||
// Collect DBMS parameters
|
||||
out = statement.executeQuery(PARAMETERS_SQL_WITH_HIDDEN);
|
||||
while (out.next()) {
|
||||
dbParameters.put(out.getString(1).toLowerCase(), out.getString(2));
|
||||
}
|
||||
|
||||
// Collect DBMS internal metrics
|
||||
out = statement.executeQuery(METRICS_SQL);
|
||||
while (out.next()) {
|
||||
dbMetrics.put(out.getString(1).toLowerCase(), out.getString(2));
|
||||
}
|
||||
conn.close();
|
||||
} catch (SQLException e) {
|
||||
LOG.error("Error while collecting DB parameters: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String collectParameters() {
|
||||
JSONStringer stringer = new JSONStringer();
|
||||
try {
|
||||
stringer.object();
|
||||
stringer.key(JSON_GLOBAL_KEY);
|
||||
JSONObject jobLocal = new JSONObject();
|
||||
JSONObject job = new JSONObject();
|
||||
for (Map.Entry<String, String> entry : dbParameters.entrySet()) {
|
||||
job.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
// "global is a fake view_name (a placeholder)"
|
||||
jobLocal.put("global", job);
|
||||
stringer.value(jobLocal);
|
||||
stringer.key(JSON_LOCAL_KEY);
|
||||
stringer.value(null);
|
||||
stringer.endObject();
|
||||
} catch (JSONException jsonexn) {
|
||||
jsonexn.printStackTrace();
|
||||
}
|
||||
return JSONUtil.format(stringer.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String collectMetrics() {
|
||||
JSONStringer stringer = new JSONStringer();
|
||||
try {
|
||||
stringer.object();
|
||||
stringer.key(JSON_GLOBAL_KEY);
|
||||
JSONObject jobGlobal = new JSONObject();
|
||||
JSONObject job = new JSONObject();
|
||||
for (Map.Entry<String, String> entry : dbMetrics.entrySet()) {
|
||||
job.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
// "global" is a placeholder
|
||||
jobGlobal.put("global", job);
|
||||
stringer.value(jobGlobal);
|
||||
stringer.key(JSON_LOCAL_KEY);
|
||||
stringer.value(null);
|
||||
stringer.endObject();
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return JSONUtil.format(stringer.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* OtterTune - PostgresCollector.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller.collectors;
|
||||
|
||||
import com.controller.util.JSONUtil;
|
||||
import com.controller.util.json.JSONException;
|
||||
import com.controller.util.json.JSONObject;
|
||||
import com.controller.util.json.JSONStringer;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
public class PostgresCollector extends DBCollector {
|
||||
private static final Logger LOG = Logger.getLogger(PostgresCollector.class);
|
||||
|
||||
private static final String VERSION_SQL = "SELECT version();";
|
||||
|
||||
private static final String PARAMETERS_SQL = "SHOW ALL;";
|
||||
|
||||
private boolean oldVersion = false;
|
||||
|
||||
private static final String[] PG_STAT_VIEWS = {
|
||||
"pg_stat_archiver", "pg_stat_bgwriter", "pg_stat_database",
|
||||
"pg_stat_database_conflicts", "pg_stat_user_tables", "pg_statio_user_tables",
|
||||
"pg_stat_user_indexes", "pg_statio_user_indexes"
|
||||
};
|
||||
|
||||
private static final String[] PG_STAT_VIEWS_OLD_VERSION = {
|
||||
"pg_stat_bgwriter", "pg_stat_database",
|
||||
"pg_stat_database_conflicts", "pg_stat_user_tables", "pg_statio_user_tables",
|
||||
"pg_stat_user_indexes", "pg_statio_user_indexes"
|
||||
};
|
||||
|
||||
private static final String[] PG_STAT_VIEWS_LOCAL_DATABASE = {
|
||||
"pg_stat_database", "pg_stat_database_conflicts"
|
||||
};
|
||||
private static final String PG_STAT_VIEWS_LOCAL_DATABASE_KEY = "datname";
|
||||
private static final String[] PG_STAT_VIEWS_LOCAL_TABLE = {
|
||||
"pg_stat_user_tables", "pg_statio_user_tables"
|
||||
};
|
||||
private static final String PG_STAT_VIEWS_LOCAL_TABLE_KEY = "relname";
|
||||
private static final String[] PG_STAT_VIEWS_LOCAL_INDEXES = {
|
||||
"pg_stat_user_indexes", "pg_statio_user_indexes"
|
||||
};
|
||||
private static final String PG_STAT_VIEWS_LOCAL_INDEXES_KEY = "relname";
|
||||
|
||||
private final Map<String, List<Map<String, String>>> pgMetrics;
|
||||
|
||||
public PostgresCollector(String oriDBUrl, String username, String password) {
|
||||
pgMetrics = new HashMap<>();
|
||||
try {
|
||||
Connection conn = DriverManager.getConnection(oriDBUrl, username, password);
|
||||
|
||||
Statement s = conn.createStatement();
|
||||
|
||||
// Collect DBMS version
|
||||
ResultSet out = s.executeQuery(VERSION_SQL);
|
||||
if (out.next()) {
|
||||
String[] outStr = out.getString(1).split(" ");
|
||||
String[] verStr = outStr[1].split("\\.");
|
||||
this.version.append(verStr[0]);
|
||||
this.version.append(".");
|
||||
this.version.append(verStr[1]);
|
||||
}
|
||||
|
||||
// Collect DBMS parameters
|
||||
out = s.executeQuery(PARAMETERS_SQL);
|
||||
while (out.next()) {
|
||||
dbParameters.put(out.getString("name"), out.getString("setting"));
|
||||
}
|
||||
|
||||
// Collect DBMS internal metrics
|
||||
String[] pgStatViews = PG_STAT_VIEWS;
|
||||
if (Float.parseFloat(this.version.toString()) < 9.4) {
|
||||
this.oldVersion = true;
|
||||
pgStatViews = PG_STAT_VIEWS_OLD_VERSION;
|
||||
}
|
||||
|
||||
for (String viewName : pgStatViews) {
|
||||
out = s.executeQuery("SELECT * FROM " + viewName);
|
||||
pgMetrics.put(viewName, getMetrics(out));
|
||||
}
|
||||
conn.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
LOG.error("Error while collecting DB parameters: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMetrics() {
|
||||
return (pgMetrics.isEmpty() == false);
|
||||
}
|
||||
|
||||
private JSONObject genMapJSONObj(Map<String, String> mapin) {
|
||||
JSONObject res = new JSONObject();
|
||||
try {
|
||||
for (String key : mapin.keySet()) {
|
||||
res.put(key, mapin.get(key));
|
||||
}
|
||||
} catch (JSONException je) {
|
||||
LOG.error(je);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private JSONObject genLocalJSONObj(String viewName, String jsonKeyName) {
|
||||
JSONObject thisViewObj = new JSONObject();
|
||||
List<Map<String, String>> thisViewList = pgMetrics.get(viewName);
|
||||
try {
|
||||
for (Map<String, String> dbmap : thisViewList) {
|
||||
String jsonkey = dbmap.get(jsonKeyName);
|
||||
thisViewObj.put(jsonkey, genMapJSONObj(dbmap));
|
||||
}
|
||||
} catch (JSONException je) {
|
||||
LOG.error(je);
|
||||
}
|
||||
return thisViewObj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String collectMetrics() {
|
||||
JSONStringer stringer = new JSONStringer();
|
||||
try {
|
||||
stringer.object();
|
||||
stringer.key(JSON_GLOBAL_KEY);
|
||||
// create global objects for two views: "pg_stat_archiver" and "pg_stat_bgwriter"
|
||||
JSONObject jobGlobal = new JSONObject();
|
||||
// "pg_stat_archiver" (only one instance in the list) >= version 9.4
|
||||
if (!this.oldVersion) {
|
||||
Map<String, String> archiverList = pgMetrics.get("pg_stat_archiver").get(0);
|
||||
jobGlobal.put("pg_stat_archiver", genMapJSONObj(archiverList));
|
||||
}
|
||||
|
||||
// "pg_stat_bgwriter" (only one instance in the list)
|
||||
Map<String, String> bgwriterList = pgMetrics.get("pg_stat_bgwriter").get(0);
|
||||
jobGlobal.put("pg_stat_bgwriter", genMapJSONObj(bgwriterList));
|
||||
|
||||
// add global json object
|
||||
stringer.value(jobGlobal);
|
||||
stringer.key(JSON_LOCAL_KEY);
|
||||
// create local objects for the rest of the views
|
||||
JSONObject jobLocal = new JSONObject();
|
||||
|
||||
// "table"
|
||||
JSONObject jobTable = new JSONObject();
|
||||
for (int i = 0; i < PG_STAT_VIEWS_LOCAL_TABLE.length; i++) {
|
||||
String viewName = PG_STAT_VIEWS_LOCAL_TABLE[i];
|
||||
String jsonKeyName = PG_STAT_VIEWS_LOCAL_TABLE_KEY;
|
||||
jobTable.put(viewName, genLocalJSONObj(viewName, jsonKeyName));
|
||||
}
|
||||
jobLocal.put("table", jobTable);
|
||||
|
||||
// "database"
|
||||
JSONObject jobDatabase = new JSONObject();
|
||||
for (int i = 0; i < PG_STAT_VIEWS_LOCAL_DATABASE.length; i++) {
|
||||
String viewName = PG_STAT_VIEWS_LOCAL_DATABASE[i];
|
||||
String jsonKeyName = PG_STAT_VIEWS_LOCAL_DATABASE_KEY;
|
||||
jobDatabase.put(viewName, genLocalJSONObj(viewName, jsonKeyName));
|
||||
}
|
||||
jobLocal.put("database", jobDatabase);
|
||||
|
||||
// "indexes"
|
||||
JSONObject jobIndexes = new JSONObject();
|
||||
for (int i = 0; i < PG_STAT_VIEWS_LOCAL_INDEXES.length; i++) {
|
||||
String viewName = PG_STAT_VIEWS_LOCAL_INDEXES[i];
|
||||
String jsonKeyName = PG_STAT_VIEWS_LOCAL_INDEXES_KEY;
|
||||
jobIndexes.put(viewName, genLocalJSONObj(viewName, jsonKeyName));
|
||||
}
|
||||
jobLocal.put("indexes", jobIndexes);
|
||||
|
||||
// add local json object
|
||||
stringer.value(jobLocal);
|
||||
stringer.endObject();
|
||||
|
||||
} catch (JSONException jsonexn) {
|
||||
jsonexn.printStackTrace();
|
||||
}
|
||||
|
||||
return JSONUtil.format(stringer.toString());
|
||||
}
|
||||
|
||||
private static List<Map<String, String>> getMetrics(ResultSet out) throws SQLException {
|
||||
ResultSetMetaData metadata = out.getMetaData();
|
||||
int numColumns = metadata.getColumnCount();
|
||||
String[] columnNames = new String[numColumns];
|
||||
for (int i = 0; i < numColumns; ++i) {
|
||||
columnNames[i] = metadata.getColumnName(i + 1).toLowerCase();
|
||||
}
|
||||
|
||||
List<Map<String, String>> metrics = new ArrayList<Map<String, String>>();
|
||||
while (out.next()) {
|
||||
Map<String, String> metricMap = new TreeMap<String, String>();
|
||||
for (int i = 0; i < numColumns; ++i) {
|
||||
metricMap.put(columnNames[i], out.getString(i + 1));
|
||||
}
|
||||
metrics.add(metricMap);
|
||||
}
|
||||
return metrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String collectParameters() {
|
||||
JSONStringer stringer = new JSONStringer();
|
||||
try {
|
||||
stringer.object();
|
||||
stringer.key(JSON_GLOBAL_KEY);
|
||||
JSONObject jobLocal = new JSONObject();
|
||||
JSONObject job = new JSONObject();
|
||||
for (String k : dbParameters.keySet()) {
|
||||
job.put(k, dbParameters.get(k));
|
||||
}
|
||||
// "global is a fake view_name (a placeholder)"
|
||||
jobLocal.put("global", job);
|
||||
stringer.value(jobLocal);
|
||||
stringer.key(JSON_LOCAL_KEY);
|
||||
stringer.value(null);
|
||||
stringer.endObject();
|
||||
} catch (JSONException jsonexn) {
|
||||
jsonexn.printStackTrace();
|
||||
}
|
||||
return JSONUtil.format(stringer.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* OtterTune - SAPHanaCollector.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller.collectors;
|
||||
|
||||
import com.controller.util.JSONUtil;
|
||||
import com.controller.util.json.JSONException;
|
||||
import com.controller.util.json.JSONObject;
|
||||
import com.controller.util.json.JSONStringer;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
public class SAPHanaCollector extends DBCollector {
|
||||
private static final Logger LOG = Logger.getLogger(SAPHanaCollector.class);
|
||||
|
||||
private static final String VERSION_SQL = "SELECT VERSION from M_DATABASE";
|
||||
|
||||
private static final String PARAMETERS_SQL = "Select * from M_INIFILE_CONTENTS";
|
||||
|
||||
private static final String[] SAP_SYS_VIEW = {
|
||||
"m_host_agent_metrics",
|
||||
"m_caches",
|
||||
"m_disk_usage",
|
||||
"m_garbage_collection_statistics",
|
||||
"m_host_resource_utilization",
|
||||
"m_data_volumes"
|
||||
};
|
||||
|
||||
private static final String[] SAP_SYS_LOCAL_VIEW = {"m_table_statistics", "m_rs_indexes"};
|
||||
private static final String[] SAP_SYS_VIEW_GLOBAL = {
|
||||
"m_host_agent_metrics",
|
||||
"m_caches",
|
||||
"m_disk_usage",
|
||||
"m_garbage_collection_statistics",
|
||||
"m_host_resource_utilization",
|
||||
"m_data_volumes"
|
||||
};
|
||||
private static final String[] SAP_SYS_VIEW_GLOBAL_KEY = {
|
||||
"instance_id", "cache_id", "usage_type", "store_type", "host", "volume_id"
|
||||
};
|
||||
private static final String[] SAP_SYS_VIEW_LOCAL_TABLE = {"m_table_statistics"};
|
||||
private static final String[] SAP_SYS_VIEW_LOCAL_TABLE_KEY = {"table_name"};
|
||||
private static final String[] SAP_SYS_VIEW_LOCAL_INDEXES = {"m_rs_indexes"};
|
||||
private static final String[] SAP_SYS_VIEW_LOCAL_INDEXES_KEY = {"index_name"};
|
||||
|
||||
private final Map<String, List<Map<String, String>>> pgMetrics;
|
||||
|
||||
public SAPHanaCollector(String oriDBUrl, String username, String password) {
|
||||
pgMetrics = new HashMap<>();
|
||||
try {
|
||||
Connection conn = DriverManager.getConnection(oriDBUrl, username, password);
|
||||
Statement s = conn.createStatement();
|
||||
|
||||
// Collect DBMS version
|
||||
ResultSet out = s.executeQuery(VERSION_SQL);
|
||||
if (out.next()) {
|
||||
this.version.append(out.getString(1));
|
||||
}
|
||||
|
||||
// Collect DBMS parameters
|
||||
out = s.executeQuery(PARAMETERS_SQL);
|
||||
while (out.next()) {
|
||||
dbParameters.put(
|
||||
"("
|
||||
+ out.getString("FILE_NAME")
|
||||
+ ","
|
||||
+ out.getString("LAYER_NAME")
|
||||
+ ","
|
||||
+ out.getString("TENANT_NAME")
|
||||
+ ","
|
||||
+ out.getString("HOST")
|
||||
+ ","
|
||||
+ out.getString("SECTION")
|
||||
+ ","
|
||||
+ out.getString("KEY")
|
||||
+ ")",
|
||||
out.getString("VALUE"));
|
||||
}
|
||||
|
||||
// Collect DBMS internal metrics
|
||||
for (String viewName : SAP_SYS_VIEW) {
|
||||
out = s.executeQuery("SELECT * FROM " + viewName);
|
||||
pgMetrics.put(viewName, getMetrics(out));
|
||||
}
|
||||
for (String viewName : SAP_SYS_LOCAL_VIEW) {
|
||||
out = s.executeQuery("SELECT * FROM " + viewName + " where schema_name = 'SYSTEM' ");
|
||||
pgMetrics.put(viewName, getMetrics(out));
|
||||
}
|
||||
conn.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
LOG.error("Error while collecting DB parameters: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMetrics() {
|
||||
return (pgMetrics.isEmpty() == false);
|
||||
}
|
||||
|
||||
private JSONObject genMapJSONObj(Map<String, String> mapin) {
|
||||
JSONObject res = new JSONObject();
|
||||
try {
|
||||
for (String key : mapin.keySet()) {
|
||||
res.put(key, mapin.get(key));
|
||||
}
|
||||
} catch (JSONException je) {
|
||||
LOG.error(je);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private JSONObject genLocalJSONObj(String viewName, String jsonKeyName) {
|
||||
JSONObject thisViewObj = new JSONObject();
|
||||
List<Map<String, String>> thisViewList = pgMetrics.get(viewName);
|
||||
try {
|
||||
for (Map<String, String> dbmap : thisViewList) {
|
||||
String jsonkey = dbmap.get(jsonKeyName);
|
||||
thisViewObj.put(jsonkey, genMapJSONObj(dbmap));
|
||||
}
|
||||
} catch (JSONException je) {
|
||||
LOG.error(je);
|
||||
}
|
||||
return thisViewObj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String collectMetrics() {
|
||||
JSONStringer stringer = new JSONStringer();
|
||||
try {
|
||||
stringer.object();
|
||||
stringer.key(JSON_GLOBAL_KEY);
|
||||
JSONObject jobGlobal = new JSONObject();
|
||||
|
||||
JSONObject jobMetric = new JSONObject();
|
||||
for (int i = 0; i < SAP_SYS_VIEW_GLOBAL.length; i++) {
|
||||
String viewName = SAP_SYS_VIEW_GLOBAL[i];
|
||||
String jsonKeyName = SAP_SYS_VIEW_GLOBAL_KEY[i];
|
||||
jobGlobal.put(viewName, genLocalJSONObj(viewName, jsonKeyName));
|
||||
}
|
||||
// add global json object
|
||||
stringer.value(jobGlobal);
|
||||
stringer.key(JSON_LOCAL_KEY);
|
||||
|
||||
// create local objects for the rest of the views
|
||||
JSONObject jobLocal = new JSONObject();
|
||||
|
||||
// "table"
|
||||
JSONObject jobTable = new JSONObject();
|
||||
for (int i = 0; i < SAP_SYS_VIEW_LOCAL_TABLE.length; i++) {
|
||||
String viewName = SAP_SYS_VIEW_LOCAL_TABLE[i];
|
||||
String jsonKeyName = SAP_SYS_VIEW_LOCAL_TABLE_KEY[i];
|
||||
jobTable.put(viewName, genLocalJSONObj(viewName, jsonKeyName));
|
||||
}
|
||||
jobLocal.put("table", jobTable);
|
||||
|
||||
// "indexes"
|
||||
JSONObject jobIndexes = new JSONObject();
|
||||
for (int i = 0; i < SAP_SYS_VIEW_LOCAL_INDEXES.length; i++) {
|
||||
String viewName = SAP_SYS_VIEW_LOCAL_INDEXES[i];
|
||||
String jsonKeyName = SAP_SYS_VIEW_LOCAL_INDEXES_KEY[i];
|
||||
jobIndexes.put(viewName, genLocalJSONObj(viewName, jsonKeyName));
|
||||
}
|
||||
jobLocal.put("indexes", jobIndexes);
|
||||
|
||||
// add local json object
|
||||
stringer.value(jobLocal);
|
||||
stringer.endObject();
|
||||
|
||||
} catch (JSONException jsonexn) {
|
||||
jsonexn.printStackTrace();
|
||||
}
|
||||
|
||||
return JSONUtil.format(stringer.toString());
|
||||
}
|
||||
|
||||
private static List<Map<String, String>> getMetrics(ResultSet out) throws SQLException {
|
||||
ResultSetMetaData metadata = out.getMetaData();
|
||||
int numColumns = metadata.getColumnCount();
|
||||
String[] columnNames = new String[numColumns];
|
||||
for (int i = 0; i < numColumns; ++i) {
|
||||
columnNames[i] = metadata.getColumnName(i + 1).toLowerCase();
|
||||
}
|
||||
|
||||
List<Map<String, String>> metrics = new ArrayList<Map<String, String>>();
|
||||
while (out.next()) {
|
||||
Map<String, String> metricMap = new TreeMap<String, String>();
|
||||
for (int i = 0; i < numColumns; ++i) {
|
||||
metricMap.put(columnNames[i], out.getString(i + 1));
|
||||
}
|
||||
metrics.add(metricMap);
|
||||
}
|
||||
return metrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String collectParameters() {
|
||||
JSONStringer stringer = new JSONStringer();
|
||||
try {
|
||||
stringer.object();
|
||||
stringer.key(JSON_GLOBAL_KEY);
|
||||
JSONObject jobLocal = new JSONObject();
|
||||
JSONObject job = new JSONObject();
|
||||
for (String k : dbParameters.keySet()) {
|
||||
job.put(k, dbParameters.get(k));
|
||||
}
|
||||
// "global is a fake view_name (a placeholder)"
|
||||
jobLocal.put("global", job);
|
||||
stringer.value(jobLocal);
|
||||
stringer.key(JSON_LOCAL_KEY);
|
||||
stringer.value(null);
|
||||
stringer.endObject();
|
||||
} catch (JSONException jsonexn) {
|
||||
jsonexn.printStackTrace();
|
||||
}
|
||||
return JSONUtil.format(stringer.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "summary of collector output",
|
||||
"description": "config files: user input",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"database_type": {
|
||||
"type" : "string"
|
||||
},
|
||||
"database_url": {
|
||||
"type" : "string"
|
||||
},
|
||||
"username" :{
|
||||
"type" : "string"
|
||||
},
|
||||
"password": {
|
||||
"type" : "string"
|
||||
},
|
||||
"upload_code": {
|
||||
"type" : "string"
|
||||
},
|
||||
"upload_url": {
|
||||
"type" : "string"
|
||||
},
|
||||
"workload_name": {
|
||||
"type" : "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"database_type",
|
||||
"database_url",
|
||||
"username",
|
||||
"password",
|
||||
"upload_code",
|
||||
"upload_url",
|
||||
"workload_name"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "collector output",
|
||||
"description": "Collected metrics or knobs info",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"global" : {
|
||||
"type": ["object", "null"],
|
||||
"patternProperties" : {
|
||||
"^[A-Za-z0-9 -_]" : {
|
||||
"type" : "object",
|
||||
"patternProperties" : {
|
||||
"^[A-Za-z0-9 -_]" : {
|
||||
"type" : "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"local" : {
|
||||
"type": ["object", "null"],
|
||||
"patternProperties" : {
|
||||
"^[A-Za-z0-9 -_]" : {
|
||||
"type" : "object",
|
||||
"patternProperties" : {
|
||||
"^[A-Za-z0-9 -_]" : {
|
||||
"type" : "object",
|
||||
"patternProperties" : {
|
||||
"^[A-Za-z0-9 -_]" : {
|
||||
"type" : "object",
|
||||
"patternProperties" : {
|
||||
"^[A-Za-z0-9 -_]" : {
|
||||
"type" : "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["global", "local"]
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "summary of collector output",
|
||||
"description": "output summary",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"database_type": {
|
||||
"type" : "string"
|
||||
},
|
||||
"start_time": {
|
||||
"type" : "number"
|
||||
},
|
||||
"observation_time" :{
|
||||
"type" : "number"
|
||||
},
|
||||
"end_time": {
|
||||
"type" : "number"
|
||||
},
|
||||
"database_version": {
|
||||
"type" : "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"database_type",
|
||||
"start_time",
|
||||
"observation_time",
|
||||
"end_time",
|
||||
"database_version"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* OtterTune - DatabaseType.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/** Database Type. */
|
||||
public enum DatabaseType {
|
||||
|
||||
/** Parameters: (1) JDBC Driver String */
|
||||
MYSQL("com.mysql.jdbc.Driver"),
|
||||
MYROCKS("com.mysql.jdbc.Driver"),
|
||||
POSTGRES("org.postgresql.Driver"),
|
||||
SAPHANA("com.sap.db.jdbc.Driver"),
|
||||
ORACLE("oracle.jdbc.driver.OracleDriver");
|
||||
|
||||
private DatabaseType(String driver) {
|
||||
this.driver = driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the suggested driver string to use in the configuration xml This corresponds to the
|
||||
* <B>'driver'</b> attribute.
|
||||
*/
|
||||
private final String driver;
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// ACCESSORS
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the suggested driver string to use for the given database type
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getSuggestedDriver() {
|
||||
return (this.driver);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// STATIC METHODS + MEMBERS
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
protected static final Map<Integer, DatabaseType> idx_lookup =
|
||||
new HashMap<Integer, DatabaseType>();
|
||||
protected static final Map<String, DatabaseType> name_lookup =
|
||||
new HashMap<String, DatabaseType>();
|
||||
|
||||
static {
|
||||
for (DatabaseType vt : EnumSet.allOf(DatabaseType.class)) {
|
||||
DatabaseType.idx_lookup.put(vt.ordinal(), vt);
|
||||
DatabaseType.name_lookup.put(vt.name().toUpperCase(), vt);
|
||||
}
|
||||
}
|
||||
|
||||
public static DatabaseType get(String name) {
|
||||
DatabaseType ret = DatabaseType.name_lookup.get(name.toUpperCase());
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* OtterTune - JSONSchemaType.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller.types;
|
||||
|
||||
import com.controller.util.FileUtil;
|
||||
import com.controller.util.ValidationUtils;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
|
||||
import com.github.fge.jsonschema.main.JsonSchema;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public enum JSONSchemaType {
|
||||
|
||||
/** Parameters: (1) schema filename */
|
||||
OUTPUT("schema.json"),
|
||||
CONFIG("config_schema.json"),
|
||||
SUMMARY("summary_schema.json");
|
||||
|
||||
// Path to JSON schema directory
|
||||
private static final String SCHEMA_PATH = "src/main/java/com/controller/json_validation_schema";
|
||||
|
||||
private final JsonSchema schema;
|
||||
|
||||
private JSONSchemaType(String fileName) {
|
||||
JsonSchema newSchema = null;
|
||||
String configPath = FileUtil.joinPath(SCHEMA_PATH, fileName);
|
||||
try {
|
||||
newSchema = ValidationUtils.getSchemaNode(new File(configPath));
|
||||
} catch (IOException | ProcessingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.schema = newSchema;
|
||||
}
|
||||
|
||||
public JsonSchema getSchema() {
|
||||
return this.schema;
|
||||
}
|
||||
|
||||
public static boolean isValidJson(JSONSchemaType schemaType, String jsonString) {
|
||||
try {
|
||||
JsonNode jsonNode = ValidationUtils.getJsonNode(jsonString);
|
||||
return ValidationUtils.isJsonValid(schemaType.getSchema(), jsonNode);
|
||||
} catch (IOException | ProcessingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isValidJson(JSONSchemaType schemaType, File jsonFile) {
|
||||
try {
|
||||
JsonNode jsonNode = ValidationUtils.getJsonNode(jsonFile);
|
||||
return ValidationUtils.isJsonValid(schemaType.getSchema(), jsonNode);
|
||||
} catch (IOException | ProcessingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* OtterTune - ClassUtil.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller.util;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.apache.commons.collections15.CollectionUtils;
|
||||
import org.apache.commons.lang.ClassUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/** @author pavlo */
|
||||
public abstract class ClassUtil {
|
||||
private static final Logger LOG = Logger.getLogger(ClassUtil.class);
|
||||
|
||||
private static final Class<?>[] EMPTY_ARRAY = new Class[] {};
|
||||
|
||||
private static final Map<Class<?>, List<Class<?>>> CACHE_getSuperClasses =
|
||||
new HashMap<Class<?>, List<Class<?>>>();
|
||||
private static final Map<Class<?>, Set<Class<?>>> CACHE_getInterfaceClasses =
|
||||
new HashMap<Class<?>, Set<Class<?>>>();
|
||||
|
||||
/**
|
||||
* Check if the given object is an array (primitve or native).
|
||||
* http://www.java2s.com/Code/Java/Reflection/Checkifthegivenobjectisanarrayprimitveornative.htm
|
||||
*
|
||||
* @param obj Object to test.
|
||||
* @return True of the object is an array.
|
||||
*/
|
||||
public static boolean isArray(final Object obj) {
|
||||
return (obj != null ? obj.getClass().isArray() : false);
|
||||
}
|
||||
|
||||
public static boolean[] isArray(final Object[] objs) {
|
||||
boolean[] isArray = new boolean[objs.length];
|
||||
for (int i = 0; i < objs.length; i++) {
|
||||
isArray[i] = ClassUtil.isArray(objs[i]);
|
||||
} // FOR
|
||||
return (isArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Enum array to a Field array This assumes that the name of each Enum element
|
||||
* corresponds to a data member in the clas
|
||||
*
|
||||
* @param <E>
|
||||
* @param clazz
|
||||
* @param members
|
||||
* @return
|
||||
* @throws NoSuchFieldException
|
||||
*/
|
||||
public static <E extends Enum<?>> Field[] getFieldsFromMembersEnum(Class<?> clazz, E[] members)
|
||||
throws NoSuchFieldException {
|
||||
Field[] fields = new Field[members.length];
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
fields[i] = clazz.getDeclaredField(members[i].name().toLowerCase());
|
||||
} // FOR
|
||||
return (fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generic types for the given field
|
||||
*
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static List<Class<?>> getGenericTypes(Field field) {
|
||||
ArrayList<Class<?>> genericClasses = new ArrayList<Class<?>>();
|
||||
Type gtype = field.getGenericType();
|
||||
if (gtype instanceof ParameterizedType) {
|
||||
ParameterizedType ptype = (ParameterizedType) gtype;
|
||||
getGenericTypesImpl(ptype, genericClasses);
|
||||
}
|
||||
return (genericClasses);
|
||||
}
|
||||
|
||||
private static void getGenericTypesImpl(ParameterizedType ptype, List<Class<?>> classes) {
|
||||
// list the actual type arguments
|
||||
for (Type t : ptype.getActualTypeArguments()) {
|
||||
if (t instanceof Class) {
|
||||
// System.err.println("C: " + t);
|
||||
classes.add((Class<?>) t);
|
||||
} else if (t instanceof ParameterizedType) {
|
||||
ParameterizedType next = (ParameterizedType) t;
|
||||
// System.err.println("PT: " + next);
|
||||
classes.add((Class<?>) next.getRawType());
|
||||
getGenericTypesImpl(next, classes);
|
||||
}
|
||||
} // FOR
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an ordered list of all the sub-classes for a given class Useful when dealing with
|
||||
* generics
|
||||
*
|
||||
* @param elementClass
|
||||
* @return
|
||||
*/
|
||||
public static List<Class<?>> getSuperClasses(Class<?> elementClass) {
|
||||
List<Class<?>> ret = ClassUtil.CACHE_getSuperClasses.get(elementClass);
|
||||
if (ret == null) {
|
||||
ret = new ArrayList<Class<?>>();
|
||||
while (elementClass != null) {
|
||||
ret.add(elementClass);
|
||||
elementClass = elementClass.getSuperclass();
|
||||
} // WHILE
|
||||
ret = Collections.unmodifiableList(ret);
|
||||
ClassUtil.CACHE_getSuperClasses.put(elementClass, ret);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a set of all of the interfaces that the element_class implements
|
||||
*
|
||||
* @param elementClass
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Collection<Class<?>> getInterfaces(Class<?> elementClass) {
|
||||
Set<Class<?>> ret = ClassUtil.CACHE_getInterfaceClasses.get(elementClass);
|
||||
if (ret == null) {
|
||||
// ret = new HashSet<Class<?>>();
|
||||
// Queue<Class<?>> queue = new LinkedList<Class<?>>();
|
||||
// queue.add(element_class);
|
||||
// while (!queue.isEmpty()) {
|
||||
// Class<?> current = queue.poll();
|
||||
// for (Class<?> i : current.getInterfaces()) {
|
||||
// ret.add(i);
|
||||
// queue.add(i);
|
||||
// } // FOR
|
||||
// } // WHILE
|
||||
ret = new HashSet<Class<?>>(ClassUtils.getAllInterfaces(elementClass));
|
||||
if (elementClass.isInterface()) {
|
||||
ret.add(elementClass);
|
||||
}
|
||||
ret = Collections.unmodifiableSet(ret);
|
||||
ClassUtil.CACHE_getInterfaceClasses.put(elementClass, ret);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T newInstance(String className, Object[] params, Class<?>[] classes) {
|
||||
return ((T) ClassUtil.newInstance(ClassUtil.getClass(className), params, classes));
|
||||
}
|
||||
|
||||
public static <T> T newInstance(Class<T> targetClass, Object[] params, Class<?>[] classes) {
|
||||
// Class<?> const_params[] = new Class<?>[params.length];
|
||||
// for (int i = 0; i < params.length; i++) {
|
||||
// const_params[i] = params[i].getClass();
|
||||
// System.err.println("[" + i + "] " + params[i] + " " + params[i].getClass());
|
||||
// } // FOR
|
||||
|
||||
Constructor<T> constructor = ClassUtil.getConstructor(targetClass, classes);
|
||||
T ret = null;
|
||||
try {
|
||||
ret = constructor.newInstance(params);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(
|
||||
"Failed to create new instance of " + targetClass.getSimpleName(), ex);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an object for the given class and initialize it from conf
|
||||
*
|
||||
* @param theClass class of which an object is created
|
||||
* @param expected the expected parent class or interface
|
||||
* @return a new object
|
||||
*/
|
||||
public static <T> T newInstance(Class<?> theClass, Class<T> expected) {
|
||||
T result;
|
||||
try {
|
||||
if (!expected.isAssignableFrom(theClass)) {
|
||||
throw new Exception(
|
||||
"Specified class "
|
||||
+ theClass.getName()
|
||||
+ ""
|
||||
+ "does not extend/implement "
|
||||
+ expected.getName());
|
||||
}
|
||||
Class<? extends T> clazz = (Class<? extends T>) theClass;
|
||||
Constructor<? extends T> meth = clazz.getDeclaredConstructor(EMPTY_ARRAY);
|
||||
meth.setAccessible(true);
|
||||
result = meth.newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> T newInstance(String className, Class<T> expected)
|
||||
throws ClassNotFoundException {
|
||||
return newInstance(getClass(className), expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <T>
|
||||
* @param targetClass
|
||||
* @param params
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Constructor<T> getConstructor(Class<T> targetClass, Class<?>... params) {
|
||||
NoSuchMethodException error = null;
|
||||
try {
|
||||
return (targetClass.getConstructor(params));
|
||||
} catch (NoSuchMethodException ex) {
|
||||
// The first time we get this it can be ignored
|
||||
// We'll try to be nice and find a match for them
|
||||
error = ex;
|
||||
}
|
||||
assert (error != null);
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("TARGET CLASS: " + targetClass);
|
||||
LOG.debug("TARGET PARAMS: " + Arrays.toString(params));
|
||||
}
|
||||
|
||||
List<Class<?>>[] paramSuper = (List<Class<?>>[]) new List[params.length];
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
paramSuper[i] = ClassUtil.getSuperClasses(params[i]);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(" SUPER[" + params[i].getSimpleName() + "] => " + paramSuper[i]);
|
||||
}
|
||||
} // FOR
|
||||
|
||||
for (Constructor<?> c : targetClass.getConstructors()) {
|
||||
Class<?>[] ctypes = c.getParameterTypes();
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("CANDIDATE: " + c);
|
||||
LOG.debug("CANDIDATE PARAMS: " + Arrays.toString(ctypes));
|
||||
}
|
||||
if (params.length != ctypes.length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
List<Class<?>> csuper = ClassUtil.getSuperClasses(ctypes[i]);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(" SUPER[" + ctypes[i].getSimpleName() + "] => " + csuper);
|
||||
}
|
||||
if (CollectionUtils.intersection(paramSuper[i], csuper).isEmpty() == false) {
|
||||
return ((Constructor<T>) c);
|
||||
}
|
||||
} // FOR (param)
|
||||
} // FOR (constructors)
|
||||
throw new RuntimeException(
|
||||
"Failed to retrieve constructor for " + targetClass.getSimpleName(), error);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param className
|
||||
* @return
|
||||
*/
|
||||
public static Class<?> getClass(String className) {
|
||||
Class<?> targetClass = null;
|
||||
try {
|
||||
ClassLoader loader = ClassLoader.getSystemClassLoader();
|
||||
targetClass = (Class<?>) loader.loadClass(className);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Failed to retrieve class for " + className, ex);
|
||||
}
|
||||
return (targetClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if asserts are enabled. This assumes that we're always using the default system
|
||||
* ClassLoader
|
||||
*/
|
||||
public static boolean isAssertsEnabled() {
|
||||
boolean ret = false;
|
||||
try {
|
||||
assert (false);
|
||||
} catch (AssertionError ex) {
|
||||
ret = true;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
/*
|
||||
* OtterTune - CollectionUtil.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller.util;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import org.apache.commons.collections15.set.ListOrderedSet;
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
|
||||
/** @author pavlo */
|
||||
public abstract class CollectionUtil {
|
||||
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
/**
|
||||
* Put all of the elements in items into the given array This assumes that the array has been
|
||||
* pre-allocated
|
||||
*
|
||||
* @param <T>
|
||||
* @param items
|
||||
* @param array
|
||||
*/
|
||||
public static <T> void toArray(
|
||||
Collection<T> items, Object[] array, boolean convertToPrimitive) {
|
||||
assert (items.size() == array.length);
|
||||
|
||||
int i = 0;
|
||||
for (T t : items) {
|
||||
if (convertToPrimitive) {
|
||||
if (t instanceof Long) {
|
||||
array[i] = ((Long) t).longValue();
|
||||
} else if (t instanceof Integer) {
|
||||
array[i] = ((Integer) t).intValue();
|
||||
} else if (t instanceof Double) {
|
||||
array[i] = ((Double) t).doubleValue();
|
||||
} else if (t instanceof Boolean) {
|
||||
array[i] = ((Boolean) t).booleanValue();
|
||||
}
|
||||
} else {
|
||||
array[i] = t;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public static int[] toIntArray(Collection<Integer> items) {
|
||||
int[] ret = new int[items.size()];
|
||||
int idx = 0;
|
||||
for (Integer i : items) {
|
||||
assert (i != null);
|
||||
ret[idx++] = i.intValue();
|
||||
} // FOR
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put all the values of an Iterator into a List
|
||||
*
|
||||
* @param <T>
|
||||
* @param it
|
||||
* @return
|
||||
*/
|
||||
public static <T> List<T> list(Iterator<T> it) {
|
||||
List<T> list = new ArrayList<T>();
|
||||
CollectionUtil.addAll(list, it);
|
||||
return (list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put all of the values of an Enumeration into a new List
|
||||
*
|
||||
* @param <T>
|
||||
* @param e
|
||||
* @return
|
||||
*/
|
||||
public static <T> List<T> list(Enumeration<T> e) {
|
||||
return (list(iterable(e)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Put all of the values of an Iterable into a new List
|
||||
*
|
||||
* @param <T>
|
||||
* @param it
|
||||
* @return
|
||||
*/
|
||||
public static <T> List<T> list(Iterable<T> it) {
|
||||
return (list(it.iterator()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Put all the values of an Iterator into a Set
|
||||
*
|
||||
* @param <T>
|
||||
* @param it
|
||||
* @return
|
||||
*/
|
||||
public static <T> Set<T> set(Iterator<T> it) {
|
||||
Set<T> set = new HashSet<T>();
|
||||
CollectionUtil.addAll(set, it);
|
||||
return (set);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put all of the values of an Iterable into a new Set
|
||||
*
|
||||
* @param <T>
|
||||
* @param it
|
||||
* @return
|
||||
*/
|
||||
public static <T> Set<T> set(Iterable<T> it) {
|
||||
return (set(it.iterator()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing the string representations of the elements in the collection
|
||||
*
|
||||
* @param <T>
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
public static <T> List<String> toStringList(Collection<T> data) {
|
||||
List<String> ret = new ArrayList<String>();
|
||||
for (T t : data) {
|
||||
ret.add(t.toString());
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set containing the string representations of the elements in the collection
|
||||
*
|
||||
* @param <T>
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
public static <T> Set<String> toStringSet(Collection<T> data) {
|
||||
Set<String> ret = new HashSet<String>();
|
||||
for (T t : data) {
|
||||
ret.add(t.toString());
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a random value from the given Collection
|
||||
*
|
||||
* @param <T>
|
||||
* @param items
|
||||
*/
|
||||
public static <T> T random(Collection<T> items) {
|
||||
return (CollectionUtil.random(items, RANDOM));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a random value from the given Collection
|
||||
*
|
||||
* @param <T>
|
||||
* @param items
|
||||
* @param rand
|
||||
* @return
|
||||
*/
|
||||
public static <T> T random(Collection<T> items, Random rand) {
|
||||
int idx = rand.nextInt(items.size());
|
||||
return (CollectionUtil.get(items, idx));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a random value from the given Iterable
|
||||
*
|
||||
* @param <T>
|
||||
* @param it
|
||||
* @return
|
||||
*/
|
||||
public static <T> T random(Iterable<T> it) {
|
||||
return (CollectionUtil.random(it, RANDOM));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a random value from the given Iterable
|
||||
*
|
||||
* @param <T>
|
||||
* @param it
|
||||
* @param rand
|
||||
* @return
|
||||
*/
|
||||
public static <T> T random(Iterable<T> it, Random rand) {
|
||||
List<T> list = new ArrayList<T>();
|
||||
for (T t : it) {
|
||||
list.add(t);
|
||||
} // FOR
|
||||
return (CollectionUtil.random(list, rand));
|
||||
}
|
||||
|
||||
public static <E extends Enum<?>> Set<E> getAllExcluding(E[] elements, E... excluding) {
|
||||
Set<E> excludeSet = new HashSet<E>();
|
||||
for (E e : excluding) {
|
||||
excludeSet.add(e);
|
||||
}
|
||||
|
||||
Set<E> elementsSet = new HashSet<E>();
|
||||
for (int i = 0; i < elements.length; i++) {
|
||||
if (!excludeSet.contains(elements[i])) {
|
||||
elementsSet.add(elements[i]);
|
||||
}
|
||||
} // FOR
|
||||
return (elementsSet);
|
||||
// Crappy java....
|
||||
// Object new_elements[] = new Object[elements_set.size()];
|
||||
// elements_set.toArray(new_elements);
|
||||
// return ((E[])new_elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all the items in the array to a Collection
|
||||
*
|
||||
* @param <T>
|
||||
* @param data
|
||||
* @param items
|
||||
*/
|
||||
public static <T> Collection<T> addAll(Collection<T> data, T... items) {
|
||||
for (T i : (T[]) items) {
|
||||
data.add(i);
|
||||
}
|
||||
return (data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all the items in the Enumeration into a Collection
|
||||
*
|
||||
* @param <T>
|
||||
* @param data
|
||||
* @param items
|
||||
*/
|
||||
public static <T> Collection<T> addAll(Collection<T> data, Enumeration<T> items) {
|
||||
while (items.hasMoreElements()) {
|
||||
data.add(items.nextElement());
|
||||
} // WHILE
|
||||
return (data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all of the items from the Iterable into the given collection
|
||||
*
|
||||
* @param <T>
|
||||
* @param data
|
||||
* @param items
|
||||
*/
|
||||
public static <T> Collection<T> addAll(Collection<T> data, Iterable<T> items) {
|
||||
return (CollectionUtil.addAll(data, items.iterator()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all of the items from the Iterator into the given collection
|
||||
*
|
||||
* @param <T>
|
||||
* @param data
|
||||
* @param items
|
||||
*/
|
||||
public static <T> Collection<T> addAll(Collection<T> data, Iterator<T> items) {
|
||||
while (items.hasNext()) {
|
||||
data.add(items.next());
|
||||
} // WHILE
|
||||
return (data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <T>
|
||||
* @param <U>
|
||||
* @param map
|
||||
* @return
|
||||
*/
|
||||
public static <T, U extends Comparable<U>> T getGreatest(Map<T, U> map) {
|
||||
T maxKey = null;
|
||||
U maxValue = null;
|
||||
for (Entry<T, U> e : map.entrySet()) {
|
||||
T key = e.getKey();
|
||||
U value = e.getValue();
|
||||
if (maxValue == null || value.compareTo(maxValue) > 0) {
|
||||
maxValue = value;
|
||||
maxKey = key;
|
||||
}
|
||||
} // FOR
|
||||
return (maxKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first item in a Iterable
|
||||
*
|
||||
* @param <T>
|
||||
* @param items
|
||||
* @return
|
||||
*/
|
||||
public static <T> T first(Iterable<T> items) {
|
||||
return (CollectionUtil.get(items, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first item in a Iterator
|
||||
*
|
||||
* @param <T>
|
||||
* @param items
|
||||
* @return
|
||||
*/
|
||||
public static <T> T first(Iterator<T> items) {
|
||||
return (items.hasNext() ? items.next() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first item in an Enumeration
|
||||
*
|
||||
* @param <T>
|
||||
* @param items
|
||||
* @return
|
||||
*/
|
||||
public static <T> T first(Enumeration<T> items) {
|
||||
return (items.hasMoreElements() ? items.nextElement() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ith element of a set. Super lame
|
||||
*
|
||||
* @param <T>
|
||||
* @param items
|
||||
* @param idx
|
||||
* @return
|
||||
*/
|
||||
public static <T> T get(Iterable<T> items, int idx) {
|
||||
if (items instanceof AbstractList<?>) {
|
||||
return ((AbstractList<T>) items).get(idx);
|
||||
} else if (items instanceof ListOrderedSet<?>) {
|
||||
return ((ListOrderedSet<T>) items).get(idx);
|
||||
}
|
||||
int ctr = 0;
|
||||
for (T t : items) {
|
||||
if (ctr++ == idx) {
|
||||
return (t);
|
||||
}
|
||||
}
|
||||
return (null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last item in an Iterable
|
||||
*
|
||||
* @param <T>
|
||||
* @param items
|
||||
* @return
|
||||
*/
|
||||
public static <T> T last(Iterable<T> items) {
|
||||
T last = null;
|
||||
if (items instanceof AbstractList<?>) {
|
||||
AbstractList<T> list = (AbstractList<T>) items;
|
||||
last = (list.isEmpty() ? null : list.get(list.size() - 1));
|
||||
} else {
|
||||
for (T t : items) {
|
||||
last = t;
|
||||
}
|
||||
}
|
||||
return (last);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last item in an array
|
||||
*
|
||||
* @param <T>
|
||||
* @param items
|
||||
* @return
|
||||
*/
|
||||
public static <T> T last(T... items) {
|
||||
if (items != null && items.length > 0) {
|
||||
return (items[items.length - 1]);
|
||||
}
|
||||
return (null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <K>
|
||||
* @param <V>
|
||||
* @param map
|
||||
* @return
|
||||
*/
|
||||
public static <K extends Comparable<?>, V> List<V> getSortedList(
|
||||
SortedMap<K, Collection<V>> map) {
|
||||
List<V> ret = new ArrayList<V>();
|
||||
for (Collection<V> col : map.values()) {
|
||||
ret.addAll(col);
|
||||
} // FOR
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap an Iterable around an Iterator
|
||||
*
|
||||
* @param <T>
|
||||
* @param it
|
||||
* @return
|
||||
*/
|
||||
public static <T> Iterable<T> iterable(final Iterator<T> it) {
|
||||
return (new Iterable<T>() {
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return (it);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static <T> Iterable<T> iterable(final T[] values) {
|
||||
return (new Iterable<T>() {
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return new Iterator<T>() {
|
||||
private int idx = 0;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return (this.idx < values.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
if (this.idx == values.length) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
return values[this.idx++];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap an Iterable around an Enumeration
|
||||
*
|
||||
* @param <T>
|
||||
* @param e
|
||||
* @return
|
||||
*/
|
||||
public static <T> Iterable<T> iterable(final Enumeration<T> e) {
|
||||
return (new Iterable<T>() {
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return new Iterator<T>() {
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return (e.hasMoreElements());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
return (e.nextElement());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static <T> T pop(Collection<T> items) {
|
||||
T t = CollectionUtil.first(items);
|
||||
if (t != null) {
|
||||
boolean ret = items.remove(t);
|
||||
assert (ret);
|
||||
}
|
||||
return (t);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
* OtterTune - FileUtil.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/** @author pavlo */
|
||||
public abstract class FileUtil {
|
||||
private static final Logger LOG = Logger.getLogger(FileUtil.class);
|
||||
|
||||
private static final Pattern EXT_SPLIT = Pattern.compile("\\.");
|
||||
|
||||
/**
|
||||
* Join path components
|
||||
*
|
||||
* @param args
|
||||
* @return
|
||||
*/
|
||||
public static String joinPath(String... args) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (String a : args) {
|
||||
if (a != null && a.length() > 0) {
|
||||
if (!first) {
|
||||
result.append("/");
|
||||
}
|
||||
result.append(a);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a basename for a file, find the next possible filename if this file already exists. For
|
||||
* example, if the file test.res already exists, create a file called, test.1.res
|
||||
*
|
||||
* @param basename
|
||||
* @return
|
||||
*/
|
||||
public static String getNextFilename(String basename) {
|
||||
|
||||
if (!exists(basename)) {
|
||||
return basename;
|
||||
}
|
||||
|
||||
File f = new File(basename);
|
||||
if (f != null && f.isFile()) {
|
||||
String[] parts = EXT_SPLIT.split(basename);
|
||||
|
||||
// Check how many files already exist
|
||||
int counter = 1;
|
||||
String nextName = parts[0] + "." + counter + "." + parts[1];
|
||||
while (exists(nextName)) {
|
||||
++counter;
|
||||
nextName = parts[0] + "." + counter + "." + parts[1];
|
||||
}
|
||||
return nextName;
|
||||
}
|
||||
|
||||
// Should we throw instead??
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean exists(String path) {
|
||||
return (new File(path).exists());
|
||||
}
|
||||
|
||||
public static String realpath(String path) {
|
||||
File f = new File(path);
|
||||
String ret = null;
|
||||
try {
|
||||
ret = f.getCanonicalPath();
|
||||
} catch (Exception ex) {
|
||||
LOG.warn(ex);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
public static String basename(String path) {
|
||||
return (new File(path)).getName();
|
||||
}
|
||||
|
||||
public static String getExtension(File f) {
|
||||
if (f != null && f.isFile()) {
|
||||
String[] parts = EXT_SPLIT.split(f.getName());
|
||||
if (parts.length > 1) {
|
||||
return (parts[parts.length - 1]);
|
||||
}
|
||||
}
|
||||
return (null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create any directory in the list paths if it doesn't exist
|
||||
*
|
||||
* @param paths
|
||||
*/
|
||||
public static void makeDirIfNotExists(String... paths) {
|
||||
for (String p : paths) {
|
||||
if (p == null) {
|
||||
continue;
|
||||
}
|
||||
File f = new File(p);
|
||||
if (f.exists() == false) {
|
||||
f.mkdirs();
|
||||
}
|
||||
} // FOR
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a File handle to a temporary file location
|
||||
*
|
||||
* @param ext the suffix of the filename
|
||||
* @param deleteOnExit whether to delete this file after the JVM exits
|
||||
* @return
|
||||
*/
|
||||
public static File getTempFile(String ext, boolean deleteOnExit) {
|
||||
return getTempFile(null, ext, deleteOnExit);
|
||||
}
|
||||
|
||||
public static File getTempFile(String ext) {
|
||||
return (FileUtil.getTempFile(null, ext, false));
|
||||
}
|
||||
|
||||
public static File getTempFile(String prefix, String suffix, boolean deleteOnExit) {
|
||||
File tempFile;
|
||||
if (suffix != null && suffix.startsWith(".") == false) {
|
||||
suffix = "." + suffix;
|
||||
}
|
||||
if (prefix == null) {
|
||||
prefix = "hstore";
|
||||
}
|
||||
|
||||
try {
|
||||
tempFile = File.createTempFile(prefix, suffix);
|
||||
if (deleteOnExit) {
|
||||
tempFile.deleteOnExit();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
return (tempFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsafely create a temporary directory Yes I said that this was unsafe. I don't care...
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static File getTempDirectory() {
|
||||
final File temp = FileUtil.getTempFile(null);
|
||||
if (!(temp.delete())) {
|
||||
throw new RuntimeException("Could not delete temp file: " + temp.getAbsolutePath());
|
||||
} else if (!(temp.mkdir())) {
|
||||
throw new RuntimeException("Could not create temp directory: " + temp.getAbsolutePath());
|
||||
}
|
||||
return (temp);
|
||||
}
|
||||
|
||||
public static File writeStringToFile(String filePath, String content) throws IOException {
|
||||
return (FileUtil.writeStringToFile(new File(filePath), content));
|
||||
}
|
||||
|
||||
public static File writeStringToFile(File file, String content) throws IOException {
|
||||
FileWriter writer = new FileWriter(file);
|
||||
writer.write(content);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
return (file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the given string to a temporary file Will not delete the file after the JVM exits
|
||||
*
|
||||
* @param content
|
||||
* @return
|
||||
*/
|
||||
public static File writeStringToTempFile(String content) {
|
||||
return (writeStringToTempFile(content, "tmp", false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the given string to a temporary file with the given extension as the suffix Will not
|
||||
* delete the file after the JVM exits
|
||||
*
|
||||
* @param content
|
||||
* @param ext
|
||||
* @return
|
||||
*/
|
||||
public static File writeStringToTempFile(String content, String ext) {
|
||||
return (writeStringToTempFile(content, ext, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the given string to a temporary file with the given extension as the suffix If
|
||||
* deleteOnExit is true, then the file will be removed when the JVM exits
|
||||
*
|
||||
* @param content
|
||||
* @param ext
|
||||
* @param deleteOnExit
|
||||
* @return
|
||||
*/
|
||||
public static File writeStringToTempFile(String content, String ext, boolean deleteOnExit) {
|
||||
File tempFile = FileUtil.getTempFile(ext, deleteOnExit);
|
||||
try {
|
||||
FileUtil.writeStringToFile(tempFile, content);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return tempFile;
|
||||
}
|
||||
|
||||
public static String readFile(File path) {
|
||||
LOG.debug(path);
|
||||
return (readFile(path.getAbsolutePath()));
|
||||
}
|
||||
|
||||
public static String readFile(String path) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
try {
|
||||
BufferedReader in = FileUtil.getReader(path);
|
||||
while (in.ready()) {
|
||||
buffer.append(in.readLine()).append("\n");
|
||||
} // WHILE
|
||||
in.close();
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException("Failed to read file contents from '" + path + "'", ex);
|
||||
}
|
||||
return (buffer.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a BufferedReader for the given input path Can handle both gzip and plain text files
|
||||
*
|
||||
* @param path
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static BufferedReader getReader(String path) throws IOException {
|
||||
return (FileUtil.getReader(new File(path)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a BufferedReader for the given input path Can handle both gzip and plain text files
|
||||
*
|
||||
* @param file
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static BufferedReader getReader(File file) throws IOException {
|
||||
if (!file.exists()) {
|
||||
throw new IOException("The file '" + file + "' does not exist");
|
||||
}
|
||||
|
||||
BufferedReader in = null;
|
||||
if (file.getPath().endsWith(".gz")) {
|
||||
FileInputStream fin = new FileInputStream(file);
|
||||
GZIPInputStream gzis = new GZIPInputStream(fin);
|
||||
in = new BufferedReader(new InputStreamReader(gzis));
|
||||
LOG.debug("Reading in the zipped contents of '" + file.getName() + "'");
|
||||
} else {
|
||||
in = new BufferedReader(new FileReader(file));
|
||||
LOG.debug("Reading in the contents of '" + file.getName() + "'");
|
||||
}
|
||||
return (in);
|
||||
}
|
||||
|
||||
public static byte[] readBytesFromFile(String path) throws IOException {
|
||||
File file = new File(path);
|
||||
FileInputStream in = new FileInputStream(file);
|
||||
|
||||
// Create the byte array to hold the data
|
||||
long length = file.length();
|
||||
byte[] bytes = new byte[(int) length];
|
||||
|
||||
LOG.debug("Reading in the contents of '" + file.getAbsolutePath() + "'");
|
||||
|
||||
// Read in the bytes
|
||||
int offset = 0;
|
||||
int numRead = 0;
|
||||
while ((offset < bytes.length)
|
||||
&& ((numRead = in.read(bytes, offset, bytes.length - offset)) >= 0)) {
|
||||
offset += numRead;
|
||||
} // WHILE
|
||||
if (offset < bytes.length) {
|
||||
throw new IOException("Failed to read the entire contents of '" + file.getName() + "'");
|
||||
}
|
||||
in.close();
|
||||
return (bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the path to a directory below our current location in the source tree Throws a
|
||||
* RuntimeException if we go beyond our repository checkout
|
||||
*
|
||||
* @param dirName
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static File findDirectory(String dirName) throws IOException {
|
||||
return (FileUtil.find(dirName, new File(".").getCanonicalFile(), true).getCanonicalFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the path to a directory below our current location in the source tree Throws a
|
||||
* RuntimeException if we go beyond our repository checkout
|
||||
*
|
||||
* @param dirName
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static File findFile(String fileName) throws IOException {
|
||||
return (FileUtil.find(fileName, new File(".").getCanonicalFile(), false).getCanonicalFile());
|
||||
}
|
||||
|
||||
private static final File find(String name, File current, boolean isdir) throws IOException {
|
||||
LOG.debug("Find Current Location = " + current);
|
||||
boolean hasSvn = false;
|
||||
for (File file : current.listFiles()) {
|
||||
if (file.getCanonicalPath().endsWith(File.separator + name) && file.isDirectory() == isdir) {
|
||||
return (file);
|
||||
// Make sure that we don't go to far down...
|
||||
} else if (file.getCanonicalPath().endsWith(File.separator + ".svn")) {
|
||||
hasSvn = true;
|
||||
}
|
||||
} // FOR
|
||||
// If we didn't see an .svn directory, then we went too far down
|
||||
if (!hasSvn) {
|
||||
throw new RuntimeException(
|
||||
"Unable to find directory '" + name + "' [last_dir=" + current.getAbsolutePath() + "]");
|
||||
}
|
||||
File next = new File(current.getCanonicalPath() + File.separator + "");
|
||||
return (FileUtil.find(name, next, isdir));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all the files in a directory whose name starts with the provided prefix
|
||||
*
|
||||
* @param dir
|
||||
* @param filePrefix
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static List<File> getFilesInDirectory(final File dir, final String filePrefix)
|
||||
throws IOException {
|
||||
assert (dir.isDirectory()) : "Invalid search directory path: " + dir;
|
||||
FilenameFilter filter =
|
||||
new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File dir, String name) {
|
||||
return (name.startsWith(filePrefix));
|
||||
}
|
||||
};
|
||||
return (Arrays.asList(dir.listFiles(filter)));
|
||||
}
|
||||
|
||||
public static String getAbsPath(String dirPath) {
|
||||
String current = null;
|
||||
try {
|
||||
current = new java.io.File(dirPath).getCanonicalPath();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return current;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* OtterTune - JSONSerializable.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller.util;
|
||||
|
||||
import com.controller.util.json.JSONException;
|
||||
import com.controller.util.json.JSONObject;
|
||||
import com.controller.util.json.JSONString;
|
||||
import com.controller.util.json.JSONStringer;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface JSONSerializable extends JSONString {
|
||||
public void save(String outputPath) throws IOException;
|
||||
|
||||
public void load(String inputPath) throws IOException;
|
||||
|
||||
public void toJSON(JSONStringer stringer) throws JSONException;
|
||||
|
||||
public void fromJSON(JSONObject jsonObject) throws JSONException;
|
||||
}
|
||||
@@ -0,0 +1,800 @@
|
||||
/*
|
||||
* OtterTune - JSONUtil.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller.util;
|
||||
|
||||
import com.controller.util.json.JSONArray;
|
||||
import com.controller.util.json.JSONException;
|
||||
import com.controller.util.json.JSONObject;
|
||||
import com.controller.util.json.JSONStringer;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/** @author pavlo */
|
||||
public abstract class JSONUtil {
|
||||
private static final Logger LOG = Logger.getLogger(JSONUtil.class.getName());
|
||||
|
||||
private static final String JSON_CLASS_SUFFIX = "_class";
|
||||
private static final Map<Class<?>, Field[]> SERIALIZABLE_FIELDS =
|
||||
new HashMap<Class<?>, Field[]>();
|
||||
|
||||
/**
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static Field[] getSerializableFields(Class<?> clazz, String... fieldsToExclude) {
|
||||
Field[] ret = SERIALIZABLE_FIELDS.get(clazz);
|
||||
if (ret == null) {
|
||||
Collection<String> exclude = CollectionUtil.addAll(new HashSet<String>(), fieldsToExclude);
|
||||
synchronized (SERIALIZABLE_FIELDS) {
|
||||
ret = SERIALIZABLE_FIELDS.get(clazz);
|
||||
if (ret == null) {
|
||||
List<Field> fields = new ArrayList<Field>();
|
||||
for (Field f : clazz.getFields()) {
|
||||
int modifiers = f.getModifiers();
|
||||
if (Modifier.isTransient(modifiers) == false
|
||||
&& Modifier.isPublic(modifiers) == true
|
||||
&& Modifier.isStatic(modifiers) == false
|
||||
&& exclude.contains(f.getName()) == false) {
|
||||
fields.add(f);
|
||||
}
|
||||
} // FOR
|
||||
ret = fields.toArray(new Field[0]);
|
||||
SERIALIZABLE_FIELDS.put(clazz, ret);
|
||||
}
|
||||
} // SYNCH
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON Pretty Print
|
||||
*
|
||||
* @param json
|
||||
* @return
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static String format(String json) {
|
||||
try {
|
||||
return (JSONUtil.format(new JSONObject(json)));
|
||||
} catch (RuntimeException ex) {
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON Pretty Print
|
||||
*
|
||||
* @param <T>
|
||||
* @param object
|
||||
* @return
|
||||
*/
|
||||
public static <T extends JSONSerializable> String format(T object) {
|
||||
JSONStringer stringer = new JSONStringer();
|
||||
try {
|
||||
if (object instanceof JSONObject) {
|
||||
return ((JSONObject) object).toString(2);
|
||||
}
|
||||
stringer.object();
|
||||
object.toJSON(stringer);
|
||||
stringer.endObject();
|
||||
} catch (JSONException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
return (JSONUtil.format(stringer.toString()));
|
||||
}
|
||||
|
||||
public static String format(JSONObject o) {
|
||||
try {
|
||||
return o.toString(1);
|
||||
} catch (JSONException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <T>
|
||||
* @param object
|
||||
* @return
|
||||
*/
|
||||
public static String toJSONString(Object object) {
|
||||
JSONStringer stringer = new JSONStringer();
|
||||
try {
|
||||
if (object instanceof JSONSerializable) {
|
||||
stringer.object();
|
||||
((JSONSerializable) object).toJSON(stringer);
|
||||
stringer.endObject();
|
||||
} else if (object != null) {
|
||||
Class<?> clazz = object.getClass();
|
||||
// stringer.key(clazz.getSimpleName());
|
||||
JSONUtil.writeFieldValue(stringer, clazz, object);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return (stringer.toString());
|
||||
}
|
||||
|
||||
public static <T extends JSONSerializable> T fromJSONString(T t, String json) {
|
||||
try {
|
||||
JSONObject jsonObject = new JSONObject(json);
|
||||
t.fromJSON(jsonObject);
|
||||
} catch (JSONException ex) {
|
||||
throw new RuntimeException("Failed to deserialize object " + t, ex);
|
||||
}
|
||||
return (t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the contents of a JSONSerializable object out to a file on the local disk
|
||||
*
|
||||
* @param <T>
|
||||
* @param object
|
||||
* @param outputPath
|
||||
* @throws IOException
|
||||
*/
|
||||
public static <T extends JSONSerializable> void save(T object, String outputPath)
|
||||
throws IOException {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(
|
||||
"Writing out contents of "
|
||||
+ object.getClass().getSimpleName()
|
||||
+ " to '"
|
||||
+ outputPath
|
||||
+ "'");
|
||||
}
|
||||
File f = new File(outputPath);
|
||||
try {
|
||||
FileUtil.makeDirIfNotExists(f.getParent());
|
||||
String json = object.toJSONString();
|
||||
FileUtil.writeStringToFile(f, format(json));
|
||||
} catch (Exception ex) {
|
||||
LOG.error(
|
||||
"Failed to serialize the " + object.getClass().getSimpleName() + " file '" + f + "'", ex);
|
||||
throw new IOException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load in a JSONSerialable stored in a file
|
||||
*
|
||||
* @param <T>
|
||||
* @param object
|
||||
* @param inputPath
|
||||
* @throws Exception
|
||||
*/
|
||||
public static <T extends JSONSerializable> void load(T object, String inputPath)
|
||||
throws IOException {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(
|
||||
"Loading in serialized "
|
||||
+ object.getClass().getSimpleName()
|
||||
+ " from '"
|
||||
+ inputPath
|
||||
+ "'");
|
||||
}
|
||||
String contents = FileUtil.readFile(inputPath);
|
||||
if (contents.isEmpty()) {
|
||||
throw new IOException(
|
||||
"The " + object.getClass().getSimpleName() + " file '" + inputPath + "' is empty");
|
||||
}
|
||||
try {
|
||||
object.fromJSON(new JSONObject(contents));
|
||||
} catch (Exception ex) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.error(
|
||||
"Failed to deserialize the "
|
||||
+ object.getClass().getSimpleName()
|
||||
+ " from file '"
|
||||
+ inputPath
|
||||
+ "'",
|
||||
ex);
|
||||
}
|
||||
throw new IOException(ex);
|
||||
}
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("The loading of the " + object.getClass().getSimpleName() + " is complete");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given Enum, write out the contents of the corresponding field to the JSONObject We assume
|
||||
* that the given object has matching fields that correspond to the Enum members, except that
|
||||
* their names are lower case.
|
||||
*
|
||||
* @param <E>
|
||||
* @param <T>
|
||||
* @param stringer
|
||||
* @param object
|
||||
* @param baseClass
|
||||
* @param members
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static <E extends Enum<?>, T> void fieldsToJSON(
|
||||
JSONStringer stringer, T object, Class<? extends T> baseClass, E[] members)
|
||||
throws JSONException {
|
||||
try {
|
||||
fieldsToJSON(
|
||||
stringer, object, baseClass, ClassUtil.getFieldsFromMembersEnum(baseClass, members));
|
||||
} catch (NoSuchFieldException ex) {
|
||||
throw new JSONException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given list of Fields, write out the contents of the corresponding field to the JSONObject
|
||||
* The each of the JSONObject's elements will be the upper case version of the Field's name
|
||||
*
|
||||
* @param <T>
|
||||
* @param stringer
|
||||
* @param object
|
||||
* @param baseClass
|
||||
* @param fields
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static <T> void fieldsToJSON(
|
||||
JSONStringer stringer, T object, Class<? extends T> baseClass, Field[] fields)
|
||||
throws JSONException {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Serializing out " + fields.length + " elements for " + baseClass.getSimpleName());
|
||||
}
|
||||
for (Field f : fields) {
|
||||
String jsonKey = f.getName().toUpperCase();
|
||||
stringer.key(jsonKey);
|
||||
|
||||
try {
|
||||
Class<?> fclass = f.getType();
|
||||
Object fvalue = f.get(object);
|
||||
|
||||
// Null
|
||||
if (fvalue == null) {
|
||||
writeFieldValue(stringer, fclass, fvalue);
|
||||
// Maps
|
||||
} else if (fvalue instanceof Map) {
|
||||
writeFieldValue(stringer, fclass, fvalue);
|
||||
// Everything else
|
||||
} else {
|
||||
writeFieldValue(stringer, fclass, fvalue);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new JSONException(ex);
|
||||
}
|
||||
} // FOR
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stringer
|
||||
* @param fieldClass
|
||||
* @param fieldValue
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static void writeFieldValue(
|
||||
JSONStringer stringer, Class<?> fieldClass, Object fieldValue) throws JSONException {
|
||||
// Null
|
||||
if (fieldValue == null) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("writeNullFieldValue(" + fieldClass + ", " + fieldValue + ")");
|
||||
}
|
||||
stringer.value(null);
|
||||
|
||||
// Collections
|
||||
} else if (ClassUtil.getInterfaces(fieldClass).contains(Collection.class)) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("writeCollectionFieldValue(" + fieldClass + ", " + fieldValue + ")");
|
||||
}
|
||||
stringer.array();
|
||||
for (Object value : (Collection<?>) fieldValue) {
|
||||
if (value == null) {
|
||||
stringer.value(null);
|
||||
} else {
|
||||
writeFieldValue(stringer, value.getClass(), value);
|
||||
}
|
||||
} // FOR
|
||||
stringer.endArray();
|
||||
|
||||
// Maps
|
||||
} else if (fieldValue instanceof Map) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("writeMapFieldValue(" + fieldClass + ", " + fieldValue + ")");
|
||||
}
|
||||
stringer.object();
|
||||
for (Entry<?, ?> e : ((Map<?, ?>) fieldValue).entrySet()) {
|
||||
// We can handle null keys
|
||||
String keyValue = null;
|
||||
if (e.getKey() != null) {
|
||||
// deserialize it on the other side
|
||||
Class<?> keyClass = e.getKey().getClass();
|
||||
keyValue = makePrimitiveValue(keyClass, e.getKey()).toString();
|
||||
}
|
||||
stringer.key(keyValue);
|
||||
|
||||
// We can also handle null values. Where is your god now???
|
||||
if (e.getValue() == null) {
|
||||
stringer.value(null);
|
||||
} else {
|
||||
writeFieldValue(stringer, e.getValue().getClass(), e.getValue());
|
||||
}
|
||||
} // FOR
|
||||
stringer.endObject();
|
||||
|
||||
// Primitive
|
||||
} else {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("writePrimitiveFieldValue(" + fieldClass + ", " + fieldValue + ")");
|
||||
}
|
||||
stringer.value(makePrimitiveValue(fieldClass, fieldValue));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data from the given JSONObject and populate the given Map
|
||||
*
|
||||
* @param jsonObject
|
||||
* @param map
|
||||
* @param innerClasses
|
||||
* @throws Exception
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected static void readMapField(
|
||||
final JSONObject jsonObject, final Map map, final Stack<Class> innerClasses)
|
||||
throws Exception {
|
||||
Class<?> keyClass = innerClasses.pop();
|
||||
Class<?> valClass = innerClasses.pop();
|
||||
Collection<Class<?>> valInterfaces = ClassUtil.getInterfaces(valClass);
|
||||
|
||||
assert (jsonObject != null);
|
||||
for (String jsonKey : CollectionUtil.iterable(jsonObject.keys())) {
|
||||
final Stack<Class> nextInnerClasses = new Stack<Class>();
|
||||
nextInnerClasses.addAll(innerClasses);
|
||||
assert (nextInnerClasses.equals(innerClasses));
|
||||
|
||||
// KEY
|
||||
Object key = JSONUtil.getPrimitiveValue(jsonKey, keyClass);
|
||||
|
||||
// VALUE
|
||||
Object object = null;
|
||||
if (jsonObject.isNull(jsonKey)) {
|
||||
// Nothing...
|
||||
} else if (valInterfaces.contains(List.class)) {
|
||||
object = new ArrayList();
|
||||
readCollectionField(
|
||||
jsonObject.getJSONArray(jsonKey), (Collection) object, nextInnerClasses);
|
||||
} else if (valInterfaces.contains(Set.class)) {
|
||||
object = new HashSet();
|
||||
readCollectionField(
|
||||
jsonObject.getJSONArray(jsonKey), (Collection) object, nextInnerClasses);
|
||||
} else if (valInterfaces.contains(Map.class)) {
|
||||
object = new HashMap();
|
||||
readMapField(jsonObject.getJSONObject(jsonKey), (Map) object, nextInnerClasses);
|
||||
} else {
|
||||
String jsonString = jsonObject.getString(jsonKey);
|
||||
try {
|
||||
object = JSONUtil.getPrimitiveValue(jsonString, valClass);
|
||||
} catch (Exception ex) {
|
||||
System.err.println("val_interfaces: " + valInterfaces);
|
||||
LOG.error(
|
||||
"Failed to deserialize value '"
|
||||
+ jsonString
|
||||
+ "' from inner map key '"
|
||||
+ jsonKey
|
||||
+ "'");
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
map.put(key, object);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data from the given JSONArray and populate the given Collection
|
||||
*
|
||||
* @param jsonArray
|
||||
* @param collection
|
||||
* @param innerClasses
|
||||
* @throws Exception
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected static void readCollectionField(
|
||||
final JSONArray jsonArray, final Collection collection, final Stack<Class> innerClasses)
|
||||
throws Exception {
|
||||
// We need to figure out what the inner type of the collection is
|
||||
// If it's a Collection or a Map, then we need to instantiate it before
|
||||
// we can call readFieldValue() again for it.
|
||||
Class innerClass = innerClasses.pop();
|
||||
Collection<Class<?>> innerInterfaces = ClassUtil.getInterfaces(innerClass);
|
||||
|
||||
for (int i = 0, cnt = jsonArray.length(); i < cnt; i++) {
|
||||
final Stack<Class> nextInnerClasses = new Stack<Class>();
|
||||
nextInnerClasses.addAll(innerClasses);
|
||||
assert (nextInnerClasses.equals(innerClasses));
|
||||
Object value = null;
|
||||
|
||||
// Null
|
||||
if (jsonArray.isNull(i)) {
|
||||
value = null;
|
||||
// Lists
|
||||
} else if (innerInterfaces.contains(List.class)) {
|
||||
value = new ArrayList();
|
||||
readCollectionField(jsonArray.getJSONArray(i), (Collection) value, nextInnerClasses);
|
||||
// Sets
|
||||
} else if (innerInterfaces.contains(Set.class)) {
|
||||
value = new HashSet();
|
||||
readCollectionField(jsonArray.getJSONArray(i), (Collection) value, nextInnerClasses);
|
||||
// Maps
|
||||
} else if (innerInterfaces.contains(Map.class)) {
|
||||
value = new HashMap();
|
||||
readMapField(jsonArray.getJSONObject(i), (Map) value, nextInnerClasses);
|
||||
// Values
|
||||
} else {
|
||||
String jsonString = jsonArray.getString(i);
|
||||
value = JSONUtil.getPrimitiveValue(jsonString, innerClass);
|
||||
}
|
||||
collection.add(value);
|
||||
} // FOR
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jsonObject
|
||||
* @param jsonKey
|
||||
* @param fieldHandle
|
||||
* @param object
|
||||
* @throws Exception
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void readFieldValue(
|
||||
final JSONObject jsonObject, final String jsonKey, Field fieldHandle, Object object)
|
||||
throws Exception {
|
||||
assert (jsonObject.has(jsonKey)) : "No entry exists for '" + jsonKey + "'";
|
||||
Class<?> fieldClass = fieldHandle.getType();
|
||||
Object fieldObject = fieldHandle.get(object);
|
||||
// String field_name = field_handle.getName();
|
||||
|
||||
// Null
|
||||
if (jsonObject.isNull(jsonKey)) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Field " + jsonKey + " is null");
|
||||
}
|
||||
fieldHandle.set(object, null);
|
||||
|
||||
// Collections
|
||||
} else if (ClassUtil.getInterfaces(fieldClass).contains(Collection.class)) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Field " + jsonKey + " is a collection");
|
||||
}
|
||||
assert (fieldObject != null);
|
||||
Stack<Class> innerClasses = new Stack<Class>();
|
||||
innerClasses.addAll(ClassUtil.getGenericTypes(fieldHandle));
|
||||
Collections.reverse(innerClasses);
|
||||
|
||||
JSONArray jsonInner = jsonObject.getJSONArray(jsonKey);
|
||||
if (jsonInner == null) {
|
||||
throw new JSONException("No array exists for '" + jsonKey + "'");
|
||||
}
|
||||
readCollectionField(jsonInner, (Collection) fieldObject, innerClasses);
|
||||
|
||||
// Maps
|
||||
} else if (fieldObject instanceof Map) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Field " + jsonKey + " is a map");
|
||||
}
|
||||
assert (fieldObject != null);
|
||||
Stack<Class> innerClasses = new Stack<Class>();
|
||||
innerClasses.addAll(ClassUtil.getGenericTypes(fieldHandle));
|
||||
Collections.reverse(innerClasses);
|
||||
|
||||
JSONObject jsonInner = jsonObject.getJSONObject(jsonKey);
|
||||
if (jsonInner == null) {
|
||||
throw new JSONException("No object exists for '" + jsonKey + "'");
|
||||
}
|
||||
readMapField(jsonInner, (Map) fieldObject, innerClasses);
|
||||
|
||||
// Everything else...
|
||||
} else {
|
||||
Class explicitFieldClass = JSONUtil.getClassForField(jsonObject, jsonKey);
|
||||
if (explicitFieldClass != null) {
|
||||
fieldClass = explicitFieldClass;
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(
|
||||
"Found explict field class " + fieldClass.getSimpleName() + " for " + jsonKey);
|
||||
}
|
||||
}
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Field " + jsonKey + " is primitive type " + fieldClass.getSimpleName());
|
||||
}
|
||||
Object value = JSONUtil.getPrimitiveValue(jsonObject.getString(jsonKey), fieldClass);
|
||||
fieldHandle.set(object, value);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Set field " + jsonKey + " to '" + value + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For the given enum, load in the values from the JSON object into the current object This will
|
||||
* throw errors if a field is missing
|
||||
*
|
||||
* @param <E>
|
||||
* @param jsonObject
|
||||
* @param members
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static <E extends Enum<?>, T> void fieldsFromJSON(
|
||||
JSONObject jsonObject, T object, Class<? extends T> baseClass, E... members)
|
||||
throws JSONException {
|
||||
JSONUtil.fieldsFromJSON(jsonObject, object, baseClass, false, members);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the given enum, load in the values from the JSON object into the current object If
|
||||
* ignore_missing is false, then JSONUtil will not throw an error if a field is missing
|
||||
*
|
||||
* @param <E>
|
||||
* @param <T>
|
||||
* @param jsonObject
|
||||
* @param object
|
||||
* @param baseClass
|
||||
* @param ignoreMissing
|
||||
* @param members
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static <E extends Enum<?>, T> void fieldsFromJSON(
|
||||
JSONObject jsonObject,
|
||||
T object,
|
||||
Class<? extends T> baseClass,
|
||||
boolean ignoreMissing,
|
||||
E... members)
|
||||
throws JSONException {
|
||||
try {
|
||||
fieldsFromJSON(
|
||||
jsonObject,
|
||||
object,
|
||||
baseClass,
|
||||
ignoreMissing,
|
||||
ClassUtil.getFieldsFromMembersEnum(baseClass, members));
|
||||
} catch (NoSuchFieldException ex) {
|
||||
throw new JSONException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For the given list of Fields, load in the values from the JSON object into the current object
|
||||
* If ignore_missing is false, then JSONUtil will not throw an error if a field is missing
|
||||
*
|
||||
* @param <E>
|
||||
* @param <T>
|
||||
* @param jsonObject
|
||||
* @param object
|
||||
* @param baseClass
|
||||
* @param ignoreMissing
|
||||
* @param fields
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static <E extends Enum<?>, T> void fieldsFromJSON(
|
||||
JSONObject jsonObject,
|
||||
T object,
|
||||
Class<? extends T> baseClass,
|
||||
boolean ignoreMissing,
|
||||
Field... fields)
|
||||
throws JSONException {
|
||||
for (Field fieldHandle : fields) {
|
||||
String jsonKey = fieldHandle.getName().toUpperCase();
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Retreiving value for field '" + jsonKey + "'");
|
||||
}
|
||||
|
||||
if (!jsonObject.has(jsonKey)) {
|
||||
String msg =
|
||||
"JSONObject for "
|
||||
+ baseClass.getSimpleName()
|
||||
+ " does not have key '"
|
||||
+ jsonKey
|
||||
+ "': "
|
||||
+ CollectionUtil.list(jsonObject.keys());
|
||||
if (ignoreMissing) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.warn(msg);
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
throw new JSONException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
readFieldValue(jsonObject, jsonKey, fieldHandle, object);
|
||||
} catch (Exception ex) {
|
||||
// System.err.println(field_class + ": " + ClassUtil.getSuperClasses(field_class));
|
||||
LOG.error(
|
||||
"Unable to deserialize field '" + jsonKey + "' from " + baseClass.getSimpleName(),
|
||||
ex);
|
||||
throw new JSONException(ex);
|
||||
}
|
||||
} // FOR
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the class of a field if it was stored in the JSONObject along with the value If there is
|
||||
* no class information, then this will return null
|
||||
*
|
||||
* @param jsonObject
|
||||
* @param jsonKey
|
||||
* @return
|
||||
* @throws JSONException
|
||||
*/
|
||||
private static Class<?> getClassForField(JSONObject jsonObject, String jsonKey)
|
||||
throws JSONException {
|
||||
Class<?> fieldClass = null;
|
||||
// Check whether we also stored the class
|
||||
if (jsonObject.has(jsonKey + JSON_CLASS_SUFFIX)) {
|
||||
try {
|
||||
fieldClass = ClassUtil.getClass(jsonObject.getString(jsonKey + JSON_CLASS_SUFFIX));
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Failed to include class for field '" + jsonKey + "'", ex);
|
||||
throw new JSONException(ex);
|
||||
}
|
||||
}
|
||||
return (fieldClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the proper serialization string for the given value
|
||||
*
|
||||
* @param fieldClass
|
||||
* @param fieldValue
|
||||
* @return
|
||||
*/
|
||||
private static Object makePrimitiveValue(Class<?> fieldClass, Object fieldValue) {
|
||||
Object value = null;
|
||||
|
||||
// Class
|
||||
if (fieldClass.equals(Class.class)) {
|
||||
value = ((Class<?>) fieldValue).getName();
|
||||
// JSONSerializable
|
||||
} else if (ClassUtil.getInterfaces(fieldClass).contains(JSONSerializable.class)) {
|
||||
// Just return the value back. The JSON library will take care of it
|
||||
// System.err.println(field_class + ": " + field_value);
|
||||
value = fieldValue;
|
||||
// Everything else
|
||||
} else {
|
||||
value = fieldValue; // .toString();
|
||||
}
|
||||
return (value);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the given JSON string, figure out what kind of object it is and return it
|
||||
*
|
||||
* @param jsonValue
|
||||
* @param fieldClass
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static Object getPrimitiveValue(String jsonValue, Class<?> fieldClass) throws Exception {
|
||||
Object value = null;
|
||||
|
||||
// Class
|
||||
if (fieldClass.equals(Class.class)) {
|
||||
value = ClassUtil.getClass(jsonValue);
|
||||
if (value == null) {
|
||||
throw new JSONException("Failed to get class from '" + jsonValue + "'");
|
||||
}
|
||||
// Enum
|
||||
} else if (fieldClass.isEnum()) {
|
||||
for (Object o : fieldClass.getEnumConstants()) {
|
||||
Enum<?> e = (Enum<?>) o;
|
||||
if (jsonValue.equals(e.name())) {
|
||||
return (e);
|
||||
}
|
||||
} // FOR
|
||||
throw new JSONException(
|
||||
"Invalid enum value '"
|
||||
+ jsonValue
|
||||
+ "': "
|
||||
+ Arrays.toString(fieldClass.getEnumConstants()));
|
||||
// JSONSerializable
|
||||
} else if (ClassUtil.getInterfaces(fieldClass).contains(JSONSerializable.class)) {
|
||||
value = ClassUtil.newInstance(fieldClass, null, null);
|
||||
((JSONSerializable) value).fromJSON(new JSONObject(jsonValue));
|
||||
// Boolean
|
||||
} else if (fieldClass.equals(Boolean.class) || fieldClass.equals(boolean.class)) {
|
||||
// We have to use field_class.equals() because the value may be null
|
||||
value = Boolean.parseBoolean(jsonValue);
|
||||
// Short
|
||||
} else if (fieldClass.equals(Short.class) || fieldClass.equals(short.class)) {
|
||||
value = Short.parseShort(jsonValue);
|
||||
// Integer
|
||||
} else if (fieldClass.equals(Integer.class) || fieldClass.equals(int.class)) {
|
||||
value = Integer.parseInt(jsonValue);
|
||||
// Long
|
||||
} else if (fieldClass.equals(Long.class) || fieldClass.equals(long.class)) {
|
||||
value = Long.parseLong(jsonValue);
|
||||
// Float
|
||||
} else if (fieldClass.equals(Float.class) || fieldClass.equals(float.class)) {
|
||||
value = Float.parseFloat(jsonValue);
|
||||
// Double
|
||||
} else if (fieldClass.equals(Double.class) || fieldClass.equals(double.class)) {
|
||||
value = Double.parseDouble(jsonValue);
|
||||
// String
|
||||
} else if (fieldClass.equals(String.class)) {
|
||||
value = jsonValue.toString();
|
||||
}
|
||||
return (value);
|
||||
}
|
||||
|
||||
public static Class<?> getPrimitiveType(String jsonValue) {
|
||||
Object value = null;
|
||||
|
||||
// CHECKSTYLE:OFF
|
||||
// Class
|
||||
try {
|
||||
value = ClassUtil.getClass(jsonValue);
|
||||
if (value != null) return (Class.class);
|
||||
} catch (Throwable ex) {
|
||||
} // IGNORE
|
||||
|
||||
// Short
|
||||
try {
|
||||
value = Short.parseShort(jsonValue);
|
||||
return (Short.class);
|
||||
} catch (NumberFormatException ex) {
|
||||
} // IGNORE
|
||||
|
||||
// Integer
|
||||
try {
|
||||
value = Integer.parseInt(jsonValue);
|
||||
return (Integer.class);
|
||||
} catch (NumberFormatException ex) {
|
||||
} // IGNORE
|
||||
|
||||
// Long
|
||||
try {
|
||||
value = Long.parseLong(jsonValue);
|
||||
return (Long.class);
|
||||
} catch (NumberFormatException ex) {
|
||||
} // IGNORE
|
||||
|
||||
// Float
|
||||
try {
|
||||
value = Float.parseFloat(jsonValue);
|
||||
return (Float.class);
|
||||
} catch (NumberFormatException ex) {
|
||||
} // IGNORE
|
||||
|
||||
// Double
|
||||
try {
|
||||
value = Double.parseDouble(jsonValue);
|
||||
return (Double.class);
|
||||
} catch (NumberFormatException ex) {
|
||||
} // IGNORE
|
||||
// CHECKSTYLE:ON
|
||||
|
||||
// Boolean
|
||||
if (jsonValue.equalsIgnoreCase("true") || jsonValue.equalsIgnoreCase("false")) {
|
||||
return (Boolean.class);
|
||||
}
|
||||
|
||||
// Default: String
|
||||
return (String.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* OtterTune - ValidationUtils.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller.util;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.github.fge.jackson.JsonLoader;
|
||||
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
|
||||
import com.github.fge.jsonschema.core.report.ProcessingMessage;
|
||||
import com.github.fge.jsonschema.core.report.ProcessingReport;
|
||||
import com.github.fge.jsonschema.main.JsonSchema;
|
||||
import com.github.fge.jsonschema.main.JsonSchemaFactory;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
public class ValidationUtils {
|
||||
|
||||
public static final String JSON_V4_SCHEMA_IDENTIFIER = "http://json-schema.org/draft-04/schema#";
|
||||
public static final String JSON_SCHEMA_IDENTIFIER_ELEMENT = "$schema";
|
||||
|
||||
public static JsonNode getJsonNode(String jsonText) throws IOException {
|
||||
return JsonLoader.fromString(jsonText);
|
||||
} // getJsonNode(text) ends
|
||||
|
||||
public static JsonNode getJsonNode(File jsonFile) throws IOException {
|
||||
return JsonLoader.fromFile(jsonFile);
|
||||
} // getJsonNode(File) ends
|
||||
|
||||
public static JsonNode getJsonNode(URL url) throws IOException {
|
||||
return JsonLoader.fromURL(url);
|
||||
} // getJsonNode(URL) ends
|
||||
|
||||
public static JsonNode getJsonNodeFromResource(String resource) throws IOException {
|
||||
return JsonLoader.fromResource(resource);
|
||||
} // getJsonNode(Resource) ends
|
||||
|
||||
public static JsonSchema getSchemaNode(String schemaText)
|
||||
throws IOException, ProcessingException {
|
||||
final JsonNode schemaNode = getJsonNode(schemaText);
|
||||
return getSchemaNodeHelper(schemaNode);
|
||||
} // getSchemaNode(text) ends
|
||||
|
||||
public static JsonSchema getSchemaNode(File schemaFile) throws IOException, ProcessingException {
|
||||
final JsonNode schemaNode = getJsonNode(schemaFile);
|
||||
return getSchemaNodeHelper(schemaNode);
|
||||
} // getSchemaNode(File) ends
|
||||
|
||||
public static JsonSchema getSchemaNode(URL schemaFile) throws IOException, ProcessingException {
|
||||
final JsonNode schemaNode = getJsonNode(schemaFile);
|
||||
return getSchemaNodeHelper(schemaNode);
|
||||
} // getSchemaNode(URL) ends
|
||||
|
||||
public static JsonSchema getSchemaNodeFromResource(String resource)
|
||||
throws IOException, ProcessingException {
|
||||
final JsonNode schemaNode = getJsonNodeFromResource(resource);
|
||||
return getSchemaNodeHelper(schemaNode);
|
||||
} // getSchemaNode() ends
|
||||
|
||||
public static void validateJson(String schemaText, String jsonText)
|
||||
throws IOException, ProcessingException {
|
||||
final JsonSchema schemaNode = getSchemaNode(schemaText);
|
||||
final JsonNode jsonNode = getJsonNode(jsonText);
|
||||
validateJson(schemaNode, jsonNode);
|
||||
} // validateJson(text) ends
|
||||
|
||||
public static void validateJson(File schemaFile, File jsonFile)
|
||||
throws IOException, ProcessingException {
|
||||
final JsonSchema schemaNode = getSchemaNode(schemaFile);
|
||||
final JsonNode jsonNode = getJsonNode(jsonFile);
|
||||
validateJson(schemaNode, jsonNode);
|
||||
} // validateJson(File) ends
|
||||
|
||||
public static void validateJson(JsonSchema jsonSchemaNode, JsonNode jsonNode)
|
||||
throws ProcessingException {
|
||||
ProcessingReport report = jsonSchemaNode.validate(jsonNode);
|
||||
if (!report.isSuccess()) {
|
||||
for (ProcessingMessage processingMessage : report) {
|
||||
throw new ProcessingException(processingMessage);
|
||||
}
|
||||
}
|
||||
} // validateJson(Node) ends
|
||||
|
||||
public static void validateJson(URL schemaDocument, URL jsonDocument)
|
||||
throws IOException, ProcessingException {
|
||||
final JsonSchema schemaNode = getSchemaNode(schemaDocument);
|
||||
final JsonNode jsonNode = getJsonNode(jsonDocument);
|
||||
validateJson(schemaNode, jsonNode);
|
||||
} // validateJson(URL) ends
|
||||
|
||||
public static boolean isJsonValid(JsonSchema jsonSchemaNode, JsonNode jsonNode)
|
||||
throws ProcessingException {
|
||||
ProcessingReport report = jsonSchemaNode.validate(jsonNode);
|
||||
return report.isSuccess();
|
||||
} // validateJson(Node) ends
|
||||
|
||||
public static boolean isJsonValid(String schemaText, String jsonText)
|
||||
throws ProcessingException, IOException {
|
||||
final JsonSchema schemaNode = getSchemaNode(schemaText);
|
||||
final JsonNode jsonNode = getJsonNode(jsonText);
|
||||
return isJsonValid(schemaNode, jsonNode);
|
||||
} // validateJson(Node) ends
|
||||
|
||||
public static boolean isJsonValid(File schemaFile, File jsonFile)
|
||||
throws ProcessingException, IOException {
|
||||
final JsonSchema schemaNode = getSchemaNode(schemaFile);
|
||||
final JsonNode jsonNode = getJsonNode(jsonFile);
|
||||
return isJsonValid(schemaNode, jsonNode);
|
||||
} // validateJson(Node) ends
|
||||
|
||||
public static boolean isJsonValid(URL schemaURL, URL jsonURL)
|
||||
throws ProcessingException, IOException {
|
||||
final JsonSchema schemaNode = getSchemaNode(schemaURL);
|
||||
final JsonNode jsonNode = getJsonNode(jsonURL);
|
||||
return isJsonValid(schemaNode, jsonNode);
|
||||
} // validateJson(Node) ends
|
||||
|
||||
public static void validateJsonResource(String schemaResource, String jsonResource)
|
||||
throws IOException, ProcessingException {
|
||||
final JsonSchema schemaNode = getSchemaNode(schemaResource);
|
||||
final JsonNode jsonNode = getJsonNodeFromResource(jsonResource);
|
||||
validateJson(schemaNode, jsonNode);
|
||||
} // validateJsonResource() ends
|
||||
|
||||
private static JsonSchema getSchemaNodeHelper(JsonNode jsonNode) throws ProcessingException {
|
||||
final JsonNode schemaIdentifier = jsonNode.get(JSON_SCHEMA_IDENTIFIER_ELEMENT);
|
||||
if (null == schemaIdentifier) {
|
||||
((ObjectNode) jsonNode).put(JSON_SCHEMA_IDENTIFIER_ELEMENT, JSON_V4_SCHEMA_IDENTIFIER);
|
||||
}
|
||||
|
||||
final JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
|
||||
return factory.getJsonSchema(jsonNode);
|
||||
} // getSchemaNodeHelper() ends
|
||||
}
|
||||
@@ -0,0 +1,862 @@
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.controller.util.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A JSONArray is an ordered sequence of values. Its external text form is a string wrapped in
|
||||
* square brackets with commas separating the values. The internal form is an object having <code>
|
||||
* get</code> and <code>opt</code> methods for accessing the values by index, and <code>put</code>
|
||||
* methods for adding or replacing values. The values can be any of these types: <code>Boolean
|
||||
* </code>, <code>JSONArray</code>, <code>JSONObject</code>, <code>Number</code>, <code>String
|
||||
* </code>, or the <code>JSONObject.NULL object</code>.
|
||||
*
|
||||
* <p>The constructor can convert a JSON text into a Java object. The <code>toString</code> method
|
||||
* converts to JSON text.
|
||||
*
|
||||
* <p>A <code>get</code> method returns a value if one can be found, and throws an exception if one
|
||||
* cannot be found. An <code>opt</code> method returns a default value instead of throwing an
|
||||
* exception, and so is useful for obtaining optional values.
|
||||
*
|
||||
* <p>The generic <code>get()</code> and <code>opt()</code> methods return an object which you can
|
||||
* cast or query for type. There are also typed <code>get</code> and <code>opt</code> methods that
|
||||
* do type checking and type coersion for you.
|
||||
*
|
||||
* <p>The texts produced by the <code>toString</code> methods strictly conform to JSON syntax rules.
|
||||
* The constructors are more forgiving in the texts they will accept:
|
||||
*
|
||||
* <ul>
|
||||
* <li>An extra <code>,</code> <small>(comma)</small> may appear just before the closing
|
||||
* bracket.
|
||||
* <li>The <code>null</code> value will be inserted when there is <code>,</code>
|
||||
* <small>(comma)</small> elision.
|
||||
* <li>Strings may be quoted with <code>'</code> <small>(single quote)</small>.
|
||||
* <li>Strings do not need to be quoted at all if they do not begin with a quote or single quote,
|
||||
* and if they do not contain leading or trailing spaces, and if they do not contain any of
|
||||
* these characters: <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers
|
||||
* and if they are not the reserved words <code>true</code>, <code>false</code>, or <code>null
|
||||
* </code>.
|
||||
* <li>Values can be separated by <code>;</code> <small>(semicolon)</small> as well as by <code>,
|
||||
* </code> <small>(comma)</small>.
|
||||
* <li>Numbers may have the <code>0-</code> <small>(octal)</small> or <code>0x-</code>
|
||||
* <small>(hex)</small> prefix.
|
||||
* <li>Comments written in the slashshlash, slashstar, and hash conventions will be ignored.
|
||||
* </ul>
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2008-09-18
|
||||
*/
|
||||
public class JSONArray {
|
||||
|
||||
/** The arrayList where the JSONArray's properties are kept. */
|
||||
private ArrayList<Object> myArrayList;
|
||||
|
||||
/** Construct an empty JSONArray. */
|
||||
public JSONArray() {
|
||||
this.myArrayList = new ArrayList<Object>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONArray from a JSONTokener.
|
||||
*
|
||||
* @param x A JSONTokener
|
||||
* @throws JSONException If there is a syntax error.
|
||||
*/
|
||||
public JSONArray(JSONTokener x) throws JSONException {
|
||||
this();
|
||||
char c = x.nextClean();
|
||||
char q;
|
||||
if (c == '[') {
|
||||
q = ']';
|
||||
} else if (c == '(') {
|
||||
q = ')';
|
||||
} else {
|
||||
throw x.syntaxError("A JSONArray text must start with '['");
|
||||
}
|
||||
if (x.nextClean() == ']') {
|
||||
return;
|
||||
}
|
||||
x.back();
|
||||
for (; ; ) {
|
||||
if (x.nextClean() == ',') {
|
||||
x.back();
|
||||
this.myArrayList.add(null);
|
||||
} else {
|
||||
x.back();
|
||||
this.myArrayList.add(x.nextValue());
|
||||
}
|
||||
c = x.nextClean();
|
||||
switch (c) {
|
||||
case ';':
|
||||
case ',':
|
||||
if (x.nextClean() == ']') {
|
||||
return;
|
||||
}
|
||||
x.back();
|
||||
break;
|
||||
case ']':
|
||||
case ')':
|
||||
if (q != c) {
|
||||
throw x.syntaxError("Expected a '" + new Character(q) + "'");
|
||||
}
|
||||
return;
|
||||
default:
|
||||
throw x.syntaxError("Expected a ',' or ']'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONArray from a source JSON text.
|
||||
*
|
||||
* @param source A string that begins with <code>[</code> <small>(left bracket)</small> and
|
||||
* ends with <code>]</code> <small>(right bracket)</small>.
|
||||
* @throws JSONException If there is a syntax error.
|
||||
*/
|
||||
public JSONArray(String source) throws JSONException {
|
||||
this(new JSONTokener(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONArray from a Collection.
|
||||
*
|
||||
* @param collection A Collection.
|
||||
*/
|
||||
public JSONArray(Collection<?> collection) {
|
||||
this.myArrayList =
|
||||
(collection == null) ? new ArrayList<Object>() : new ArrayList<Object>(collection);
|
||||
}
|
||||
|
||||
/** Construct a JSONArray from a collection of beans. The collection should have Java Beans. */
|
||||
public JSONArray(Collection<?> collection, boolean includeSuperClass) {
|
||||
this.myArrayList = new ArrayList<Object>();
|
||||
if (collection != null) {
|
||||
for (Iterator<?> iter = collection.iterator(); iter.hasNext(); ) {
|
||||
this.myArrayList.add(new JSONObject(iter.next(), includeSuperClass));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONArray from an array
|
||||
*
|
||||
* @throws JSONException If not an array.
|
||||
*/
|
||||
public JSONArray(Object array) throws JSONException {
|
||||
this();
|
||||
if (array.getClass().isArray()) {
|
||||
int length = Array.getLength(array);
|
||||
for (int i = 0; i < length; i += 1) {
|
||||
this.put(Array.get(array, i));
|
||||
}
|
||||
} else {
|
||||
throw new JSONException("JSONArray initial value should be a string or collection or array.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONArray from an array with a bean. The array should have Java Beans.
|
||||
*
|
||||
* @throws JSONException If not an array.
|
||||
*/
|
||||
public JSONArray(Object array, boolean includeSuperClass) throws JSONException {
|
||||
this();
|
||||
if (array.getClass().isArray()) {
|
||||
int length = Array.getLength(array);
|
||||
for (int i = 0; i < length; i += 1) {
|
||||
this.put(new JSONObject(Array.get(array, i), includeSuperClass));
|
||||
}
|
||||
} else {
|
||||
throw new JSONException("JSONArray initial value should be a string or collection or array.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object value associated with an index.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return An object value.
|
||||
* @throws JSONException If there is no value for the index.
|
||||
*/
|
||||
public Object get(int index) throws JSONException {
|
||||
Object o = opt(index);
|
||||
if (o == null) {
|
||||
throw new JSONException("JSONArray[" + index + "] not found.");
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the boolean value associated with an index. The string values "true" and "false" are
|
||||
* converted to boolean.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The truth.
|
||||
* @throws JSONException If there is no value for the index or if the value is not convertable to
|
||||
* boolean.
|
||||
*/
|
||||
public boolean getBoolean(int index) throws JSONException {
|
||||
Object o = get(index);
|
||||
if (o.equals(Boolean.FALSE)
|
||||
|| (o instanceof String && ((String) o).equalsIgnoreCase("false"))) {
|
||||
return false;
|
||||
} else if (o.equals(Boolean.TRUE)
|
||||
|| (o instanceof String && ((String) o).equalsIgnoreCase("true"))) {
|
||||
return true;
|
||||
}
|
||||
throw new JSONException("JSONArray[" + index + "] is not a Boolean.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the double value associated with an index.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The value.
|
||||
* @throws JSONException If the key is not found or if the value cannot be converted to a number.
|
||||
*/
|
||||
public double getDouble(int index) throws JSONException {
|
||||
Object o = get(index);
|
||||
try {
|
||||
return o instanceof Number
|
||||
? ((Number) o).doubleValue()
|
||||
: Double.valueOf((String) o).doubleValue();
|
||||
} catch (Exception e) {
|
||||
throw new JSONException("JSONArray[" + index + "] is not a number.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the int value associated with an index.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The value.
|
||||
* @throws JSONException If the key is not found or if the value cannot be converted to a number.
|
||||
* if the value cannot be converted to a number.
|
||||
*/
|
||||
public int getInt(int index) throws JSONException {
|
||||
Object o = get(index);
|
||||
return o instanceof Number ? ((Number) o).intValue() : (int) getDouble(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JSONArray associated with an index.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return A JSONArray value.
|
||||
* @throws JSONException If there is no value for the index. or if the value is not a JSONArray
|
||||
*/
|
||||
public JSONArray getJSONArray(int index) throws JSONException {
|
||||
Object o = get(index);
|
||||
if (o instanceof JSONArray) {
|
||||
return (JSONArray) o;
|
||||
}
|
||||
throw new JSONException("JSONArray[" + index + "] is not a JSONArray.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JSONObject associated with an index.
|
||||
*
|
||||
* @param index subscript
|
||||
* @return A JSONObject value.
|
||||
* @throws JSONException If there is no value for the index or if the value is not a JSONObject
|
||||
*/
|
||||
public JSONObject getJSONObject(int index) throws JSONException {
|
||||
Object o = get(index);
|
||||
if (o instanceof JSONObject) {
|
||||
return (JSONObject) o;
|
||||
}
|
||||
throw new JSONException("JSONArray[" + index + "] is not a JSONObject.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the long value associated with an index.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The value.
|
||||
* @throws JSONException If the key is not found or if the value cannot be converted to a number.
|
||||
*/
|
||||
public long getLong(int index) throws JSONException {
|
||||
Object o = get(index);
|
||||
return o instanceof Number ? ((Number) o).longValue() : (long) getDouble(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string associated with an index.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return A string value.
|
||||
* @throws JSONException If there is no value for the index.
|
||||
*/
|
||||
public String getString(int index) throws JSONException {
|
||||
return get(index).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the value is null.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return true if the value at the index is null, or if there is no value.
|
||||
*/
|
||||
public boolean isNull(int index) {
|
||||
return JSONObject.NULL.equals(opt(index));
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a string from the contents of this JSONArray. The <code>separator</code> string is
|
||||
* inserted between each element. Warning: This method assumes that the data structure is
|
||||
* acyclical.
|
||||
*
|
||||
* @param separator A string that will be inserted between the elements.
|
||||
* @return a string.
|
||||
* @throws JSONException If the array contains an invalid number.
|
||||
*/
|
||||
public String join(String separator) throws JSONException {
|
||||
int len = length();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
for (int i = 0; i < len; i += 1) {
|
||||
if (i > 0) {
|
||||
sb.append(separator);
|
||||
}
|
||||
sb.append(JSONObject.valueToString(this.myArrayList.get(i)));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of elements in the JSONArray, included nulls.
|
||||
*
|
||||
* @return The length (or size).
|
||||
*/
|
||||
public int length() {
|
||||
return this.myArrayList.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional object value associated with an index.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return An object value, or null if there is no object at that index.
|
||||
*/
|
||||
public Object opt(int index) {
|
||||
return (index < 0 || index >= length()) ? null : this.myArrayList.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional boolean value associated with an index. It returns false if there is no value
|
||||
* at that index, or if the value is not Boolean.TRUE or the String "true".
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The truth.
|
||||
*/
|
||||
public boolean optBoolean(int index) {
|
||||
return optBoolean(index, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional boolean value associated with an index. It returns the defaultValue if there
|
||||
* is no value at that index or if it is not a Boolean or the String "true" or "false" (case
|
||||
* insensitive).
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @param defaultValue A boolean default.
|
||||
* @return The truth.
|
||||
*/
|
||||
public boolean optBoolean(int index, boolean defaultValue) {
|
||||
try {
|
||||
return getBoolean(index);
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional double value associated with an index. NaN is returned if there is no value
|
||||
* for the index, or if the value is not a number and cannot be converted to a number.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The value.
|
||||
*/
|
||||
public double optDouble(int index) {
|
||||
return optDouble(index, Double.NaN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional double value associated with an index. The defaultValue is returned if there
|
||||
* is no value for the index, or if the value is not a number and cannot be converted to a number.
|
||||
*
|
||||
* @param index subscript
|
||||
* @param defaultValue The default value.
|
||||
* @return The value.
|
||||
*/
|
||||
public double optDouble(int index, double defaultValue) {
|
||||
try {
|
||||
return getDouble(index);
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional int value associated with an index. Zero is returned if there is no value for
|
||||
* the index, or if the value is not a number and cannot be converted to a number.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The value.
|
||||
*/
|
||||
public int optInt(int index) {
|
||||
return optInt(index, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional int value associated with an index. The defaultValue is returned if there is
|
||||
* no value for the index, or if the value is not a number and cannot be converted to a number.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @param defaultValue The default value.
|
||||
* @return The value.
|
||||
*/
|
||||
public int optInt(int index, int defaultValue) {
|
||||
try {
|
||||
return getInt(index);
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional JSONArray associated with an index.
|
||||
*
|
||||
* @param index subscript
|
||||
* @return A JSONArray value, or null if the index has no value, or if the value is not a
|
||||
* JSONArray.
|
||||
*/
|
||||
public JSONArray optJSONArray(int index) {
|
||||
Object o = opt(index);
|
||||
return o instanceof JSONArray ? (JSONArray) o : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional JSONObject associated with an index. Null is returned if the key is not found,
|
||||
* or null if the index has no value, or if the value is not a JSONObject.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return A JSONObject value.
|
||||
*/
|
||||
public JSONObject optJSONObject(int index) {
|
||||
Object o = opt(index);
|
||||
return o instanceof JSONObject ? (JSONObject) o : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional long value associated with an index. Zero is returned if there is no value for
|
||||
* the index, or if the value is not a number and cannot be converted to a number.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return The value.
|
||||
*/
|
||||
public long optLong(int index) {
|
||||
return optLong(index, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional long value associated with an index. The defaultValue is returned if there is
|
||||
* no value for the index, or if the value is not a number and cannot be converted to a number.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @param defaultValue The default value.
|
||||
* @return The value.
|
||||
*/
|
||||
public long optLong(int index, long defaultValue) {
|
||||
try {
|
||||
return getLong(index);
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional string value associated with an index. It returns an empty string if there is
|
||||
* no value at that index. If the value is not a string and is not null, then it is coverted to a
|
||||
* string.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @return A String value.
|
||||
*/
|
||||
public String optString(int index) {
|
||||
return optString(index, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the optional string associated with an index. The defaultValue is returned if the key is
|
||||
* not found.
|
||||
*
|
||||
* @param index The index must be between 0 and length() - 1.
|
||||
* @param defaultValue The default value.
|
||||
* @return A String value.
|
||||
*/
|
||||
public String optString(int index, String defaultValue) {
|
||||
Object o = opt(index);
|
||||
return o != null ? o.toString() : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a boolean value. This increases the array's length by one.
|
||||
*
|
||||
* @param value A boolean value.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(boolean value) {
|
||||
put(value ? Boolean.TRUE : Boolean.FALSE);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a value in the JSONArray, where the value will be a JSONArray which is produced from a
|
||||
* Collection.
|
||||
*
|
||||
* @param value A Collection value.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(Collection<?> value) {
|
||||
put(new JSONArray(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a double value. This increases the array's length by one.
|
||||
*
|
||||
* @param value A double value.
|
||||
* @throws JSONException if the value is not finite.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(double value) throws JSONException {
|
||||
Double d = new Double(value);
|
||||
JSONObject.testValidity(d);
|
||||
put(d);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an int value. This increases the array's length by one.
|
||||
*
|
||||
* @param value An int value.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(int value) {
|
||||
put(new Integer(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an long value. This increases the array's length by one.
|
||||
*
|
||||
* @param value A long value.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(long value) {
|
||||
put(new Long(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a value in the JSONArray, where the value will be a JSONObject which is produced from a
|
||||
* Map.
|
||||
*
|
||||
* @param value A Map value.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(Map<?, ?> value) {
|
||||
put(new JSONObject(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an object value. This increases the array's length by one.
|
||||
*
|
||||
* @param value An object value. The value should be a Boolean, Double, Integer, JSONArray,
|
||||
* JSONObject, Long, or String, or the JSONObject.NULL object.
|
||||
* @return this.
|
||||
*/
|
||||
public JSONArray put(Object value) {
|
||||
this.myArrayList.add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put or replace a boolean value in the JSONArray. If the index is greater than the length of the
|
||||
* JSONArray, then null elements will be added as necessary to pad it out.
|
||||
*
|
||||
* @param index The subscript.
|
||||
* @param value A boolean value.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative.
|
||||
*/
|
||||
public JSONArray put(int index, boolean value) throws JSONException {
|
||||
put(index, value ? Boolean.TRUE : Boolean.FALSE);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a value in the JSONArray, where the value will be a JSONArray which is produced from a
|
||||
* Collection.
|
||||
*
|
||||
* @param index The subscript.
|
||||
* @param value A Collection value.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative or if the value is not finite.
|
||||
*/
|
||||
public JSONArray put(int index, Collection<?> value) throws JSONException {
|
||||
put(index, new JSONArray(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put or replace a double value. If the index is greater than the length of the JSONArray, then
|
||||
* null elements will be added as necessary to pad it out.
|
||||
*
|
||||
* @param index The subscript.
|
||||
* @param value A double value.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative or if the value is not finite.
|
||||
*/
|
||||
public JSONArray put(int index, double value) throws JSONException {
|
||||
put(index, new Double(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put or replace an int value. If the index is greater than the length of the JSONArray, then
|
||||
* null elements will be added as necessary to pad it out.
|
||||
*
|
||||
* @param index The subscript.
|
||||
* @param value An int value.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative.
|
||||
*/
|
||||
public JSONArray put(int index, int value) throws JSONException {
|
||||
put(index, new Integer(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put or replace a long value. If the index is greater than the length of the JSONArray, then
|
||||
* null elements will be added as necessary to pad it out.
|
||||
*
|
||||
* @param index The subscript.
|
||||
* @param value A long value.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative.
|
||||
*/
|
||||
public JSONArray put(int index, long value) throws JSONException {
|
||||
put(index, new Long(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a value in the JSONArray, where the value will be a JSONObject which is produced from a
|
||||
* Map.
|
||||
*
|
||||
* @param index The subscript.
|
||||
* @param value The Map value.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative or if the the value is an invalid number.
|
||||
*/
|
||||
public JSONArray put(int index, Map<?, ?> value) throws JSONException {
|
||||
put(index, new JSONObject(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put or replace an object value in the JSONArray. If the index is greater than the length of the
|
||||
* JSONArray, then null elements will be added as necessary to pad it out.
|
||||
*
|
||||
* @param index The subscript.
|
||||
* @param value The value to put into the array. The value should be a Boolean, Double, Integer,
|
||||
* JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
|
||||
* @return this.
|
||||
* @throws JSONException If the index is negative or if the the value is an invalid number.
|
||||
*/
|
||||
public JSONArray put(int index, Object value) throws JSONException {
|
||||
JSONObject.testValidity(value);
|
||||
if (index < 0) {
|
||||
throw new JSONException("JSONArray[" + index + "] not found.");
|
||||
}
|
||||
if (index < length()) {
|
||||
this.myArrayList.set(index, value);
|
||||
} else {
|
||||
while (index != length()) {
|
||||
put(JSONObject.NULL);
|
||||
}
|
||||
put(value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONObject by combining a JSONArray of names with the values of this JSONArray.
|
||||
*
|
||||
* @param names A JSONArray containing a list of key strings. These will be paired with the
|
||||
* values.
|
||||
* @return A JSONObject, or null if there are no names or if this JSONArray has no values.
|
||||
* @throws JSONException If any of the names are null.
|
||||
*/
|
||||
public JSONObject toJSONObject(JSONArray names) throws JSONException {
|
||||
if (names == null || names.length() == 0 || length() == 0) {
|
||||
return null;
|
||||
}
|
||||
JSONObject jo = new JSONObject();
|
||||
for (int i = 0; i < names.length(); i += 1) {
|
||||
jo.put(names.getString(i), this.opt(i));
|
||||
}
|
||||
return jo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a JSON text of this JSONArray. For compactness, no unnecessary whitespace is added. If it
|
||||
* is not possible to produce a syntactically correct JSON text then null will be returned
|
||||
* instead. This could occur if the array contains an invalid number.
|
||||
*
|
||||
* <p>Warning: This method assumes that the data structure is acyclical.
|
||||
*
|
||||
* @return a printable, displayable, transmittable representation of the array.
|
||||
*/
|
||||
public String toString() {
|
||||
try {
|
||||
return '[' + join(",") + ']';
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a prettyprinted JSON text of this JSONArray. Warning: This method assumes that the data
|
||||
* structure is acyclical.
|
||||
*
|
||||
* @param indentFactor The number of spaces to add to each level of indentation.
|
||||
* @return a printable, displayable, transmittable representation of the object, beginning with
|
||||
* <code>[</code> <small>(left bracket)</small> and ending with <code>]</code>
|
||||
* <small>(right bracket)</small>.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public String toString(int indentFactor) throws JSONException {
|
||||
return toString(indentFactor, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a prettyprinted JSON text of this JSONArray. Warning: This method assumes that the data
|
||||
* structure is acyclical.
|
||||
*
|
||||
* @param indentFactor The number of spaces to add to each level of indentation.
|
||||
* @param indent The indention of the top level.
|
||||
* @return a printable, displayable, transmittable representation of the array.
|
||||
* @throws JSONException
|
||||
*/
|
||||
String toString(int indentFactor, int indent) throws JSONException {
|
||||
int len = length();
|
||||
if (len == 0) {
|
||||
return "[]";
|
||||
}
|
||||
int i;
|
||||
StringBuffer sb = new StringBuffer("[");
|
||||
if (len == 1) {
|
||||
sb.append(JSONObject.valueToString(this.myArrayList.get(0), indentFactor, indent));
|
||||
} else {
|
||||
int newindent = indent + indentFactor;
|
||||
// sb.append('\n');
|
||||
|
||||
boolean intType = false;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
if (this.myArrayList.get(i).getClass() != Integer.class) {
|
||||
if (i == 0) {
|
||||
sb.append('\n');
|
||||
}
|
||||
if (i > 0) {
|
||||
sb.append(",\n");
|
||||
}
|
||||
for (int j = 0; j < newindent; j += 1) {
|
||||
sb.append(' ');
|
||||
}
|
||||
} else {
|
||||
intType = true;
|
||||
if (i > 0) sb.append(", ");
|
||||
}
|
||||
sb.append(JSONObject.valueToString(this.myArrayList.get(i), indentFactor, newindent));
|
||||
}
|
||||
if (intType == false) {
|
||||
sb.append('\n');
|
||||
for (i = 0; i < indent; i += 1) {
|
||||
sb.append(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the contents of the JSONArray as JSON text to a writer. For compactness, no whitespace is
|
||||
* added.
|
||||
*
|
||||
* <p>Warning: This method assumes that the data structure is acyclical.
|
||||
*
|
||||
* @return The writer.
|
||||
* @throws JSONException
|
||||
*/
|
||||
public Writer write(Writer writer) throws JSONException {
|
||||
try {
|
||||
boolean b = false;
|
||||
int len = length();
|
||||
|
||||
writer.write('[');
|
||||
|
||||
for (int i = 0; i < len; i += 1) {
|
||||
if (b) {
|
||||
writer.write(',');
|
||||
}
|
||||
Object v = this.myArrayList.get(i);
|
||||
if (v instanceof JSONObject) {
|
||||
((JSONObject) v).write(writer);
|
||||
} else if (v instanceof JSONArray) {
|
||||
((JSONArray) v).write(writer);
|
||||
} else {
|
||||
writer.write(JSONObject.valueToString(v));
|
||||
}
|
||||
b = true;
|
||||
}
|
||||
writer.write(']');
|
||||
return writer;
|
||||
} catch (IOException e) {
|
||||
throw new JSONException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.controller.util.json;
|
||||
|
||||
/**
|
||||
* The JSONException is thrown by the JSON.org classes then things are amiss.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2008-09-18
|
||||
*/
|
||||
public class JSONException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private Throwable cause;
|
||||
|
||||
/**
|
||||
* Constructs a JSONException with an explanatory message.
|
||||
*
|
||||
* @param message Detail about the reason for the exception.
|
||||
*/
|
||||
public JSONException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public JSONException(Throwable t) {
|
||||
super(t.getMessage());
|
||||
this.cause = t;
|
||||
}
|
||||
|
||||
public Throwable getCause() {
|
||||
return this.cause;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,16 @@
|
||||
package com.controller.util.json;
|
||||
/**
|
||||
* The <code>JSONString</code> interface allows a <code>toJSONString()</code> method so that a class
|
||||
* can change the behavior of <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>,
|
||||
* and <code>JSONWriter.value(</code>Object<code>)</code>. The <code>toJSONString</code> method will
|
||||
* be used instead of the default behavior of using the Object's <code>toString()</code> method and
|
||||
* quoting the result.
|
||||
*/
|
||||
public interface JSONString {
|
||||
/**
|
||||
* The <code>toJSONString</code> method allows a class to produce its own JSON serialization.
|
||||
*
|
||||
* @return A strictly syntactically correct JSON text.
|
||||
*/
|
||||
public String toJSONString();
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
Copyright (c) 2006 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.controller.util.json;
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* JSONStringer provides a quick and convenient way of producing JSON text. The texts produced
|
||||
* strictly conform to JSON syntax rules. No whitespace is added, so the results are ready for
|
||||
* transmission or storage. Each instance of JSONStringer can produce one JSON text.
|
||||
*
|
||||
* <p>A JSONStringer instance provides a <code>value</code> method for appending values to the text,
|
||||
* and a <code>key</code> method for adding keys before values in objects. There are <code>array
|
||||
* </code> and <code>endArray</code> methods that make and bound array values, and <code>object
|
||||
* </code> and <code>endObject</code> methods which make and bound object values. All of these
|
||||
* methods return the JSONWriter instance, permitting cascade style. For example,
|
||||
*
|
||||
* <pre>
|
||||
* myString = new JSONStringer()
|
||||
* .object()
|
||||
* .key("JSON")
|
||||
* .value("Hello, World!")
|
||||
* .endObject()
|
||||
* .toString();</pre>
|
||||
*
|
||||
* which produces the string
|
||||
*
|
||||
* <pre>
|
||||
* {"JSON":"Hello, World!"}</pre>
|
||||
*
|
||||
* <p>The first method called must be <code>array</code> or <code>object</code>. There are no
|
||||
* methods for adding commas or colons. JSONStringer adds them for you. Objects and arrays can be
|
||||
* nested up to 20 levels deep.
|
||||
*
|
||||
* <p>This can sometimes be easier than using a JSONObject to build a string.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2008-09-18
|
||||
*/
|
||||
public class JSONStringer extends JSONWriter {
|
||||
/** Make a fresh JSONStringer. It can be used to build one JSON text. */
|
||||
public JSONStringer() {
|
||||
super(new StringWriter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JSON text. This method is used to obtain the product of the JSONStringer instance.
|
||||
* It will return <code>null</code> if there was a problem in the construction of the JSON text
|
||||
* (such as the calls to <code>array</code> were not properly balanced with calls to <code>
|
||||
* endArray</code>).
|
||||
*
|
||||
* @return The JSON text.
|
||||
*/
|
||||
public String toString() {
|
||||
return this.mode == 'd' ? this.writer.toString() : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
Copyright (c) 2002 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.controller.util.json;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
/**
|
||||
* A JSONTokener takes a source string and extracts characters and tokens from it. It is used by the
|
||||
* JSONObject and JSONArray constructors to parse JSON source strings.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2008-09-18
|
||||
*/
|
||||
public class JSONTokener {
|
||||
|
||||
private int index;
|
||||
private Reader reader;
|
||||
private char lastChar;
|
||||
private boolean useLastChar;
|
||||
|
||||
/**
|
||||
* Construct a JSONTokener from a string.
|
||||
*
|
||||
* @param reader A reader.
|
||||
*/
|
||||
public JSONTokener(Reader reader) {
|
||||
this.reader = reader.markSupported() ? reader : new BufferedReader(reader);
|
||||
this.useLastChar = false;
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONTokener from a string.
|
||||
*
|
||||
* @param s A source string.
|
||||
*/
|
||||
public JSONTokener(String s) {
|
||||
this(new StringReader(s));
|
||||
}
|
||||
|
||||
/**
|
||||
* Back up one character. This provides a sort of lookahead capability, so that you can test for a
|
||||
* digit or letter before attempting to parse the next number or identifier.
|
||||
*/
|
||||
public void back() throws JSONException {
|
||||
if (useLastChar || index <= 0) {
|
||||
throw new JSONException("Stepping back two steps is not supported");
|
||||
}
|
||||
index -= 1;
|
||||
useLastChar = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hex value of a character (base16).
|
||||
*
|
||||
* @param c A character between '0' and '9' or between 'A' and 'F' or between 'a' and 'f'.
|
||||
* @return An int between 0 and 15, or -1 if c was not a hex digit.
|
||||
*/
|
||||
public static int dehexchar(char c) {
|
||||
if (c >= '0' && c <= '9') {
|
||||
return c - '0';
|
||||
}
|
||||
if (c >= 'A' && c <= 'F') {
|
||||
return c - ('A' - 10);
|
||||
}
|
||||
if (c >= 'a' && c <= 'f') {
|
||||
return c - ('a' - 10);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the source string still contains characters that next() can consume.
|
||||
*
|
||||
* @return true if not yet at the end of the source.
|
||||
*/
|
||||
public boolean more() throws JSONException {
|
||||
char nextChar = next();
|
||||
if (nextChar == 0) {
|
||||
return false;
|
||||
}
|
||||
back();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next character in the source string.
|
||||
*
|
||||
* @return The next character, or 0 if past the end of the source string.
|
||||
*/
|
||||
public char next() throws JSONException {
|
||||
if (this.useLastChar) {
|
||||
this.useLastChar = false;
|
||||
if (this.lastChar != 0) {
|
||||
this.index += 1;
|
||||
}
|
||||
return this.lastChar;
|
||||
}
|
||||
int c;
|
||||
try {
|
||||
c = this.reader.read();
|
||||
} catch (IOException exc) {
|
||||
throw new JSONException(exc);
|
||||
}
|
||||
|
||||
if (c <= 0) { // End of stream
|
||||
this.lastChar = 0;
|
||||
return 0;
|
||||
}
|
||||
this.index += 1;
|
||||
this.lastChar = (char) c;
|
||||
return this.lastChar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume the next character, and check that it matches a specified character.
|
||||
*
|
||||
* @param c The character to match.
|
||||
* @return The character.
|
||||
* @throws JSONException if the character does not match.
|
||||
*/
|
||||
public char next(char c) throws JSONException {
|
||||
char n = next();
|
||||
if (n != c) {
|
||||
throw syntaxError("Expected '" + c + "' and instead saw '" + n + "'");
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next n characters.
|
||||
*
|
||||
* @param n The number of characters to take.
|
||||
* @return A string of n characters.
|
||||
* @throws JSONException Substring bounds error if there are not n characters remaining in the
|
||||
* source string.
|
||||
*/
|
||||
public String next(int n) throws JSONException {
|
||||
if (n == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
char[] buffer = new char[n];
|
||||
int pos = 0;
|
||||
|
||||
if (this.useLastChar) {
|
||||
this.useLastChar = false;
|
||||
buffer[0] = this.lastChar;
|
||||
pos = 1;
|
||||
}
|
||||
|
||||
try {
|
||||
int len;
|
||||
while ((pos < n) && ((len = reader.read(buffer, pos, n - pos)) != -1)) {
|
||||
pos += len;
|
||||
}
|
||||
} catch (IOException exc) {
|
||||
throw new JSONException(exc);
|
||||
}
|
||||
this.index += pos;
|
||||
|
||||
if (pos < n) {
|
||||
throw syntaxError("Substring bounds error");
|
||||
}
|
||||
|
||||
this.lastChar = buffer[n - 1];
|
||||
return new String(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next char in the string, skipping whitespace.
|
||||
*
|
||||
* @throws JSONException
|
||||
* @return A character, or 0 if there are no more characters.
|
||||
*/
|
||||
public char nextClean() throws JSONException {
|
||||
for (; ; ) {
|
||||
char c = next();
|
||||
if (c == 0 || c > ' ') {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the characters up to the next close quote character. Backslash processing is done. The
|
||||
* formal JSON format does not allow strings in single quotes, but an implementation is allowed to
|
||||
* accept them.
|
||||
*
|
||||
* @param quote The quoting character, either <code>"</code> <small>(double quote)</small> or
|
||||
* <code>'</code> <small>(single quote)</small>.
|
||||
* @return A String.
|
||||
* @throws JSONException Unterminated string.
|
||||
*/
|
||||
public String nextString(char quote) throws JSONException {
|
||||
char c;
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (; ; ) {
|
||||
c = next();
|
||||
switch (c) {
|
||||
case 0:
|
||||
case '\n':
|
||||
case '\r':
|
||||
throw syntaxError("Unterminated string");
|
||||
case '\\':
|
||||
c = next();
|
||||
switch (c) {
|
||||
case 'b':
|
||||
sb.append('\b');
|
||||
break;
|
||||
case 't':
|
||||
sb.append('\t');
|
||||
break;
|
||||
case 'n':
|
||||
sb.append('\n');
|
||||
break;
|
||||
case 'f':
|
||||
sb.append('\f');
|
||||
break;
|
||||
case 'r':
|
||||
sb.append('\r');
|
||||
break;
|
||||
case 'u':
|
||||
sb.append((char) Integer.parseInt(next(4), 16));
|
||||
break;
|
||||
case 'x':
|
||||
sb.append((char) Integer.parseInt(next(2), 16));
|
||||
break;
|
||||
default:
|
||||
sb.append(c);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (c == quote) {
|
||||
return sb.toString();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text up but not including the specified character or the end of line, whichever comes
|
||||
* first.
|
||||
*
|
||||
* @param d A delimiter character.
|
||||
* @return A string.
|
||||
*/
|
||||
public String nextTo(char d) throws JSONException {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (; ; ) {
|
||||
char c = next();
|
||||
if (c == d || c == 0 || c == '\n' || c == '\r') {
|
||||
if (c != 0) {
|
||||
back();
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text up but not including one of the specified delimiter characters or the end of line,
|
||||
* whichever comes first.
|
||||
*
|
||||
* @param delimiters A set of delimiter characters.
|
||||
* @return A string, trimmed.
|
||||
*/
|
||||
public String nextTo(String delimiters) throws JSONException {
|
||||
char c;
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (; ; ) {
|
||||
c = next();
|
||||
if (delimiters.indexOf(c) >= 0 || c == 0 || c == '\n' || c == '\r') {
|
||||
if (c != 0) {
|
||||
back();
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next value. The value can be a Boolean, Double, Integer, JSONArray, JSONObject, Long,
|
||||
* or String, or the JSONObject.NULL object.
|
||||
*
|
||||
* @throws JSONException If syntax error.
|
||||
* @return An object.
|
||||
*/
|
||||
public Object nextValue() throws JSONException {
|
||||
char c = nextClean();
|
||||
String s;
|
||||
|
||||
switch (c) {
|
||||
case '"':
|
||||
case '\'':
|
||||
return nextString(c);
|
||||
case '{':
|
||||
back();
|
||||
return new JSONObject(this);
|
||||
case '[':
|
||||
case '(':
|
||||
back();
|
||||
return new JSONArray(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle unquoted text. This could be the values true, false, or
|
||||
* null, or it can be a number. An implementation (such as this one)
|
||||
* is allowed to also accept non-standard forms.
|
||||
*
|
||||
* Accumulate characters until we reach the end of the text or a
|
||||
* formatting character.
|
||||
*/
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
|
||||
sb.append(c);
|
||||
c = next();
|
||||
}
|
||||
back();
|
||||
|
||||
s = sb.toString().trim();
|
||||
if (s.equals("")) {
|
||||
throw syntaxError("Missing value");
|
||||
}
|
||||
return JSONObject.stringToValue(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip characters until the next character is the requested character. If the requested character
|
||||
* is not found, no characters are skipped.
|
||||
*
|
||||
* @param to A character to skip to.
|
||||
* @return The requested character, or zero if the requested character is not found.
|
||||
*/
|
||||
public char skipTo(char to) throws JSONException {
|
||||
char c;
|
||||
try {
|
||||
int startIndex = this.index;
|
||||
reader.mark(Integer.MAX_VALUE);
|
||||
do {
|
||||
c = next();
|
||||
if (c == 0) {
|
||||
reader.reset();
|
||||
this.index = startIndex;
|
||||
return c;
|
||||
}
|
||||
} while (c != to);
|
||||
} catch (IOException exc) {
|
||||
throw new JSONException(exc);
|
||||
}
|
||||
|
||||
back();
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a JSONException to signal a syntax error.
|
||||
*
|
||||
* @param message The error message.
|
||||
* @return A JSONException object, suitable for throwing
|
||||
*/
|
||||
public JSONException syntaxError(String message) {
|
||||
return new JSONException(message + toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a printable string of this JSONTokener.
|
||||
*
|
||||
* @return " at character [this.index]"
|
||||
*/
|
||||
public String toString() {
|
||||
return " at character " + index;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
Copyright (c) 2006 JSON.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
The Software shall be used for Good, not Evil.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.controller.util.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* JSONWriter provides a quick and convenient way of producing JSON text. The texts produced
|
||||
* strictly conform to JSON syntax rules. No whitespace is added, so the results are ready for
|
||||
* transmission or storage. Each instance of JSONWriter can produce one JSON text.
|
||||
*
|
||||
* <p>A JSONWriter instance provides a <code>value</code> method for appending values to the text,
|
||||
* and a <code>key</code> method for adding keys before values in objects. There are <code>array
|
||||
* </code> and <code>endArray</code> methods that make and bound array values, and <code>object
|
||||
* </code> and <code>endObject</code> methods which make and bound object values. All of these
|
||||
* methods return the JSONWriter instance, permitting a cascade style. For example,
|
||||
*
|
||||
* <pre>
|
||||
* new JSONWriter(myWriter)
|
||||
* .object()
|
||||
* .key("JSON")
|
||||
* .value("Hello, World!")
|
||||
* .endObject();</pre>
|
||||
*
|
||||
* which writes
|
||||
*
|
||||
* <pre>
|
||||
* {"JSON":"Hello, World!"}</pre>
|
||||
*
|
||||
* <p>The first method called must be <code>array</code> or <code>object</code>. There are no
|
||||
* methods for adding commas or colons. JSONWriter adds them for you. Objects and arrays can be
|
||||
* nested up to 20 levels deep.
|
||||
*
|
||||
* <p>This can sometimes be easier than using a JSONObject to build a string.
|
||||
*
|
||||
* @author JSON.org
|
||||
* @version 2008-09-18
|
||||
*/
|
||||
public class JSONWriter {
|
||||
private static final int maxdepth = 20;
|
||||
|
||||
/** The comma flag determines if a comma should be output before the next value. */
|
||||
private boolean comma;
|
||||
|
||||
/** The current mode. Values: 'a' (array), 'd' (done), 'i' (initial), 'k' (key), 'o' (object). */
|
||||
protected char mode;
|
||||
|
||||
/** The object/array stack. */
|
||||
private JSONObject stack[];
|
||||
|
||||
/** The stack top index. A value of 0 indicates that the stack is empty. */
|
||||
private int top;
|
||||
|
||||
/** The writer that will receive the output. */
|
||||
protected Writer writer;
|
||||
|
||||
/** Make a fresh JSONWriter. It can be used to build one JSON text. */
|
||||
public JSONWriter(Writer w) {
|
||||
this.comma = false;
|
||||
this.mode = 'i';
|
||||
this.stack = new JSONObject[maxdepth];
|
||||
this.top = 0;
|
||||
this.writer = w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a value.
|
||||
*
|
||||
* @param s A string value.
|
||||
* @return this
|
||||
* @throws JSONException If the value is out of sequence.
|
||||
*/
|
||||
private JSONWriter append(String s) throws JSONException {
|
||||
if (s == null) {
|
||||
throw new JSONException("Null pointer");
|
||||
}
|
||||
if (this.mode == 'o' || this.mode == 'a') {
|
||||
try {
|
||||
if (this.comma && this.mode == 'a') {
|
||||
this.writer.write(',');
|
||||
}
|
||||
this.writer.write(s);
|
||||
} catch (IOException e) {
|
||||
throw new JSONException(e);
|
||||
}
|
||||
if (this.mode == 'o') {
|
||||
this.mode = 'k';
|
||||
}
|
||||
this.comma = true;
|
||||
return this;
|
||||
}
|
||||
throw new JSONException("Value out of sequence.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin appending a new array. All values until the balancing <code>endArray</code> will be
|
||||
* appended to this array. The <code>endArray</code> method must be called to mark the array's
|
||||
* end.
|
||||
*
|
||||
* @return this
|
||||
* @throws JSONException If the nesting is too deep, or if the object is started in the wrong
|
||||
* place (for example as a key or after the end of the outermost array or object).
|
||||
*/
|
||||
public JSONWriter array() throws JSONException {
|
||||
if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
|
||||
this.push(null);
|
||||
this.append("[");
|
||||
this.comma = false;
|
||||
return this;
|
||||
}
|
||||
throw new JSONException("Misplaced array.");
|
||||
}
|
||||
|
||||
/**
|
||||
* End something.
|
||||
*
|
||||
* @param m Mode
|
||||
* @param c Closing character
|
||||
* @return this
|
||||
* @throws JSONException If unbalanced.
|
||||
*/
|
||||
private JSONWriter end(char m, char c) throws JSONException {
|
||||
if (this.mode != m) {
|
||||
throw new JSONException(m == 'o' ? "Misplaced endObject." : "Misplaced endArray.");
|
||||
}
|
||||
this.pop(m);
|
||||
try {
|
||||
this.writer.write(c);
|
||||
} catch (IOException e) {
|
||||
throw new JSONException(e);
|
||||
}
|
||||
this.comma = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* End an array. This method most be called to balance calls to <code>array</code>.
|
||||
*
|
||||
* @return this
|
||||
* @throws JSONException If incorrectly nested.
|
||||
*/
|
||||
public JSONWriter endArray() throws JSONException {
|
||||
return this.end('a', ']');
|
||||
}
|
||||
|
||||
/**
|
||||
* End an object. This method most be called to balance calls to <code>object</code>.
|
||||
*
|
||||
* @return this
|
||||
* @throws JSONException If incorrectly nested.
|
||||
*/
|
||||
public JSONWriter endObject() throws JSONException {
|
||||
return this.end('k', '}');
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a key. The key will be associated with the next value. In an object, every value must be
|
||||
* preceded by a key.
|
||||
*
|
||||
* @param s A key string.
|
||||
* @return this
|
||||
* @throws JSONException If the key is out of place. For example, keys do not belong in arrays or
|
||||
* if the key is null.
|
||||
*/
|
||||
public JSONWriter key(String s) throws JSONException {
|
||||
if (s == null) {
|
||||
throw new JSONException("Null key.");
|
||||
}
|
||||
if (this.mode == 'k') {
|
||||
try {
|
||||
if (this.comma) {
|
||||
this.writer.write(',');
|
||||
}
|
||||
stack[top - 1].putOnce(s, Boolean.TRUE);
|
||||
this.writer.write(JSONObject.quote(s));
|
||||
this.writer.write(':');
|
||||
this.comma = false;
|
||||
this.mode = 'o';
|
||||
return this;
|
||||
} catch (IOException e) {
|
||||
throw new JSONException(e);
|
||||
}
|
||||
}
|
||||
throw new JSONException("Misplaced key.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin appending a new object. All keys and values until the balancing <code>endObject</code>
|
||||
* will be appended to this object. The <code>endObject</code> method must be called to mark the
|
||||
* object's end.
|
||||
*
|
||||
* @return this
|
||||
* @throws JSONException If the nesting is too deep, or if the object is started in the wrong
|
||||
* place (for example as a key or after the end of the outermost array or object).
|
||||
*/
|
||||
public JSONWriter object() throws JSONException {
|
||||
if (this.mode == 'i') {
|
||||
this.mode = 'o';
|
||||
}
|
||||
if (this.mode == 'o' || this.mode == 'a') {
|
||||
this.append("{");
|
||||
this.push(new JSONObject());
|
||||
this.comma = false;
|
||||
return this;
|
||||
}
|
||||
throw new JSONException("Misplaced object.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop an array or object scope.
|
||||
*
|
||||
* @param c The scope to close.
|
||||
* @throws JSONException If nesting is wrong.
|
||||
*/
|
||||
private void pop(char c) throws JSONException {
|
||||
if (this.top <= 0) {
|
||||
throw new JSONException("Nesting error.");
|
||||
}
|
||||
char m = this.stack[this.top - 1] == null ? 'a' : 'k';
|
||||
if (m != c) {
|
||||
throw new JSONException("Nesting error.");
|
||||
}
|
||||
this.top -= 1;
|
||||
this.mode = this.top == 0 ? 'd' : this.stack[this.top - 1] == null ? 'a' : 'k';
|
||||
}
|
||||
|
||||
/**
|
||||
* Push an array or object scope.
|
||||
*
|
||||
* @param c The scope to open.
|
||||
* @throws JSONException If nesting is too deep.
|
||||
*/
|
||||
private void push(JSONObject jo) throws JSONException {
|
||||
if (this.top >= maxdepth) {
|
||||
throw new JSONException("Nesting too deep.");
|
||||
}
|
||||
this.stack[this.top] = jo;
|
||||
this.mode = jo == null ? 'a' : 'k';
|
||||
this.top += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append either the value <code>true</code> or the value <code>false</code>.
|
||||
*
|
||||
* @param b A boolean.
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
*/
|
||||
public JSONWriter value(boolean b) throws JSONException {
|
||||
return this.append(b ? "true" : "false");
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a double value.
|
||||
*
|
||||
* @param d A double.
|
||||
* @return this
|
||||
* @throws JSONException If the number is not finite.
|
||||
*/
|
||||
public JSONWriter value(double d) throws JSONException {
|
||||
return this.value(new Double(d));
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a long value.
|
||||
*
|
||||
* @param l A long.
|
||||
* @return this
|
||||
* @throws JSONException
|
||||
*/
|
||||
public JSONWriter value(long l) throws JSONException {
|
||||
return this.append(Long.toString(l));
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an object value.
|
||||
*
|
||||
* @param o The object to append. It can be null, or a Boolean, Number, String, JSONObject, or
|
||||
* JSONArray, or an object with a toJSONString() method.
|
||||
* @return this
|
||||
* @throws JSONException If the value is out of sequence.
|
||||
*/
|
||||
public JSONWriter value(Object o) throws JSONException {
|
||||
return this.append(JSONObject.valueToString(o));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,440 @@
|
||||
package com.controller.util.json;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Test class. This file is not formally a member of the com.controller.util.json library. It is
|
||||
* just a casual test tool.
|
||||
*/
|
||||
public class Test {
|
||||
|
||||
/**
|
||||
* Entry point.
|
||||
*
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String args[]) {
|
||||
Iterator<?> it;
|
||||
JSONArray a;
|
||||
JSONObject j;
|
||||
JSONStringer jj;
|
||||
String s;
|
||||
|
||||
/**
|
||||
* Obj is a typical class that implements JSONString. It also provides some beanie methods that
|
||||
* can be used to construct a JSONObject. It also demonstrates constructing a JSONObject with an
|
||||
* array of names.
|
||||
*/
|
||||
class Obj implements JSONString {
|
||||
public String aString;
|
||||
public double aNumber;
|
||||
public boolean aBoolean;
|
||||
|
||||
public Obj(String string, double n, boolean b) {
|
||||
this.aString = string;
|
||||
this.aNumber = n;
|
||||
this.aBoolean = b;
|
||||
}
|
||||
|
||||
public double getNumber() {
|
||||
return this.aNumber;
|
||||
}
|
||||
|
||||
public String getString() {
|
||||
return this.aString;
|
||||
}
|
||||
|
||||
public boolean isBoolean() {
|
||||
return this.aBoolean;
|
||||
}
|
||||
|
||||
public String getBENT() {
|
||||
return "All uppercase key";
|
||||
}
|
||||
|
||||
public String getX() {
|
||||
return "x";
|
||||
}
|
||||
|
||||
public String toJSONString() {
|
||||
return "{"
|
||||
+ JSONObject.quote(this.aString)
|
||||
+ ":"
|
||||
+ JSONObject.doubleToString(this.aNumber)
|
||||
+ "}";
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.getString()
|
||||
+ " "
|
||||
+ this.getNumber()
|
||||
+ " "
|
||||
+ this.isBoolean()
|
||||
+ "."
|
||||
+ this.getBENT()
|
||||
+ " "
|
||||
+ this.getX();
|
||||
}
|
||||
}
|
||||
|
||||
Obj obj = new Obj("A beany object", 42, true);
|
||||
|
||||
try {
|
||||
|
||||
s =
|
||||
"{ \"entity\": { \"imageURL\": \"\", \"name\": \"IXXXXXXXXXXXXX\", \"id\": 12336, \"ratingCount\": null, \"averageRating\": null } }";
|
||||
j = new JSONObject(s);
|
||||
System.out.println(j.toString(2));
|
||||
|
||||
jj = new JSONStringer();
|
||||
s =
|
||||
jj.object()
|
||||
.key("single")
|
||||
.value("MARIE HAA'S")
|
||||
.key("Johnny")
|
||||
.value("MARIE HAA\\'S")
|
||||
.key("foo")
|
||||
.value("bar")
|
||||
.key("baz")
|
||||
.array()
|
||||
.object()
|
||||
.key("quux")
|
||||
.value("Thanks, Josh!")
|
||||
.endObject()
|
||||
.endArray()
|
||||
.key("obj keys")
|
||||
.value(JSONObject.getNames(obj))
|
||||
.endObject()
|
||||
.toString();
|
||||
System.out.println(s);
|
||||
|
||||
System.out.println(
|
||||
new JSONStringer()
|
||||
.object()
|
||||
.key("a")
|
||||
.array()
|
||||
.array()
|
||||
.array()
|
||||
.value("b")
|
||||
.endArray()
|
||||
.endArray()
|
||||
.endArray()
|
||||
.endObject()
|
||||
.toString());
|
||||
|
||||
jj = new JSONStringer();
|
||||
jj.array();
|
||||
jj.value(1);
|
||||
jj.array();
|
||||
jj.value(null);
|
||||
jj.array();
|
||||
jj.object();
|
||||
jj.key("empty-array").array().endArray();
|
||||
jj.key("answer").value(42);
|
||||
jj.key("null").value(null);
|
||||
jj.key("false").value(false);
|
||||
jj.key("true").value(true);
|
||||
jj.key("big").value(123456789e+88);
|
||||
jj.key("small").value(123456789e-88);
|
||||
jj.key("empty-object").object().endObject();
|
||||
jj.key("long");
|
||||
jj.value(9223372036854775807L);
|
||||
jj.endObject();
|
||||
jj.value("two");
|
||||
jj.endArray();
|
||||
jj.value(true);
|
||||
jj.endArray();
|
||||
jj.value(98.6);
|
||||
jj.value(-100.0);
|
||||
jj.object();
|
||||
jj.endObject();
|
||||
jj.object();
|
||||
jj.key("one");
|
||||
jj.value(1.00);
|
||||
jj.endObject();
|
||||
jj.value(obj);
|
||||
jj.endArray();
|
||||
System.out.println(jj.toString());
|
||||
|
||||
System.out.println(new JSONArray(jj.toString()).toString(4));
|
||||
|
||||
int ar[] = {1, 2, 3};
|
||||
JSONArray ja = new JSONArray(ar);
|
||||
System.out.println(ja.toString());
|
||||
|
||||
String sa[] = {"aString", "aNumber", "aBoolean"};
|
||||
j = new JSONObject(obj, sa);
|
||||
j.put("Testing JSONString interface", obj);
|
||||
System.out.println(j.toString(4));
|
||||
|
||||
j =
|
||||
new JSONObject(
|
||||
"{slashes: '///', closetag: '</script>', backslash:'\\\\', ei: {quotes: '\"\\''},eo: {a: '\"quoted\"', b:\"don't\"}, quotes: [\"'\", '\"']}");
|
||||
System.out.println(j.toString(2));
|
||||
System.out.println("");
|
||||
|
||||
j =
|
||||
new JSONObject(
|
||||
"{foo: [true, false,9876543210, 0.0, 1.00000001, 1.000000000001, 1.00000000000000001,"
|
||||
+ " .00000000000000001, 2.00, 0.1, 2e100, -32,[],{}, \"string\"], "
|
||||
+ " to : null, op : 'Good',"
|
||||
+ "ten:10} postfix comment");
|
||||
j.put("String", "98.6");
|
||||
j.put("JSONObject", new JSONObject());
|
||||
j.put("JSONArray", new JSONArray());
|
||||
j.put("int", 57);
|
||||
j.put("double", 123456789012345678901234567890.);
|
||||
j.put("true", true);
|
||||
j.put("false", false);
|
||||
j.put("null", JSONObject.NULL);
|
||||
j.put("bool", "true");
|
||||
j.put("zero", -0.0);
|
||||
j.put("\\u2028", "\u2028");
|
||||
j.put("\\u2029", "\u2029");
|
||||
a = j.getJSONArray("foo");
|
||||
a.put(666);
|
||||
a.put(2001.99);
|
||||
a.put("so \"fine\".");
|
||||
a.put("so <fine>.");
|
||||
a.put(true);
|
||||
a.put(false);
|
||||
a.put(new JSONArray());
|
||||
a.put(new JSONObject());
|
||||
j.put("keys", JSONObject.getNames(j));
|
||||
System.out.println(j.toString(4));
|
||||
|
||||
System.out.println("String: " + j.getDouble("String"));
|
||||
System.out.println(" bool: " + j.getBoolean("bool"));
|
||||
System.out.println(" to: " + j.getString("to"));
|
||||
System.out.println(" true: " + j.getString("true"));
|
||||
System.out.println(" foo: " + j.getJSONArray("foo"));
|
||||
System.out.println(" op: " + j.getString("op"));
|
||||
System.out.println(" ten: " + j.getInt("ten"));
|
||||
System.out.println(" oops: " + j.optBoolean("oops"));
|
||||
|
||||
j =
|
||||
new JSONObject(
|
||||
"{nix: null, nux: false, null: 'null', 'Request-URI': '/', Method: 'GET', 'HTTP-Version': 'HTTP/1.0'}");
|
||||
System.out.println(j.toString(2));
|
||||
System.out.println("isNull: " + j.isNull("nix"));
|
||||
System.out.println(" has: " + j.has("nix"));
|
||||
System.out.println("");
|
||||
|
||||
j =
|
||||
new JSONObject(
|
||||
"{Envelope: {Body: {\"ns1:doGoogleSearch\": {oe: \"latin1\", filter: true, q: \"'+search+'\", key: \"GOOGLEKEY\", maxResults: 10, \"SOAP-ENV:encodingStyle\": \"http://schemas.xmlsoap.org/soap/encoding/\", start: 0, ie: \"latin1\", safeSearch:false, \"xmlns:ns1\": \"urn:GoogleSearch\"}}}}");
|
||||
System.out.println(j.toString(2));
|
||||
System.out.println("");
|
||||
|
||||
j =
|
||||
new JSONObject(
|
||||
"{script: 'It is not allowed in HTML to send a close script tag in a string<script>because it confuses browsers</script>so we insert a backslash before the /'}");
|
||||
System.out.println(j.toString());
|
||||
System.out.println("");
|
||||
|
||||
JSONTokener jt =
|
||||
new JSONTokener("{op:'test', to:'session', pre:1}{op:'test', to:'session', pre:2}");
|
||||
j = new JSONObject(jt);
|
||||
System.out.println(j.toString());
|
||||
System.out.println("pre: " + j.optInt("pre"));
|
||||
int i = jt.skipTo('{');
|
||||
System.out.println(i);
|
||||
j = new JSONObject(jt);
|
||||
System.out.println(j.toString());
|
||||
System.out.println("");
|
||||
|
||||
a = new JSONArray(" [\"<escape>\", next is an implied null , , ok,] ");
|
||||
System.out.println(a.toString());
|
||||
System.out.println("");
|
||||
System.out.println("");
|
||||
|
||||
j =
|
||||
new JSONObject(
|
||||
"{ fun => with non-standard forms ; forgiving => This package can be used to parse formats that are similar to but not stricting conforming to JSON; why=To make it easier to migrate existing data to JSON,one = [[1.00]]; uno=[[{1=>1}]];'+':+6e66 ;pluses=+++;empty = '' , 'double':0.666,true: TRUE, false: FALSE, null=NULL;[true] = [[!,@;*]]; string=> o. k. ; \r oct=0666; hex=0x666; dec=666; o=0999; noh=0x0x}");
|
||||
System.out.println(j.toString(4));
|
||||
System.out.println("");
|
||||
if (j.getBoolean("true") && !j.getBoolean("false")) {
|
||||
System.out.println("It's all good");
|
||||
}
|
||||
|
||||
System.out.println("");
|
||||
j = new JSONObject(j, new String[] {"dec", "oct", "hex", "missing"});
|
||||
System.out.println(j.toString(4));
|
||||
|
||||
System.out.println("");
|
||||
System.out.println(new JSONStringer().array().value(a).value(j).endArray());
|
||||
|
||||
j =
|
||||
new JSONObject(
|
||||
"{string: \"98.6\", long: 2147483648, int: 2147483647, longer: 9223372036854775807, double: 9223372036854775808}");
|
||||
System.out.println(j.toString(4));
|
||||
|
||||
System.out.println("\ngetInt");
|
||||
System.out.println("int " + j.getInt("int"));
|
||||
System.out.println("long " + j.getInt("long"));
|
||||
System.out.println("longer " + j.getInt("longer"));
|
||||
System.out.println("double " + j.getInt("double"));
|
||||
System.out.println("string " + j.getInt("string"));
|
||||
|
||||
System.out.println("\ngetLong");
|
||||
System.out.println("int " + j.getLong("int"));
|
||||
System.out.println("long " + j.getLong("long"));
|
||||
System.out.println("longer " + j.getLong("longer"));
|
||||
System.out.println("double " + j.getLong("double"));
|
||||
System.out.println("string " + j.getLong("string"));
|
||||
|
||||
System.out.println("\ngetDouble");
|
||||
System.out.println("int " + j.getDouble("int"));
|
||||
System.out.println("long " + j.getDouble("long"));
|
||||
System.out.println("longer " + j.getDouble("longer"));
|
||||
System.out.println("double " + j.getDouble("double"));
|
||||
System.out.println("string " + j.getDouble("string"));
|
||||
|
||||
j.put("good sized", 9223372036854775807L);
|
||||
System.out.println(j.toString(4));
|
||||
|
||||
a = new JSONArray("[2147483647, 2147483648, 9223372036854775807, 9223372036854775808]");
|
||||
System.out.println(a.toString(4));
|
||||
|
||||
System.out.println("\nKeys: ");
|
||||
it = j.keys();
|
||||
while (it.hasNext()) {
|
||||
s = (String) it.next();
|
||||
System.out.println(s + ": " + j.getString(s));
|
||||
}
|
||||
|
||||
System.out.println("\naccumulate: ");
|
||||
j = new JSONObject();
|
||||
j.accumulate("stooge", "Curly");
|
||||
j.accumulate("stooge", "Larry");
|
||||
j.accumulate("stooge", "Moe");
|
||||
a = j.getJSONArray("stooge");
|
||||
a.put(5, "Shemp");
|
||||
System.out.println(j.toString(4));
|
||||
|
||||
System.out.println("\nwrite:");
|
||||
System.out.println(j.write(new StringWriter()));
|
||||
|
||||
Collection<?> c = null;
|
||||
Map<?, ?> m = null;
|
||||
|
||||
j = new JSONObject(m);
|
||||
a = new JSONArray(c);
|
||||
j.append("stooge", "Joe DeRita");
|
||||
j.append("stooge", "Shemp");
|
||||
j.accumulate("stooges", "Curly");
|
||||
j.accumulate("stooges", "Larry");
|
||||
j.accumulate("stooges", "Moe");
|
||||
j.accumulate("stoogearray", j.get("stooges"));
|
||||
j.put("map", m);
|
||||
j.put("collection", c);
|
||||
j.put("array", a);
|
||||
a.put(m);
|
||||
a.put(c);
|
||||
System.out.println(j.toString(4));
|
||||
|
||||
s =
|
||||
"{plist=Apple; AnimalSmells = { pig = piggish; lamb = lambish; worm = wormy; }; AnimalSounds = { pig = oink; lamb = baa; worm = baa; Lisa = \"Why is the worm talking like a lamb?\" } ; AnimalColors = { pig = pink; lamb = black; worm = pink; } } ";
|
||||
j = new JSONObject(s);
|
||||
System.out.println(j.toString(4));
|
||||
|
||||
s = " (\"San Francisco\", \"New York\", \"Seoul\", \"London\", \"Seattle\", \"Shanghai\")";
|
||||
a = new JSONArray(s);
|
||||
System.out.println(a.toString());
|
||||
|
||||
System.out.println("\nTesting Exceptions: ");
|
||||
|
||||
System.out.print("Exception: ");
|
||||
try {
|
||||
a = new JSONArray();
|
||||
a.put(Double.NEGATIVE_INFINITY);
|
||||
a.put(Double.NaN);
|
||||
System.out.println(a.toString());
|
||||
} catch (Exception e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
System.out.print("Exception: ");
|
||||
try {
|
||||
System.out.println(j.getDouble("stooge"));
|
||||
} catch (Exception e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
System.out.print("Exception: ");
|
||||
try {
|
||||
System.out.println(j.getDouble("howard"));
|
||||
} catch (Exception e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
System.out.print("Exception: ");
|
||||
try {
|
||||
System.out.println(j.put(null, "howard"));
|
||||
} catch (Exception e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
System.out.print("Exception: ");
|
||||
try {
|
||||
System.out.println(a.getDouble(0));
|
||||
} catch (Exception e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
System.out.print("Exception: ");
|
||||
try {
|
||||
System.out.println(a.get(-1));
|
||||
} catch (Exception e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
System.out.print("Exception: ");
|
||||
try {
|
||||
System.out.println(a.put(Double.NaN));
|
||||
} catch (Exception e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
System.out.print("Exception: ");
|
||||
try {
|
||||
ja = new JSONArray(new Object());
|
||||
System.out.println(ja.toString());
|
||||
} catch (Exception e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
|
||||
System.out.print("Exception: ");
|
||||
try {
|
||||
s = "[)";
|
||||
a = new JSONArray(s);
|
||||
System.out.println(a.toString());
|
||||
} catch (Exception e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
|
||||
System.out.print("Exception: ");
|
||||
try {
|
||||
s = "{\"koda\": true, \"koda\": true}";
|
||||
j = new JSONObject(s);
|
||||
System.out.println(j.toString(4));
|
||||
} catch (Exception e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
|
||||
System.out.print("Exception: ");
|
||||
try {
|
||||
jj = new JSONStringer();
|
||||
s =
|
||||
jj.object()
|
||||
.key("bosanda")
|
||||
.value("MARIE HAA'S")
|
||||
.key("bosanda")
|
||||
.value("MARIE HAA\\'S")
|
||||
.endObject()
|
||||
.toString();
|
||||
System.out.println(j.toString(4));
|
||||
} catch (Exception e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* OtterTune - AbstractJSONValidationTestCase.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller.collectors;
|
||||
|
||||
import com.controller.types.JSONSchemaType;
|
||||
import com.controller.util.FileUtil;
|
||||
import java.io.File;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public abstract class AbstractJSONValidationTestCase extends TestCase {
|
||||
|
||||
private static final String SAMPLE_OUTPUT_PATH = "sample_output";
|
||||
private static final String SAMPLE_CONFIG_PATH = "config";
|
||||
|
||||
protected String dbName;
|
||||
|
||||
protected void setUp(String dbName) throws Exception {
|
||||
super.setUp();
|
||||
this.dbName = dbName;
|
||||
}
|
||||
|
||||
public void testJsonKnobs() {
|
||||
String jsonKnobsPath = FileUtil.joinPath(SAMPLE_OUTPUT_PATH, this.dbName, "knobs.json");
|
||||
assertTrue(JSONSchemaType.isValidJson(JSONSchemaType.OUTPUT, new File(jsonKnobsPath)));
|
||||
}
|
||||
|
||||
public void testJsonMetrics() {
|
||||
String jsonMetricsBeforePath =
|
||||
FileUtil.joinPath(SAMPLE_OUTPUT_PATH, this.dbName, "metrics_before.json");
|
||||
String jsonMetricsAfterPath =
|
||||
FileUtil.joinPath(SAMPLE_OUTPUT_PATH, this.dbName, "metrics_after.json");
|
||||
assertTrue(JSONSchemaType.isValidJson(JSONSchemaType.OUTPUT, new File(jsonMetricsBeforePath)));
|
||||
assertTrue(JSONSchemaType.isValidJson(JSONSchemaType.OUTPUT, new File(jsonMetricsAfterPath)));
|
||||
}
|
||||
|
||||
public void testJsonSummary() {
|
||||
String jsonSummaryPath = FileUtil.joinPath(SAMPLE_OUTPUT_PATH, this.dbName, "summary.json");
|
||||
assertTrue(JSONSchemaType.isValidJson(JSONSchemaType.SUMMARY, new File(jsonSummaryPath)));
|
||||
}
|
||||
|
||||
public void testJsonConfig() {
|
||||
String jsonConfigPath =
|
||||
FileUtil.joinPath(SAMPLE_CONFIG_PATH, "sample_" + this.dbName + "_config.json");
|
||||
assertTrue(JSONSchemaType.isValidJson(JSONSchemaType.CONFIG, new File(jsonConfigPath)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* OtterTune - TestInvalidJSON.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller.collectors;
|
||||
|
||||
import com.controller.types.JSONSchemaType;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class TestInvalidJSON extends TestCase {
|
||||
|
||||
// Wrong number of levels for "global"
|
||||
private static final String BAD_JSON_TEXT_1 =
|
||||
"{"
|
||||
+ " \"global\" : {"
|
||||
+ " \"global\" : {"
|
||||
+ " \"auto_generate_certs\": {"
|
||||
+ " \"auto_pram\" : \"NO\""
|
||||
+ " }"
|
||||
+ " }"
|
||||
+ " },"
|
||||
+ " \"local\" : {"
|
||||
+ " }"
|
||||
+ "}";
|
||||
|
||||
// Lacking "local"
|
||||
private static final String BAD_JSON_TEXT_2 =
|
||||
"{"
|
||||
+ " \"global\" : {"
|
||||
+ " \"global1\" : {"
|
||||
+ " \"auto_generate_certs\": \"ON\""
|
||||
+ " }"
|
||||
+ " }"
|
||||
+ "}";
|
||||
|
||||
public void testBadJSONOutput() {
|
||||
assertFalse(JSONSchemaType.isValidJson(JSONSchemaType.OUTPUT, BAD_JSON_TEXT_1));
|
||||
assertFalse(JSONSchemaType.isValidJson(JSONSchemaType.OUTPUT, BAD_JSON_TEXT_2));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* OtterTune - TestMySQLJSON.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller.collectors;
|
||||
|
||||
public class TestMySQLJSON extends AbstractJSONValidationTestCase {
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp("mysql");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* OtterTune - TestOracleJSON.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller.collectors;
|
||||
|
||||
public class TestOracleJSON extends AbstractJSONValidationTestCase {
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp("oracle");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* OtterTune - TestPostgresJSON.java
|
||||
*
|
||||
* Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||
*/
|
||||
|
||||
package com.controller.collectors;
|
||||
|
||||
public class TestPostgresJSON extends AbstractJSONValidationTestCase {
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp("postgres");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user