Merge branch '2.3' into 2.4
This commit is contained in:
@ -64,4 +64,5 @@ private:
|
||||
std::vector<std::vector<std::string>> m_rows;
|
||||
|
||||
ResultSet(std::initializer_list<std::string> names);
|
||||
json_t* get_json_value(const std::string& s);
|
||||
};
|
||||
|
@ -6,7 +6,10 @@ if (BUILD_MAXCTRL)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/lib/version.js.in ${CMAKE_CURRENT_BINARY_DIR}/lib/version.js @ONLY)
|
||||
|
||||
file(GLOB_RECURSE MAXCTRL_SOURCES lib/*)
|
||||
|
||||
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/maxctrl/maxctrl
|
||||
DEPENDS ${MAXCTRL_SOURCES} maxctrl.js
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build.sh ${CMAKE_SOURCE_DIR}
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
add_custom_target(maxctrl ALL DEPENDS ${CMAKE_BINARY_DIR}/maxctrl/maxctrl)
|
||||
|
@ -112,7 +112,7 @@ module.exports = function() {
|
||||
row = []
|
||||
|
||||
fields.forEach(function(p) {
|
||||
var v = _.getPath(i, p[Object.keys(p)[0]], '')
|
||||
var v = _.getPath(i, p.path, '')
|
||||
|
||||
if (Array.isArray(v)) {
|
||||
v = v.join(', ')
|
||||
@ -162,7 +162,7 @@ module.exports = function() {
|
||||
var header = []
|
||||
|
||||
fields.forEach(function(i) {
|
||||
header.push(Object.keys(i))
|
||||
header.push(i.name)
|
||||
})
|
||||
|
||||
var table = getTable(header)
|
||||
@ -188,7 +188,7 @@ module.exports = function() {
|
||||
var header = []
|
||||
|
||||
fields.forEach(function(i) {
|
||||
header.push(Object.keys(i))
|
||||
header.push(i.name)
|
||||
})
|
||||
|
||||
var table = getTable(header)
|
||||
@ -197,7 +197,7 @@ module.exports = function() {
|
||||
row = []
|
||||
|
||||
fields.forEach(function(p) {
|
||||
var v = _.getPath(i, p[Object.keys(p)[0]], '')
|
||||
var v = _.getPath(i, p[p.name], '')
|
||||
|
||||
if (Array.isArray(v) && typeof(v[0]) != 'object') {
|
||||
v = v.join(', ')
|
||||
@ -229,7 +229,7 @@ module.exports = function() {
|
||||
separator = '\n'
|
||||
var max_field_length = 0
|
||||
fields.forEach(function (i) {
|
||||
var k = Object.keys(i)[0]
|
||||
var k = i.name
|
||||
if (k.length > max_field_length) {
|
||||
max_field_length = k.length
|
||||
}
|
||||
@ -244,8 +244,8 @@ module.exports = function() {
|
||||
}
|
||||
|
||||
fields.forEach(function(i) {
|
||||
var k = Object.keys(i)[0]
|
||||
var path = i[k]
|
||||
var k = i.name
|
||||
var path = i.path
|
||||
var v = _.getPath(data, path, '')
|
||||
|
||||
if (Array.isArray(v) && typeof(v[0]) != 'object') {
|
||||
@ -422,6 +422,24 @@ module.exports = function() {
|
||||
default: false
|
||||
}
|
||||
}
|
||||
|
||||
this.fieldDescriptions = function(fields) {
|
||||
var t = new Table({chars: {
|
||||
'top' : '', 'top-mid': '', 'top-left': '', 'top-right': '', 'left': ' ', 'right': '',
|
||||
'left-mid': '' , 'mid': '' , 'mid-mid': '', 'right-mid': '' , 'middle': '',
|
||||
'bottom' : '', 'bottom-mid': '', 'bottom-left': '', 'bottom-right': '',
|
||||
}})
|
||||
|
||||
t.push(['Field', 'Description'])
|
||||
t.push(['-----', '-----------'])
|
||||
|
||||
|
||||
for (f of fields) {
|
||||
t.push([f.name, f.description])
|
||||
}
|
||||
|
||||
return '\n\n' + t.toString()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -441,8 +459,6 @@ var tsvopts = {
|
||||
'padding-right': 0,
|
||||
compact: true
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
|
||||
function getList() {
|
||||
|
@ -13,24 +13,252 @@
|
||||
|
||||
require('./common.js')()
|
||||
|
||||
const list_servers_fields = [
|
||||
{
|
||||
name: 'Server',
|
||||
path: 'id',
|
||||
description: 'Server name'
|
||||
},
|
||||
{
|
||||
name: 'Address',
|
||||
path: 'attributes.parameters.address',
|
||||
description: 'Address where the server listens'
|
||||
},
|
||||
{
|
||||
name: 'Port',
|
||||
path: 'attributes.parameters.port',
|
||||
description: 'The port on which the server listens'
|
||||
},
|
||||
{
|
||||
name: 'Connections',
|
||||
path: 'attributes.statistics.connections',
|
||||
description: 'Current connection count'
|
||||
},
|
||||
{
|
||||
name: 'State',
|
||||
path: 'attributes.state',
|
||||
description: 'Server state'
|
||||
},
|
||||
{
|
||||
name: 'GTID',
|
||||
path: 'attributes.gtid_current_pos',
|
||||
description: 'Current value of @@gtid_current_pos'
|
||||
}
|
||||
]
|
||||
|
||||
const list_services_fields = [
|
||||
{
|
||||
name: 'Service',
|
||||
path: 'id',
|
||||
description: 'Service name'
|
||||
},
|
||||
{
|
||||
name: 'Router',
|
||||
path: 'attributes.router',
|
||||
description: 'Router used by the service'
|
||||
},
|
||||
{
|
||||
name: 'Connections',
|
||||
path: 'attributes.connections',
|
||||
description: 'Current connection count'
|
||||
},
|
||||
{
|
||||
name: 'Total Connections',
|
||||
path: 'attributes.total_connections',
|
||||
description: 'Total connection count'
|
||||
},
|
||||
{
|
||||
name: 'Servers',
|
||||
path: 'relationships.servers.data[].id',
|
||||
description: 'Servers that the service uses'
|
||||
}
|
||||
]
|
||||
|
||||
const list_listeners_fields = [
|
||||
{
|
||||
name: 'Name',
|
||||
path: 'id',
|
||||
description: 'Listener name'
|
||||
},
|
||||
{
|
||||
name: 'Port',
|
||||
path: 'attributes.parameters.port',
|
||||
description: 'The port where the listener listens'
|
||||
},
|
||||
{
|
||||
name: 'Host',
|
||||
path: 'attributes.parameters.host',
|
||||
description: 'The address or socket where the listener listens'
|
||||
},
|
||||
{
|
||||
name: 'State',
|
||||
path: 'attributes.state',
|
||||
description: 'Listener state'
|
||||
}
|
||||
]
|
||||
|
||||
const list_monitors_fields = [
|
||||
{
|
||||
name: 'Monitor',
|
||||
path: 'id',
|
||||
description: 'Monitor name'
|
||||
},
|
||||
{
|
||||
name: 'State',
|
||||
path: 'attributes.state',
|
||||
description: 'Monitor state'
|
||||
},
|
||||
{
|
||||
name: 'Servers',
|
||||
path: 'relationships.servers.data[].id',
|
||||
description: 'The servers that this monitor monitors'
|
||||
}
|
||||
]
|
||||
|
||||
const list_sessions_fields = [
|
||||
{
|
||||
name: 'Id',
|
||||
path: 'id',
|
||||
description: 'Session ID'
|
||||
},
|
||||
{
|
||||
name: 'User',
|
||||
path: 'attributes.user',
|
||||
description: 'Username'
|
||||
},
|
||||
{
|
||||
name: 'Host',
|
||||
path: 'attributes.remote',
|
||||
description: 'Client host address'
|
||||
},
|
||||
{
|
||||
name: 'Connected',
|
||||
path: 'attributes.connected',
|
||||
description: 'Time when the session started'
|
||||
},
|
||||
{
|
||||
name: 'Idle',
|
||||
path: 'attributes.idle',
|
||||
description: 'How long the session has been idle, in seconds'
|
||||
},
|
||||
{
|
||||
name: 'Service',
|
||||
path: 'relationships.services.data[].id',
|
||||
description: 'The service where the session connected'
|
||||
}
|
||||
]
|
||||
|
||||
const list_filters_fields = [
|
||||
{
|
||||
name: 'Filter',
|
||||
path: 'id',
|
||||
description: 'Filter name'
|
||||
},
|
||||
{
|
||||
name: 'Service',
|
||||
path: 'relationships.services.data[].id',
|
||||
description: 'Services that use the filter'
|
||||
},
|
||||
{
|
||||
name: 'Module',
|
||||
path: 'attributes.module',
|
||||
description: 'The module that the filter uses'
|
||||
}
|
||||
]
|
||||
|
||||
const list_modules_fields = [
|
||||
{
|
||||
name: 'Module',
|
||||
path: 'id',
|
||||
description: 'Module name'
|
||||
},
|
||||
{
|
||||
name: 'Type',
|
||||
path: 'attributes.module_type',
|
||||
description: 'Module type'
|
||||
},
|
||||
{
|
||||
name: 'Version',
|
||||
path: 'attributes.version',
|
||||
description: 'Module version'
|
||||
}
|
||||
]
|
||||
|
||||
const list_threads_fields = [
|
||||
{
|
||||
name: 'Id',
|
||||
path: 'id',
|
||||
description: 'Thread ID'
|
||||
},
|
||||
{
|
||||
name: 'Current FDs',
|
||||
path: 'attributes.stats.current_descriptors',
|
||||
description: 'Current number of managed file descriptors'
|
||||
},
|
||||
{
|
||||
name: 'Total FDs',
|
||||
path: 'attributes.stats.total_descriptors',
|
||||
description: 'Total number of managed file descriptors'
|
||||
},
|
||||
{
|
||||
name: 'Load (1s)',
|
||||
path: 'attributes.stats.load.last_second',
|
||||
description: 'Load percentage over the last second'
|
||||
},
|
||||
{
|
||||
name: 'Load (1m)',
|
||||
path: 'attributes.stats.load.last_minute',
|
||||
description: 'Load percentage over the last minute'
|
||||
},
|
||||
{
|
||||
name: 'Load (1h)',
|
||||
path: 'attributes.stats.load.last_hour',
|
||||
description: 'Load percentage over the last hour'
|
||||
}
|
||||
]
|
||||
|
||||
const list_users_fields = [
|
||||
{
|
||||
name: 'Name',
|
||||
path: 'id',
|
||||
description: 'User name'
|
||||
},
|
||||
{
|
||||
name: 'Type',
|
||||
path: 'type',
|
||||
description: 'User type'
|
||||
},
|
||||
{
|
||||
name: 'Privileges',
|
||||
path: 'attributes.account',
|
||||
description: 'User privileges'
|
||||
},
|
||||
]
|
||||
|
||||
const list_commands_fields = [
|
||||
{
|
||||
name: 'Module',
|
||||
path: 'id',
|
||||
description: 'Module name'
|
||||
},
|
||||
{
|
||||
name: 'Commands',
|
||||
path: 'attributes.commands[].id',
|
||||
description: 'Available commands'
|
||||
}
|
||||
]
|
||||
|
||||
exports.command = 'list <command>'
|
||||
exports.desc = 'List objects'
|
||||
exports.handler = function() {}
|
||||
exports.builder = function(yargs) {
|
||||
yargs
|
||||
.command('servers', 'List servers', function(yargs) {
|
||||
return yargs.epilog('List all servers in MaxScale.')
|
||||
return yargs.epilog('List all servers in MaxScale.' +
|
||||
fieldDescriptions(list_servers_fields))
|
||||
.usage('Usage: list servers')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
fields = [
|
||||
{'Server': 'id'},
|
||||
{'Address': 'attributes.parameters.address'},
|
||||
{'Port': 'attributes.parameters.port'},
|
||||
{'Connections': 'attributes.statistics.connections'},
|
||||
{'State': 'attributes.state'},
|
||||
{'GTID': 'attributes.gtid_current_pos'}
|
||||
]
|
||||
|
||||
// First, get the list of all servers
|
||||
return getJson(host, 'servers')
|
||||
@ -76,52 +304,41 @@ exports.builder = function(yargs) {
|
||||
}
|
||||
})
|
||||
})
|
||||
.then(() => filterResource(res, fields))
|
||||
.then((res) => rawCollectionAsTable(res, fields))
|
||||
.then(() => filterResource(res, list_servers_fields))
|
||||
.then((res) => rawCollectionAsTable(res, list_servers_fields))
|
||||
})
|
||||
})
|
||||
})
|
||||
.command('services', 'List services', function(yargs) {
|
||||
return yargs.epilog('List all services and the servers they use.')
|
||||
return yargs.epilog('List all services and the servers they use.' +
|
||||
fieldDescriptions(list_services_fields))
|
||||
.usage('Usage: list services')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
return getCollection(host, 'services',[
|
||||
{'Service': 'id'},
|
||||
{'Router': 'attributes.router'},
|
||||
{'Connections': 'attributes.connections'},
|
||||
{'Total Connections': 'attributes.total_connections'},
|
||||
{'Servers': 'relationships.servers.data[].id'}
|
||||
])
|
||||
return getCollection(host, 'services', list_services_fields)
|
||||
})
|
||||
})
|
||||
.command('listeners <service>', 'List listeners of a service', function(yargs) {
|
||||
return yargs.epilog('List listeners for a service.')
|
||||
return yargs.epilog('List listeners for a service.' +
|
||||
fieldDescriptions(list_listeners_fields))
|
||||
.usage('Usage: list listeners <service>')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
return getSubCollection(host, 'services/' + argv.service, 'attributes.listeners', [
|
||||
{'Name': 'id'},
|
||||
{'Port': 'attributes.parameters.port'},
|
||||
{'Host': 'attributes.parameters.host'},
|
||||
{'State': 'attributes.state'}
|
||||
])
|
||||
return getSubCollection(host, 'services/' + argv.service, 'attributes.listeners', list_listeners_fields)
|
||||
})
|
||||
})
|
||||
.command('monitors', 'List monitors', function(yargs) {
|
||||
return yargs.epilog('List all monitors in MaxScale.')
|
||||
return yargs.epilog('List all monitors in MaxScale.' +
|
||||
fieldDescriptions(list_monitors_fields))
|
||||
.usage('Usage: list monitors')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
return getCollection(host, 'monitors', [
|
||||
{'Monitor': 'id'},
|
||||
{'State': 'attributes.state'},
|
||||
{'Servers': 'relationships.servers.data[].id'}
|
||||
])
|
||||
return getCollection(host, 'monitors', list_monitors_fields)
|
||||
})
|
||||
})
|
||||
.command('sessions', 'List sessions', function(yargs) {
|
||||
return yargs.epilog('List all client sessions.')
|
||||
return yargs.epilog('List all client sessions.' +
|
||||
fieldDescriptions(list_sessions_fields))
|
||||
.usage('Usage: list sessions')
|
||||
.group([rDnsOption.shortname], 'Options:')
|
||||
.option(rDnsOption.shortname, rDnsOption.definition)
|
||||
@ -131,76 +348,53 @@ exports.builder = function(yargs) {
|
||||
if (argv[this.rDnsOption.shortname]) {
|
||||
resource += '?' + this.rDnsOption.optionOn
|
||||
}
|
||||
return getCollection(host, resource,[
|
||||
{'Id': 'id'},
|
||||
{'User': 'attributes.user'},
|
||||
{'Host': 'attributes.remote'},
|
||||
{'Connected': 'attributes.connected'},
|
||||
{'Idle': 'attributes.idle'},
|
||||
{'Service': 'relationships.services.data[].id'}
|
||||
])
|
||||
return getCollection(host, 'sessions', list_sessions_fields)
|
||||
})
|
||||
})
|
||||
.command('filters', 'List filters', function(yargs) {
|
||||
return yargs.epilog('List all filters in MaxScale.')
|
||||
return yargs.epilog('List all filters in MaxScale.' +
|
||||
fieldDescriptions(list_filters_fields))
|
||||
.usage('Usage: list filters')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
return getCollection(host, 'filters', [
|
||||
{'Filter': 'id'},
|
||||
{'Service': 'relationships.services.data[].id'},
|
||||
{'Module': 'attributes.module'}
|
||||
])
|
||||
return getCollection(host, 'filters', list_filters_fields)
|
||||
})
|
||||
})
|
||||
.command('modules', 'List loaded modules', function(yargs) {
|
||||
return yargs.epilog('List all currently loaded modules.')
|
||||
return yargs.epilog('List all currently loaded modules.' +
|
||||
fieldDescriptions(list_modules_fields))
|
||||
.usage('Usage: list modules')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
return getCollection(host, 'maxscale/modules',[
|
||||
{'Module':'id'},
|
||||
{'Type':'attributes.module_type'},
|
||||
{'Version': 'attributes.version'}
|
||||
])
|
||||
return getCollection(host, 'maxscale/modules', list_modules_fields)
|
||||
})
|
||||
})
|
||||
.command('threads', 'List threads', function(yargs) {
|
||||
return yargs.epilog('List all worker threads.')
|
||||
return yargs.epilog('List all worker threads.' +
|
||||
fieldDescriptions(list_threads_fields))
|
||||
.usage('Usage: list threads')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
return getCollection(host, 'maxscale/threads', [
|
||||
{'Id': 'id'},
|
||||
{'Current FDs': 'attributes.stats.current_descriptors'},
|
||||
{'Total FDs': 'attributes.stats.total_descriptors'},
|
||||
{'Load (1s)': 'attributes.stats.load.last_second'},
|
||||
{'Load (1m)': 'attributes.stats.load.last_minute'},
|
||||
{'Load (1h)': 'attributes.stats.load.last_hour'}
|
||||
])
|
||||
return getCollection(host, 'maxscale/threads', list_threads_fields)
|
||||
})
|
||||
})
|
||||
.command('users', 'List created users', function(yargs) {
|
||||
return yargs.epilog('List network the users that can be used to connect to the MaxScale REST API as well as enabled local accounts.')
|
||||
return yargs.epilog('List network the users that can be used to connect to the MaxScale REST API' +
|
||||
' as well as enabled local accounts.' +
|
||||
fieldDescriptions(list_users_fields))
|
||||
.usage('Usage: list users')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
return getCollection(host, 'users',[
|
||||
{'Name':'id'},
|
||||
{'Type':'type'},
|
||||
{'Privileges':'attributes.account'},
|
||||
])
|
||||
return getCollection(host, 'users', list_users_fields)
|
||||
})
|
||||
})
|
||||
.command('commands', 'List module commands', function(yargs) {
|
||||
return yargs.epilog('List all available module commands.')
|
||||
return yargs.epilog('List all available module commands.' +
|
||||
fieldDescriptions(list_commands_fields))
|
||||
.usage('Usage: list commands')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
return getCollection(host, 'maxscale/modules',[
|
||||
{'Module':'id'},
|
||||
{'Commands': 'attributes.commands[].id'}
|
||||
])
|
||||
return getCollection(host, 'maxscale/modules', list_commands_fields)
|
||||
})
|
||||
})
|
||||
.usage('Usage: list <command>')
|
||||
|
@ -14,94 +14,438 @@
|
||||
require('./common.js')()
|
||||
|
||||
const server_fields = [
|
||||
{'Server': 'id'},
|
||||
{'Address': 'attributes.parameters.address'},
|
||||
{'Port': 'attributes.parameters.port'},
|
||||
{'State': 'attributes.state'},
|
||||
{'Last Event': 'attributes.last_event'},
|
||||
{'Triggered At': 'attributes.triggered_at'},
|
||||
{'Services': 'relationships.services.data[].id'},
|
||||
{'Monitors': 'relationships.monitors.data[].id'},
|
||||
{'Master ID': 'attributes.master_id'},
|
||||
{'Node ID': 'attributes.node_id'},
|
||||
{'Slave Server IDs': 'attributes.slaves'},
|
||||
{'Statistics': 'attributes.statistics'},
|
||||
{'Parameters': 'attributes.parameters'}
|
||||
{
|
||||
name: 'Server',
|
||||
path: 'id',
|
||||
description: 'Server name'
|
||||
},
|
||||
{
|
||||
name: 'Address',
|
||||
path: 'attributes.parameters.address',
|
||||
description: 'Address where the server listens'
|
||||
},
|
||||
{
|
||||
name: 'Port',
|
||||
path: 'attributes.parameters.port',
|
||||
description: 'The port on which the server listens'
|
||||
},
|
||||
{
|
||||
name: 'State',
|
||||
path: 'attributes.state',
|
||||
description: 'Server state'
|
||||
},
|
||||
{
|
||||
name: 'Last Event',
|
||||
path: 'attributes.last_event',
|
||||
description: 'The type of the latest event'
|
||||
},
|
||||
{
|
||||
name: 'Triggered At',
|
||||
path: 'attributes.triggered_at',
|
||||
description: 'Time when the latest event was triggered at'
|
||||
},
|
||||
{
|
||||
name: 'Services',
|
||||
path: 'relationships.services.data[].id',
|
||||
description: 'Services that use this server'
|
||||
},
|
||||
{
|
||||
name: 'Monitors',
|
||||
path: 'relationships.monitors.data[].id',
|
||||
description: 'Monitors that monitor this server'
|
||||
},
|
||||
{
|
||||
name: 'Master ID',
|
||||
path: 'attributes.master_id',
|
||||
description: 'The server ID of the master'
|
||||
},
|
||||
{
|
||||
name: 'Node ID',
|
||||
path: 'attributes.node_id',
|
||||
description: 'The node ID of this server'
|
||||
},
|
||||
{
|
||||
name: 'Slave Server IDs',
|
||||
path: 'attributes.slaves',
|
||||
description: 'List of slave server IDs'
|
||||
},
|
||||
{
|
||||
name: 'Statistics',
|
||||
path: 'attributes.statistics',
|
||||
description: 'Server statistics'
|
||||
},
|
||||
{
|
||||
name: 'Parameters',
|
||||
path: 'attributes.parameters',
|
||||
description: 'Server parameters'
|
||||
}
|
||||
]
|
||||
|
||||
const service_fields = [
|
||||
{'Service': 'id'},
|
||||
{'Router': 'attributes.router'},
|
||||
{'State': 'attributes.state'},
|
||||
{'Started At': 'attributes.started'},
|
||||
{'Current Connections': 'attributes.connections'},
|
||||
{'Total Connections': 'attributes.total_connections'},
|
||||
{'Servers': 'relationships.servers.data[].id'},
|
||||
{'Parameters': 'attributes.parameters'},
|
||||
{'Router Diagnostics': 'attributes.router_diagnostics'}
|
||||
{
|
||||
name: 'Service',
|
||||
path: 'id',
|
||||
description: 'Service name'
|
||||
},
|
||||
{
|
||||
name: 'Router',
|
||||
path: 'attributes.router',
|
||||
description: 'Router that the service uses'
|
||||
},
|
||||
{
|
||||
name: 'State',
|
||||
path: 'attributes.state',
|
||||
description: 'Service state'
|
||||
},
|
||||
{
|
||||
name: 'Started At',
|
||||
path: 'attributes.started',
|
||||
description: 'When the service was started'
|
||||
},
|
||||
{
|
||||
name: 'Current Connections',
|
||||
path: 'attributes.connections',
|
||||
description: 'Current connection count'
|
||||
},
|
||||
{
|
||||
name: 'Total Connections',
|
||||
path: 'attributes.total_connections',
|
||||
description: 'Total connection count'
|
||||
},
|
||||
{
|
||||
name: 'Servers',
|
||||
path: 'relationships.servers.data[].id',
|
||||
description: 'Servers that the service uses'
|
||||
},
|
||||
{
|
||||
name: 'Parameters',
|
||||
path: 'attributes.parameters',
|
||||
description: 'Service parameter'
|
||||
},
|
||||
{
|
||||
name: 'Router Diagnostics',
|
||||
path: 'attributes.router_diagnostics',
|
||||
description: 'Diagnostics provided by the router module'
|
||||
}
|
||||
]
|
||||
|
||||
const monitor_fields = [
|
||||
{'Monitor': 'id'},
|
||||
{'State': 'attributes.state'},
|
||||
{'Servers': 'relationships.servers.data[].id'},
|
||||
{'Parameters': 'attributes.parameters'},
|
||||
{'Monitor Diagnostics': 'attributes.monitor_diagnostics'}
|
||||
{
|
||||
name: 'Monitor',
|
||||
path: 'id',
|
||||
description: 'Monitor name'
|
||||
},
|
||||
{
|
||||
name: 'State',
|
||||
path: 'attributes.state',
|
||||
description: 'Monitor state'
|
||||
},
|
||||
{
|
||||
name: 'Servers',
|
||||
path: 'relationships.servers.data[].id',
|
||||
description: 'The servers that this monitor monitors'
|
||||
},
|
||||
{
|
||||
name: 'Parameters',
|
||||
path: 'attributes.parameters',
|
||||
description: 'Monitor parameters'
|
||||
},
|
||||
{
|
||||
name: 'Monitor Diagnostics',
|
||||
path: 'attributes.monitor_diagnostics',
|
||||
description: 'Diagnostics provided by the monitor module'
|
||||
}
|
||||
]
|
||||
|
||||
const session_fields = [
|
||||
{'Id': 'id'},
|
||||
{'Service': 'relationships.services.data[].id'},
|
||||
{'State': 'attributes.state'},
|
||||
{'User': 'attributes.user'},
|
||||
{'Host': 'attributes.remote'},
|
||||
{'Connected': 'attributes.connected'},
|
||||
{'Idle': 'attributes.idle'},
|
||||
{'Connections': 'attributes.connections[].server'},
|
||||
{'Connection IDs': 'attributes.connections[].protocol_diagnostics.connection_id'},
|
||||
{'Queries': 'attributes.queries[].statement'},
|
||||
{'Log': 'attributes.log'}
|
||||
{
|
||||
name: 'Id',
|
||||
path: 'id',
|
||||
description: 'Session ID'
|
||||
},
|
||||
{
|
||||
name: 'Service',
|
||||
path: 'relationships.services.data[].id',
|
||||
description: 'The service where the session connected'
|
||||
},
|
||||
{
|
||||
name: 'State',
|
||||
path: 'attributes.state',
|
||||
description: 'Session state'
|
||||
},
|
||||
{
|
||||
name: 'User',
|
||||
path: 'attributes.user',
|
||||
description: 'Username'
|
||||
},
|
||||
{
|
||||
name: 'Host',
|
||||
path: 'attributes.remote',
|
||||
description: 'Client host address'
|
||||
},
|
||||
{
|
||||
name: 'Connected',
|
||||
path: 'attributes.connected',
|
||||
description: 'Time when the session started'
|
||||
},
|
||||
{
|
||||
name: 'Idle',
|
||||
path: 'attributes.idle',
|
||||
description: 'How long the session has been idle, in seconds'
|
||||
},
|
||||
{
|
||||
name: 'Connections',
|
||||
path: 'attributes.connections[].server',
|
||||
description: 'Ordered list of backend connections'
|
||||
},
|
||||
{
|
||||
name: 'Connection IDs',
|
||||
path: 'attributes.connections[].protocol_diagnostics.connection_id',
|
||||
description: 'Thread IDs for the backend connections'
|
||||
},
|
||||
{
|
||||
name: 'Queries',
|
||||
path: 'attributes.queries[].statement',
|
||||
description: 'Query history'
|
||||
},
|
||||
{
|
||||
name: 'Log',
|
||||
path: 'attributes.log',
|
||||
description: 'Per-session log messages'
|
||||
}
|
||||
]
|
||||
|
||||
const filter_fields = [
|
||||
{'Filter': 'id'},
|
||||
{'Module': 'attributes.module'},
|
||||
{'Services': 'relationships.services.data[].id'},
|
||||
{'Parameters': 'attributes.parameters'}
|
||||
{
|
||||
name: 'Filter',
|
||||
path: 'id',
|
||||
description: 'Filter name'
|
||||
},
|
||||
{
|
||||
name: 'Module',
|
||||
path: 'attributes.module',
|
||||
description: 'The module that the filter uses'
|
||||
},
|
||||
{
|
||||
name: 'Services',
|
||||
path: 'relationships.services.data[].id',
|
||||
description: 'Services that use the filter'
|
||||
},
|
||||
{
|
||||
name: 'Parameters',
|
||||
path: 'attributes.parameters',
|
||||
description: 'Filter parameters'
|
||||
}
|
||||
]
|
||||
|
||||
const module_fields = [
|
||||
{'Module': 'id'},
|
||||
{'Type': 'attributes.module_type'},
|
||||
{'Version': 'attributes.version'},
|
||||
{'Maturity': 'attributes.maturity'},
|
||||
{'Description': 'attributes.description'},
|
||||
{'Parameters': 'attributes.parameters'},
|
||||
{'Commands': 'attributes.commands'}
|
||||
{
|
||||
name: 'Module',
|
||||
path: 'id',
|
||||
description: 'Module name'
|
||||
},
|
||||
{
|
||||
name: 'Type',
|
||||
path: 'attributes.module_type',
|
||||
description: 'Module type'
|
||||
},
|
||||
{
|
||||
name: 'Version',
|
||||
path: 'attributes.version',
|
||||
description: 'Module version'
|
||||
},
|
||||
{
|
||||
name: 'Maturity',
|
||||
path: 'attributes.maturity',
|
||||
description: 'Module maturity'
|
||||
},
|
||||
{
|
||||
name: 'Description',
|
||||
path: 'attributes.description',
|
||||
description: 'Short description about the module'
|
||||
},
|
||||
{
|
||||
name: 'Parameters',
|
||||
path: 'attributes.parameters',
|
||||
description: 'All the parameters that the module accepts'
|
||||
},
|
||||
{
|
||||
name: 'Commands',
|
||||
path: 'attributes.commands',
|
||||
description: 'Commands that the module provides'
|
||||
}
|
||||
]
|
||||
|
||||
const thread_fields = [
|
||||
{'Id': 'id'},
|
||||
{'Accepts': 'attributes.stats.accepts'},
|
||||
{'Reads': 'attributes.stats.reads'},
|
||||
{'Writes': 'attributes.stats.writes'},
|
||||
{'Hangups': 'attributes.stats.hangups'},
|
||||
{'Errors': 'attributes.stats.errors'},
|
||||
{'Blocking polls': 'attributes.stats.blocking_polls'},
|
||||
{'Avg event queue length': 'attributes.stats.avg_event_queue_length'},
|
||||
{'Max event queue length': 'attributes.stats.max_event_queue_length'},
|
||||
{'Max exec time': 'attributes.stats.max_exec_time'},
|
||||
{'Max queue time': 'attributes.stats.max_queue_time'},
|
||||
{'Current FDs': 'attributes.stats.current_descriptors'},
|
||||
{'Total FDs': 'attributes.stats.total_descriptors'},
|
||||
{'Load (1s)': 'attributes.stats.load.last_second'},
|
||||
{'Load (1m)': 'attributes.stats.load.last_minute'},
|
||||
{'Load (1h)': 'attributes.stats.load.last_hour'},
|
||||
{'QC cache size': 'attributes.stats.query_classifier_cache.size'},
|
||||
{'QC cache inserts': 'attributes.stats.query_classifier_cache.inserts'},
|
||||
{'QC cache hits': 'attributes.stats.query_classifier_cache.hits'},
|
||||
{'QC cache misses': 'attributes.stats.query_classifier_cache.misses'},
|
||||
{'QC cache evictions': 'attributes.stats.query_classifier_cache.evictions'},
|
||||
{
|
||||
name: 'Id',
|
||||
path: 'id',
|
||||
description: 'Thread ID'
|
||||
},
|
||||
{
|
||||
name: 'Accepts',
|
||||
path: 'attributes.stats.accepts',
|
||||
description: 'Number of TCP accepts done by this thread'
|
||||
},
|
||||
{
|
||||
name: 'Reads',
|
||||
path: 'attributes.stats.reads',
|
||||
description: 'Number of EPOLLIN events'
|
||||
},
|
||||
{
|
||||
name: 'Writes',
|
||||
path: 'attributes.stats.writes',
|
||||
description: 'Number of EPOLLOUT events'
|
||||
},
|
||||
{
|
||||
name: 'Hangups',
|
||||
path: 'attributes.stats.hangups',
|
||||
description: 'Number of EPOLLHUP and EPOLLRDUP events'
|
||||
},
|
||||
{
|
||||
name: 'Errors',
|
||||
path: 'attributes.stats.errors',
|
||||
description: 'Number of EPOLLERR events'
|
||||
},
|
||||
{
|
||||
name: 'Avg event queue length',
|
||||
path: 'attributes.stats.avg_event_queue_length',
|
||||
description: 'Average number of events returned by one epoll_wait call'
|
||||
},
|
||||
{
|
||||
name: 'Max event queue length',
|
||||
path: 'attributes.stats.max_event_queue_length',
|
||||
description: 'Maximum number of events returned by one epoll_wait call'
|
||||
},
|
||||
{
|
||||
name: 'Max exec time',
|
||||
path: 'attributes.stats.max_exec_time',
|
||||
description: 'The longest time spent processing events returned by a epoll_wait call'
|
||||
},
|
||||
{
|
||||
name: 'Max queue time',
|
||||
path: 'attributes.stats.max_queue_time',
|
||||
description: 'The longest time an event had to wait before it was processed'
|
||||
},
|
||||
{
|
||||
name: 'Current FDs',
|
||||
path: 'attributes.stats.current_descriptors',
|
||||
description: 'Current number of managed file descriptors'
|
||||
},
|
||||
{
|
||||
name: 'Total FDs',
|
||||
path: 'attributes.stats.total_descriptors',
|
||||
description: 'Total number of managed file descriptors'
|
||||
},
|
||||
{
|
||||
name: 'Load (1s)',
|
||||
path: 'attributes.stats.load.last_second',
|
||||
description: 'Load percentage over the last second'
|
||||
},
|
||||
{
|
||||
name: 'Load (1m)',
|
||||
path: 'attributes.stats.load.last_minute',
|
||||
description: 'Load percentage over the last minute'
|
||||
},
|
||||
{
|
||||
name: 'Load (1h)',
|
||||
path: 'attributes.stats.load.last_hour',
|
||||
description: 'Load percentage over the last hour'
|
||||
},
|
||||
{
|
||||
name: 'QC cache size',
|
||||
path: 'attributes.stats.query_classifier_cache.size',
|
||||
description: 'Query classifier size'
|
||||
},
|
||||
{
|
||||
name: 'QC cache inserts',
|
||||
path: 'attributes.stats.query_classifier_cache.inserts',
|
||||
description: 'Number of times a new query was added into the query classification cache'
|
||||
},
|
||||
{
|
||||
name: 'QC cache hits',
|
||||
path: 'attributes.stats.query_classifier_cache.hits',
|
||||
description: 'How many times a query classification was found in the query classification cache'
|
||||
},
|
||||
{
|
||||
name: 'QC cache misses',
|
||||
path: 'attributes.stats.query_classifier_cache.misses',
|
||||
description: 'How many times a query classification was not found in the query classification cache'
|
||||
},
|
||||
{
|
||||
name: 'QC cache evictions',
|
||||
path: 'attributes.stats.query_classifier_cache.evictions',
|
||||
description: 'How many times a query classification result was evicted from the query classification cache'
|
||||
},
|
||||
]
|
||||
|
||||
const show_maxscale_fields = [
|
||||
{
|
||||
name: 'Version',
|
||||
path: 'attributes.version',
|
||||
description: 'MaxScale version'
|
||||
},
|
||||
{
|
||||
name: 'Commit',
|
||||
path: 'attributes.commit',
|
||||
description: 'MaxScale commit ID'
|
||||
},
|
||||
{
|
||||
name: 'Started At',
|
||||
path: 'attributes.started_at',
|
||||
description: 'Time when MaxScale was started'
|
||||
},
|
||||
{
|
||||
name: 'Activated At',
|
||||
path: 'attributes.activated_at',
|
||||
description: 'Time when MaxScale left passive mode'
|
||||
},
|
||||
{
|
||||
name: 'Uptime',
|
||||
path: 'attributes.uptime',
|
||||
description: 'Time MaxScale has been running'
|
||||
},
|
||||
{
|
||||
name: 'Parameters',
|
||||
path: 'attributes.parameters',
|
||||
description: 'Global MaxScale parameters'
|
||||
}
|
||||
]
|
||||
|
||||
const show_logging_fields = [
|
||||
{
|
||||
name: 'Current Log File',
|
||||
path: 'attributes.log_file',
|
||||
description: 'The current log file MaxScale is logging into'
|
||||
},
|
||||
{
|
||||
name: 'Enabled Log Levels',
|
||||
path: 'attributes.log_priorities',
|
||||
description: 'List of log levels enabled in MaxScale'
|
||||
},
|
||||
{
|
||||
name: 'Parameters',
|
||||
path: 'attributes.parameters',
|
||||
description: 'Logging parameters'
|
||||
}
|
||||
]
|
||||
|
||||
const show_commands_fields = [
|
||||
{
|
||||
name: 'Command',
|
||||
path: 'id',
|
||||
description: 'Command name'
|
||||
},
|
||||
{
|
||||
name: 'Parameters',
|
||||
path: 'attributes.parameters[].type',
|
||||
description: 'Parameters the command supports'
|
||||
},
|
||||
{
|
||||
name: 'Descriptions',
|
||||
path: 'attributes.parameters[].description',
|
||||
description: 'Parameter descriptions'
|
||||
}
|
||||
]
|
||||
|
||||
exports.command = 'show <command>'
|
||||
@ -113,7 +457,7 @@ exports.builder = function(yargs) {
|
||||
return yargs.epilog('Show detailed information about a server. The `Parameters` ' +
|
||||
'field contains the currently configured parameters for this ' +
|
||||
'server. See `help alter server` for more details about altering ' +
|
||||
'server parameters.')
|
||||
'server parameters.' + fieldDescriptions(server_fields))
|
||||
.usage('Usage: show server <server>')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
@ -121,7 +465,8 @@ exports.builder = function(yargs) {
|
||||
})
|
||||
})
|
||||
.command('servers', 'Show all servers', function(yargs) {
|
||||
return yargs.epilog('Show detailed information about all servers.')
|
||||
return yargs.epilog('Show detailed information about all servers.' +
|
||||
fieldDescriptions(server_fields))
|
||||
.usage('Usage: show servers')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
@ -132,7 +477,7 @@ exports.builder = function(yargs) {
|
||||
return yargs.epilog('Show detailed information about a service. The `Parameters` ' +
|
||||
'field contains the currently configured parameters for this ' +
|
||||
'service. See `help alter service` for more details about altering ' +
|
||||
'service parameters.')
|
||||
'service parameters.' + fieldDescriptions(service_fields))
|
||||
.usage('Usage: show service <service>')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
@ -140,7 +485,8 @@ exports.builder = function(yargs) {
|
||||
})
|
||||
})
|
||||
.command('services', 'Show all services', function(yargs) {
|
||||
return yargs.epilog('Show detailed information about all services.')
|
||||
return yargs.epilog('Show detailed information about all services.' +
|
||||
fieldDescriptions(service_fields))
|
||||
.usage('Usage: show services')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
@ -151,7 +497,7 @@ exports.builder = function(yargs) {
|
||||
return yargs.epilog('Show detailed information about a monitor. The `Parameters` ' +
|
||||
'field contains the currently configured parameters for this ' +
|
||||
'monitor. See `help alter monitor` for more details about altering ' +
|
||||
'monitor parameters.')
|
||||
'monitor parameters.' + fieldDescriptions(monitor_fields))
|
||||
.usage('Usage: show monitor <monitor>')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
@ -159,7 +505,8 @@ exports.builder = function(yargs) {
|
||||
})
|
||||
})
|
||||
.command('monitors', 'Show all monitors', function(yargs) {
|
||||
return yargs.epilog('Show detailed information about all monitors.')
|
||||
return yargs.epilog('Show detailed information about all monitors.' +
|
||||
fieldDescriptions(monitor_fields))
|
||||
.usage('Usage: show monitors')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
@ -173,7 +520,8 @@ exports.builder = function(yargs) {
|
||||
'ID of a particular session.\n\n' +
|
||||
'The `Connections` field lists the servers to which ' +
|
||||
'the session is connected and the `Connection IDs` ' +
|
||||
'field lists the IDs for those connections.')
|
||||
'field lists the IDs for those connections.' +
|
||||
fieldDescriptions(session_fields))
|
||||
.usage('Usage: show session <session>')
|
||||
.group([rDnsOption.shortname], 'Options:')
|
||||
.option(rDnsOption.shortname, rDnsOption.definition)
|
||||
@ -188,7 +536,8 @@ exports.builder = function(yargs) {
|
||||
})
|
||||
.command('sessions', 'Show all sessions', function(yargs) {
|
||||
return yargs.epilog('Show detailed information about all sessions. ' +
|
||||
'See `help show session` for more details.')
|
||||
'See `help show session` for more details.' +
|
||||
fieldDescriptions(session_fields))
|
||||
.usage('Usage: show sessions')
|
||||
.group([rDnsOption.shortname], 'Options:')
|
||||
.option(rDnsOption.shortname, rDnsOption.definition)
|
||||
@ -202,7 +551,8 @@ exports.builder = function(yargs) {
|
||||
})
|
||||
})
|
||||
.command('filter <filter>', 'Show filter', function(yargs) {
|
||||
return yargs.epilog('The list of services that use this filter is show in the `Services` field.')
|
||||
return yargs.epilog('The list of services that use this filter is show in the `Services` field.' +
|
||||
fieldDescriptions(filter_fields))
|
||||
.usage('Usage: show filter <filter>')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
@ -210,7 +560,8 @@ exports.builder = function(yargs) {
|
||||
})
|
||||
})
|
||||
.command('filters', 'Show all filters', function(yargs) {
|
||||
return yargs.epilog('Show detailed information of all filters.')
|
||||
return yargs.epilog('Show detailed information of all filters.' +
|
||||
fieldDescriptions(filter_fields))
|
||||
.usage('Usage: show filters')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
@ -219,7 +570,8 @@ exports.builder = function(yargs) {
|
||||
})
|
||||
.command('module <module>', 'Show loaded module', function(yargs) {
|
||||
return yargs.epilog('This command shows all available parameters as well as ' +
|
||||
'detailed version information of a loaded module.')
|
||||
'detailed version information of a loaded module.' +
|
||||
fieldDescriptions(module_fields))
|
||||
.usage('Usage: show module <module>')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
@ -227,7 +579,8 @@ exports.builder = function(yargs) {
|
||||
})
|
||||
})
|
||||
.command('modules', 'Show all loaded modules', function(yargs) {
|
||||
return yargs.epilog('Displays detailed information about all modules.')
|
||||
return yargs.epilog('Displays detailed information about all modules.' +
|
||||
fieldDescriptions(module_fields))
|
||||
.usage('Usage: show modules')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
@ -236,22 +589,16 @@ exports.builder = function(yargs) {
|
||||
})
|
||||
.command('maxscale', 'Show MaxScale information', function(yargs) {
|
||||
return yargs.epilog('See `help alter maxscale` for more details about altering ' +
|
||||
'MaxScale parameters.')
|
||||
'MaxScale parameters.' + fieldDescriptions(show_maxscale_fields))
|
||||
.usage('Usage: show maxscale')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
return getResource(host, 'maxscale', [
|
||||
{'Version': 'attributes.version'},
|
||||
{'Commit': 'attributes.commit'},
|
||||
{'Started At': 'attributes.started_at'},
|
||||
{'Activated At': 'attributes.activated_at'},
|
||||
{'Uptime': 'attributes.uptime'},
|
||||
{'Parameters': 'attributes.parameters'}
|
||||
])
|
||||
return getResource(host, 'maxscale', show_maxscale_fields)
|
||||
})
|
||||
})
|
||||
.command('thread <thread>', 'Show thread', function(yargs) {
|
||||
return yargs.epilog('Show detailed information about a worker thread.')
|
||||
return yargs.epilog('Show detailed information about a worker thread.' +
|
||||
fieldDescriptions(thread_fields))
|
||||
.usage('Usage: show thread <thread>')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
@ -259,7 +606,8 @@ exports.builder = function(yargs) {
|
||||
})
|
||||
})
|
||||
.command('threads', 'Show all threads', function(yargs) {
|
||||
return yargs.epilog('Show detailed information about all worker threads.')
|
||||
return yargs.epilog('Show detailed information about all worker threads.' +
|
||||
fieldDescriptions(thread_fields))
|
||||
.usage('Usage: show threads')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
@ -268,28 +616,21 @@ exports.builder = function(yargs) {
|
||||
})
|
||||
.command('logging', 'Show MaxScale logging information', function(yargs) {
|
||||
return yargs.epilog('See `help alter logging` for more details about altering ' +
|
||||
'logging parameters.')
|
||||
'logging parameters.' + fieldDescriptions(show_logging_fields))
|
||||
.usage('Usage: show logging')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
return getResource(host, 'maxscale/logs', [
|
||||
{'Current Log File': 'attributes.log_file'},
|
||||
{'Enabled Log Levels': 'attributes.log_priorities'},
|
||||
{'Parameters': 'attributes.parameters'}
|
||||
])
|
||||
return getResource(host, 'maxscale/logs', show_logging_fields)
|
||||
})
|
||||
})
|
||||
.command('commands <module>', 'Show module commands of a module', function(yargs) {
|
||||
return yargs.epilog('This command shows the parameters the command expects with ' +
|
||||
'the parameter descriptions.')
|
||||
'the parameter descriptions.' + fieldDescriptions(show_commands_fields))
|
||||
.usage('Usage: show commands <module>')
|
||||
}, function(argv) {
|
||||
maxctrl(argv, function(host) {
|
||||
return getSubCollection(host, 'maxscale/modules/' + argv.module, 'attributes.commands', [
|
||||
{'Command': 'id'},
|
||||
{'Parameters': 'attributes.parameters[].type'},
|
||||
{'Descriptions': 'attributes.parameters[].description'}
|
||||
])
|
||||
return getSubCollection(host, 'maxscale/modules/' + argv.module, 'attributes.commands',
|
||||
show_commands_fields)
|
||||
})
|
||||
})
|
||||
.command('qc_cache', 'Show query classifier cache', function(yargs) {
|
||||
|
@ -1259,7 +1259,7 @@ mxs_pcre2_result_t modutil_mysql_wildcard_match(const char* pattern, const char*
|
||||
return rval;
|
||||
}
|
||||
|
||||
static inline bool is_next(mxs::Buffer::iterator it, mxs::Buffer::iterator end, const std::string& str)
|
||||
static inline bool is_next(uint8_t* it, uint8_t* end, const std::string& str)
|
||||
{
|
||||
mxb_assert(it != end);
|
||||
for (auto s_it = str.begin(); s_it != str.end(); ++s_it, ++it)
|
||||
@ -1316,12 +1316,11 @@ static const LUT is_special([](uint8_t c) {
|
||||
c) != std::string::npos;
|
||||
});
|
||||
|
||||
static std::pair<bool, mxs::Buffer::iterator> probe_number(mxs::Buffer::iterator it,
|
||||
mxs::Buffer::iterator end)
|
||||
static inline std::pair<bool, uint8_t*> probe_number(uint8_t* it, uint8_t* end)
|
||||
{
|
||||
mxb_assert(it != end);
|
||||
mxb_assert(is_digit(*it));
|
||||
std::pair<bool, mxs::Buffer::iterator> rval = std::make_pair(true, it);
|
||||
std::pair<bool, uint8_t*> rval = std::make_pair(true, it);
|
||||
bool is_hex = *it == '0';
|
||||
bool allow_hex = false;
|
||||
|
||||
@ -1348,7 +1347,7 @@ static std::pair<bool, mxs::Buffer::iterator> probe_number(mxs::Buffer::iterator
|
||||
else if (*it == 'e')
|
||||
{
|
||||
// Possible scientific notation number
|
||||
auto next_it = std::next(it);
|
||||
auto next_it = it + 1;
|
||||
|
||||
if (next_it == end || (!is_digit(*next_it) && *next_it != '-'))
|
||||
{
|
||||
@ -1365,7 +1364,7 @@ static std::pair<bool, mxs::Buffer::iterator> probe_number(mxs::Buffer::iterator
|
||||
else if (*it == '.')
|
||||
{
|
||||
// Possible decimal number
|
||||
auto next_it = std::next(it);
|
||||
auto next_it = it + 1;
|
||||
|
||||
if (next_it != end && !is_digit(*next_it))
|
||||
{
|
||||
@ -1415,7 +1414,7 @@ static inline bool is_negation(const std::string& str, int i)
|
||||
return rval;
|
||||
}
|
||||
|
||||
mxs::Buffer::iterator find_char(mxs::Buffer::iterator it, const mxs::Buffer::iterator& end, char c)
|
||||
static inline uint8_t* find_char(uint8_t* it, uint8_t* end, char c)
|
||||
{
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
@ -1440,13 +1439,13 @@ namespace maxscale
|
||||
|
||||
std::string get_canonical(GWBUF* querybuf)
|
||||
{
|
||||
std::string rval;
|
||||
mxb_assert(GWBUF_IS_CONTIGUOUS(querybuf));
|
||||
uint8_t* it = GWBUF_DATA(querybuf) + MYSQL_HEADER_LEN + 1;
|
||||
uint8_t* end = GWBUF_DATA(querybuf) + gwbuf_length(querybuf);
|
||||
std::string rval(end - it, 0);
|
||||
int i = 0;
|
||||
rval.resize(gwbuf_length(querybuf) - MYSQL_HEADER_LEN + 1);
|
||||
mxs::Buffer buf(querybuf);
|
||||
|
||||
for (auto it = std::next(buf.begin(), MYSQL_HEADER_LEN + 1); // Skip packet header and command
|
||||
it != buf.end(); ++it)
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (!is_special(*it))
|
||||
{
|
||||
@ -1456,9 +1455,9 @@ std::string get_canonical(GWBUF* querybuf)
|
||||
else if (*it == '\\')
|
||||
{
|
||||
// Jump over any escaped values
|
||||
rval[i++] += *it++;
|
||||
rval[i++] = *it++;
|
||||
|
||||
if (it != buf.end())
|
||||
if (it != end)
|
||||
{
|
||||
rval[i++] = *it;
|
||||
}
|
||||
@ -1479,19 +1478,19 @@ std::string get_canonical(GWBUF* querybuf)
|
||||
rval[i++] = ' ';
|
||||
}
|
||||
}
|
||||
else if (*it == '/' && is_next(it, buf.end(), "/*"))
|
||||
else if (*it == '/' && is_next(it, end, "/*"))
|
||||
{
|
||||
auto comment_start = std::next(it, 2);
|
||||
if (comment_start == buf.end())
|
||||
if (comment_start == end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (*comment_start != '!' && *comment_start != 'M')
|
||||
{
|
||||
// Non-executable comment
|
||||
while (it != buf.end())
|
||||
while (it != end)
|
||||
{
|
||||
if (is_next(it, buf.end(), "*/"))
|
||||
if (is_next(it, end, "*/"))
|
||||
{
|
||||
// Comment end marker, return to normal parsing
|
||||
++it;
|
||||
@ -1500,7 +1499,7 @@ std::string get_canonical(GWBUF* querybuf)
|
||||
++it;
|
||||
}
|
||||
|
||||
if (it == buf.end())
|
||||
if (it == end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -1512,10 +1511,10 @@ std::string get_canonical(GWBUF* querybuf)
|
||||
}
|
||||
}
|
||||
else if ((*it == '#' || *it == '-')
|
||||
&& (is_next(it, buf.end(), "# ") || is_next(it, buf.end(), "-- ")))
|
||||
&& (is_next(it, end, "# ") || is_next(it, end, "-- ")))
|
||||
{
|
||||
// End-of-line comment, jump to the next line if one exists
|
||||
while (it != buf.end())
|
||||
while (it != end)
|
||||
{
|
||||
if (*it == '\n')
|
||||
{
|
||||
@ -1523,7 +1522,7 @@ std::string get_canonical(GWBUF* querybuf)
|
||||
}
|
||||
else if (*it == '\r')
|
||||
{
|
||||
if ((is_next(it, buf.end(), "\r\n")))
|
||||
if ((is_next(it, end, "\r\n")))
|
||||
{
|
||||
++it;
|
||||
}
|
||||
@ -1533,14 +1532,14 @@ std::string get_canonical(GWBUF* querybuf)
|
||||
++it;
|
||||
}
|
||||
|
||||
if (it == buf.end())
|
||||
if (it == end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (is_digit(*it) && (i == 0 || (!is_alnum(rval[i - 1]) && rval[i - 1] != '_')))
|
||||
{
|
||||
auto num_end = probe_number(it, buf.end());
|
||||
auto num_end = probe_number(it, end);
|
||||
|
||||
if (num_end.first)
|
||||
{
|
||||
@ -1556,7 +1555,7 @@ std::string get_canonical(GWBUF* querybuf)
|
||||
else if (*it == '\'' || *it == '"')
|
||||
{
|
||||
char c = *it;
|
||||
if ((it = find_char(std::next(it), buf.end(), c)) == buf.end())
|
||||
if ((it = find_char(it + 1, end, c)) == end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -1565,7 +1564,7 @@ std::string get_canonical(GWBUF* querybuf)
|
||||
else if (*it == '`')
|
||||
{
|
||||
auto start = it;
|
||||
if ((it = find_char(std::next(it), buf.end(), '`')) == buf.end())
|
||||
if ((it = find_char(it + 1, end, '`')) == end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -1578,7 +1577,7 @@ std::string get_canonical(GWBUF* querybuf)
|
||||
rval[i++] = *it;
|
||||
}
|
||||
|
||||
mxb_assert(it != buf.end());
|
||||
mxb_assert(it != end);
|
||||
}
|
||||
|
||||
// Remove trailing whitespace
|
||||
@ -1590,8 +1589,6 @@ std::string get_canonical(GWBUF* querybuf)
|
||||
// Shrink the buffer so that the internal bookkeeping of std::string remains up to date
|
||||
rval.resize(i);
|
||||
|
||||
buf.release();
|
||||
|
||||
return rval;
|
||||
}
|
||||
}
|
||||
|
@ -208,6 +208,24 @@ void ResultSet::write(DCB* dcb)
|
||||
mysql_send_eof(dcb, seqno);
|
||||
}
|
||||
|
||||
json_t* ResultSet::get_json_value(const std::string& s)
|
||||
{
|
||||
json_t* js;
|
||||
char* end;
|
||||
long l = strtol(s.c_str(), &end, 10);
|
||||
|
||||
if (end != s.c_str() && *end == '\0')
|
||||
{
|
||||
js = json_integer(l);
|
||||
}
|
||||
else
|
||||
{
|
||||
js = json_string(s.c_str());
|
||||
}
|
||||
|
||||
return js;
|
||||
}
|
||||
|
||||
void ResultSet::write_as_json(DCB* dcb)
|
||||
{
|
||||
json_t* arr = json_array();
|
||||
@ -218,7 +236,7 @@ void ResultSet::write_as_json(DCB* dcb)
|
||||
|
||||
for (size_t i = 0; i < row.size(); i++)
|
||||
{
|
||||
json_object_set_new(obj, m_columns[i].c_str(), json_string(row[i].c_str()));
|
||||
json_object_set_new(obj, m_columns[i].c_str(), get_json_value(row[i]));
|
||||
}
|
||||
|
||||
json_array_append_new(arr, obj);
|
||||
@ -227,4 +245,6 @@ void ResultSet::write_as_json(DCB* dcb)
|
||||
char* js = json_dumps(arr, JSON_INDENT(4));
|
||||
dcb_printf(dcb, "%s", js);
|
||||
MXS_FREE(js);
|
||||
|
||||
json_decref(arr);
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ struct
|
||||
uint64_t next_session_id;
|
||||
uint32_t retain_last_statements;
|
||||
session_dump_statements_t dump_statements;
|
||||
uint32_t session_trace;
|
||||
uint32_t session_trace;
|
||||
} this_unit =
|
||||
{
|
||||
1,
|
||||
@ -160,7 +160,6 @@ bool session_start(MXS_SESSION* session)
|
||||
|
||||
session->state = SESSION_STATE_STARTED;
|
||||
mxb::atomic::add(&session->service->stats.n_sessions, 1, mxb::atomic::RELAXED);
|
||||
mxb::atomic::add(&session->service->stats.n_current, 1, mxb::atomic::RELAXED);
|
||||
|
||||
MXS_INFO("Started %s client session [%" PRIu64 "] for '%s' from %s",
|
||||
session->service->name(), session->ses_id,
|
||||
@ -279,8 +278,6 @@ static void session_final_free(MXS_SESSION* ses)
|
||||
|
||||
session->state = SESSION_STATE_TO_BE_FREED;
|
||||
|
||||
mxb::atomic::add(&session->service->stats.n_current, -1, mxb::atomic::RELAXED);
|
||||
|
||||
if (session->client_dcb)
|
||||
{
|
||||
dcb_free_all_memory(session->client_dcb);
|
||||
@ -1162,6 +1159,9 @@ Session::Session(const SListener& listener)
|
||||
{
|
||||
m_retain_last_statements = this_unit.retain_last_statements;
|
||||
}
|
||||
|
||||
mxb::atomic::add(&service->stats.n_current, 1, mxb::atomic::RELAXED);
|
||||
mxb_assert(service->stats.n_current >= 0);
|
||||
}
|
||||
|
||||
Session::~Session()
|
||||
@ -1176,6 +1176,9 @@ Session::~Session()
|
||||
f.filter->obj->closeSession(f.instance, f.session);
|
||||
f.filter->obj->freeSession(f.instance, f.session);
|
||||
}
|
||||
|
||||
mxb::atomic::add(&service->stats.n_current, -1, mxb::atomic::RELAXED);
|
||||
mxb_assert(service->stats.n_current >= 0);
|
||||
}
|
||||
|
||||
void Session::set_client_dcb(DCB* dcb)
|
||||
@ -1696,6 +1699,6 @@ void Session::dump_session_log()
|
||||
log += s;
|
||||
}
|
||||
|
||||
MXS_NOTICE("Session log for session (%" PRIu64"): \n%s ", ses_id, log.c_str());
|
||||
MXS_NOTICE("Session log for session (%" PRIu64 "): \n%s ", ses_id, log.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
add_executable(profile_trxboundaryparser profile_trxboundaryparser.cc)
|
||||
add_executable(profile_get_canonical profile_get_canonical.cc)
|
||||
add_executable(test_adminusers test_adminusers.cc)
|
||||
add_executable(test_atomic test_atomic.cc)
|
||||
add_executable(test_buffer test_buffer.cc)
|
||||
@ -28,6 +29,7 @@ add_executable(test_utils test_utils.cc)
|
||||
add_executable(test_session_track test_session_track.cc)
|
||||
|
||||
target_link_libraries(profile_trxboundaryparser maxscale-common)
|
||||
target_link_libraries(profile_get_canonical maxscale-common)
|
||||
target_link_libraries(test_adminusers maxscale-common)
|
||||
target_link_libraries(test_atomic maxscale-common)
|
||||
target_link_libraries(test_buffer maxscale-common)
|
||||
|
46
server/core/test/profile_get_canonical.cc
Normal file
46
server/core/test/profile_get_canonical.cc
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
||||
*
|
||||
* Change Date: 2022-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
#include <maxscale/ccdefs.hh>
|
||||
#include <maxscale/modutil.hh>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <chrono>
|
||||
|
||||
using Clock = std::chrono::steady_clock;
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::milliseconds;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int ITERATIONS = 10000000;
|
||||
|
||||
for (std::string line; std::getline(std::cin, line);)
|
||||
{
|
||||
GWBUF* buf = modutil_create_query(line.c_str());
|
||||
auto start = Clock::now();
|
||||
|
||||
for (int i = 0; i < ITERATIONS; i++)
|
||||
{
|
||||
auto str = mxs::get_canonical(buf);
|
||||
}
|
||||
|
||||
auto end = Clock::now();
|
||||
gwbuf_free(buf);
|
||||
|
||||
std::cout << line << "\n"
|
||||
<< duration_cast<milliseconds>(end - start).count() << "ms\n\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -26,8 +26,6 @@ Session::Session(Client* pClient, const SListener& listener)
|
||||
{
|
||||
MXS_SESSION* pSession = this;
|
||||
|
||||
memset((void*)pSession, 0, sizeof(MXS_SESSION));
|
||||
|
||||
pSession->state = SESSION_STATE_CREATED;
|
||||
|
||||
pSession->client_dcb = &m_client_dcb;
|
||||
|
@ -1419,13 +1419,15 @@ static void worker_func(int thread_id, void* data)
|
||||
for (TargetList::iterator it = info->targets.begin();
|
||||
it != info->targets.end(); it++)
|
||||
{
|
||||
LocalClient* client = LocalClient::create(&info->session, &info->protocol, it->first);
|
||||
GWBUF* buffer = modutil_create_query(it->second.c_str());
|
||||
client->queue_query(buffer);
|
||||
gwbuf_free(buffer);
|
||||
if (LocalClient* client = LocalClient::create(&info->session, &info->protocol, it->first))
|
||||
{
|
||||
GWBUF* buffer = modutil_create_query(it->second.c_str());
|
||||
client->queue_query(buffer);
|
||||
gwbuf_free(buffer);
|
||||
|
||||
// The LocalClient needs to delete itself once the queries are done
|
||||
client->self_destruct();
|
||||
// The LocalClient needs to delete itself once the queries are done
|
||||
client->self_destruct();
|
||||
}
|
||||
}
|
||||
|
||||
delete info;
|
||||
|
Reference in New Issue
Block a user