#!/bin/bash
################################################################################
# Copyright (c) 2013-2017 VMware, Inc. All rights reserved.
################################################################################
# Script which is called by archive_command for vCenter
#
# As of now this script does not do much, just generating a log dump of the
# completed segment with pg_waldump. Errors coming out of pg_waldump are
# simply ignored as that would be the case for backup and history files.
# No space cleanup action is performed, a single segment dump not getting
# normally up to 300kB after compression. And this is used now just for
# testing purposes.

THIS_DIR=`dirname $0`

# Ensure that global variables are loaded.
source /etc/profile

# Minimum check to ensure that environment variable able to redirect the
# rest of the settings is available. The rest of the sanity checks is done
# just after that.
if [ -z $VMWARE_POSTGRES_BASE ]; then
   echo "VMWARE_POSTGRES_BASE is not set."
   echo "Check your installation."
   exit 1
fi

# Sanity check for environment. Note that VMWARE_POSTGRES_BASE is used
# for consistency with the check done previously.
SANITY_FILE=$VMWARE_POSTGRES_BASE/scripts/vpostgres_sanity_checks
if [ -f $SANITY_FILE ]; then
   source $SANITY_FILE
else
   echo "Sanity check file for environment variables of VMware Postgres"
   echo "is not available. Check your installation."
   exit 1
fi

# Leave if archive folder does not exist, this archive command could be
# launched on an instance that had an in-place upgrade on which the
# partition dedicated to WAL archiving does not exist.
if [ ! -d "${VMWARE_POSTGRES_ARCHIVE}" ]; then
   exit 0
fi

XLOG_FILE_PATH=$1
XLOG_FILE_NAME=$2

SEGMENT_FILE_GZ=${XLOG_FILE_NAME}.gz
SEGMENT_FULL_PATH_GZ="${VMWARE_POSTGRES_ARCHIVE}/${SEGMENT_FILE_GZ}"

# Leave if file exists. Note that promoted standbys archive the last,
# partial segment of the previous timeline. There is a risk to cause
# an overlap but for VCHA deployments that is actually fine as the
# archives of master and its standby live on separate servers.
if [ -e "${SEGMENT_FULL_PATH_GZ}" ]; then
   echo "${SEGMENT_FILE_GZ} found in archives... Leaving"
   exit 0
fi

CURRENT_TIME=$(date)
echo "Archiving segment ${XLOG_FILE_NAME} at ${CURRENT_TIME}"

# Amount of free space necessary for at least two segment files. Compressed
# segments take far less than 16MB but this looks better as a safety measure
# to make sure that the segment archived is persistent on disk.
ARCHIVE_FREESPACE_THRESHOLD=32768

# Take any purging actions before doing anything.
free_space=$(df -k "${VMWARE_POSTGRES_ARCHIVE}" | tail -n 1 | tr -s ' ' | cut -d' ' -f 4)

# Remove multiple things if necessary. We need enough space to store for
# subsequent operations. There is no risk of infinite loop here as no other
# services are using the WAL archive partition.
while [ "$free_space" -lt ${ARCHIVE_FREESPACE_THRESHOLD} ]; do
   GZ_FILE_TO_DELETE=$(ls "${VMWARE_POSTGRES_ARCHIVE}" | grep -E -m1 -x '[0-9A-Fa-f]{24}.gz')
   rm -f "${VMWARE_POSTGRES_ARCHIVE}/${GZ_FILE_TO_DELETE}"
   echo "Purged $GZ_FILE_TO_DELETE from the archives."

   # Refresh free space number for next loop if needed.
   free_space=$(df -k "${VMWARE_POSTGRES_ARCHIVE}" | tail -n 1 | tr -s ' ' | cut -d' ' -f 4)
done

# Finally copy the new WAL file in the archive
# 1) Copy it physically as a gzip file.
# 2) Make it persistent on disk. This step is essential to ensure that even
#    in the event of a crash the data will durably persist.

# This creates the SEGMENT_FULL_PATH_GZ entry.
gzip --stdout "${XLOG_FILE_PATH}" > "${SEGMENT_FULL_PATH_GZ}"

# Now move it to a temporary file and fsync it to disk.
mv "${SEGMENT_FULL_PATH_GZ}" "${SEGMENT_FULL_PATH_GZ}.tmp"
dd if="${SEGMENT_FULL_PATH_GZ}.tmp" of="${SEGMENT_FULL_PATH_GZ}" conv=fsync
rm "${SEGMENT_FULL_PATH_GZ}.tmp"

echo "Finished archiving of $XLOG_FILE_NAME"
exit 0
