@ -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_valu e) ;
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 , $ variabl e_uuid, $ modified_date ) = $ anvil - > Database - > read_variabl e ( { debug = > $ debug , variabl e_name = > $ variabl e_name} ) ;
my ( $ lock_value , $ stat e_uuid, $ modified_date ) = $ anvil - > Database - > read_stat e ( { debug = > $ debug , stat e_name = > $ stat e_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 $ co unt = $ anvil - > Databa se- > que ry ( { 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 } ) ;