#!/usr/bin/perl -I../www/libs

use strict;
use warnings;

use Time::HiRes ();

use ECS::Cache::Memcached ();

package API::Utils;

# number of seconds it's OK for the slave to be behind (excludes edit page)
my $ACCEPTABLE_SLAVE_LAG = 120;
my $CATEGORY_LAG_WAIT = 3;
return 1;

###############################################################################
# try and determine if the slave is reliable enough to read from,
# almost assuredly not perfect

sub check_slave(%) {
    my $p = shift;

    my $query = "select
            transactionLog.transactionTime
        from
            transactionLog
        order by
            transactionLog.transactionLogID desc
        limit 1";
    my $get_slave_last_update = $p->{'dbhr'}->prepare($query);
    $get_slave_last_update->execute();
    my $slave_last_update = $get_slave_last_update->fetchrow_array();

    # this should be the maximum possible amount of time that has passed
    # since a statement replicated. it's possible that there just haven't
    # been anything to replicate. we're assuming that all clocks involved
    # are synched up within a reasonable margin (a few seconds is close enough)
    my $last_update_ago = time() - $slave_last_update;

    if($last_update_ago < $ACCEPTABLE_SLAVE_LAG) {
        # looks good
        return 1;
    }

}

###############################################################################
# add a transaction for a given transactionKey and prime the cache for it

sub add_transaction(%) {
    my $p = shift;

    my $query = "insert into
            transactionLog
        set
            transactionTime = ?";
    my $add_transaction = $p->{'dbh'}->prepare($query);
    $add_transaction->execute(time());
    my $transactionID = $p->{'dbh'}->{'mysql_insertid'};

    ECS::Cache::Memcached::setData({
        'key'   => 'transaction_API_' . $p->{'transactionKey'},
        'data'  => $transactionID,
        });
}

###############################################################################

sub wait_transaction(%) {
    my $p = shift;

    my $transactionID = ECS::Cache::Memcached::getData({
        'key'   => 'transaction_API_' . $p->{'transactionKey'},
        });

    # if the cache hasn't yet been primed for this section,
    # assume the worst and read from the master
    if(not $transactionID) {
        # add a dummy record so this doesn't happen again
        API::Utils::add_transaction({
            'dbh'       => $p->{'dbh'},
            'transactionKey' => $p->{'transactionKey'},
            });
        return 0;
    }

    my $query = "select
            1
        from
            transactionLog
        where
            transactionLog.transactionLogID = ?
        limit 1";
    my $check_transaction = $p->{'dbhr'}->prepare($query);

    # we'll wait a few seconds for the transaction to show up on the slave
    my $give_up_time = Time::HiRes::time() + $CATEGORY_LAG_WAIT;
    while(Time::HiRes::time() < $give_up_time) {
        $check_transaction->execute($transactionID);
        if($check_transaction->rows() > 0) {
            # looks good
            return 1;
        }

        # give the database a break between polling
        Time::HiRes::sleep(0.1);
    }

    # the slave is missing the latest transaction for this section,
    # so it's (probably) missing other changes related to this section.
    return 0;
}

###############################################################################

