63
63
# Note that exiting 0 here is against LSB, but Debian policy and LSB conflict
64
64
# here, so we have to pick one.
65
[ -f /usr/lib/openvista/functions ] || exit 0
65
[[ -f /usr/lib/openvista/functions ]] || exit 0
67
# Source function library.
68
[ -f /etc/rc.d/init.d/functions ] && . /etc/rc.d/init.d/functions
69
[ -f /lib/lsb/init-functions ] && . /lib/lsb/init-functions
67
# source function libraries
68
# CentOS/RHEL, provides action(), status()
69
[[ -f /etc/rc.d/init.d/functions ]] && . /etc/rc.d/init.d/functions
70
# Ubuntu/Debian, provides log_daemon_msg(), status_of_proc()
71
[[ -f /lib/lsb/init-functions ]] && . /lib/lsb/init-functions
70
73
. /usr/lib/openvista/functions
75
log_command_usage "$@"
79
# Display usage information.
81
Usage: openvista-databases {start|stop|restart|force-reload} [INSTANCE_NAME]
74
set_gtm_env "$1" || return 1
88
set_gtm_env -v "$instance" || return $?
78
logger -p user.info -t "openvista-databases[$$]" -- Performing recovery on $instance database
80
mupip journal -recover -backward '*' 2>&1 \
82
| logger -p user.info -t "openvista-databases[$$]"
83
retval=${PIPESTATUS[0]}
84
[ $retval -eq 0 ] || return 1
92
# A recovery is performed only following a non-clean shutdown.
94
# When terminate_processes() stops mumps processes, it checks that they
95
# have, in fact, exited. If they have, it writes a 'clean' flag to
96
# /etc/openvista/clean_shutdown_[instance].
98
# Here, that flag is checked and removed. The recovery is only performed if
99
# the shutdown was not clean. Otherwise, rolling back the journal on a
100
# primary replicating server could prevent the secondary from getting the
101
# transactions that were backlogged at the time of the primary's shutdown,
102
# and so the secondary instance(s) would need to be resynced with a complete
103
# backup and restore (using `ovinstancerepl resync [instance]`) in order to
104
# restart replication.
106
# The clean flag should normally be removed here, but the openvista init
107
# script will also make sure that the flag is removed just before it runs
108
# the ZSTART routine on an instance.
109
if clean_flag get "$instance"; then
110
log -l "Found the clean shutdown flag for $instance database"
111
clean_flag set "$instance" false
113
log -l "Did not find the clean shutdown flag for $instance database"
114
log -l "Performing recovery on $instance database"
115
mupip journal -recover -backward '*' 2>&1 \
118
(( "${PIPESTATUS[0]}" == 0 )) || return 1
86
121
# According to Bhaskar, database files should not need to be run down after
87
122
# a successful recovery. However, we've observed GT.M complaining about
88
123
# databases requring rundown after a system crash, even after successful
89
# journal recovery, on both our own OpenVista appliance and the WorldVistA
90
# VOE "four-slice toaster" appliance. An easy (and somewhat reliable) way to
91
# trigger the not-rundown effect is to connect with CIS, then halt the machine
92
# by killing qemu. Upon the next boot, the journal recovery will run, but
93
# attempts to access the database will result in not-rundown errors. Adding
94
# a call to mupip rundown here seems to fix the issue.
124
# journal recovery, on both our own OpenVista appliance and the WorldVistA
125
# VOE "four-slice toaster" appliance. An easy (and somewhat reliable) way
126
# to trigger the not-rundown effect is to connect with CIS, then halt the
127
# machine by killing qemu. Upon the next boot, the journal recovery will
128
# run, but attempts to access the database will result in not-rundown
129
# errors. Adding a call to mupip rundown here seems to fix the issue.
95
130
mupip rundown -region DEFAULT 2>&1 \
97
| logger -p user.info -t "openvista-databases[$$]"
98
retval=${PIPESTATUS[0]}
99
[ $retval -eq 0 ] || return 1
101
# Re-enable journaling
102
mupip set -journal="ENABLE,ON,BEFORE_IMAGES" -region DEFAULT 2>&1 \
104
| logger -p user.info -t "openvista-databases[$$]"
105
retval=${PIPESTATUS[0]}
106
[ $retval -eq 0 ] || return 1
133
(( "${PIPESTATUS[0]}" == 0 )) || return 1
135
# Re-enable journaling and, if configured, replication
136
case $replication_mode in
138
log -lc "Re-enabling journaling and replication on $instance" \
141
# Turning on replication automatically enables journaling.
142
mupip set -replication=ON \
143
-region DEFAULT 2>&1 \
146
(( "${PIPESTATUS[0]}" == 0 )) || return 1
149
log -l "Re-enabling journaling on $instance database"
151
mupip set -journal="ENABLE,ON,BEFORE_IMAGES" \
153
-region DEFAULT 2>&1 \
156
(( "${PIPESTATUS[0]}" == 0 )) || return 1
160
log -l "Creating new physical segment for SCRATCH on $instance database"
108
162
# Back up scratch.dat - we're going to create a new one. The previous
109
163
# backup will be overwritten.
110
mv -f "$root/$instance/globals/scratch.dat" "$root/$instance/globals/scratch.dat~"
112
[ $retval -eq 0 ] || return 1
164
mv -f "$root/$instance/globals/scratch.dat" \
165
"$root/$instance/globals/scratch.dat~" \
114
168
mupip create -region=SCRATCH 2>&1 \
116
| logger -p user.info -t "openvista-databases[$$]"
117
retval=${PIPESTATUS[0]}
118
[ $retval -eq 0 ] || return 1
171
(( "${PIPESTATUS[0]}" == 0 )) || return 1
120
logger -p user.info -t "openvista-databases[$$]" -- Database recovery complete, $instance database is ready for use
173
log -l "Database $instance is ready for use"
125
178
terminate_processes()
127
set_gtm_env "$1" || return 1
129
logger -p user.info -t "openvista-databases[$$]" -- Terminating mumps processes in $instance
131
# find all processes using this database and kill them
132
for pid in `ls /proc`; do
133
[ -L "/proc/$pid/cwd" ] || continue
134
cwd=`readlink "/proc/$pid/cwd"`
135
[ "$root/$instance/tmp" = "$cwd" ] || continue
137
[ -L "/proc/$pid/exe" ] || continue
138
exe=`readlink "/proc/$pid/exe"`
139
exe_base=`basename "$exe"`
140
[ "mumps" = "$exe_base" ] || continue
142
mupip stop "$pid" 2>&1 \
144
| logger -p user.info -t "openvista-databases[$$]"
180
# Make sure all mumps processes using the database are stopped.
181
# Early in the shutdown sequence the /etc/init.d/openvista script calls
182
# the ZSTOP routine on the instance to stop OpenVista mumps processes.
183
# This function first allows some time for the processes to stop
184
# themselves in response to that routine, and then it calls `mupip stop`
185
# to more forcefully stop them. It then waits again for the processes to
186
# be stopped. Both wait loops check each second to see if the processes
187
# are stopped, so the function will not wait any longer than the time it
188
# actually takes for the processes to stop. There are at least three
190
# 1) To allow applications to complete whatever task they are in the
191
# middle of and stop at a point that makes sense in the context of
193
# 2) To keep the system from shutting down while a process is writing
194
# data, which might corrupt the database.
195
# 3) To allow openvista-databases to write a 'clean' flag
196
# (representing that the problem of #2 was avoided) so that on
197
# system startup, openvista-databases will know that a database
198
# recovery won't be necessary.
201
set_gtm_env -v "$instance" || return $?
203
log -l "Terminating OpenVista processes in $instance"
207
# allow time for ZSTOP, called by openvista, to succeed in stopping tasks
208
# The %ZISTCPS routine listens on the RPC broker port for 30 seconds at a
209
# time and will only respond to ZSTOP after its current listen period is
210
# up. So we will wait up to 35 seconds.
212
for (( i=0; i!=$max_wait; i++ )); do
213
mumps_pids=( $(get_mumps_pids "$instance") )
214
(( "${#mumps_pids[@]}" == 0 )) && break
147
# wait for processes to die
217
log -l "Waited $i seconds for all processes to die from ZSTOP"
219
# kill any processes that are still using this database
220
# Generally, they should have already been stopped by ZSTOP.
221
mumps_pids=( $(get_mumps_pids "$instance") )
222
mumps_process_count=${#mumps_pids[@]}
223
if (( "$mumps_process_count" != 0 )); then
224
log -l "$mumps_process_count mumps processes remain after ZSTOP"
226
for pid in "${mumps_pids[@]}"; do
227
num=$(( $(array_index "$pid" "${mumps_pids[@]}") + 1 ))
228
log -lc "Calling MUPIP STOP on process $pid" \
229
"($num of $mumps_process_count)"
230
mupip stop "$pid" 2>&1 \
236
# wait for any mumps processes to stop, and set the clean flag
237
# The clean flag is used by recover_backward() to determine whether to run
238
# backward recovery on the database. If all mumps processes for the
239
# database were successfully stopped before shutdown, then the database
240
# should not require recovery, but if mumps processes were still running
241
# when the server was shut down, either because they failed to stop or
242
# because the shutdown was irregular, e.g. in the case of power failure,
243
# then the database potentially requires recovery.
244
if wait_for_mumps_to_stop "$instance"; then
245
clean_flag set "$instance" true
246
# This would be a good place to perform RUNDOWN on the database, except
247
# that the replication source server is still using the database file.
248
# So openvista-replication takes care of the database rundown.
250
clean_flag set "$instance" false
256
wait_for_mumps_to_stop()
258
# Allow time for all mumps processes to stop.
261
# how many times to give more time if mumps process count is reduced
262
local allowed_tries=6
263
# seconds to wait for mumps process count to be zero
264
local allowed_delay=20
269
local initial_mumps_process_count
270
local mumps_process_count
271
for (( try=0; try!=$allowed_tries; try++ )); do
272
mumps_pids=( $(get_mumps_pids "$instance") )
273
initial_mumps_process_count=${#mumps_pids[@]}
274
[[ "$initial_mumps_process_count" == 0 ]] || log -srlc \
275
"$initial_mumps_process_count mumps processes still running," \
276
"will wait up to $allowed_delay seconds for them to stop"
277
for (( time_left=$allowed_delay; time_left!=0; time_left-- )); do
278
mumps_pids=( $(get_mumps_pids "$instance") )
279
mumps_process_count=${#mumps_pids[@]}
280
[[ "$mumps_process_count" == "0" ]] && break
283
if [[ "$mumps_process_count" == "0" ]]; then
284
log -l "There are no mumps processes running"
286
elif (( "$mumps_process_count" >= \
287
"$initial_mumps_process_count" )); then
289
"$mumps_process_count mumps processes are still running," \
290
"but the allowed time of $allowed_delay seconds is exceeded"
292
"Remaining mumps processes:" ${mumps_pids[@]}
296
"The number of mumps processes was reduced in the past" \
297
"$allowed_delay seconds, so another $allowed_delay seconds" \
298
"will be allowed for remaining mumps processes to exit"
300
"Remaining mumps processes:" ${mumps_pids[@]}
304
(( "$mumps_process_count" == 0 ))
309
# Set the clean flag for openvista-databases to find on startup.
315
clean_flag_file="$root/$instance/etc/clean_shutdown"
319
[[ -e "$clean_flag_file" ]]
324
# write the clean flag
325
echo "openvista-databases completed a clean shutdown of" \
326
"$instance database at $(date --rfc-3339=ns)" \
328
if [[ -e "$clean_flag_file" ]]; then
330
"Wrote the clean shutdown flag for $instance database"
333
"Shutdown was clean for $instance database, but failed" \
334
"to write the clean shutdown flag"
337
# erase the clean flag
338
if [[ -e "$clean_flag_file" ]]; then
339
if rm -f "$clean_flag_file"; then
341
"Removed the clean shutdown flag for $instance" \
345
"Failed to remove the clean shutdown flag for" \
353
exit_command 1 "Error: clean_flag() received invalid argument(s)"
153
358
# While it would be possible to run the journal recovery and database
154
359
# rundown as a normal user, root access is required to delete/re-create
155
360
# scratch.dat. Root access is also required to run mupip stop.
156
if [ `id -u` -ne 0 ]; then
157
echo "openvista-databases: Must be run as root" >&2
361
if [[ $(id -u) != 0 ]]; then
362
log -sr "openvista-databases: Must be run as root"
158
363
exit 4 # LSB: user had insufficient privilege
161
# check for for valid arguments (requires correct permissions to do; must happen after permission checks)
163
set_gtm_env "$2" || {
164
echo "openvista-databases: $instance: Not an OpenVista instance" >&2
165
exit 2 # LSB: invalid or excess argument(s)
366
# check for for valid arguments
368
if [[ "$instance" ]]; then
369
is_openvista_instance "$instance" || exit_command 2 "$ov_error"
374
# For 'start' and 'stop', the ov_init_action calls provide the exit value
375
# for the script. The CentOS/RHEL subsys lock is set and cleared
376
# independently of the return code, because a partial failure of one action
377
# should not cause the other to be skipped. The lock is only set or cleared
378
# when being called without an instance name argument. Any error from
379
# touching or removing the lock file is hidden from the console so that the
380
# script can be run without an instance name by a non-root admin without
381
# printing confusing error messages.
172
if function_exists "action"; then
173
echo "Performing backward journal recovery on OpenVista databases..."
174
elif function_exists "log_daemon_msg"; then
175
log_daemon_msg "Performing backward journal recovery on OpenVista databases"
178
for instance in `list_openvista_instances`; do
179
if function_exists "action"; then
180
action $" Performing recovery on $instance database: " recover_backward "$instance"
181
elif function_exists "log_daemon_msg"; then
182
log_progress_msg "$instance"
183
recover_backward "$instance" || end_msg=1
185
recover_backward "$instance"
189
if function_exists "log_daemon_msg"; then
190
log_end_msg ${end_msg:-0}
383
instance_function=recover_backward
384
if function_exists "action"; then
386
touch /var/lock/subsys/openvista-databases \
388
ov_init_action_rhel "$instance_function" \
389
"Performing recovery if needed on OpenVista databases" \
390
"Performing recovery if needed on {instance} database" \
392
elif function_exists "log_daemon_msg"; then
394
ov_init_action_debian "$instance_function" \
395
"Performing recovery if needed on OpenVista databases" \
396
"Performing recovery if needed on OpenVista database" \
193
if function_exists "action"; then
194
action $"Performing recovery on $instance database: " recover_backward "$instance"
195
elif function_exists "log_daemon_msg"; then
196
log_daemon_msg "Performing backward journal recovery on OpenVista databases" "$instance"
197
recover_backward "$instance"
200
recover_backward "$instance"
400
ov_init_action_other "$instance_function" "$instance"
206
if function_exists "action"; then
207
echo "Terminating remaining mumps processes..."
208
elif function_exists "log_daemon_msg"; then
209
log_daemon_msg "Terminating remaining mumps processes"
212
for instance in `list_openvista_instances`; do
213
if function_exists "action"; then
214
action $" Terminating mumps processes in $instance: " terminate_processes "$instance"
215
elif function_exists "log_daemon_msg"; then
216
log_progress_msg "$instance"
217
terminate_processes "$instance" || end_msg=1
219
terminate_processes "$instance"
223
if function_exists "log_daemon_msg"; then
224
log_end_msg ${end_msg:-0}
404
instance_function=terminate_processes
405
if function_exists "action"; then
407
[[ "$instance" ]] || rm -f /var/lock/subsys/openvista-databases \
409
ov_init_action_rhel "$instance_function" \
410
"Terminating remaining OpenVista processes" \
411
"Terminating OpenVista processes in {instance}" \
413
elif function_exists "log_daemon_msg"; then
415
ov_init_action_debian "$instance_function" \
416
"Terminating remaining OpenVista processes" \
417
"Terminating remaining OpenVista processes" \
227
if function_exists "action"; then
228
action $"Terminating mumps processes in $instance: " terminate_processes "$instance"
229
elif function_exists "log_daemon_msg"; then
230
log_daemon_msg "Terminating remaining mumps processes" "$instance"
231
terminate_processes "$instance"
234
terminate_processes "$instance"
421
ov_init_action_other "$instance_function" "$instance"
238
424
restart|force-reload)