Skip to content

Commit dd7ec84

Browse files
committed
[#22126] yugabyted: Support for specifying multiple data directories.
Summary: To add support for specifying multiple data directories, we have introduced `additional_data_dir` config which will store the additional data directories specified after giving the primary data directory. Example: yugabyted start --data_dir=/mnt/disk1,/mnt/disk2,/mnt/disk3 The `--data_dir` flag is assigned the first value /mnt/disk1 and rest of the csv values will get assigned to `--additional_data_dir`. Jira: DB-11050 Test Plan: https://docs.google.com/spreadsheets/d/1yAmZlakkxd-tZ_4F9Od1auPXLIWPk5GI2SZRKTlRR6w/edit#gid=1934593794 Reviewers: nikhil Reviewed By: nikhil Subscribers: shikhar.sahay Differential Revision: https://phorge.dev.yugabyte.com/D34907
1 parent d2774c9 commit dd7ec84

File tree

1 file changed

+105
-37
lines changed

1 file changed

+105
-37
lines changed

bin/yugabyted

+105-37
Original file line numberDiff line numberDiff line change
@@ -991,6 +991,8 @@ class ControlScript(object):
991991
Output.print_out("Stopped {} using config {}.".format(SCRIPT_NAME, self.conf_file))
992992
logpath = self.configs.saved_data.get("log_dir")
993993
datapath = self.configs.saved_data.get("data_dir")
994+
additional_datapaths = self.configs.saved_data.get(
995+
"additional_data_dir").split(',')
994996
gen_certs_dir = self.configs.saved_data.get("gen_certs_dir")
995997
certs_dir = self.configs.saved_data.get("certs_dir")
996998
config_path = os.path.dirname(self.conf_file)
@@ -1008,6 +1010,16 @@ class ControlScript(object):
10081010
shutil.rmtree(datapath)
10091011
Output.print_out("Deleted data at {}.".format(datapath))
10101012

1013+
is_additional_datapath_deleted = False
1014+
for path in additional_datapaths:
1015+
if os.path.isdir(path):
1016+
is_additional_datapath_deleted = True
1017+
shutil.rmtree(path)
1018+
1019+
if is_additional_datapath_deleted:
1020+
Output.print_out("Deleted additional data at {}".format(
1021+
", ".join(additional_datapaths)))
1022+
10111023
if os.path.isdir(gen_certs_dir):
10121024
shutil.rmtree(gen_certs_dir)
10131025
Output.print_out("Deleted generated certs at {}.".format(gen_certs_dir))
@@ -2763,10 +2775,17 @@ class ControlScript(object):
27632775
if tserver_flags.find("enable_ysql_conn_mgr") != -1:
27642776
METRICS_SNAPSHOT_LIST.append("ysql_conn_mgr")
27652777

2778+
# Check for multiple data directories
2779+
fs_data_dirs = self.configs.saved_data.get("data_dir")
2780+
additional_data_dirs = self.configs.saved_data.get(
2781+
"additional_data_dir")
2782+
if additional_data_dirs:
2783+
fs_data_dirs += "," + additional_data_dirs
2784+
27662785
common_gflags = [
27672786
"--stop_on_parent_termination",
27682787
"--undefok=stop_on_parent_termination",
2769-
"--fs_data_dirs={}".format(self.configs.saved_data.get("data_dir")),
2788+
"--fs_data_dirs={}".format(fs_data_dirs),
27702789
"--webserver_interface={}".format(advertise_ip),
27712790
"--metrics_snapshotter_tserver_metrics_whitelist={}".format(
27722791
",".join(METRICS_SNAPSHOT_LIST)),
@@ -5112,8 +5131,37 @@ class ControlScript(object):
51125131
os.path.abspath(
51135132
os.path.expanduser(args.config)))
51145133
user_configs = Configs.parse_user_config_file(args.config)
5134+
# User should not be able to override data_dir
5135+
if (self.configs.saved_data.get("cluster_member")
5136+
and args.data_dir is None):
5137+
user_configs_data_dir = [
5138+
path for path in user_configs.get("data_dir").split(',')
5139+
]
5140+
config_data_dir = [self.configs.saved_data.get("data_dir")] + \
5141+
[x for x in self.configs.saved_data.get(
5142+
"additional_data_dir").split(',') if x]
5143+
# Existing data directories cannot be removed or changed
5144+
# through changing the user config file during restart
5145+
if len(user_configs_data_dir) < len(config_data_dir) or \
5146+
user_configs_data_dir[:len(config_data_dir)] != config_data_dir:
5147+
Output.print_out(
5148+
"Data directory already exists at: {}.".format(
5149+
", ".join(config_data_dir))
5150+
)
5151+
sys.exit(1)
5152+
5153+
data_dir = self.configs.saved_data.get("data_dir")
5154+
additional_data_dir = self.configs.saved_data.get(
5155+
"additional_data_dir")
51155156
# Update saved configs with user configurations
51165157
self.configs.saved_data.update(user_configs)
5158+
# If args.data_dir is given then do not
5159+
# change the data_path with user configs
5160+
if (args.data_dir is not None and
5161+
self.configs.saved_data.get("cluster_member")):
5162+
self.configs.saved_data["data_dir"] = data_dir
5163+
self.configs.saved_data["additional_data_dir"] = \
5164+
additional_data_dir
51175165

51185166
return self.configs
51195167
# Parse the config file and input parent flags to validate and set them.
@@ -5138,52 +5186,59 @@ class ControlScript(object):
51385186
conf_dir = os.path.dirname(self.conf_file)
51395187
self.configs = self.handle_config_files(args, conf_dir, self.conf_file, base_dir)
51405188

5141-
for path_args in ("data_dir", "log_dir"):
5142-
path = getattr(args, path_args, None)
5143-
if path:
5144-
setattr(args, path_args, os.path.abspath(os.path.realpath(path)))
5145-
5146-
if args.data_dir is not None:
5147-
args.data_dir = os.path.expanduser(args.data_dir)
5148-
5149-
config_data_dir = self.configs.saved_data.get("data_dir")
5150-
if (config_data_dir and os.path.exists(config_data_dir) and
5151-
config_data_dir != args.data_dir):
5152-
has_errors = True
5153-
# TODO: Gradefully handle this case... User should be able to override config.
5154-
Output.print_out(
5155-
"Data directory already exists at {}.".format(config_data_dir))
5156-
5157-
if args.log_dir is not None:
5158-
args.log_dir = os.path.expanduser(args.log_dir)
5159-
5160-
config_log_dir = self.configs.saved_data.get("log_dir")
5161-
if (config_log_dir and os.path.exists(config_log_dir) and
5162-
config_log_dir != args.log_dir):
5163-
Output.print_out(
5164-
"Old log directory already exists at {}. New logs will go to {}".format(
5165-
config_log_dir, args.log_dir))
5189+
if self.configs.saved_data.get("cluster_member"):
5190+
if args.data_dir is not None:
5191+
data_dir_list = [
5192+
os.path.abspath(os.path.realpath(os.path.expanduser(path)))
5193+
for path in args.data_dir.split(',')
5194+
]
5195+
config_data_dir = [self.configs.saved_data.get("data_dir")] + \
5196+
[x for x in self.configs.saved_data.get(
5197+
"additional_data_dir").split(',') if x]
5198+
# Existing data directories cannot be removed or changed
5199+
if len(data_dir_list) < len(config_data_dir) or \
5200+
data_dir_list[:len(config_data_dir)] != config_data_dir:
5201+
has_errors = True
5202+
Output.print_out(
5203+
"Data directory already exists at: {}.".format(
5204+
", ".join(config_data_dir))
5205+
)
5206+
if args.log_dir is not None:
5207+
args.log_dir = os.path.abspath(os.path.realpath(
5208+
os.path.expanduser(args.log_dir)))
5209+
config_log_dir = self.configs.saved_data.get("log_dir")
5210+
# Existing log directory can be changed
5211+
if config_log_dir != args.log_dir:
5212+
Output.print_out(
5213+
"Old log directory already exists at {}. New logs will go to {}".format(
5214+
config_log_dir, args.log_dir))
51665215

51675216
if has_errors:
51685217
sys.exit(1)
51695218

51705219
parent_flags = ["log_dir", "data_dir"]
51715220
# Override configs and defaults with user specified variables
51725221
for k, v in get_kv(args.__dict__):
5173-
if (v is not None and k in parent_flags and k in self.configs.saved_data
5174-
and v != self.configs.saved_data.get(k)):
5222+
if (v is not None and k in parent_flags and k in self.configs.saved_data):
51755223
self.configs.saved_data[k] = v
51765224

51775225
data_dir = self.configs.saved_data["data_dir"]
5226+
data_dir_paths = data_dir.split(',')
5227+
self.configs.saved_data["data_dir"] = data_dir_paths[0]
5228+
if len(data_dir_paths) > 1:
5229+
self.configs.saved_data["additional_data_dir"] = \
5230+
','.join(data_dir_paths[1:])
51785231
log_dir = self.configs.saved_data["log_dir"]
51795232
self.configs.save_configs()
51805233

5181-
if not os.path.isdir(data_dir):
5182-
os.makedirs(data_dir)
5234+
for dir_path in data_dir_paths:
5235+
if not os.path.isdir(dir_path):
5236+
os.makedirs(dir_path)
51835237
if not os.path.isdir(log_dir):
51845238
os.makedirs(log_dir)
51855239

5186-
self.script = ScriptProcessManager(log_dir, data_dir)
5240+
self.script = ScriptProcessManager(log_dir,
5241+
self.configs.saved_data.get("data_dir"))
51875242

51885243
# Check and validate the flags regarding the secure deployment of the node.
51895244
# Check whether the certs files are present or not.
@@ -6769,6 +6824,7 @@ class Configs(object):
67696824
def __init__(self, config_file, base_dir):
67706825
self.saved_data = {
67716826
"data_dir": os.path.join(base_dir, "data"),
6827+
"additional_data_dir": "",
67726828
"log_dir": os.path.join(base_dir, "logs"),
67736829
"gen_certs_dir": os.path.join(base_dir, "generated_certs"),
67746830
"master_rpc_port": DEFAULT_MASTER_RPC_PORT,
@@ -6890,13 +6946,25 @@ class Configs(object):
68906946
# Expand path variables in config files
68916947
@staticmethod
68926948
def expand_path_variables(configs):
6893-
paths = ["data_dir", "log_dir", "certs_dir", "gen_certs_dir", "ca_cert_file_path"]
6949+
paths = ["log_dir", "certs_dir", "gen_certs_dir", "ca_cert_file_path"]
6950+
multi_paths = ["data_dir"]
68946951
for key, value in configs.items():
6895-
if value is not None and key in paths:
6896-
if "$" in value:
6897-
configs[key] = os.path.expanduser(os.path.expandvars(value))
6898-
else:
6899-
configs[key] = os.path.expanduser(value)
6952+
if value is not None:
6953+
if key in multi_paths:
6954+
configs[key] = ','.join([
6955+
os.path.abspath(os.path.realpath(
6956+
os.path.expanduser(os.path.expandvars(path))) \
6957+
if "$" in path else \
6958+
os.path.abspath(os.path.realpath(os.path.expanduser(path)))
6959+
) for path in value.split(',')
6960+
])
6961+
elif key in paths:
6962+
configs[key] = (
6963+
os.path.abspath(os.path.realpath(
6964+
os.path.expanduser(os.path.expandvars(value))))
6965+
if "$" in value else
6966+
os.path.abspath(os.path.realpath(os.path.expanduser(value)))
6967+
)
69006968

69016969
return configs
69026970

0 commit comments

Comments
 (0)