Skip to content

Commit 2f64108

Browse files
committed
Write (some of the) command line options to a configuration file.
This allows to later review how the command was run, and more importantly editing the configuration file (via new commands, not implemented yet) and signal the already running pgcopydb to dynamically apply new settings.
1 parent 19f72f6 commit 2f64108

7 files changed

Lines changed: 1204 additions & 0 deletions

File tree

src/bin/pgcopydb/cli_common.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "cli_common.h"
1818
#include "cli_root.h"
1919
#include "commandline.h"
20+
#include "config.h"
2021
#include "copydb.h"
2122
#include "env_utils.h"
2223
#include "file_utils.h"
@@ -1155,6 +1156,16 @@ cli_copy_prepare_specs(CopyDataSpec *copySpecs, CopyDataSection section)
11551156
exit(EXIT_CODE_INTERNAL_ERROR);
11561157
}
11571158

1159+
strlcpy(copyDBoptions.dir, copySpecs->cfPaths.topdir, MAXPGPATH);
1160+
1161+
(void) config_init(&copyDBoptions);
1162+
1163+
if (!config_write_file(&copyDBoptions, copySpecs->cfPaths.conffile))
1164+
{
1165+
/* errors have already been logged */
1166+
exit(EXIT_CODE_INTERNAL_ERROR);
1167+
}
1168+
11581169
if (!copydb_init_specs(copySpecs, &copyDBoptions, section))
11591170
{
11601171
/* errors have already been logged */

src/bin/pgcopydb/config.c

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
/*
2+
* src/bin/pgcopydb/config.c
3+
* Configuration functions for pgcopydb.
4+
*
5+
* Licensed under the PostgreSQL License.
6+
*
7+
*/
8+
9+
#include <inttypes.h>
10+
#include <stdbool.h>
11+
#include <unistd.h>
12+
13+
#include "config.h"
14+
#include "defaults.h"
15+
#include "ini_file.h"
16+
#include "log.h"
17+
#include "parsing_utils.h"
18+
19+
#define OPTION_PGCOPYDB_DIR(config) \
20+
make_strbuf_option("pgcopydb", "dir", "dir", true, MAXCONNINFO, \
21+
config->dir)
22+
23+
#define OPTION_PGCOPYDB_SOURCE(config) \
24+
make_strbuf_option("pgcopydb", "source", "source", true, MAXCONNINFO, \
25+
config->source_pguri)
26+
27+
#define OPTION_PGCOPYDB_TARGET(config) \
28+
make_strbuf_option("pgcopydb", "target", "source", true, MAXCONNINFO, \
29+
config->target_pguri)
30+
31+
#define OPTION_PGCOPYDB_TABLE_JOBS(config) \
32+
make_int_option_default("pgcopydb", "table-jobs", "table-jobs", \
33+
true, &(config->tableJobs), \
34+
DEFAULT_TABLE_JOBS)
35+
36+
#define OPTION_PGCOPYDB_INDEX_JOBS(config) \
37+
make_int_option_default("pgcopydb", "index-jobs", "index-jobs", \
38+
true, &(config->indexJobs), \
39+
DEFAULT_INDEX_JOBS)
40+
41+
#define SET_INI_OPTIONS_ARRAY(config) \
42+
{ \
43+
OPTION_PGCOPYDB_DIR(config), \
44+
OPTION_PGCOPYDB_SOURCE(config), \
45+
OPTION_PGCOPYDB_TARGET(config), \
46+
OPTION_PGCOPYDB_TABLE_JOBS(config), \
47+
OPTION_PGCOPYDB_INDEX_JOBS(config), \
48+
INI_OPTION_LAST \
49+
}
50+
51+
52+
/*
53+
* config_init initializes a CopyDBOptions with the default values.
54+
*/
55+
void
56+
config_init(CopyDBOptions *config)
57+
{
58+
IniOption options[] = SET_INI_OPTIONS_ARRAY(config);
59+
60+
log_trace("config_init");
61+
62+
if (!ini_validate_options(options))
63+
{
64+
log_error("Please review your setup options per above messages");
65+
exit(EXIT_CODE_BAD_CONFIG);
66+
}
67+
}
68+
69+
70+
/*
71+
* config_read_file overrides values in given CopyDBOptions with whatever
72+
* values are read from given configuration filename.
73+
*/
74+
bool
75+
config_read_file(CopyDBOptions *config, const char *filename)
76+
{
77+
IniOption options[] = SET_INI_OPTIONS_ARRAY(config);
78+
79+
log_debug("Reading configuration from %s", filename);
80+
81+
if (!read_ini_file(filename, options))
82+
{
83+
log_error("Failed to parse configuration file \"%s\"", filename);
84+
return false;
85+
}
86+
87+
return true;
88+
}
89+
90+
91+
/*
92+
* config_write_file writes the current values in given CopyDBOptions to
93+
* filename.
94+
*/
95+
bool
96+
config_write_file(CopyDBOptions *config, const char *filename)
97+
{
98+
log_trace("config_write_file \"%s\"", filename);
99+
100+
FILE *fileStream = fopen_with_umask(filename, "w", FOPEN_FLAGS_W, 0644);
101+
if (fileStream == NULL)
102+
{
103+
/* errors have already been logged */
104+
return false;
105+
}
106+
107+
bool success = config_write(fileStream, config);
108+
109+
if (fclose(fileStream) == EOF)
110+
{
111+
log_error("Failed to write file \"%s\"", filename);
112+
return false;
113+
}
114+
115+
return success;
116+
}
117+
118+
119+
/*
120+
* config_write write the current config to given STREAM.
121+
*/
122+
bool
123+
config_write(FILE *stream, CopyDBOptions *config)
124+
{
125+
IniOption options[] = SET_INI_OPTIONS_ARRAY(config);
126+
127+
return write_ini_to_stream(stream, options);
128+
}
129+
130+
131+
/*
132+
* config_to_json populates given jsRoot object with the INI configuration
133+
* sections as JSON objects, and the options as keys to those objects.
134+
*/
135+
bool
136+
config_to_json(CopyDBOptions *config, JSON_Value *js)
137+
{
138+
JSON_Object *jsRoot = json_value_get_object(js);
139+
IniOption options[] = SET_INI_OPTIONS_ARRAY(config);
140+
141+
return ini_to_json(jsRoot, options);
142+
}
143+
144+
145+
/*
146+
* config_log_settings outputs a DEBUG line per each config parameter in the
147+
* given CopyDBOptions.
148+
*/
149+
void
150+
config_log_settings(CopyDBOptions *config)
151+
{
152+
log_debug("pgcopydb.dir: %s", config->dir);
153+
log_debug("pgcopydb.source_pguri: %s", config->source_pguri);
154+
log_debug("pgcopydb.target_pguri: %s", config->target_pguri);
155+
156+
log_debug("pgcopydb.table-jobs: %d", config->tableJobs);
157+
log_debug("pgcopydb.index-jobs: %d", config->indexJobs);
158+
}
159+
160+
161+
/*
162+
* config_get_setting returns the current value of the given option "path"
163+
* (thats a section.option string). The value is returned in the pre-allocated
164+
* value buffer of size size.
165+
*/
166+
bool
167+
config_get_setting(CopyDBOptions *config,
168+
const char *filename,
169+
const char *path,
170+
char *value, size_t size)
171+
{
172+
IniOption options[] = SET_INI_OPTIONS_ARRAY(config);
173+
174+
return ini_get_setting(filename, options, path, value, size);
175+
}
176+
177+
178+
/*
179+
* config_set_setting sets the setting identified by "path" (section.option) to
180+
* the given value. The value is passed in as a string, which is going to be
181+
* parsed if necessary.
182+
*/
183+
bool
184+
config_set_setting(CopyDBOptions *config,
185+
const char *filename,
186+
const char *path,
187+
char *value)
188+
{
189+
IniOption options[] = SET_INI_OPTIONS_ARRAY(config);
190+
191+
log_trace("config_set_setting: %s = %s", path, value);
192+
193+
if (!ini_set_setting(filename, options, path, value))
194+
{
195+
/* errors have already been logged */
196+
return false;
197+
}
198+
199+
return true;
200+
}
201+
202+
203+
/*
204+
* config_merge_options merges any option setup in options into config. Its
205+
* main use is to override configuration file settings with command line
206+
* options.
207+
*/
208+
bool
209+
config_merge_options(CopyDBOptions *config, CopyDBOptions *options,
210+
const char *filename)
211+
{
212+
IniOption configOptions[] = SET_INI_OPTIONS_ARRAY(config);
213+
IniOption optionsOptions[] = SET_INI_OPTIONS_ARRAY(options);
214+
215+
log_trace("config_merge_options");
216+
217+
if (ini_merge(configOptions, optionsOptions))
218+
{
219+
return config_write_file(config, filename);
220+
}
221+
222+
return false;
223+
}

src/bin/pgcopydb/config.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* src/bin/pgcopydb/config.h
3+
* Configuration data structure and function definitions
4+
*
5+
* Licensed under the PostgreSQL License.
6+
*
7+
*/
8+
9+
#ifndef CONFIG_H
10+
#define CONFIG_H
11+
12+
#include <limits.h>
13+
#include <stdbool.h>
14+
15+
#include "cli_common.h"
16+
#include "config.h"
17+
#include "defaults.h"
18+
19+
20+
void config_init(CopyDBOptions *config);
21+
bool config_read_file(CopyDBOptions *config, const char *filename);
22+
bool config_write_file(CopyDBOptions *config, const char *filename);
23+
bool config_write(FILE *stream, CopyDBOptions *config);
24+
bool config_to_json(CopyDBOptions *config, JSON_Value *js);
25+
void config_log_settings(CopyDBOptions *config);
26+
27+
bool config_get_setting(CopyDBOptions *config,
28+
const char *filename,
29+
const char *path,
30+
char *value, size_t size);
31+
32+
bool config_set_setting(CopyDBOptions *config,
33+
const char *filename,
34+
const char *path,
35+
char *value);
36+
37+
bool config_merge_options(CopyDBOptions *config, CopyDBOptions *options,
38+
const char *filename);
39+
40+
#endif /* CONFIG_H */

src/bin/pgcopydb/copydb.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,9 @@ copydb_prepare_filepaths(CopyFilePaths *cfPaths,
438438
/* first copy the top directory */
439439
strlcpy(cfPaths->topdir, topdir, sizeof(cfPaths->topdir));
440440

441+
/* prepare the path to the config.ini file */
442+
sformat(cfPaths->conffile, MAXPGPATH, "%s/config.ini", cfPaths->topdir);
443+
441444
/* some processes use an additional per-service pidfile */
442445
if (serviceName != NULL)
443446
{

src/bin/pgcopydb/copydb_paths.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ typedef struct CDCPaths
5959
typedef struct CopyFilePaths
6060
{
6161
char topdir[MAXPGPATH]; /* /tmp/pgcopydb */
62+
char conffile[MAXPGPATH]; /* /tmp/pgcopydb/config.ini */
6263
char pidfile[MAXPGPATH]; /* /tmp/pgcopydb/pgcopydb.pid */
6364
char spidfile[MAXPGPATH]; /* /tmp/pgcopydb/pgcopydb.service.pid */
6465
char snfile[MAXPGPATH]; /* /tmp/pgcopydb/snapshot */

0 commit comments

Comments
 (0)