This is another big commit with a lot of DB work. Getting closer to sorting out the frequent resyncs.

* Changes Database->connect to always use the first DB connected to, not the local one if that applies. This treats the first DB (sorted by UUID) as "primary" and the second (or third...) as more of a backup.
* Moved db_in_use and lock_request to use the 'states' table instead of the variables table. These are set and removed so often that it was messing up things with resync's when the data is transient anyway. Fixed multiple bugs with both to better set and clear properly.
* Created Database->read_state() to assist with the above changes.
* Updated Database->refresh_timestamp() to specifically check that the returned time stamp differs from the previously used one, looping until they differ if needed.
* Disabled striker-manage-install-target when called to update the repos, as the Install Target function doesn't work at this point.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 3 years ago
parent 24f5d39dff
commit 911f7cfb6a
  1. 491
      Anvil/Tools/Database.pm
  2. 6
      share/words.xml
  3. 37
      tools/anvil-daemon
  4. 6
      tools/striker-manage-install-target

@ -627,7 +627,7 @@ sub check_agent_data
# Hold if a lock has been requested. # Hold if a lock has been requested.
$anvil->Database->locking({debug => $debug}); $anvil->Database->locking({debug => $debug});
# Mark that we're not active. # Mark that we're now active.
$anvil->Database->mark_active({debug => $debug, set => 1}); $anvil->Database->mark_active({debug => $debug, set => 1});
# Sync the database, if needed. # Sync the database, if needed.
@ -1779,12 +1779,17 @@ sub connect
push @{$successful_connections}, $uuid; push @{$successful_connections}, $uuid;
} }
# Before we try to connect, see if this is a local database and, if so, make sure it's setup. # We always use the first DB we connect to, even if we're a DB ourselves. This helps with
if ($is_local) # consistency and leaves second (or third...) as backups.
if (not $anvil->data->{sys}{database}{read_uuid})
{ {
$anvil->data->{sys}{database}{read_uuid} = $uuid; $anvil->data->{sys}{database}{read_uuid} = $uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::read_uuid" => $anvil->data->{sys}{database}{read_uuid} }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::read_uuid" => $anvil->data->{sys}{database}{read_uuid} }});
}
# Before we try to connect, see if this is a local database and, if so, make sure it's setup.
if ($is_local)
{
# If we're being called with 'all', don't set active as we could be just checking if # If we're being called with 'all', don't set active as we could be just checking if
# we're active or not. # we're active or not.
if (not $all) if (not $all)
@ -1811,15 +1816,9 @@ sub connect
} }
} }
} }
elsif (not $anvil->data->{sys}{database}{read_uuid})
{
$anvil->data->{sys}{database}{read_uuid} = $uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::read_uuid" => $anvil->data->{sys}{database}{read_uuid} }});
}
# If this isn't a local database, read the target's Anvil! version (if available) and make # If this isn't a local database, read the target's Anvil! version (if available) and make
# sure it matches ours. If it doesn't, skip this database. # sure it matches ours. If it doesn't, skip this database.
if (not $is_local) else
{ {
my ($local_anvil_version, $local_schema_version) = $anvil->_anvil_version({debug => $debug}); my ($local_anvil_version, $local_schema_version) = $anvil->_anvil_version({debug => $debug});
my ($remote_anvil_version, $remote_schema_version) = $anvil->Get->anvil_version({ my ($remote_anvil_version, $remote_schema_version) = $anvil->Get->anvil_version({
@ -1847,8 +1846,9 @@ sub connect
# Delete the information about this database. We'll try again on next # Delete the information about this database. We'll try again on next
# ->connect(). # ->connect().
delete $anvil->data->{database}{$uuid}; $anvil->data->{sys}{database}{read_uuid} = "" if $anvil->data->{sys}{database}{read_uuid} eq $uuid;
$anvil->data->{sys}{database}{connections}--; $anvil->data->{sys}{database}{connections}--;
delete $anvil->data->{database}{$uuid};
next; next;
} }
} }
@ -12327,7 +12327,7 @@ sub insert_or_update_states
$hosts_ok = 0; $hosts_ok = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { hosts_ok => $hosts_ok }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { hosts_ok => $hosts_ok }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "warning_0144", variables => { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "warning_0144", variables => {
state_info => $state_name." -> ".$state_note, state_info => $state_name." -> ".$state_note,
db_uuid => $db_uuid, db_uuid => $db_uuid,
host_uuid => $state_host_uuid, host_uuid => $state_host_uuid,
@ -12418,49 +12418,8 @@ INSERT INTO
} }
else else
{ {
# Query the rest of the values and see if anything changed. # There's no history schema so we just UPDATE (in case, as in DB locking, the age since last
my $query = " # update is important).
SELECT
state_name,
state_host_uuid,
state_note
FROM
states
WHERE
state_uuid = ".$anvil->Database->quote($state_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
if (not $count)
{
# I have a state_uuid but no matching record. Probably an error.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0216", variables => { uuid_name => "state_uuid", uuid => $state_uuid }});
return("");
}
foreach my $row (@{$results})
{
my $old_state_name = $row->[0];
my $old_state_host_uuid = $row->[1];
my $old_state_note = $row->[2];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
old_state_name => $old_state_name,
old_state_host_uuid => $old_state_host_uuid,
old_state_note => $old_state_note,
}});
# Anything change?
if (($old_state_name ne $state_name) or
($old_state_host_uuid ne $state_host_uuid) or
($old_state_note ne $state_note))
{
# Something changed, save.
my $query = " my $query = "
UPDATE UPDATE
states states
@ -12475,8 +12434,6 @@ WHERE
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
$anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__}); $anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
} }
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { state_uuid => $state_uuid }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { state_uuid => $state_uuid }});
return($state_uuid); return($state_uuid);
@ -14635,21 +14592,47 @@ sub locking
}}); }});
# These are used to ID this lock. # These are used to ID this lock.
my $source_name = $anvil->Get->host_name; my $source_name = $anvil->Get->short_host_name;
my $source_uuid = $anvil->data->{sys}{host_uuid}; my $source_uuid = $anvil->Get->host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
source_name => $source_name, source_name => $source_name,
source_uuid => $source_uuid, source_uuid => $source_uuid,
}}); }});
my $set = 0; my $set = 0;
my $variable_name = "lock_request"; my $state_name = "lock_request";
my $variable_value = $source_name."::".$source_uuid."::".time; my $new_state_note = $source_name."::".$source_uuid."::".time;
my $old_state_note = $source_name."::".$source_uuid."::%";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
variable_name => $variable_name, state_name => $state_name,
variable_value => $variable_value, new_state_note => $new_state_note,
old_state_note => $old_state_note,
}}); }});
my $wildcard_select_query = "
SELECT
state_note
FROM
states
WHERE
state_host_uuid = ".$anvil->Database->quote($source_uuid)."
AND
state_name = ".$anvil->Database->quote($state_name)."
AND
state_note LIKE ".$anvil->Database->quote($old_state_note)."
;";
my $wildcard_delete_query = "
DELETE FROM
states
WHERE
state_host_uuid = ".$anvil->Database->quote($source_uuid)."
AND
state_name = ".$anvil->Database->quote($state_name)."
AND
state_note LIKE ".$anvil->Database->quote($old_state_note)."
;";
# Make sure we have a sane lock age # Make sure we have a sane lock age
if ((not defined $anvil->data->{sys}{database}{locking}{reap_age}) or if ((not defined $anvil->data->{sys}{database}{locking}{reap_age}) or
(not $anvil->data->{sys}{database}{locking}{reap_age}) or (not $anvil->data->{sys}{database}{locking}{reap_age}) or
@ -14660,17 +14643,15 @@ sub locking
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::locking::reap_age" => $anvil->data->{sys}{database}{locking}{reap_age} }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::locking::reap_age" => $anvil->data->{sys}{database}{locking}{reap_age} }});
} }
# If I have been asked to check, we will return the variable_uuid if a lock is set. # If I have been asked to check, we will return the state_note if a lock is set.
if ($check) if ($check)
{ {
my ($lock_value, $variable_uuid, $modified_date) = $anvil->Database->read_variable({debug => $debug, variable_name => $variable_name}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { wildcard_select_query => $wildcard_select_query }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { my $state_note = $anvil->Database->query({query => $wildcard_select_query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
lock_value => $lock_value, $state_note = "" if not defined $state_note;
variable_uuid => $variable_uuid, $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { state_note => $state_note }});
modified_date => $modified_date,
}});
return($lock_value); return($state_note);
} }
# If I've been asked to clear a lock, do so now. # If I've been asked to clear a lock, do so now.
@ -14678,32 +14659,25 @@ sub locking
{ {
# We check to see if there is a lock before we clear it. This way we don't log that we # We check to see if there is a lock before we clear it. This way we don't log that we
# released a lock unless we really released a lock. # released a lock unless we really released a lock.
my ($lock_value, $variable_uuid, $modified_date) = $anvil->Database->read_variable({debug => $debug, line => __LINE__, variable_name => $variable_name}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { wildcard_select_query => $wildcard_select_query }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { my $results = $anvil->Database->query({debug => $debug, query => $wildcard_select_query, source => $THIS_FILE, line => __LINE__});
lock_value => $lock_value, my $count = @{$results};
variable_uuid => $variable_uuid, $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count }});
modified_date => $modified_date,
}});
if ($lock_value) if ($count)
{ {
my $variable_uuid = $anvil->Database->insert_or_update_variables({ ### NOTE: There is not history schema for states, so we just delete it.
variable_name => $variable_name, # Delete the state(s).
variable_value => "", $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { wildcard_delete_query => $wildcard_delete_query }});
variable_default => "", $anvil->Database->write({debug => $debug, query => $wildcard_delete_query, source => $THIS_FILE, line => __LINE__});
variable_description => "striker_0289",
variable_section => "database",
variable_source_uuid => "NULL",
variable_source_table => "",
});
$anvil->data->{sys}{database}{local_lock_active} = 0; $anvil->data->{sys}{database}{local_lock_active} = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
variable_uuid => $variable_uuid,
"sys::local_lock_active" => $anvil->data->{sys}{database}{local_lock_active}, "sys::local_lock_active" => $anvil->data->{sys}{database}{local_lock_active},
}}); }});
# Log that the lock has been released. # Log that the lock has been released.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0039", variables => { host => $anvil->Get->host_name }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0039", variables => { host => $anvil->Get->host_name }});
} }
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { set => $set }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { set => $set }});
@ -14713,34 +14687,41 @@ sub locking
# If I've been asked to renew, do so now. # If I've been asked to renew, do so now.
if ($renew) if ($renew)
{ {
# Yup, do it. # Yup, do it. Delete any old states first, thoguh. Batch them together to avoid there being
my $variable_uuid = $anvil->Database->insert_or_update_variables({ # a time where another process could falsely see no locks are held.
variable_name => $variable_name, my $queries = [];
variable_value => $variable_value, push @{$queries}, $wildcard_delete_query;
variable_default => "", push @{$queries}, "
variable_description => "striker_0289", INSERT INTO
variable_section => "database", states
variable_source_uuid => "NULL", (
variable_source_table => "", state_uuid,
}); state_name,
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { variable_uuid => $variable_uuid }}); state_host_uuid,
state_note,
if ($variable_uuid) modified_date
) VALUES (
".$anvil->Database->quote($anvil->Get->uuid).",
".$anvil->Database->quote($state_name).",
".$anvil->Database->quote($source_uuid).",
".$anvil->Database->quote($new_state_note).",
".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
);";
foreach my $query (@{$queries})
{ {
$set = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { set => $set }});
} }
$anvil->Database->write({debug => $debug, query => $queries, source => $THIS_FILE, line => __LINE__});
$anvil->data->{sys}{database}{local_lock_active} = time; $anvil->data->{sys}{database}{local_lock_active} = time;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
variable_uuid => $variable_uuid,
"sys::local_lock_active" => $anvil->data->{sys}{database}{local_lock_active}, "sys::local_lock_active" => $anvil->data->{sys}{database}{local_lock_active},
}}); }});
# Log that we've renewed the lock. # Log that we've renewed the lock.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0044", variables => { host => $anvil->Get->short_host_name }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0044", variables => { host => $anvil->Get->short_host_name }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { set => $set }}); return(1);
return($set);
} }
# We always check for, and then wait for, locks. Read in the locks, if any. If any are set and they are # We always check for, and then wait for, locks. Read in the locks, if any. If any are set and they are
@ -14752,11 +14733,12 @@ sub locking
$waiting = 0; $waiting = 0;
# See if we had a lock. # See if we had a lock.
my ($lock_value, $variable_uuid, $modified_date) = $anvil->Database->read_variable({debug => $debug, variable_name => $variable_name}); my ($lock_value, $state_uuid, $modified_date) = $anvil->Database->read_state({debug => $debug, state_name => $state_name});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
waiting => $waiting, waiting => $waiting,
lock_value => $lock_value, lock_value => $lock_value,
variable_uuid => $variable_uuid, state_uuid => $state_uuid,
state_host_uuid => $anvil->Get->host_uuid,
modified_date => $modified_date, modified_date => $modified_date,
}}); }});
if ($lock_value =~ /^(.*?)::(.*?)::(\d+)/) if ($lock_value =~ /^(.*?)::(.*?)::(\d+)/)
@ -14779,17 +14761,11 @@ sub locking
# If the lock is stale, delete it. # If the lock is stale, delete it.
if ($current_time > $timeout_time) if ($current_time > $timeout_time)
{ {
### NOTE: There is no history schema for states.
# The lock is stale. # The lock is stale.
my $variable_uuid = $anvil->Database->insert_or_update_variables({ my $query = "DELETE FROM states WHERE state_uuid = ".$state_uuid.";";
variable_name => $variable_name, $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
variable_value => "", $anvil->Database->write({debug => $debug, query => $query, source => $THIS_FILE, line => __LINE__});
variable_default => "",
variable_description => "striker_0289",
variable_section => "database",
variable_source_uuid => "",
variable_source_table => "",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { variable_uuid => $variable_uuid }});
} }
# Only wait if this isn't our own lock. # Only wait if this isn't our own lock.
elsif ($lock_source_uuid ne $source_uuid) elsif ($lock_source_uuid ne $source_uuid)
@ -14812,30 +14788,40 @@ sub locking
if ($request) if ($request)
{ {
# Yup, do it. # Yup, do it.
my $variable_uuid = $anvil->Database->insert_or_update_variables({ my $state_uuid = $anvil->Get->uuid;
variable_name => $variable_name, my $queries = [];
variable_value => $variable_value, push @{$queries}, $wildcard_delete_query;
variable_default => "", push @{$queries}, "
variable_description => "striker_0289", INSERT INTO
variable_section => "database", states
variable_source_uuid => "NULL", (
variable_source_table => "", state_uuid,
}); state_name,
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { variable_uuid => $variable_uuid }}); state_host_uuid,
state_note,
if ($variable_uuid) modified_date
) VALUES (
".$anvil->Database->quote($state_uuid).",
".$anvil->Database->quote($state_name).",
".$anvil->Database->quote($source_uuid).",
".$anvil->Database->quote($new_state_note).",
".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
);";
foreach my $query (@{$queries})
{ {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
}
$anvil->Database->write({debug => $debug, query => $queries, source => $THIS_FILE, line => __LINE__});
$set = 1; $set = 1;
$anvil->data->{sys}{database}{local_lock_active} = time; $anvil->data->{sys}{database}{local_lock_active} = time;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
set => $set, set => $set,
variable_uuid => $variable_uuid,
"sys::local_lock_active" => $anvil->data->{sys}{database}{local_lock_active}, "sys::local_lock_active" => $anvil->data->{sys}{database}{local_lock_active},
}}); }});
# Log that we've got the lock. # Log that we've got the lock.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0045", variables => { host => $anvil->Get->short_host_name }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0045", variables => { host => $anvil->Get->short_host_name }});
}
} }
# Now return. # Now return.
@ -15366,31 +15352,32 @@ sub mark_active
return(0); return(0);
} }
my $value = $set ? 1 : 0; # Record that we're using each available striker DB UUID.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { value => $value }});
foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}}) foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}})
{ {
# TODO: When unsetting, should we just go directly to a deletion? This method gets us the my $state_name = "db_in_use::".$uuid."::".$$;
# state_uuid though, which is convenient. $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
my $pid = $$; set => $set,
my $state_name = "db_in_use::".$uuid."::".$pid; state_name => $state_name,
}});
if ($set)
{
my $state_uuid = $anvil->Database->insert_or_update_states({ my $state_uuid = $anvil->Database->insert_or_update_states({
debug => $debug, debug => $debug,
state_name => $state_name, state_name => $state_name,
state_host_uuid => $anvil->data->{sys}{host_uuid}, state_host_uuid => $anvil->Get->host_uuid,
state_note => $value, state_note => "1",
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { state_uuid => $state_uuid }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { state_uuid => $state_uuid }});
}
# Being a state, if we're clearing, now delete the entry. else
# NOTE: The 'state' table has no history schema
if (not $set)
{ {
# Broadly clear all states that are '0' now. ### NOTE: The 'state' table has no history schema
my $query = "DELETE FROM states WHERE state_name LIKE 'db_in_use%' AND state_note != '1';"; # Delete this specific db_in_use, if it exists.
my $query = "DELETE FROM states WHERE state_name = ".$anvil->Database->quote($state_name)." AND state_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid).";";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0124", variables => { query => $query }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0124", variables => { query => $query }});
$anvil->Database->write({debug => $debug, uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__}); $anvil->Database->write({debug => $debug, query => $query, source => $THIS_FILE, line => __LINE__});
} }
} }
return(0); return(0);
@ -15776,6 +15763,123 @@ sub read
} }
=head2 read_state
This reads a C<< state_note >> from the C<< states >> table. An anonymous array reference is returned with the C<< state_name >>, C<< state_uuid >>, and C<< modified_date >> (in unix time format) in that order.
If anything goes wrong, C<< !!error!! >> is returned for all values in the array reference. If the state didn't exist in the database, an empty string will be returned.
Parameters;
=head3 state_uuid (optional)
If specified, this specifies the state UUID to read. When this parameter is specified, the C<< state_name >> parameter is ignored.
=head3 state_name (required)
This is the name of the state we're reading.
=head3 state_host_uuid (optional)
This is the C<< host_uuid >> of the state we're reading
=head3 uuid (optional)
If set, this specified which database to read the C<< state_note >> from.
=cut
sub read_state
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", states => { method => "Database->read_state()" }});
my $state_uuid = $parameter->{state_uuid} ? $parameter->{state_uuid} : "";
my $state_name = $parameter->{state_name} ? $parameter->{state_name} : "";
my $state_host_uuid = $parameter->{state_host_uuid} ? $parameter->{state_host_uuid} : "";
my $uuid = $parameter->{uuid} ? $parameter->{uuid} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
uuid => $uuid,
state_uuid => $state_uuid,
state_name => $state_name,
state_host_uuid => $state_host_uuid,
}});
if ((not $uuid) && ($anvil->data->{sys}{database}{read_uuid}))
{
$uuid = $anvil->data->{sys}{database}{read_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }});
}
# Do we have either the state name or UUID?
if ((not $state_name) && (not $state_uuid))
{
# Throw an error and exit.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0704"});
return("!!error!!", "!!error!!", "!!error!!");
}
# If we don't have a UUID, see if we can find one for the given SMTP server name.
my $query = "
SELECT
state_note,
state_uuid,
round(extract(epoch from modified_date)) AS mtime
FROM
states
WHERE ";
if ($state_uuid)
{
$query .= "
state_uuid = ".$anvil->Database->quote($state_uuid);
}
else
{
$query .= "
state_name = ".$anvil->Database->quote($state_name);
if ($state_host_uuid ne "")
{
$query .= "
AND
state_host_uuid = ".$anvil->Database->quote($state_host_uuid)."
";
}
}
$query .= ";";
$query =~ s/'NULL'/NULL/g;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0124", states => { query => $query }});
my $state_note = "";
my $mtime = "";
my $results = $anvil->Database->query({debug => $debug, uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
$state_note = $row->[0];
$state_uuid = $row->[1];
$mtime = $row->[2];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
state_note => $state_note,
state_uuid => $state_uuid,
mtime => $mtime,
}});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
state_note => $state_note,
state_uuid => $state_uuid,
mtime => $mtime,
}});
return($state_note, $state_uuid, $mtime);
}
=head2 read_variable =head2 read_variable
This reads a variable from the C<< variables >> table. Be sure to only use the reply from here to override what might have been set in a config file. This method always returns the data from the database itself. This reads a variable from the C<< variables >> table. Be sure to only use the reply from here to override what might have been set in a config file. This method always returns the data from the database itself.
@ -15922,10 +16026,38 @@ sub refresh_timestamp
my $parameter = shift; my $parameter = shift;
my $anvil = $self->parent; my $anvil = $self->parent;
my $match = 0;
my $ok = 0;
until ($ok)
{
my $query = "SELECT cast(now() AS timestamp with time zone);"; my $query = "SELECT cast(now() AS timestamp with time zone);";
my $new_time = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; my $new_time = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
if (($anvil->data->{sys}{database}{timestamp}) && ($anvil->data->{sys}{database}{timestamp} eq $new_time))
{
# Log that we hit this, then loop until we get a different result.
if (not $match)
{
$match = 1;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0702"});
}
}
else
{
# Different result. If we looped, log that we're clear now.
$ok = 1;
if ($match)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0703", variables => {
old_time => $anvil->data->{sys}{database}{timestamp},
new_time => $new_time,
}});
}
# Store the time stamp.
$anvil->data->{sys}{database}{timestamp} = $new_time; $anvil->data->{sys}{database}{timestamp} = $new_time;
}
}
return($anvil->data->{sys}{database}{timestamp}); return($anvil->data->{sys}{database}{timestamp});
} }
@ -16213,7 +16345,7 @@ sub resync_databases
my $query = "DELETE FROM history.".$table." WHERE history_id = ".$history_id.";"; my $query = "DELETE FROM history.".$table." WHERE history_id = ".$history_id.";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
#$anvil->Database->write({debug => $debug, uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__}); $anvil->Database->write({debug => $debug, uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__});
next; next;
} }
@ -16537,9 +16669,24 @@ sub shutdown
variable_source_table => "", variable_source_table => "",
}); });
# This query will be called repeatedly.
my $query = "
SELECT
state_uuid,
state_name,
state_host_uuid
FROM
states
WHERE
state_name
LIKE
'db_in_use::".$host_uuid."::%'
AND
state_note = '1'
;";
# Now wait for all clients to disconnect. # Now wait for all clients to disconnect.
my $waiting = 1; my $waiting = 1;
my $query = "SELECT state_uuid, state_name FROM states WHERE state_name LIKE 'db_in_use::".$host_uuid."::%' AND state_note = '1';";
my $wait_time = 600; my $wait_time = 600;
my $stop_waiting = time + $wait_time; my $stop_waiting = time + $wait_time;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
@ -16549,13 +16696,13 @@ sub shutdown
}}); }});
while($waiting) while($waiting)
{ {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); # PIDs will track pids using our DB locally. Users tracks how many other clients are using
# our DB.
my $pids = ""; my $pids = "";
my $count = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; my $users = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count }});
if ($count) # Check for any users using us.
{ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results}; my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
@ -16570,13 +16717,18 @@ sub shutdown
{ {
my $state_uuid = $row->[0]; my $state_uuid = $row->[0];
my $state_name = $row->[1]; my $state_name = $row->[1];
my $state_host_uuid = $row->[2];
my $state_pid = ($state_name =~ /db_in_use::.*?::(.*)$/)[0]; my $state_pid = ($state_name =~ /db_in_use::.*?::(.*)$/)[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:state_uuid' => $state_uuid, 's1:state_uuid' => $state_uuid,
's2:state_name' => $state_name, 's2:state_name' => $state_name,
's3:state_pid' => $state_pid, 's3:state_pid' => $state_pid,
's4:state_host_uuid' => $state_host_uuid,
's4:our_pid' => $$, 's4:our_pid' => $$,
}}); }});
# If this is held by us, make sure we ignore our active PID.
if ($state_host_uuid eq $anvil->Get->host_uuid)
{
if ($state_pid eq $$) if ($state_pid eq $$)
{ {
# This is us, ignore it. # This is us, ignore it.
@ -16599,14 +16751,19 @@ sub shutdown
$pids .= $state_pid.","; $pids .= $state_pid.",";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { pids => $pids }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { pids => $pids }});
} }
}
$pids =~ s/,$//; $pids =~ s/,$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { pids => $pids }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { pids => $pids }});
} }
else
{
$users++;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { users => $users }});
}
}
} }
# If there's no count, we're done. # If there's no count, we're done.
if (not $pids) if ((not $pids) && (not $users))
{ {
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0697"}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0697"});
$waiting = 0; $waiting = 0;
@ -16633,19 +16790,7 @@ sub shutdown
$anvil->Database->write({debug => $debug, uuid => $host_uuid, query => $query, source => $THIS_FILE, line => __LINE__}); $anvil->Database->write({debug => $debug, uuid => $host_uuid, query => $query, source => $THIS_FILE, line => __LINE__});
# Mark ourself as no longer using the DB # Mark ourself as no longer using the DB
my $pid = $$; $anvil->Database->mark_active->({set => 0});
my $state_name = "db_in_use::".$host_uuid."::".$pid;
my $state_uuid = $anvil->Database->insert_or_update_states({
debug => $debug,
state_name => $state_name,
state_host_uuid => $anvil->data->{sys}{host_uuid},
state_note => "0",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { state_uuid => $state_uuid }});
$query = "DELETE FROM states WHERE state_name LIKE 'db_in_use%' AND state_note != '1';";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0124", variables => { query => $query }});
$anvil->Database->write({debug => $debug, uuid => $host_uuid, query => $query, source => $THIS_FILE, line => __LINE__});
# Close our own connection. # Close our own connection.
$anvil->Database->locking({debug => $debug, release => 1}); $anvil->Database->locking({debug => $debug, release => 1});

@ -2121,6 +2121,9 @@ The file: [#!variable!file!#] needs to be updated. The difference is:
<key name="log_0699">[ Note ] - The Striker database host: [#!variable!host!#] is inactive, skipping it.</key> <key name="log_0699">[ Note ] - The Striker database host: [#!variable!host!#] is inactive, skipping it.</key>
<key name="log_0700">[ Note ] - Deleting the contents of the hash: [#!variable!hash!#].</key> <key name="log_0700">[ Note ] - Deleting the contents of the hash: [#!variable!hash!#].</key>
<key name="log_0701">Running the scan agent: [#!variable!agent_name!#]...</key> <key name="log_0701">Running the scan agent: [#!variable!agent_name!#]...</key>
<key name="log_0702">I was asked to update the timestamp, but the returned timestamp matches the last one. Will loop until a new timestamp is returned.</key>
<key name="log_0703">The timestamp has been updated from: [#!variable!old_time!#] to: [#!variable!new_time!#].</key>
<key name="log_0704"><![CDATA[[ Error ] - The method Database->read_state() was called but both the 'state_name' and 'state_uuid' parameters were not passed or both were empty.]]></key>
<!-- Messages for users (less technical than log entries), though sometimes used for logs, too. --> <!-- Messages for users (less technical than log entries), though sometimes used for logs, too. -->
<key name="message_0001">The host name: [#!variable!target!#] does not resolve to an IP address.</key> <key name="message_0001">The host name: [#!variable!target!#] does not resolve to an IP address.</key>
@ -2541,6 +2544,7 @@ Available options;
<key name="message_0288">#!variable!total_cores!#c (#!variable!sockets!#s, #!variable!cores!#c, #!variable!threads!#t), #!variable!model!#, #!variable!mode!#</key> <key name="message_0288">#!variable!total_cores!#c (#!variable!sockets!#s, #!variable!cores!#c, #!variable!threads!#t), #!variable!model!#, #!variable!mode!#</key>
<key name="message_0289">#!variable!cores!#c (#!variable!threads!#t)</key> <key name="message_0289">#!variable!cores!#c (#!variable!threads!#t)</key>
<key name="message_0290">-=] Server Usage and Anvil! Node Resource Availability</key> <key name="message_0290">-=] Server Usage and Anvil! Node Resource Availability</key>
<key name="message_0291">This program is currently disabled, please see NOTE in the header for more information.</key>
<!-- Success messages shown to the user --> <!-- Success messages shown to the user -->
<key name="ok_0001">Saved the mail server information successfully!</key> <key name="ok_0001">Saved the mail server information successfully!</key>
@ -3212,7 +3216,7 @@ We will sleep a bit and try again.
<key name="warning_0137">[ Warning ] - Timed out waiting for the connections to the peers, and the local resource(s) is not in 'UpToDate' state. Booting the server will likely fail.</key> <key name="warning_0137">[ Warning ] - Timed out waiting for the connections to the peers, and the local resource(s) is not in 'UpToDate' state. Booting the server will likely fail.</key>
<key name="warning_0138">[ Warning ] - Timed out waiting for the connections to the peers.</key> <key name="warning_0138">[ Warning ] - Timed out waiting for the connections to the peers.</key>
<key name="warning_0139">[ Warning ] - We're using: [#!variable!ram_used!#] (#!variable!ram_used_bytes!# Bytes). but there is a job: [#!variable!job_command!#] is runnng, which might be why the RAM is high. NOT exiting while this program is running.</key> <key name="warning_0139">[ Warning ] - We're using: [#!variable!ram_used!#] (#!variable!ram_used_bytes!# Bytes). but there is a job: [#!variable!job_command!#] is runnng, which might be why the RAM is high. NOT exiting while this program is running.</key>
<key name="warning_0140">[ Warning ] - A no-longer active PID: [#!variable!pid!#] had marked our database as "in_use", but the PID is gone now. Reaping the flag.</key> <key name="warning_0140">[ Warning ] - A no-longer active PID: [#!variable!pid!#] had marked the database: [#!variable!db!#] as "in_use", but the PID is gone now. Reaping the flag.</key>
<key name="warning_0141">[ Warning ] - We waited for: [#!variable!wait_time!#] seconds for all users of the local database to exit. Giving up waiting and taking the database down now.</key> <key name="warning_0141">[ Warning ] - We waited for: [#!variable!wait_time!#] seconds for all users of the local database to exit. Giving up waiting and taking the database down now.</key>
<key name="warning_0142">[ Warning ] - The command: [#!variable!command!#] is still using our database.</key> <key name="warning_0142">[ Warning ] - The command: [#!variable!command!#] is still using our database.</key>
<key name="warning_0143">[ Warning ] - While evaluating database shutdown, the host UUID: [#!variable!host_uuid!#] was not yet found in the database on host: [#!variable!db_uuid!#]. DB shutdown will not happen until all hosts are in all DBs.</key> <key name="warning_0143">[ Warning ] - While evaluating database shutdown, the host UUID: [#!variable!host_uuid!#] was not yet found in the database on host: [#!variable!db_uuid!#]. DB shutdown will not happen until all hosts are in all DBs.</key>

@ -682,6 +682,11 @@ sub handle_periodic_tasks
} }
} }
# Reap old db_in_use states over 6 hours old.
my $query = "DELETE FROM states WHERE state_name LIKE 'db_in_use%' AND modified_date < (SELECT now() - interval '6 hour');\n";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
$anvil->Database->write({debug => 2, query => $query, source => $THIS_FILE, line => __LINE__});
# Update the next check time. # Update the next check time.
$anvil->data->{timing}{next_ten_minute_check} = $now_time + $anvil->data->{timing}{ten_minute_checks}; $anvil->data->{timing}{next_ten_minute_check} = $now_time + $anvil->data->{timing}{ten_minute_checks};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
@ -719,7 +724,7 @@ sub handle_periodic_tasks
job_description => "job_0017", job_description => "job_0017",
job_progress => 0, job_progress => 0,
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { job_uuid => $job_uuid }});
# Update the OUI data. # Update the OUI data.
($job_uuid) = $anvil->Database->insert_or_update_jobs({ ($job_uuid) = $anvil->Database->insert_or_update_jobs({
@ -767,8 +772,6 @@ sub check_db_in_use_states
# We only reap db_in_use entries for us. # We only reap db_in_use entries for us.
$anvil->System->pids(); $anvil->System->pids();
my $host_uuid = $anvil->Database->quote($anvil->Get->host_uuid);
$host_uuid =~ s/^'(.*)'$/$1/;
my $query = " my $query = "
SELECT SELECT
state_uuid, state_uuid,
@ -777,7 +780,7 @@ SELECT
FROM FROM
states states
WHERE WHERE
state_name LIKE 'db_in_use::".$host_uuid."::%' state_name LIKE 'db_in_use::%'
AND AND
state_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." state_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)."
;"; ;";
@ -795,18 +798,25 @@ AND
my $state_uuid = $row->[0]; my $state_uuid = $row->[0];
my $state_name = $row->[1]; my $state_name = $row->[1];
my $state_note = $row->[2]; my $state_note = $row->[2];
my $state_pid = ($state_name =~ /db_in_use::.*?::(.*)$/)[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:state_uuid' => $state_uuid, 's1:state_uuid' => $state_uuid,
's2:state_name' => $state_name, 's2:state_name' => $state_name,
's3:state_note' => $state_note, 's3:state_note' => $state_note,
}});
my ($db_uuid, $state_pid) = ($state_name =~ /db_in_use::(.*?)::(\d+)$/);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:db_uuid' => $anvil->Get->host_name_from_uuid({host_uuid => $db_uuid})." (".$db_uuid.")",
's4:state_pid' => $state_pid, 's4:state_pid' => $state_pid,
}}); }});
if (not exists $anvil->data->{pids}{$state_pid}) if (not exists $anvil->data->{pids}{$state_pid})
{ {
# Reap the 'db_is_use'. # Reap the 'db_is_use'.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "warning_0140", variables => { pid => $state_pid }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "warning_0140", variables => {
db => $anvil->Get->host_name_from_uuid({host_uuid => $db_uuid})." (".$db_uuid.")",
pid => $state_pid,
}});
my $query = "DELETE FROM states WHERE state_uuid = ".$anvil->Database->quote($state_uuid).";"; my $query = "DELETE FROM states WHERE state_uuid = ".$anvil->Database->quote($state_uuid).";";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
@ -1349,6 +1359,21 @@ sub handle_special_cases
$anvil->DRBD->_initialize_kmod({debug => 2}); $anvil->DRBD->_initialize_kmod({debug => 2});
} }
### TODO: Remove these later. This is here to clean up how we used to handle db_in_use and lock_request flags.
if (1)
{
# Broadly clear all states that are '0' now.
my $queries = [];
push @{$queries}, "DELETE FROM states WHERE state_name LIKE 'db_in_use::%' AND state_note != '1';";
push @{$queries}, "DELETE FROM history.variables WHERE variable_name = 'lock_request';";
push @{$queries}, "DELETE FROM variables WHERE variable_name = 'lock_request';";
foreach my $query (@{$queries})
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
}
$anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__});
}
return(0); return(0);
} }

@ -43,6 +43,7 @@
# --status - This checks to see if dhcpd is running or not, then exits (effectively checking if the # --status - This checks to see if dhcpd is running or not, then exits (effectively checking if the
# "Install Target" feature is running). # "Install Target" feature is running).
# #
# NOTE: This is currently broken. Re-enable when a solution to anvil-striker-extra is found.
# #
# TODO: # TODO:
# - Support building the install target by mounting the ISO and checking /mnt/shared/incoming for needed # - Support building the install target by mounting the ISO and checking /mnt/shared/incoming for needed
@ -186,6 +187,11 @@ if (not $configured)
$anvil->nice_exit({exit_code => 9}); $anvil->nice_exit({exit_code => 9});
} }
### TODO: Remove this when re-enabled.
print $anvil->Words->string({key => "message_0291"})."\n";
update_progress($anvil, 100, "message_0291");
$anvil->nice_exit({exit_code => 0});
# Figure out what this machine is. # Figure out what this machine is.
load_os_info($anvil); load_os_info($anvil);

Loading…
Cancel
Save