Skip to content

Commit

Permalink
add analyze index space
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaodong-ji committed Aug 21, 2024
1 parent 2a80ff5 commit 989eab1
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 0 deletions.
5 changes: 5 additions & 0 deletions core.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from handler.analyzer.analyze_sql_review import AnalyzeSQLReviewHandler
from handler.analyzer.analyze_parameter import AnalyzeParameterHandler
from handler.analyzer.analyze_variable import AnalyzeVariableHandler
from handler.analyzer.analyze_index_space import AnalyzeIndexSpaceHandler
from handler.checker.check_handler import CheckHandler
from handler.checker.check_list import CheckListHandler
from handler.gather.gather_log import GatherLogHandler
Expand Down Expand Up @@ -308,6 +309,10 @@ def analyze_fuction(self, function_type, opt):
self.set_context(function_type, 'analyze', config)
handler = AnalyzeSQLReviewHandler(self.context)
handler.handle()
elif function_type == 'analyze_index_space':
self.set_context(function_type, 'analyze', config)
handler = AnalyzeIndexSpaceHandler(self.context)
handler.handle()
else:
self._call_stdio('error', 'Not support analyze function: {0}'.format(function_type))
return False
Expand Down
18 changes: 18 additions & 0 deletions diag_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,23 @@ def __init__(self):
self.register_command(ObdiagAnalyzeVariableDiffCommand())


class ObdiagAnalyzeIndexSpaceCommand(ObdiagOriginCommand):
def __init__(self):
super(ObdiagAnalyzeIndexSpaceCommand, self).__init__('index_space', 'Analyze the space of existing or non-existent index and estimate it through the columns included in the index')
self.parser.add_option('--tenant_name', type='string', help="tenant name")
self.parser.add_option('--table_name', type='string', help="table name")
self.parser.add_option('--index_name', type='string', help="specify the index name if an index already exists in the table")
self.parser.add_option('--column_names', type='string', help="specify the column names of index that have not been created yet;eg:--column_names=c1,c2,c3")

def init(self, cmd, args):
super(ObdiagAnalyzeIndexSpaceCommand, self).init(cmd, args)
self.parser.set_usage('%s [options]' % self.prev_cmd)
return self

def _do_command(self, obdiag):
return obdiag.analyze_fuction('analyze_index_space', self.opts)


class ObdiagAnalyzeSQLCommand(ObdiagOriginCommand):

def __init__(self):
Expand Down Expand Up @@ -1023,6 +1040,7 @@ def __init__(self):
self.register_command(ObdiagAnalyzeFltTraceCommand())
self.register_command(ObdiagAnalyzeParameterCommand())
self.register_command(ObdiagAnalyzeVariableCommand())
self.register_command(ObdiagAnalyzeIndexSpaceCommand())
# self.register_command(ObdiagAnalyzeSQLCommand())
# self.register_command(ObdiagAnalyzeSQLReviewCommand())

Expand Down
149 changes: 149 additions & 0 deletions handler/analyzer/analyze_index_space.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*
# Copyright (c) 2022 OceanBase
# OceanBase Diagnostic Tool is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.

"""
@time: 2024/8/19
@file: analyze_index_space.py
@desc:
"""


import sys
from common.tool import StringUtils, Util
from common.ob_connector import OBConnector
from common.command import get_observer_version


class AnalyzeIndexSpaceHandler(object):
def __init__(self, context):
self.context = context
self.stdio = context.stdio
self.ob_version = get_observer_version(self.context)
self.sys_connector = None
self.tenant_id = None
self.table_id = None
self.index_id = None
self.column_names = []
self.estimated_table_data = None

def init_option(self):
options = self.context.options
ob_cluster = self.context.cluster_config
self.stdio.verbose('cluster config: {0}'.format(StringUtils.mask_passwords(ob_cluster)))
self.ob_cluster = ob_cluster
self.sys_connector = OBConnector(ip=ob_cluster.get("db_host"), port=ob_cluster.get("db_port"), username=ob_cluster.get("tenant_sys").get("user"), password=ob_cluster.get("tenant_sys").get("password"), stdio=self.stdio, timeout=100)
tenant_name = Util.get_option(options, 'tenant_name')
table_name = Util.get_option(options, 'table_name')
index_name = Util.get_option(options, 'index_name')
column_names = Util.get_option(options, 'column_names')
# get tenant id
tenant_data = self.sys_connector.execute_sql("select tenant_id from oceanbase.__all_tenant where tenant_name = '{0}';".format(tenant_name))
if len(tenant_data) == 0:
raise Exception("can not find tenant id by tenant name: {0}. Please check the tenant name.".format(tenant_name))
self.tenant_id = tenant_data[0][0]
if self.tenant_id is None:
raise Exception("can not find tenant id by tenant name: {0}. Please check the tenant name.".format(tenant_name))
# get table id
table_id_data = self.sys_connector.execute_sql("select table_id from oceanbase.__all_virtual_table where table_name = '{0}' and tenant_id = '{1}';".format(table_name, self.tenant_id))
if len(table_id_data) == 0:
raise Exception("can not find table id by table name: {0}. Please check the table name.".format(table_name))
self.table_id = table_id_data[0][0]
if self.table_id is None:
raise Exception("can not find table id by table name: {0}. Please check the table name.".format(table_name))
# get index id
if index_name is not None:
index_id_data = self.sys_connector.execute_sql("select table_id from oceanbase.__all_virtual_table where table_name like '%{0}%' and data_table_id = '{1}' and tenant_id = '{2}';".format(index_name, self.table_id, self.tenant_id))
if len(index_id_data) == 0:
raise Exception("can not find index id by index name: {0}. Please check the index name.".format(index_name))
self.index_id = index_id_data[0][0]
if self.index_id is None:
raise Exception("can not find index id by index name: {0}. Please check the index name.".format(index_name))
# get column names
if column_names is not None:
self.column_names = column_names.split(',')
if len(self.column_names) == 0:
raise Exception("--column_names parameter format is incorrect: {0}.".format(column_names))
return True

def handle(self):
try:
if not self.init_option():
self.stdio.error('init option failed')
return False
# evaluate the space size of the table where the index is located
self.stdio.start_loading('start query estimated_table_data_size, please wait some minutes...')
sql = "select svr_ip, svr_port, sum(original_size) as estimated_table_size from oceanbase.__all_virtual_tablet_sstable_macro_info where tablet_id in (select tablet_id from oceanbase.__all_virtual_tablet_to_table_history where table_id = {0}) and (svr_ip, svr_port) in (select svr_ip, svr_port from oceanbase.__all_virtual_ls_meta_table where role = 1) group by svr_ip, svr_port;".format(
self.table_id
)
self.stdio.verbose("execute_sql is {0}".format(sql))
self.estimated_table_data = self.sys_connector.execute_sql_return_cursor_dictionary(sql).fetchall()
self.stdio.stop_loading('succeed')
# get the sum of all column lengths
sql = "select table_id, sum(data_length) as all_columns_length from oceanbase.__all_virtual_column_history where tenant_id = '{0}' and table_id = '{1}';".format(self.tenant_id, self.table_id)
self.stdio.verbose("execute_sql is {0}".format(sql))
self.main_table_sum_of_data_length = int(self.sys_connector.execute_sql_return_cursor_dictionary(sql).fetchall()[0]["all_columns_length"])
# get the sum of column lengths included in the index
if self.index_id is not None:
sql = "select table_id, sum(data_length) as index_columns_length from oceanbase.__all_virtual_column_history where tenant_id = '{0}' and table_id = '{1}';".format(self.tenant_id, self.index_id)
self.stdio.verbose("execute_sql is {0}".format(sql))
self.index_table_sum_of_data_length = int(self.sys_connector.execute_sql_return_cursor_dictionary(sql).fetchall()[0]["index_columns_length"])
elif len(self.column_names) != 0:
sql = "select table_id, sum(data_length) as columns_length from oceanbase.__all_virtual_column_history where tenant_id = '{0}' and table_id = '{1}' and column_name in ('{2}');".format(
self.tenant_id, self.table_id, "','".join(self.column_names)
)
self.stdio.verbose("execute_sql is {0}".format(sql))
self.index_table_sum_of_data_length = int(self.sys_connector.execute_sql_return_cursor_dictionary(sql).fetchall()[0]["columns_length"])
else:
raise Exception("please specify an index or column.")

# estimate the final space size
estimated_index_data = []
for node_table_estimated_size in self.estimated_table_data:
node_estimated_index_data = {}
node_estimated_index_data["svr_ip"] = node_table_estimated_size["svr_ip"]
node_estimated_index_data["svr_port"] = node_table_estimated_size["svr_port"]
estimiated_index_size = int(self.index_table_sum_of_data_length / self.main_table_sum_of_data_length * int(node_table_estimated_size["estimated_table_size"]))
if self.ob_version == "4.2.3.0" or StringUtils.compare_versions_greater(self.ob_version, "4.2.3.0"):
self.stdio.verbose("magnification is 1.5")
target_server_estimated_size = int(estimiated_index_size * 15 / 10)
else:
self.stdio.verbose("magnification is 5.5")
target_server_estimated_size = int(estimiated_index_size * 55 / 10)
node_estimated_index_data["estimiated_index_size"] = target_server_estimated_size
estimated_index_data.append(node_estimated_index_data)
for node_estimated_index_data in estimated_index_data:
target_server_ip = node_estimated_index_data["svr_ip"]
target_server_port = node_estimated_index_data["svr_port"]
target_server_estimated_index_size = int(node_estimated_index_data["estimiated_index_size"])
# get target_server_total_size and target_server_used_size
target_server_data = self.sys_connector.execute_sql_return_cursor_dictionary(
"select total_size, used_size from oceanbase.__all_virtual_disk_stat where svr_ip = '{0}' and svr_port = {1};".format(target_server_ip, target_server_port)
).fetchall()
target_server_total_size = int(target_server_data[0]["total_size"])
target_server_used_size = int(target_server_data[0]["used_size"])
# get data_disk_usage_limit_percentage
sql = "SELECT VALUE FROM oceanbase.GV$OB_PARAMETERS WHERE SVR_IP='{0}' and SVR_PORT='{1}' and NAME LIKE \"data_disk_usage_limit_percentage\"".format(target_server_ip, target_server_port)
self.stdio.verbose("execute_sql is {0}".format(sql))
data_disk_usage_limit_percentage = int(self.sys_connector.execute_sql_return_cursor_dictionary(sql).fetchall()[0]["VALUE"])
# data_disk_usage_limit_percentage is a Cluster level configuration items
available_disk_space = int(target_server_total_size / 100 * data_disk_usage_limit_percentage - target_server_used_size)
if target_server_estimated_index_size > available_disk_space:
self.stdio.print("==>> estimated index space is {}.".format(target_server_estimated_index_size))
self.stdio.print("the disk space of server({0}:{1}) disk is not enough. please add the server disk".format(target_server_ip, target_server_port))
else:
self.stdio.print("==>> estimated index space is {}.".format(target_server_estimated_index_size))
self.stdio.print("the disk space of server({0}:{1}) is enough. Don't warn. If there are still errors, please contact the OceanBase community.".format(target_server_ip, target_server_port))
except Exception as e:
self.stdio.verbose("analyze index space error: {0}".format(e))
sys.exit()
finally:
self.stdio.verbose("end analyze index space")

0 comments on commit 989eab1

Please sign in to comment.