IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 23458


Ignore:
Timestamp:
Mar 20, 2009, 1:24:39 PM (17 years ago)
Author:
jhoblitt
Message:

retry database transactions when a deadlock is detected

Location:
trunk/Nebulous-Server
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Nebulous-Server/Changes

    r20155 r23458  
    11Revision history for Nebulous
     2
     30.17
     4    - retry database transactions when a deadlock is detected
    25
    360.16
  • trunk/Nebulous-Server/lib/Nebulous/Server.pm

    r23455 r23458  
    163163
    164164    my $uri;
    165     eval {
    166         {
    167             # create storage_object
    168             my $query = $db->prepare_cached( $sql->new_object );
    169             $query->execute('NULL', $key->path);
    170         }
    171 
    172         my $so_id;
    173         {
    174             # get object ID
    175             my $query = $db->prepare_cached( $sql->last_insert_id );
    176             $query->execute;
    177             ($so_id) = $query->fetchrow_array;
    178             # XXX finish seems to be required when using LAST_INSERT_ID() or we
    179             # get a warning about the stmt handling still be active the next
    180             # time LAST_INSERT_ID() is invoked
    181             $query->finish;
    182         }
    183 
    184         {
    185             # create storage_object_attr
    186             my $query = $db->prepare_cached( $sql->new_object_attr );
    187             $query->execute($so_id);
    188         }
    189 
    190         {
    191            
    192             # create instance with no URI
     165TRANS: do {
     166        eval {
     167            {
     168                # create storage_object
     169                my $query = $db->prepare_cached( $sql->new_object );
     170                $query->execute('NULL', $key->path);
     171            }
     172
     173            my $so_id;
     174            {
     175                # get object ID
     176                my $query = $db->prepare_cached( $sql->last_insert_id );
     177                $query->execute;
     178                ($so_id) = $query->fetchrow_array;
     179                # XXX finish seems to be required when using LAST_INSERT_ID() or we
     180                # get a warning about the stmt handling still be active the next
     181                # time LAST_INSERT_ID() is invoked
     182                $query->finish;
     183            }
     184
     185            {
     186                # create storage_object_attr
     187                my $query = $db->prepare_cached( $sql->new_object_attr );
     188                $query->execute($so_id);
     189            }
     190
     191            {
     192               
     193                # create instance with no URI
    193194#            my $query = $db->prepare_cached( $sql->new_instance );
    194             my $query = $db->prepare_cached( $sql->new_object_instance );
    195             $query->execute($vol_id);
    196         }
    197 
    198         my $ins_id;
    199         {
    200             # get instance ID
    201             my $query = $db->prepare_cached( $sql->last_insert_id );
    202             $query->execute;
    203             ($ins_id) = $query->fetchrow_array;
    204             # XXX finish seems to be required when using LAST_INSERT_ID() or we
    205             # get a warning about the stmt handling still be active the next
    206             # time LAST_INSERT_ID() is invoked
    207             $query->finish;
    208         }
    209 
    210         # Unfortunately, since we want to use the instance row's ID as part of the
    211         # actual on disk file name we can't try to create the file until after
    212         # we've create both a new storage_storage object and instance.
    213 
    214         # TODO add some stuff here to retry if unsucessful
    215         $uri = $self->_create_empty_instance_file($key->path, $so_id, $ins_id, $vol_path, $vol_xattr);
    216         $log->debug("created $uri on volume ID: $vol_id");
    217 
    218         {
    219             # update the instance with URI & vol_id that the file is on
    220             my $query = $db->prepare_cached( $sql->update_instance_uri );
    221             # vol_id, uri, ins_id
    222             $query->execute($vol_id, "$uri", $ins_id);
    223         }
    224 
    225         $db->commit;
    226         $log->debug("commit");
    227     };
    228     if ($@) {
     195                my $query = $db->prepare_cached( $sql->new_object_instance );
     196                $query->execute($vol_id);
     197            }
     198
     199            my $ins_id;
     200            {
     201                # get instance ID
     202                my $query = $db->prepare_cached( $sql->last_insert_id );
     203                $query->execute;
     204                ($ins_id) = $query->fetchrow_array;
     205                # XXX finish seems to be required when using LAST_INSERT_ID() or we
     206                # get a warning about the stmt handling still be active the next
     207                # time LAST_INSERT_ID() is invoked
     208                $query->finish;
     209            }
     210
     211            # Unfortunately, since we want to use the instance row's ID as part of the
     212            # actual on disk file name we can't try to create the file until after
     213            # we've create both a new storage_storage object and instance.
     214
     215            # TODO add some stuff here to retry if unsucessful
     216            $uri = $self->_create_empty_instance_file($key->path, $so_id, $ins_id, $vol_path, $vol_xattr);
     217            $log->debug("created $uri on volume ID: $vol_id");
     218
     219            {
     220                # update the instance with URI & vol_id that the file is on
     221                my $query = $db->prepare_cached( $sql->update_instance_uri );
     222                # vol_id, uri, ins_id
     223                $query->execute($vol_id, "$uri", $ins_id);
     224            }
     225
     226            $db->commit;
     227            $log->debug("commit");
     228        };
     229        if ($@) {
    229230#        and not $key->soft_volume
    230         $db->rollback;
    231         $log->debug("rollback");
    232         $log->logdie("error: $@");
    233     }
     231            $db->rollback;
     232            $log->debug("rollback");
     233            if ($@ =~ /Deadlock found/) {
     234                $log->warn("database deadlock retrying transaction: $@");
     235                redo TRANS;
     236            }
     237            $log->logdie("error: $@");
     238        }
     239    } while ($@);
    234240
    235241    $log->debug("leaving");
     
    269275    $newkey = parse_neb_key($newkey);
    270276
    271     TRANS: do {
     277TRANS: do {
    272278        eval {
    273279            # rename storage_object
     
    290296            if ($@ =~ /Deadlock found/) {
    291297                $log->warn("database deadlock retrying transaction: $@");
    292                 redo;
     298                redo TRANS;
    293299            }
    294300            $log->logdie("database error: $@");
     
    336342    # key1.swap -> key2
    337343
    338     eval {
    339         {
    340             # key1 -> key1.swap
    341             my $query = $db->prepare_cached($sql->rename_object);
    342             # this SQL statment takes the new key name as the first param
    343             my $rows = $query->execute($key1->path . ".swap", $key1->path);
    344 
    345             # if we affected more then one row something very bad has happened.
    346             unless ($rows == 1) {
    347                 $query->finish;
    348                 $log->logdie("affected row count is $rows instead of 1");
    349             }
    350         }
    351 
    352         {
    353             # key2 -> key1
    354             my $query = $db->prepare_cached($sql->rename_object);
    355             # this SQL statment takes the new key name as the first param
    356             my $rows = $query->execute($key1->path, $key2->path);
    357 
    358             # if we affected more then one row something very bad has happened.
    359             unless ($rows == 1) {
    360                 $query->finish;
    361                 $log->logdie("affected row count is $rows instead of 1");
    362             }
    363         }
    364 
    365         {
    366             # key1.swap -> key2
    367             my $query = $db->prepare_cached($sql->rename_object);
    368             # this SQL statment takes the new key name as the first param
    369             my $rows = $query->execute($key2->path, $key1->path . ".swap");
    370 
    371             # if we affected more then one row something very bad has happened.
    372             unless ($rows == 1) {
    373                 $query->finish;
    374                 $log->logdie("affected row count is $rows instead of 1");
    375             }
    376         }
    377 
    378         $db->commit;
    379         $log->debug("commit");
    380     };
    381     if ($@) {
    382         $db->rollback;
    383         $log->debug("rollback");
    384         $log->logdie("database error: $@");
    385     }
     344TRANS: do {
     345        eval {
     346            {
     347                # key1 -> key1.swap
     348                my $query = $db->prepare_cached($sql->rename_object);
     349                # this SQL statment takes the new key name as the first param
     350                my $rows = $query->execute($key1->path . ".swap", $key1->path);
     351
     352                # if we affected more then one row something very bad has happened.
     353                unless ($rows == 1) {
     354                    $query->finish;
     355                    $log->logdie("affected row count is $rows instead of 1");
     356                }
     357            }
     358
     359            {
     360                # key2 -> key1
     361                my $query = $db->prepare_cached($sql->rename_object);
     362                # this SQL statment takes the new key name as the first param
     363                my $rows = $query->execute($key1->path, $key2->path);
     364
     365                # if we affected more then one row something very bad has happened.
     366                unless ($rows == 1) {
     367                    $query->finish;
     368                    $log->logdie("affected row count is $rows instead of 1");
     369                }
     370            }
     371
     372            {
     373                # key1.swap -> key2
     374                my $query = $db->prepare_cached($sql->rename_object);
     375                # this SQL statment takes the new key name as the first param
     376                my $rows = $query->execute($key2->path, $key1->path . ".swap");
     377
     378                # if we affected more then one row something very bad has happened.
     379                unless ($rows == 1) {
     380                    $query->finish;
     381                    $log->logdie("affected row count is $rows instead of 1");
     382                }
     383            }
     384
     385            $db->commit;
     386            $log->debug("commit");
     387        };
     388        if ($@) {
     389            $db->rollback;
     390            $log->debug("rollback");
     391            if ($@ =~ /Deadlock found/) {
     392                $log->warn("database deadlock retrying transaction: $@");
     393                redo TRANS;
     394            }
     395            $log->logdie("database error: $@");
     396        }
     397    } while ($@);
    386398
    387399    $log->debug("leaving");
     
    454466
    455467    my $uri;
    456     eval {
    457         my $so_id;
    458         {
    459             # verify that at least one instance is currently available
    460             my $query = $db->prepare_cached( $sql->get_object_instances );
    461             my $rows = $query->execute($key->path, 1);
    462 
    463             unless ( $rows > 0 ) {
     468TRANS: do {
     469        eval {
     470            my $so_id;
     471            {
     472                # verify that at least one instance is currently available
     473                my $query = $db->prepare_cached( $sql->get_object_instances );
     474                my $rows = $query->execute($key->path, 1);
     475
     476                unless ( $rows > 0 ) {
     477                    $query->finish;
     478                    $log->logdie( "storage object does not exist" );
     479                }
     480
     481                $so_id = $query->fetchrow_hashref->{ 'so_id' };
    464482                $query->finish;
    465                 $log->logdie( "storage object does not exist" );
    466             }
    467 
    468             $so_id = $query->fetchrow_hashref->{ 'so_id' };
    469             $query->finish;
    470         }
    471 
    472         {
    473             my $query = $db->prepare_cached( $sql->new_instance );
    474             $query->execute($so_id, $vol_id);
    475         }
    476 
    477         my $ins_id;
    478         {
    479             my $query = $db->prepare_cached( $sql->last_insert_id );
    480             $query->execute();
    481             ($ins_id) = $query->fetchrow_array;
    482             # XXX finish seems to be required when using LAST_INSERT_ID() or we
    483             # get a warning about the stmt handling still being active the next
    484             # time LAST_INSERT_ID() is invoked
    485             $query->finish;
    486         }
    487 
    488         # Unfortunately, since we want to use the instance row's ID as part of
    489         # the actual on disk file name we can't try to create the file until
    490         # after we've create both a new storage_storage object and instance.
    491 
    492         # TODO add some stuff here to retry if unsucessful
    493         $uri = $self->_create_empty_instance_file($key->path, $so_id, $ins_id, $vol_path, $vol_xattr);
    494 
    495         {
    496             my $query = $db->prepare_cached( $sql->update_instance_uri );
    497             # vol_id, uri, ins_id
    498             $query->execute($vol_id, $uri, $ins_id);
    499         }
    500 
    501         $db->commit;
    502         $log->debug("commit");
    503     };
    504     if ($@) {
    505         $db->rollback;
    506         # handle soft volumes
    507         if (defined $vol_name and defined $key->soft_volume) {
    508             $log->debug("retrying with 'any' volume");
    509             return $self->replicate_object($key->path, 'any');
    510         }
    511         $log->debug("rollback");
    512         $log->logdie("error: $@");
    513     }
     483            }
     484
     485            {
     486                my $query = $db->prepare_cached( $sql->new_instance );
     487                $query->execute($so_id, $vol_id);
     488            }
     489
     490            my $ins_id;
     491            {
     492                my $query = $db->prepare_cached( $sql->last_insert_id );
     493                $query->execute();
     494                ($ins_id) = $query->fetchrow_array;
     495                # XXX finish seems to be required when using LAST_INSERT_ID() or we
     496                # get a warning about the stmt handling still being active the next
     497                # time LAST_INSERT_ID() is invoked
     498                $query->finish;
     499            }
     500
     501            # Unfortunately, since we want to use the instance row's ID as part of
     502            # the actual on disk file name we can't try to create the file until
     503            # after we've create both a new storage_storage object and instance.
     504
     505            # TODO add some stuff here to retry if unsucessful
     506            $uri = $self->_create_empty_instance_file($key->path, $so_id, $ins_id, $vol_path, $vol_xattr);
     507
     508            {
     509                my $query = $db->prepare_cached( $sql->update_instance_uri );
     510                # vol_id, uri, ins_id
     511                $query->execute($vol_id, $uri, $ins_id);
     512            }
     513
     514            $db->commit;
     515            $log->debug("commit");
     516        };
     517        if ($@) {
     518            $db->rollback;
     519            # handle soft volumes
     520            if (defined $vol_name and defined $key->soft_volume) {
     521                $log->debug("retrying with 'any' volume");
     522                return $self->replicate_object($key->path, 'any');
     523            }
     524            $log->debug("rollback");
     525            $log->logdie("error: $@");
     526        }
     527    } while ($@);
    514528
    515529    $log->debug("leaving");
     
    551565    my $write_lock;
    552566
    553     eval {
    554         {
    555             # this will set update locks
    556             my $query = $db->prepare_cached( $sql->get_object_locks );
    557             my $rows = $query->execute( $key->path );
    558             unless ( $rows == 1 ) {
     567TRANS: do {
     568        eval {
     569            {
     570                # this will set update locks
     571                my $query = $db->prepare_cached( $sql->get_object_locks );
     572                my $rows = $query->execute( $key->path );
     573                unless ( $rows == 1 ) {
     574                    $query->finish;
     575                    $log->logdie( "storage object does not exist" );
     576                }
     577
     578                my $row = $query->fetchrow_hashref;
    559579                $query->finish;
    560                 $log->logdie( "storage object does not exist" );
    561             }
    562 
    563             my $row = $query->fetchrow_hashref;
    564             $query->finish;
    565 
    566             $so_id      = $row->{ 'so_id' };
    567             $read_lock  = $row->{ 'read_lock' };
    568             $write_lock = $row->{ 'write_lock' };
    569         }
    570 
    571         if ($type eq 'write') {
    572             # can't set a write lock twice and
    573             # can't set a write lock if there are read locks
    574             if ($write_lock) {
    575                 $log->logdie("can not write lock twice -- retry");
    576             }
    577            
    578             if ($read_lock > 0) {
    579                 $log->logdie("can not write lock after read lock -- retry");
    580             }
    581 
    582             {
    583                 my $query = $db->prepare_cached( $sql->set_write_lock );
    584                 my $rows = $query->execute($key->path);
    585            
    586                 # if we affected more then one row something very bad has happened.
    587                 unless ($rows == 1) {
    588                     $log->logdie("affected row count is $rows instead of 1");
    589                 }
    590 
    591             }
    592         } elsif ($type eq 'read') {
    593             # can't set a read lock if there's a write lock
    594             if ($write_lock) {
    595                 $log->logdie("can not read lock after write lock -- retry");
    596             }
    597 
    598             {
    599                 my $query = $db->prepare_cached( $sql->increment_read_lock );
    600                 my $rows = $query->execute($key->path);
    601            
    602                 # if we affected more then one row something very bad has happened.
    603                 unless ($rows == 1) {
    604                     $log->logdie("affected row count is $rows instead of 1");
    605                 }
    606             }
    607         }
    608 
    609         $db->commit;
    610         $log->debug("commit");
    611     };
    612     if ($@) {
    613         $db->rollback;
    614         $log->debug("rollback");
    615         $log->logdie("error: $@");
    616     }
     580
     581                $so_id      = $row->{ 'so_id' };
     582                $read_lock  = $row->{ 'read_lock' };
     583                $write_lock = $row->{ 'write_lock' };
     584            }
     585
     586            if ($type eq 'write') {
     587                # can't set a write lock twice and
     588                # can't set a write lock if there are read locks
     589                if ($write_lock) {
     590                    $log->logdie("can not write lock twice -- retry");
     591                }
     592               
     593                if ($read_lock > 0) {
     594                    $log->logdie("can not write lock after read lock -- retry");
     595                }
     596
     597                {
     598                    my $query = $db->prepare_cached( $sql->set_write_lock );
     599                    my $rows = $query->execute($key->path);
     600               
     601                    # if we affected more then one row something very bad has happened.
     602                    unless ($rows == 1) {
     603                        $log->logdie("affected row count is $rows instead of 1");
     604                    }
     605
     606                }
     607            } elsif ($type eq 'read') {
     608                # can't set a read lock if there's a write lock
     609                if ($write_lock) {
     610                    $log->logdie("can not read lock after write lock -- retry");
     611                }
     612
     613                {
     614                    my $query = $db->prepare_cached( $sql->increment_read_lock );
     615                    my $rows = $query->execute($key->path);
     616               
     617                    # if we affected more then one row something very bad has happened.
     618                    unless ($rows == 1) {
     619                        $log->logdie("affected row count is $rows instead of 1");
     620                    }
     621                }
     622            }
     623
     624            $db->commit;
     625            $log->debug("commit");
     626        };
     627        if ($@) {
     628            $db->rollback;
     629            $log->debug("rollback");
     630            if ($@ =~ /Deadlock found/) {
     631                $log->warn("database deadlock retrying transaction: $@");
     632                redo TRANS;
     633            }
     634            $log->logdie("error: $@");
     635        }
     636    } while ($@);
    617637
    618638    $log->debug("leaving");
     
    654674    my $write_lock;
    655675
    656     eval {
    657         {
    658             # this will set update locks
    659             my $query = $db->prepare_cached( $sql->get_object_locks );
    660             my $rows = $query->execute($key->path);
    661             unless ($rows == 1) {
     676TRANS: do {
     677        eval {
     678            {
     679                # this will set update locks
     680                my $query = $db->prepare_cached( $sql->get_object_locks );
     681                my $rows = $query->execute($key->path);
     682                unless ($rows == 1) {
     683                    $query->finish;
     684                    $log->logdie("storage object does not exist");
     685                }
     686
     687                my $row = $query->fetchrow_hashref;
    662688                $query->finish;
    663                 $log->logdie("storage object does not exist");
    664             }
    665 
    666             my $row = $query->fetchrow_hashref;
    667             $query->finish;
    668 
    669             $so_id      = $row->{ 'so_id' };
    670             $read_lock  = $row->{ 'read_lock' };
    671             $write_lock = $row->{ 'write_lock' };
    672         }
    673 
    674         if ($type eq 'write') {
    675             # can't remove a write lock if it doesn't exist
    676             if ($read_lock) {
    677                 $log->logdie("can not have a write lock under a read lock");
    678             }
    679 
    680             unless ($write_lock) {
    681                 $log->logdie("can not remove non-existant write lock");
    682             }
    683 
    684             {
    685                 my $query = $db->prepare_cached( $sql->delete_write_lock );
    686                 my $rows = $query->execute($key->path);
    687            
    688                 # if we affected more then one row something very bad has happened.
    689                 unless ($rows == 1) {
    690                     $log->logdie("affected row count is $rows instead of 1");
    691                 }
    692             }
    693         } elsif ($type eq 'read') {
    694             # can't remove a read lock if there's a write lock and
    695             # can't remove a read lock if there aren't any
    696             if ($write_lock) {
    697                 $log->logdie("can not have a read lock under a write lock");
    698             }
    699                
    700             if ($read_lock == 0) {
    701                 $log->logdie("can not remove non-existant read lock");
    702             }
    703 
    704             {
    705                 my $query = $db->prepare_cached( $sql->decrement_read_lock );
    706                 my $rows = $query->execute($key->path);
    707            
    708                 # if we affected more then one row something very bad has happened.
    709                 unless ($rows == 1) {
    710                     $log->logdie("affected row count is $rows instead of 1");
    711                 }
    712 
    713             }
    714         }
    715         $db->commit;
    716         $log->debug("commit");
    717     };
    718     if ($@) {
    719         $db->rollback;
    720         $log->debug("rollback");
    721         $log->logdie("error: $@");
    722     }
     689
     690                $so_id      = $row->{ 'so_id' };
     691                $read_lock  = $row->{ 'read_lock' };
     692                $write_lock = $row->{ 'write_lock' };
     693            }
     694
     695            if ($type eq 'write') {
     696                # can't remove a write lock if it doesn't exist
     697                if ($read_lock) {
     698                    $log->logdie("can not have a write lock under a read lock");
     699                }
     700
     701                unless ($write_lock) {
     702                    $log->logdie("can not remove non-existant write lock");
     703                }
     704
     705                {
     706                    my $query = $db->prepare_cached( $sql->delete_write_lock );
     707                    my $rows = $query->execute($key->path);
     708               
     709                    # if we affected more then one row something very bad has happened.
     710                    unless ($rows == 1) {
     711                        $log->logdie("affected row count is $rows instead of 1");
     712                    }
     713                }
     714            } elsif ($type eq 'read') {
     715                # can't remove a read lock if there's a write lock and
     716                # can't remove a read lock if there aren't any
     717                if ($write_lock) {
     718                    $log->logdie("can not have a read lock under a write lock");
     719                }
     720                   
     721                if ($read_lock == 0) {
     722                    $log->logdie("can not remove non-existant read lock");
     723                }
     724
     725                {
     726                    my $query = $db->prepare_cached( $sql->decrement_read_lock );
     727                    my $rows = $query->execute($key->path);
     728               
     729                    # if we affected more then one row something very bad has happened.
     730                    unless ($rows == 1) {
     731                        $log->logdie("affected row count is $rows instead of 1");
     732                    }
     733
     734                }
     735            }
     736            $db->commit;
     737            $log->debug("commit");
     738        };
     739        if ($@) {
     740            $db->rollback;
     741            $log->debug("rollback");
     742            if ($@ =~ /Deadlock found/) {
     743                $log->warn("database deadlock retrying transaction: $@");
     744                redo TRANS;
     745            }
     746            $log->logdie("error: $@");
     747        }
     748    } while ($@);
    723749
    724750    $log->debug( "leaving" );
     
    762788    $key = parse_neb_key($key);
    763789
    764     eval {
    765         my $query;
    766 
    767         if ($flags eq 'create') {
    768             $query = $db->prepare_cached( $sql->new_object_xattr );
    769         } else {
    770             # replace
    771             $query = $db->prepare_cached( $sql->replace_object_xattr );
    772         }
    773 
    774         # name, value, ext_id
    775         my $rows = $query->execute($name, $value, $key->path);
    776         $query->finish;
    777 
    778         # if we affected more then one row something very bad has happened.
    779         if ($flags eq 'create') {
    780             unless ($rows == 1) {
    781                 $log->logdie( "affected row count is $rows instead of 1" );
    782             }
    783         } else {
    784             # replace_object_xattr can effect either 1 or 2 rows.  2 rows in
    785             # the case of a replace and 1 if the xattr didn't already exist.
    786             unless ($rows == 1 or $rows == 2) {
    787                 $log->logdie( "affected row count is $rows instead of 2" );
    788             }
    789         }
    790 
    791         $db->commit;
    792         $log->debug("commit");
    793     };
    794     if ($@) {
    795         $db->rollback;
    796         $log->debug("rollback");
    797         $log->logdie("database error: $@");
    798     }
     790TRANS: do {
     791        eval {
     792            my $query;
     793
     794            if ($flags eq 'create') {
     795                $query = $db->prepare_cached( $sql->new_object_xattr );
     796            } else {
     797                # replace
     798                $query = $db->prepare_cached( $sql->replace_object_xattr );
     799            }
     800
     801            # name, value, ext_id
     802            my $rows = $query->execute($name, $value, $key->path);
     803            $query->finish;
     804
     805            # if we affected more then one row something very bad has happened.
     806            if ($flags eq 'create') {
     807                unless ($rows == 1) {
     808                    $log->logdie( "affected row count is $rows instead of 1" );
     809                }
     810            } else {
     811                # replace_object_xattr can effect either 1 or 2 rows.  2 rows in
     812                # the case of a replace and 1 if the xattr didn't already exist.
     813                unless ($rows == 1 or $rows == 2) {
     814                    $log->logdie( "affected row count is $rows instead of 2" );
     815                }
     816            }
     817
     818            $db->commit;
     819            $log->debug("commit");
     820        };
     821        if ($@) {
     822            $db->rollback;
     823            $log->debug("rollback");
     824            if ($@ =~ /Deadlock found/) {
     825                $log->warn("database deadlock retrying transaction: $@");
     826                redo TRANS;
     827            }
     828            $log->logdie("database error: $@");
     829        }
     830    } while ($@);
    799831
    800832    $log->debug("leaving");
     
    925957    $key = parse_neb_key($key);
    926958
    927     eval {
    928         my $query = $db->prepare_cached( $sql->remove_object_xattr );
    929         # ext_id, name
    930         my $rows = $query->execute($key->path, $name);
    931         $query->finish;
    932 
    933         # if we affected more then one row something very bad has happened.
    934         unless ($rows == 1) {
    935             $log->logdie( "affected row count is $rows instead of 1" );
    936         }
    937 
    938         $db->commit;
    939         $log->debug("commit");
    940     };
    941     if ($@) {
    942         $db->rollback;
    943         $log->debug("rollback");
    944         $log->logdie("database error: $@");
    945     }
     959TRANS: do {
     960        eval {
     961            my $query = $db->prepare_cached( $sql->remove_object_xattr );
     962            # ext_id, name
     963            my $rows = $query->execute($key->path, $name);
     964            $query->finish;
     965
     966            # if we affected more then one row something very bad has happened.
     967            unless ($rows == 1) {
     968                $log->logdie( "affected row count is $rows instead of 1" );
     969            }
     970
     971            $db->commit;
     972            $log->debug("commit");
     973        };
     974        if ($@) {
     975            $db->rollback;
     976            $log->debug("rollback");
     977            if ($@ =~ /Deadlock found/) {
     978                $log->warn("database deadlock retrying transaction: $@");
     979                redo TRANS;
     980            }
     981            $log->logdie("database error: $@");
     982        }
     983    } while ($@);
    946984
    947985    $log->debug("leaving");
     
    11051143    $log->debug( "entered - @_" );
    11061144
    1107     eval {
    1108         my $so_id;
    1109         my $instances;
    1110         # get so_id
    1111         {
    1112             my $query = $db->prepare_cached( $sql->get_object_from_uri );
    1113             my $rows = $query->execute( $uri );
    1114 
    1115             unless ( $rows > 0 ) {
     1145TRANS: do {
     1146        eval {
     1147            my $so_id;
     1148            my $instances;
     1149            # get so_id
     1150            {
     1151                my $query = $db->prepare_cached( $sql->get_object_from_uri );
     1152                my $rows = $query->execute( $uri );
     1153
     1154                unless ( $rows > 0 ) {
     1155                    $query->finish;
     1156                    $log->logdie( "no instance is associated with uri" );
     1157                }
     1158
     1159                $so_id = $query->fetchrow_hashref->{ 'so_id' };
    11161160                $query->finish;
    1117                 $log->logdie( "no instance is associated with uri" );
    1118             }
    1119 
    1120             $so_id = $query->fetchrow_hashref->{ 'so_id' };
    1121             $query->finish;
    1122 
    1123         }
    1124 
    1125         {
    1126             my $query = $db->prepare_cached( $sql->get_instance_count );
    1127             $query->execute( $so_id );
    1128 
    1129             $instances = $query->fetchrow_hashref->{ 'count(ins_id)' };
    1130             $query->finish;
    1131         }
    1132 
    1133         # remove instance
    1134         {
    1135             my $query = $db->prepare_cached( $sql->delete_instance );
    1136             my $rows = $query->execute( $uri );
    1137             $query->finish;
    1138            
    1139             # if we affected something other then two rows something very bad
    1140             # has happened
    1141             unless ( $rows == 1 ) {
    1142                 $log->logdie( "affected row count is $rows instead of 1" );
    1143             }
    1144         }
    1145 
    1146         # if we just deleted the last instance associated with a storage object
    1147         # remove it too
    1148         if ( $instances == 1 ) {
    1149             # we just removed the last instance
    1150             my $query = $db->prepare_cached( $sql->delete_object );
    1151             my $rows = $query->execute( $so_id );
    1152             $query->finish;
    1153 
    1154             # TODO: this will have to be changed in order to support hardlinks
    1155             unless ( $rows == 1 ) {
    1156                 $log->logdie( "affected row count is $rows instead of 2" );
    1157             }
    1158         }
    1159 
    1160         $db->commit;
    1161         $log->debug("commit");
    1162     };
    1163     if ( $@ ) {
    1164         $db->rollback;
    1165         $log->debug("rollback");
    1166         $log->logdie( "database error: $@" );
    1167     }
     1161
     1162            }
     1163
     1164            {
     1165                my $query = $db->prepare_cached( $sql->get_instance_count );
     1166                $query->execute( $so_id );
     1167
     1168                $instances = $query->fetchrow_hashref->{ 'count(ins_id)' };
     1169                $query->finish;
     1170            }
     1171
     1172            # remove instance
     1173            {
     1174                my $query = $db->prepare_cached( $sql->delete_instance );
     1175                my $rows = $query->execute( $uri );
     1176                $query->finish;
     1177               
     1178                # if we affected something other then two rows something very bad
     1179                # has happened
     1180                unless ( $rows == 1 ) {
     1181                    $log->logdie( "affected row count is $rows instead of 1" );
     1182                }
     1183            }
     1184
     1185            # if we just deleted the last instance associated with a storage object
     1186            # remove it too
     1187            if ( $instances == 1 ) {
     1188                # we just removed the last instance
     1189                my $query = $db->prepare_cached( $sql->delete_object );
     1190                my $rows = $query->execute( $so_id );
     1191                $query->finish;
     1192
     1193                # TODO: this will have to be changed in order to support hardlinks
     1194                unless ( $rows == 1 ) {
     1195                    $log->logdie( "affected row count is $rows instead of 2" );
     1196                }
     1197            }
     1198
     1199            $db->commit;
     1200            $log->debug("commit");
     1201        };
     1202        if ( $@ ) {
     1203            $db->rollback;
     1204            $log->debug("rollback");
     1205            if ($@ =~ /Deadlock found/) {
     1206                $log->warn("database deadlock retrying transaction: $@");
     1207                redo TRANS;
     1208            }
     1209            $log->logdie( "database error: $@" );
     1210        }
     1211    } while ($@);
    11681212
    11691213    $log->debug( "leaving" );
Note: See TracChangeset for help on using the changeset viewer.