#!/usr/bin/env bash

# Test support for read-only records

# Read-only records can be activated at runtime using a ctdb command.
# If read-only records are not activated, then any attempt to fetch a
# read-only copy should be automatically upgraded to a read-write
# fetch_locked().

# If read-only delegations are present, then any attempt to acquire a
# read-write fetch_lock will trigger revocation of all delegations
# before the fetch_locked().

# 1. Create a test database and some records
# 2. Try to fetch read-only records, this should not result in any delegations
# 3. Activate read-only support
# 4. Try to fetch read-only records, this should result in delegations
# 5. Do a fetchlock  and the delegations should be revoked
# 6. Try to fetch read-only records, this should result in delegations

. "${TEST_SCRIPTS_DIR}/integration.bash"

set -e

ctdb_test_init

######################################################################

# Confirm that no nodes have databases with read-only delegations
check_no_readonly ()
{
    try_command_on_node all $CTDB cattdb $testdb
    local ro_flags="RO_HAVE_READONLY|RO_HAVE_DELEGATIONS"
    local numreadonly=$(grep -c -E "$ro_flags" "$outfile") || true
    if [ $numreadonly -eq 0 ] ; then
	echo "GOOD: no read-only delegations"
    else
	echo "BAD: there are read-only delegations"
	cat "$outfile"
	exit 1
    fi
}

# Check that the test record has the correct read-only flags on the
# given nodes.  The first node is the dmaster, which should know there
# are delegations but should not be flagged as having a read-only
# copy.  Subsequent nodes should have a read-only copy but not know
# about any (other) delegations.
check_readonly ()
{
    local dmaster="$1" ; shift
    local others="$*"

    local count

    try_command_on_node $dmaster $CTDB cattdb $testdb
    count=$(grep -c -E "RO_HAVE_DELEGATIONS" "$outfile") || true
    if [ $count -eq 1 ] ; then
	echo "GOOD: dmaster ${dmaster} has read-only delegations"
    else
	echo "BAD: dmaster ${dmaster} has no read-only delegations"
	cat "$outfile"
	exit 1
    fi
    count=$(grep -c -E "RO_HAVE_READONLY" "$outfile") || true
    if [ $count -ne 0 ] ; then
	echo "BAD: dmaster ${dmaster} has a read-only copy"
	cat "$outfile"
	exit 1
    fi

    local o
    for o in $others ; do
	try_command_on_node $o $CTDB cattdb $testdb
	count=$(grep -c -E "RO_HAVE_READONLY" "$outfile") || true
	if [ $count -eq 1 ] ; then
	    echo "GOOD: node ${o} has a read-only copy"
	else
	    echo "BAD: node ${o} has no read-only copy"
	    cat "$outfile"
	    exit 1
	fi
	count=$(grep -c -E "RO_HAVE_DELEGATIONS" "$outfile") || true
	if [ $count -ne 0 ] ; then
	    echo "BAD: other node ${o} has read-only delegations"
	    cat "$outfile"
	    exit 1
	fi
    done
}

######################################################################

echo "Get list of nodes..."
ctdb_onnode 0 "-X listnodes"
all_nodes=$(awk -F'|' '{print $2}' "$outfile")

######################################################################

testdb="test.tdb"
echo "Create test database \"${testdb}\""
try_command_on_node 0 $CTDB attach $testdb

echo "Create some records..."
try_command_on_node all $CTDB_TEST_WRAPPER $VALGRIND update_record \
	-D ${testdb} -k testkey

######################################################################

echo "Try some readonly fetches, these should all be upgraded to full fetchlocks..."
try_command_on_node all $CTDB_TEST_WRAPPER $VALGRIND fetch_readonly \
	-D ${testdb} -k testkey

check_no_readonly

######################################################################

echo "Activate read-only record support for \"$testdb\"..."
try_command_on_node all $CTDB setdbreadonly $testdb

# Database should be tagged as READONLY
try_command_on_node 0 $CTDB getdbmap
db_details=$(awk -v db="$testdb" '$2 == foo="name:" db { print }' "$outfile")
if grep -q "READONLY" <<<"$db_details" ; then
    echo "GOOD: read-only record support is enabled"
else
    echo "BAD: could not activate read-only support"
    echo "$db_details"
    exit 1
fi

######################################################################

echo "Create 1 read-only delegation ..."
# dmaster=1
try_command_on_node 1 $CTDB_TEST_WRAPPER $VALGRIND update_record \
	-D ${testdb} -k testkey

# Fetch read-only to node 0
try_command_on_node 0 $CTDB_TEST_WRAPPER $VALGRIND fetch_readonly \
	-D ${testdb} -k testkey

check_readonly 1 0

######################################################################

echo "Verify that a fetchlock revokes read-only delegations..."
# Node 1 becomes dmaster
try_command_on_node 1 $CTDB_TEST_WRAPPER $VALGRIND update_record \
	-D ${testdb} -k testkey

check_no_readonly

######################################################################

echo "Create more read-only delegations..."
dmaster=1
try_command_on_node $dmaster $CTDB_TEST_WRAPPER $VALGRIND update_record \
	-D ${testdb} -k testkey

others=""
for n in $all_nodes ; do
    if [ "$n" != "$dmaster" ] ; then
	# Fetch read-only copy to this node
	try_command_on_node $n $CTDB_TEST_WRAPPER $VALGRIND fetch_readonly \
		-D ${testdb} -k testkey
	others="${others} ${n}"
    fi
done

check_readonly $dmaster $others

######################################################################

echo "Verify that a recovery will revoke the delegations..."
try_command_on_node 0 $CTDB recover

check_no_readonly
