From 9808ec3f8b11fa0ce92098a932c6be872b0e9148 Mon Sep 17 00:00:00 2001 From: Akira Sawada Date: Sun, 17 Mar 2019 12:48:01 +0900 Subject: [PATCH 1/2] Attempt to make D:OD fork safe This commit add these functions to D:OD, when forked; - Reset all transaction status in child process - Destroy and forget all cached DBI handles safely notes: - Works only when POSIX::AtFork was found - Basic logic was taken from Cache::Memcached::Fast::Safe, and some are taken from Teng/DBIx::Skinny --- lib/Data/ObjectDriver/BaseObject.pm | 12 +++++++++++ lib/Data/ObjectDriver/Driver/DBI.pm | 33 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/lib/Data/ObjectDriver/BaseObject.pm b/lib/Data/ObjectDriver/BaseObject.pm index 2c69179..eb7606a 100644 --- a/lib/Data/ObjectDriver/BaseObject.pm +++ b/lib/Data/ObjectDriver/BaseObject.pm @@ -8,6 +8,10 @@ our $HasWeaken; eval q{ use Scalar::Util qw(weaken) }; ## no critic $HasWeaken = !$@; +our $HasAtFork; +eval q{ use POSIX::AtFork }; ## no critic +$HasAtFork = !$@; + use Carp (); use Class::Trigger qw( pre_save post_save post_load pre_search @@ -668,6 +672,14 @@ sub has_partitions { }); } +# At fork, forget about parent's current transaction status. +if ( $HasAtFork ) { + POSIX::AtFork->add_to_child(sub { + @WorkingDrivers = (); + $TransactionLevel = 0; + }); +} + 1; __END__ diff --git a/lib/Data/ObjectDriver/Driver/DBI.pm b/lib/Data/ObjectDriver/Driver/DBI.pm index becdd0c..4e1d5c8 100644 --- a/lib/Data/ObjectDriver/Driver/DBI.pm +++ b/lib/Data/ObjectDriver/Driver/DBI.pm @@ -13,6 +13,14 @@ use Data::ObjectDriver::SQL; use Data::ObjectDriver::Driver::DBD; use Data::ObjectDriver::Iterator; +our $HasWeaken; +eval q{ use Scalar::Util qw(weaken) }; ## no critic +$HasWeaken = !$@; + +our $HasAtFork; +eval q{ use POSIX::AtFork }; ## no critic +$HasAtFork = !$@; + __PACKAGE__->mk_accessors(qw( dsn username password connect_options dbh get_dbh dbd prefix reuse_dbh force_no_prepared_cache)); @@ -36,6 +44,21 @@ sub init { } $driver->dbd(Data::ObjectDriver::Driver::DBD->new($type)); } + + if ( $HasWeaken && $HasAtFork ) { + # Purge Cached dbh, and reset transaction level + weaken(my $driver_weaken = $driver); + POSIX::AtFork->add_to_child(sub { + eval { + if ( my $dbh = $driver_weaken->dbh ) { + $dbh->{InactiveDestroy} = 1; + $driver_weaken->dbh(undef); + } + $driver->txn_active(0); + }; + }); + } + $driver; } @@ -752,4 +775,14 @@ sub last_error { return $driver->dbd->map_error_code($DBI::err, $DBI::errstr); } +if ( $HasAtFork ) { + # Purge all reusable db handles + POSIX::AtFork->add_to_child(sub { + for my $handle ( values %Handles ) { + $handle->{InactiveDestroy} = 1; + } + %Handles = (); + }); +} + 1; From 42e1f86653d34ea1e5792a6b2a3db4a4b6c0f80a Mon Sep 17 00:00:00 2001 From: Akira Sawada Date: Fri, 12 Apr 2019 18:23:01 +0900 Subject: [PATCH 2/2] Typo --- lib/Data/ObjectDriver/Driver/DBI.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Data/ObjectDriver/Driver/DBI.pm b/lib/Data/ObjectDriver/Driver/DBI.pm index 4e1d5c8..739866a 100644 --- a/lib/Data/ObjectDriver/Driver/DBI.pm +++ b/lib/Data/ObjectDriver/Driver/DBI.pm @@ -54,7 +54,7 @@ sub init { $dbh->{InactiveDestroy} = 1; $driver_weaken->dbh(undef); } - $driver->txn_active(0); + $driver_weaken->txn_active(0); }; }); }