4 Copyright (C) Amitay Isaacs 2016
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "system/filesys.h"
22 #include "system/locale.h"
23 #include "system/network.h"
27 #include "lib/util/debug.h"
28 #include "lib/util/smb_strtox.h"
29 #include "lib/util/tini.h"
31 #include "protocol/protocol.h"
33 #include "common/tunable.h"
41 { "MaxRedirectCount", 3, true,
42 offsetof(struct ctdb_tunable_list
, max_redirect_count
) },
43 { "SeqnumInterval", 1000, false,
44 offsetof(struct ctdb_tunable_list
, seqnum_interval
) },
45 { "ControlTimeout", 60, false,
46 offsetof(struct ctdb_tunable_list
, control_timeout
) },
47 { "TraverseTimeout", 20, false,
48 offsetof(struct ctdb_tunable_list
, traverse_timeout
) },
49 { "KeepaliveInterval", 5, false,
50 offsetof(struct ctdb_tunable_list
, keepalive_interval
) },
51 { "KeepaliveLimit", 5, false,
52 offsetof(struct ctdb_tunable_list
, keepalive_limit
) },
53 { "RecoverTimeout", 30, false,
54 offsetof(struct ctdb_tunable_list
, recover_timeout
) },
55 { "RecoverInterval", 1, false,
56 offsetof(struct ctdb_tunable_list
, recover_interval
) },
57 { "ElectionTimeout", 3, false,
58 offsetof(struct ctdb_tunable_list
, election_timeout
) },
59 { "TakeoverTimeout", 9, false,
60 offsetof(struct ctdb_tunable_list
, takeover_timeout
) },
61 { "MonitorInterval", 15, false,
62 offsetof(struct ctdb_tunable_list
, monitor_interval
) },
63 { "TickleUpdateInterval", 20, false,
64 offsetof(struct ctdb_tunable_list
, tickle_update_interval
) },
65 { "EventScriptTimeout", 30, false,
66 offsetof(struct ctdb_tunable_list
, script_timeout
) },
67 { "MonitorTimeoutCount", 20, false,
68 offsetof(struct ctdb_tunable_list
, monitor_timeout_count
) },
69 { "EventScriptUnhealthyOnTimeout", 0, true,
70 offsetof(struct ctdb_tunable_list
, script_unhealthy_on_timeout
) },
71 { "RecoveryGracePeriod", 120, false,
72 offsetof(struct ctdb_tunable_list
, recovery_grace_period
) },
73 { "RecoveryBanPeriod", 300, false,
74 offsetof(struct ctdb_tunable_list
, recovery_ban_period
) },
75 { "DatabaseHashSize", 100001, false,
76 offsetof(struct ctdb_tunable_list
, database_hash_size
) },
77 { "DatabaseMaxDead", 5, false,
78 offsetof(struct ctdb_tunable_list
, database_max_dead
) },
79 { "RerecoveryTimeout", 10, false,
80 offsetof(struct ctdb_tunable_list
, rerecovery_timeout
) },
81 { "EnableBans", 1, false,
82 offsetof(struct ctdb_tunable_list
, enable_bans
) },
83 { "DeterministicIPs", 0, true,
84 offsetof(struct ctdb_tunable_list
, deterministic_public_ips
) },
85 { "LCP2PublicIPs", 1, true,
86 offsetof(struct ctdb_tunable_list
, lcp2_public_ip_assignment
) },
87 { "ReclockPingPeriod", 60, true,
88 offsetof(struct ctdb_tunable_list
, reclock_ping_period
) },
89 { "NoIPFailback", 0, false,
90 offsetof(struct ctdb_tunable_list
, no_ip_failback
) },
91 { "DisableIPFailover", 0, true,
92 offsetof(struct ctdb_tunable_list
, disable_ip_failover
) },
93 { "VerboseMemoryNames", 0, false,
94 offsetof(struct ctdb_tunable_list
, verbose_memory_names
) },
95 { "RecdPingTimeout", 60, false,
96 offsetof(struct ctdb_tunable_list
, recd_ping_timeout
) },
97 { "RecdFailCount", 10, false,
98 offsetof(struct ctdb_tunable_list
, recd_ping_failcount
) },
99 { "LogLatencyMs", 0, false,
100 offsetof(struct ctdb_tunable_list
, log_latency_ms
) },
101 { "RecLockLatencyMs", 1000, false,
102 offsetof(struct ctdb_tunable_list
, reclock_latency_ms
) },
103 { "RecoveryDropAllIPs", 120, false,
104 offsetof(struct ctdb_tunable_list
, recovery_drop_all_ips
) },
105 { "VerifyRecoveryLock", 1, true,
106 offsetof(struct ctdb_tunable_list
, verify_recovery_lock
) },
107 { "VacuumInterval", 10, false,
108 offsetof(struct ctdb_tunable_list
, vacuum_interval
) },
109 { "VacuumMaxRunTime", 120, false,
110 offsetof(struct ctdb_tunable_list
, vacuum_max_run_time
) },
111 { "RepackLimit", 10*1000, false,
112 offsetof(struct ctdb_tunable_list
, repack_limit
) },
113 { "VacuumLimit", 5*1000, true,
114 offsetof(struct ctdb_tunable_list
, vacuum_limit
) },
115 { "VacuumFastPathCount", 60, false,
116 offsetof(struct ctdb_tunable_list
, vacuum_fast_path_count
) },
117 { "MaxQueueDropMsg", 1000*1000, false,
118 offsetof(struct ctdb_tunable_list
, max_queue_depth_drop_msg
) },
119 { "AllowUnhealthyDBRead", 0, false,
120 offsetof(struct ctdb_tunable_list
, allow_unhealthy_db_read
) },
121 { "StatHistoryInterval", 1, false,
122 offsetof(struct ctdb_tunable_list
, stat_history_interval
) },
123 { "DeferredAttachTO", 120, false,
124 offsetof(struct ctdb_tunable_list
, deferred_attach_timeout
) },
125 { "AllowClientDBAttach", 1, false,
126 offsetof(struct ctdb_tunable_list
, allow_client_db_attach
) },
127 { "RecoverPDBBySeqNum", 1, true,
128 offsetof(struct ctdb_tunable_list
, recover_pdb_by_seqnum
) },
129 { "DeferredRebalanceOnNodeAdd", 300, true,
130 offsetof(struct ctdb_tunable_list
, deferred_rebalance_on_node_add
) },
131 { "FetchCollapse", 1, false,
132 offsetof(struct ctdb_tunable_list
, fetch_collapse
) },
133 { "HopcountMakeSticky", 50, false,
134 offsetof(struct ctdb_tunable_list
, hopcount_make_sticky
) },
135 { "StickyDuration", 600, false,
136 offsetof(struct ctdb_tunable_list
, sticky_duration
) },
137 { "StickyPindown", 200, false,
138 offsetof(struct ctdb_tunable_list
, sticky_pindown
) },
139 { "NoIPTakeover", 0, false,
140 offsetof(struct ctdb_tunable_list
, no_ip_takeover
) },
141 { "DBRecordCountWarn", 100*1000, false,
142 offsetof(struct ctdb_tunable_list
, db_record_count_warn
) },
143 { "DBRecordSizeWarn", 10*1000*1000, false,
144 offsetof(struct ctdb_tunable_list
, db_record_size_warn
) },
145 { "DBSizeWarn", 100*1000*1000, false,
146 offsetof(struct ctdb_tunable_list
, db_size_warn
) },
147 { "PullDBPreallocation", 10*1024*1024, false,
148 offsetof(struct ctdb_tunable_list
, pulldb_preallocation_size
) },
149 { "NoIPHostOnAllDisabled", 1, true,
150 offsetof(struct ctdb_tunable_list
, no_ip_host_on_all_disabled
) },
151 { "Samba3AvoidDeadlocks", 0, true,
152 offsetof(struct ctdb_tunable_list
, samba3_hack
) },
153 { "TDBMutexEnabled", 1, true,
154 offsetof(struct ctdb_tunable_list
, mutex_enabled
) },
155 { "LockProcessesPerDB", 200, false,
156 offsetof(struct ctdb_tunable_list
, lock_processes_per_db
) },
157 { "RecBufferSizeLimit", 1000*1000, false,
158 offsetof(struct ctdb_tunable_list
, rec_buffer_size_limit
) },
159 { "QueueBufferSize", 1024, false,
160 offsetof(struct ctdb_tunable_list
, queue_buffer_size
) },
161 { "IPAllocAlgorithm", 2, false,
162 offsetof(struct ctdb_tunable_list
, ip_alloc_algorithm
) },
163 { "AllowMixedVersions", 0, false,
164 offsetof(struct ctdb_tunable_list
, allow_mixed_versions
) },
165 { .obsolete
= true, }
168 void ctdb_tunable_set_defaults(struct ctdb_tunable_list
*tun_list
)
172 for (i
=0; tunable_map
[i
].label
!= NULL
; i
++) {
173 size_t offset
= tunable_map
[i
].offset
;
174 uint32_t value
= tunable_map
[i
].value
;
177 value_ptr
= (uint32_t *)((uint8_t *)tun_list
+ offset
);
182 bool ctdb_tunable_get_value(struct ctdb_tunable_list
*tun_list
,
183 const char *tunable_str
, uint32_t *value
)
187 for (i
=0; tunable_map
[i
].label
!= NULL
; i
++) {
188 if (strcasecmp(tunable_map
[i
].label
, tunable_str
) == 0) {
191 value_ptr
= (uint32_t *)((uint8_t *)tun_list
+
192 tunable_map
[i
].offset
);
201 bool ctdb_tunable_set_value(struct ctdb_tunable_list
*tun_list
,
202 const char *tunable_str
, uint32_t value
,
207 for (i
=0; tunable_map
[i
].label
!= NULL
; i
++) {
208 if (strcasecmp(tunable_map
[i
].label
, tunable_str
) == 0) {
211 value_ptr
= (uint32_t *)((uint8_t *)tun_list
+
212 tunable_map
[i
].offset
);
214 if (obsolete
!= NULL
) {
215 *obsolete
= tunable_map
[i
].obsolete
;
224 struct ctdb_var_list
*ctdb_tunable_names(TALLOC_CTX
*mem_ctx
)
226 struct ctdb_var_list
*list
;
229 list
= talloc_zero(mem_ctx
, struct ctdb_var_list
);
234 for (i
=0; tunable_map
[i
].label
!= NULL
; i
++) {
235 if (tunable_map
[i
].obsolete
) {
239 list
->var
= talloc_realloc(list
, list
->var
, const char *,
241 if (list
->var
== NULL
) {
245 list
->var
[list
->count
] = talloc_strdup(list
,
246 tunable_map
[i
].label
);
247 if (list
->var
[list
->count
] == NULL
) {
261 char *ctdb_tunable_names_to_string(TALLOC_CTX
*mem_ctx
)
266 str
= talloc_strdup(mem_ctx
, ":");
271 for (i
=0; tunable_map
[i
].label
!= NULL
; i
++) {
272 if (tunable_map
[i
].obsolete
) {
276 str
= talloc_asprintf_append(str
, "%s:",
277 tunable_map
[i
].label
);
283 /* Remove the last ':' */
284 str
[strlen(str
)-1] = '\0';
289 struct tunable_load_state
{
290 struct ctdb_tunable_list
*tun_list
;
295 static bool tunable_section(const char *section
, void *private_data
)
297 struct tunable_load_state
*state
=
298 (struct tunable_load_state
*)private_data
;
300 D_ERR("%s: Invalid line for section [%s] - sections not supported \n",
303 state
->status
= false;
308 static bool tunable_option(const char *name
,
312 struct tunable_load_state
*state
=
313 (struct tunable_load_state
*)private_data
;
319 if (value
[0] == '\0') {
320 D_ERR("%s: Invalid line containing \"%s\"\n", state
->func
, name
);
321 state
->status
= false;
325 num
= smb_strtoul(value
, NULL
, 0, &ret
, SMB_STR_FULL_STR_CONV
);
327 D_ERR("%s: Invalid value \"%s\" for tunable \"%s\"\n",
331 state
->status
= false;
335 ok
= ctdb_tunable_set_value(state
->tun_list
,
340 D_ERR("%s: Unknown tunable \"%s\"\n", state
->func
, name
);
341 state
->status
= false;
345 D_ERR("%s: Obsolete tunable \"%s\"\n", state
->func
, name
);
346 state
->status
= false;
353 bool ctdb_tunable_load_file(TALLOC_CTX
*mem_ctx
,
354 struct ctdb_tunable_list
*tun_list
,
357 struct tunable_load_state state
= {
358 .tun_list
= tun_list
,
360 .func
= __FUNCTION__
,
365 ctdb_tunable_set_defaults(tun_list
);
367 fp
= fopen(file
, "r");
369 if (errno
== ENOENT
) {
370 /* Doesn't need to exist */
374 DBG_ERR("Failed to open %s\n", file
);
378 D_NOTICE("Loading tunables from %s\n", file
);
380 * allow_empty_value=true is somewhat counter-intuitive.
381 * However, if allow_empty_value=false then a tunable with no
382 * equals or value is regarded as empty and is simply ignored.
383 * Use true so an "empty value" can be caught in
386 * tunable_section() and tunable_option() return true while
387 * setting state.status=false, allowing all possible errors
388 * with tunables and values to be reported. This helps to
389 * avoid a potential game of whack-a-mole in a well-formed
390 * file with multiple minor errors.
392 status
= tini_parse(fp
, true, tunable_section
, tunable_option
, &state
);
397 DBG_ERR("Syntax error\n");
400 return status
&& state
.status
;