tada! the new worm
authormiker <miker@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Mon, 7 Nov 2005 13:13:55 +0000 (13:13 +0000)
committermiker <miker@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Mon, 7 Nov 2005 13:13:55 +0000 (13:13 +0000)
git-svn-id: svn://svn.open-ils.org/ILS/trunk@1969 dcc99617-32d9-48b4-a31d-7c20da2025e4

Open-ILS/src/perlmods/OpenILS/Application/Storage.pm
Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI.pm
Open-ILS/src/perlmods/OpenILS/Application/Storage/Driver/Pg.pm
Open-ILS/src/perlmods/OpenILS/Application/Storage/Driver/Pg/storage.pm
Open-ILS/src/perlmods/OpenILS/Application/WoRM.pm

index 9d273d6..d02cc9c 100644 (file)
@@ -44,7 +44,8 @@ sub initialize {
                $log->debug("FAILURE LOADING Publisher!  $@", ERROR);
                throw OpenILS::EX::PANIC ( "FAILURE LOADING Publisher!  :  $@" );
        }
                $log->debug("FAILURE LOADING Publisher!  $@", ERROR);
                throw OpenILS::EX::PANIC ( "FAILURE LOADING Publisher!  :  $@" );
        }
-       eval 'use OpenILS::Application::Storage::WORM;';
+       #eval 'use OpenILS::Application::Storage::WORM;';
+       eval 'use OpenILS::Application::WoRM;';
        if ($@) {
                $log->debug("FAILURE LOADING WORM!  $@", ERROR);
                throw OpenILS::EX::PANIC ( "FAILURE LOADING WoRM!  :  $@" );
        if ($@) {
                $log->debug("FAILURE LOADING WORM!  $@", ERROR);
                throw OpenILS::EX::PANIC ( "FAILURE LOADING WoRM!  :  $@" );
@@ -65,7 +66,8 @@ sub child_init {
        );
 
        if (OpenILS::Application::Storage::CDBI->db_Main()) {
        );
 
        if (OpenILS::Application::Storage::CDBI->db_Main()) {
-               OpenILS::Application::Storage::WORM->child_init();
+               #OpenILS::Application::Storage::WORM->child_init();
+               OpenILS::Application::WoRM->child_init();
                $log->debug("Success initializing driver!", DEBUG);
                return 1;
        }
                $log->debug("Success initializing driver!", DEBUG);
                return 1;
        }
@@ -97,6 +99,28 @@ __PACKAGE__->register_method(
        argc            => 0,
 );
 
        argc            => 0,
 );
 
+sub savepoint_placeholder {
+       return 1;
+}
+__PACKAGE__->register_method(
+       method          => 'savepoint_placeholder',
+       api_name        => 'open-ils.storage.savepoint.set',
+       api_level       => 1,
+       argc            => 1,
+);
+__PACKAGE__->register_method(
+       method          => 'savepoint_placeholder',
+       api_name        => 'open-ils.storage.savepoint.release',
+       api_level       => 1,
+       argc            => 1,
+);
+__PACKAGE__->register_method(
+       method          => 'savepoint_placeholder',
+       api_name        => 'open-ils.storage.savepoint.rollback',
+       api_level       => 1,
+       argc            => 1,
+);
+
 sub commit_xaction {
        my $self = shift;
        my $client = shift;
 sub commit_xaction {
        my $self = shift;
        my $client = shift;
index 0155c96..a6f7049 100644 (file)
@@ -13,6 +13,7 @@ use OpenILS::Application::Storage::CDBI::metabib;
 use OpenILS::Application::Storage::CDBI::money;
 use OpenILS::Application::Storage::CDBI::permission;
 
 use OpenILS::Application::Storage::CDBI::money;
 use OpenILS::Application::Storage::CDBI::permission;
 
+use JSON;
 use OpenSRF::Utils::Logger;
 use OpenSRF::EX qw/:try/;
 
 use OpenSRF::Utils::Logger;
 use OpenSRF::EX qw/:try/;
 
@@ -173,6 +174,9 @@ sub merge {
 
        delete $$arg{$_} for (keys %$search);
 
 
        delete $$arg{$_} for (keys %$search);
 
+       $log->debug("CDBI->merge: \$search is $search (".ref($search)." : ".join(',',map{"$_ => $$search{$_}"}keys(%$search)).")",DEBUG);
+       $log->debug("CDBI->merge: \$arg is $arg (".ref($arg)." : ".join(',',map{"$_ => $$arg{$_}"}keys(%$arg)).")",DEBUG);
+
        my @objs = ($self);
        @objs = $self->search_where($search) unless (ref $self);
 
        my @objs = ($self);
        @objs = $self->search_where($search) unless (ref $self);
 
@@ -192,20 +196,32 @@ sub remote_update {
 
        delete $$arg{$_} for (keys %$search);
 
 
        delete $$arg{$_} for (keys %$search);
 
-       my @objs = $self->search_where($search);
-       if (@objs == 0) {
-               throw OpenSRF::EX::WARN ("No objects found for remote_update.  Perhaps you meant to use merge?");
-       } else {
-               $_->update($arg) for (@objs);
-               return scalar(@objs);
-       }
+       $log->debug("CDBI->remote_update: \$search is $search (".ref($search)." : ".join(',',map{"$_ => $$search{$_}"}keys(%$search)).")",DEBUG);
+       $log->debug("CDBI->remote_update: \$arg is $arg (".ref($arg)." : ".join(',',map{"$_ => $$arg{$_}"}keys(%$arg)).")",DEBUG);
+
+       my @finds = sort keys %$search;
+       my @sets = sort keys %$arg;
+
+       my @find_vals = @$search{@finds};
+       my @set_vals = @$arg{@sets};
+
+       my $sql = 'UPDATE %s SET %s WHERE %s';
+
+       my $table = $self->table;
+       my $set = join(', ', map { "$_=?" } @sets);
+       my $where = join(', ', map { "$_=?" } @finds);
+
+       my $sth = $self->db_Main->prepare(sprintf($sql, $table, $set, $where));
+       $sth->execute(@set_vals,@find_vals);
+       return $sth->rows;
+
 }
 
 sub create {
        my $self = shift;
        my $arg = shift;
 
 }
 
 sub create {
        my $self = shift;
        my $arg = shift;
 
-       $log->debug("\$arg is $arg (".ref($arg).")",DEBUG);
+       $log->debug("CDBI->create: \$arg is $arg (".ref($arg)." : ".JSON->perl2JSON($arg).")",DEBUG);
 
        if (ref($arg) && UNIVERSAL::isa($arg => 'Fieldmapper')) {
                return $self->create_from_fieldmapper($arg,@_);
 
        if (ref($arg) && UNIVERSAL::isa($arg => 'Fieldmapper')) {
                return $self->create_from_fieldmapper($arg,@_);
@@ -249,14 +265,18 @@ sub delete {
 
        my $class = ref($self) || $self;
 
 
        my $class = ref($self) || $self;
 
+       warn "HERE 1 --";
        if (ref($arg) and UNIVERSAL::isa($arg => 'Fieldmapper')) {
        if (ref($arg) and UNIVERSAL::isa($arg => 'Fieldmapper')) {
-               $self = $self->retrieve($arg);
-               unless (defined $self) {
-                       $log->debug("ARG! Couldn't retrieve record ".$arg->id, DEBUG);
-                       throw OpenSRF::EX::WARN ("ARG! Couldn't retrieve record ");
-               }
+               $arg = $arg->id;
        }
 
        }
 
+       $self = $self->retrieve($arg);
+       unless (defined $self) {
+               $log->debug("ARG! Couldn't retrieve record ".$arg->id, DEBUG);
+               throw OpenSRF::EX::WARN ("ARG! Couldn't retrieve record ");
+       }
+
+       warn "HERE 2 --";
        if ($class->find_column( 'last_xact_id' )) {
                my $xact_id = $self->current_xact_id;
                
        if ($class->find_column( 'last_xact_id' )) {
                my $xact_id = $self->current_xact_id;
                
@@ -270,7 +290,10 @@ sub delete {
                $self->SUPER::update;
        }
 
                $self->SUPER::update;
        }
 
+       warn "HERE 3 --";
        $self->SUPER::delete;
        $self->SUPER::delete;
+       warn "HERE 4 --";
+
        return 1;
 }
 
        return 1;
 }
 
index 09090e1..f4c3335 100644 (file)
@@ -44,6 +44,7 @@
                                AutoCommit => 1,
                                PrintError => 1,
                                Taint => 1,
                                AutoCommit => 1,
                                PrintError => 1,
                                Taint => 1,
+                               #TraceLevel => "1|SQL",
                                pg_enable_utf8 => 1,
                                pg_server_prepare => 0,
                                FetchHashKeyName => 'NAME_lc',
                                pg_enable_utf8 => 1,
                                pg_server_prepare => 0,
                                FetchHashKeyName => 'NAME_lc',
index d4ecbd3..a066969 100644 (file)
 
                my $xact_id = $pg->current_xact_id;
 
 
                my $xact_id = $pg->current_xact_id;
 
+               my $success = 1;
                try {
                        $log->debug("Committing trasaction with Open-ILS XACT-ID [$xact_id]", INFO);
                        my $dbh = OpenILS::Application::Storage::CDBI->db_Main;
                try {
                        $log->debug("Committing trasaction with Open-ILS XACT-ID [$xact_id]", INFO);
                        my $dbh = OpenILS::Application::Storage::CDBI->db_Main;
                } catch Error with {
                        my $e = shift;
                        $log->debug("Failed to commit trasaction with Open-ILS XACT-ID [$xact_id]: ".$e, INFO);
                } catch Error with {
                        my $e = shift;
                        $log->debug("Failed to commit trasaction with Open-ILS XACT-ID [$xact_id]: ".$e, INFO);
-                       return 0;
+                       $success = 0;
                };
                
                $pg->current_xact_session->unregister_callback( death => 
                };
                
                $pg->current_xact_session->unregister_callback( death => 
 
                $pg->unset_xact_session;
 
 
                $pg->unset_xact_session;
 
-               return 1;
+               return $success;
                
        }
        __PACKAGE__->register_method(
                
        }
        __PACKAGE__->register_method(
                my $self = shift;
 
                my $xact_id = $pg->current_xact_id;
                my $self = shift;
 
                my $xact_id = $pg->current_xact_id;
+
+               my $success = 1;
                try {
                        my $dbh = OpenILS::Application::Storage::CDBI->db_Main;
                        $log->debug("Rolling back a trasaction with Open-ILS XACT-ID [$xact_id]", INFO);
                try {
                        my $dbh = OpenILS::Application::Storage::CDBI->db_Main;
                        $log->debug("Rolling back a trasaction with Open-ILS XACT-ID [$xact_id]", INFO);
                } catch Error with {
                        my $e = shift;
                        $log->debug("Failed to roll back trasaction with Open-ILS XACT-ID [$xact_id]: ".$e, INFO);
                } catch Error with {
                        my $e = shift;
                        $log->debug("Failed to roll back trasaction with Open-ILS XACT-ID [$xact_id]: ".$e, INFO);
-                       return 0;
+                       $success = 0;
                };
        
                $pg->current_xact_session->unregister_callback( death =>
                };
        
                $pg->current_xact_session->unregister_callback( death =>
 
                $pg->unset_xact_session;
 
 
                $pg->unset_xact_session;
 
-               return 1;
+               return $success;
        }
        __PACKAGE__->register_method(
                method          => 'pg_rollback_xaction',
        }
        __PACKAGE__->register_method(
                method          => 'pg_rollback_xaction',
                argc            => 0,
        );
 
                argc            => 0,
        );
 
+       sub set_savepoint {
+               my $self = shift;
+               my $client = shift;
+               my $sp = shift || 'osrf_savepoint';
+               return OpenILS::Application::Storage::CDBI->db_Main->pg_savepoint($sp);
+       }
+       __PACKAGE__->register_method(
+               method          => 'set_savepoint',
+               api_name        => 'open-ils.storage.savepoint.set',
+               api_level       => 1,
+               argc            => 1,
+       );
+
+       sub release_savepoint {
+               my $self = shift;
+               my $client = shift;
+               my $sp = shift || 'osrf_savepoint';
+               return OpenILS::Application::Storage::CDBI->db_Main->pg_release($sp);
+       }
+       __PACKAGE__->register_method(
+               method          => 'release_savepoint',
+               api_name        => 'open-ils.storage.savepoint.release',
+               api_level       => 1,
+               argc            => 1,
+       );
+
+       sub rollback_to_savepoint {
+               my $self = shift;
+               my $client = shift;
+               my $sp = shift || 'osrf_savepoint';
+               return OpenILS::Application::Storage::CDBI->db_Main->pg_rollback_to($sp);
+       }
+       __PACKAGE__->register_method(
+               method          => 'rollback_to_savepoint',
+               api_name        => 'open-ils.storage.savepoint.rollback',
+               api_level       => 1,
+               argc            => 1,
+       );
+
+
        sub copy_create {
                my $self = shift;
                my $client = shift;
        sub copy_create {
                my $self = shift;
                my $client = shift;
                        next unless ($node);
                        my $line = join("\t", map { defined($node->$_()) ? $node->$_() : '\N' } @cols);
                        $log->debug("COPY line: [$line]",DEBUG);
                        next unless ($node);
                        my $line = join("\t", map { defined($node->$_()) ? $node->$_() : '\N' } @cols);
                        $log->debug("COPY line: [$line]",DEBUG);
-                       $dbh->func($line."\n", 'putline');
+                       $dbh->pg_putline($line."\n");
                }
 
                }
 
-               $dbh->func('endcopy');
+               $dbh->pg_endcopy || $log->debug("Could not end COPY with pg_endcopy", WARN);
+
+               $log->debug('COPY import for '.$cdbi->table." ($col_list) complete", DEBUG);
 
                return scalar(@fm_nodes);
        }
 
                return scalar(@fm_nodes);
        }
index 53beb21..292fbe0 100644 (file)
@@ -50,15 +50,14 @@ sub post_init {
                $mods_sheet = $xslt->parse_stylesheet( $xslt_doc );
        }
 
                $mods_sheet = $xslt->parse_stylesheet( $xslt_doc );
        }
 
-       if (!__PACKAGE__->st_sess()) {
-               $log->debug("Creating cached storage server session", DEBUG);
-               __PACKAGE__->st_sess( OpenSRF::AppSession->create('open-ils.storage') );
-       }
+       #if (!__PACKAGE__->st_sess()) {
+       #       $log->debug("Creating cached storage server session", DEBUG);
+       #       __PACKAGE__->st_sess( OpenSRF::AppSession->create('open-ils.storage') );
+       #}
 
        unless (keys %$xpathset) {
 
        unless (keys %$xpathset) {
-               my $req = __PACKAGE__->st_sess()->request('open-ils.storage.direct.config.metabib_field.retrieve.all');
-               while (my $resp = $req->recv) {
-                       my $f = $resp->content;
+               my $req = __PACKAGE__->storage_req('open-ils.storage.direct.config.metabib_field.retrieve.all.atomic');
+               for my $f (@$req) {
                        $xpathset->{ $f->field_class }->{ $f->name }->{xpath} = $f->xpath;
                        $xpathset->{ $f->field_class }->{ $f->name }->{id} = $f->id;
                        $log->debug("Loaded XPath from DB: ".$f->field_class." => ".$f->name." : ".$f->xpath, DEBUG);
                        $xpathset->{ $f->field_class }->{ $f->name }->{xpath} = $f->xpath;
                        $xpathset->{ $f->field_class }->{ $f->name }->{id} = $f->id;
                        $log->debug("Loaded XPath from DB: ".$f->field_class." => ".$f->name." : ".$f->xpath, DEBUG);
@@ -69,7 +68,7 @@ sub post_init {
 
 sub in_transaction {
        OpenILS::Application::WoRM->post_init();
 
 sub in_transaction {
        OpenILS::Application::WoRM->post_init();
-       return __PACKAGE__->st_sess->request( 'open-ils.storage.transaction.current' )->gather(1);
+       return __PACKAGE__->storage_req( 'open-ils.storage.transaction.current' );
 }
 
 sub begin_transaction {
 }
 
 sub begin_transaction {
@@ -77,24 +76,44 @@ sub begin_transaction {
        my $client = shift;
        
        OpenILS::Application::WoRM->post_init();
        my $client = shift;
        
        OpenILS::Application::WoRM->post_init();
-       my $outer_xact = __PACKAGE__->st_sess->request( 'open-ils.storage.transaction.current' )->gather(1);
+       my $outer_xact = __PACKAGE__->storage_req( 'open-ils.storage.transaction.current' );
        
        try {
                if (!$outer_xact) {
                        $log->debug("WoRM isn't inside a transaction, starting one now.", INFO);
        
        try {
                if (!$outer_xact) {
                        $log->debug("WoRM isn't inside a transaction, starting one now.", INFO);
-                       __PACKAGE__->st_sess->connect;
-                       my $r = __PACKAGE__->st_sess->request( 'open-ils.storage.transaction.begin' )->gather(1);
+                       #__PACKAGE__->st_sess->connect;
+                       my $r = __PACKAGE__->storage_req( 'open-ils.storage.transaction.begin', $client );
                        unless (defined $r and $r) {
                        unless (defined $r and $r) {
-                               __PACKAGE__->st_sess->request( 'open-ils.storage.transaction.rollback' )->gather(1);
-                               __PACKAGE__->st_sess->disconnect;
+                               __PACKAGE__->storage_req( 'open-ils.storage.transaction.rollback' );
+                               #__PACKAGE__->st_sess->disconnect;
                                throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!")
                        }
                }
                                throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!")
                        }
                }
-       } catch Error with {
+       } otherwise {
                $log->debug("WoRM Couldn't BEGIN transaction!", ERROR)
        };
 
                $log->debug("WoRM Couldn't BEGIN transaction!", ERROR)
        };
 
-       return __PACKAGE__->st_sess->request( 'open-ils.storage.transaction.current' )->gather(1);
+       return __PACKAGE__->storage_req( 'open-ils.storage.transaction.current' );
+}
+
+sub rollback_transaction {
+       my $self = shift;
+       my $client = shift;
+
+       OpenILS::Application::WoRM->post_init();
+       my $outer_xact = __PACKAGE__->storage_req( 'open-ils.storage.transaction.current' );
+
+       try {
+               if ($outer_xact) {
+                       __PACKAGE__->storage_req( 'open-ils.storage.transaction.rollback' );
+               } else {
+                       $log->debug("WoRM isn't inside a transaction.", INFO);
+               }
+       } catch Error with {
+               throw OpenSRF::EX::PANIC ("WoRM Couldn't COMMIT transaction!")
+       };
+
+       return 1;
 }
 
 sub commit_transaction {
 }
 
 sub commit_transaction {
@@ -102,16 +121,17 @@ sub commit_transaction {
        my $client = shift;
 
        OpenILS::Application::WoRM->post_init();
        my $client = shift;
 
        OpenILS::Application::WoRM->post_init();
-       my $outer_xact = __PACKAGE__->st_sess->request( 'open-ils.storage.transaction.current' )->gather(1);
+       my $outer_xact = __PACKAGE__->storage_req( 'open-ils.storage.transaction.current' );
 
        try {
 
        try {
-               if (__PACKAGE__->st_sess->connected && $outer_xact) {
-                       my $r = __PACKAGE__->st_sess->request( 'open-ils.storage.transaction.commit' )->gather(1);
+               #if (__PACKAGE__->st_sess->connected && $outer_xact) {
+               if ($outer_xact) {
+                       my $r = __PACKAGE__->storage_req( 'open-ils.storage.transaction.commit' );
                        unless (defined $r and $r) {
                        unless (defined $r and $r) {
-                               __PACKAGE__->st_sess->request( 'open-ils.storage.transaction.rollback' )->gather(1);
+                               __PACKAGE__->storage_req( 'open-ils.storage.transaction.rollback' );
                                throw OpenSRF::EX::PANIC ("Couldn't COMMIT transaction!")
                        }
                                throw OpenSRF::EX::PANIC ("Couldn't COMMIT transaction!")
                        }
-                       __PACKAGE__->st_sess->disconnect;
+                       #__PACKAGE__->st_sess->disconnect;
                } else {
                        $log->debug("WoRM isn't inside a transaction.", INFO);
                }
                } else {
                        $log->debug("WoRM isn't inside a transaction.", INFO);
                }
@@ -124,7 +144,9 @@ sub commit_transaction {
 
 sub storage_req {
        my $self = shift;
 
 sub storage_req {
        my $self = shift;
-       __PACKAGE__->st_sess->request( @_ )->gather(1);
+       my $method = shift;
+       my @res = __PACKAGE__->method_lookup( $method )->run( @_ );
+       return shift( @res );
 }
 
 sub scrub_authority_record {
 }
 
 sub scrub_authority_record {
@@ -134,15 +156,27 @@ sub scrub_authority_record {
 
        my $commit = 0;
        if (!OpenILS::Application::WoRM->in_transaction) {
 
        my $commit = 0;
        if (!OpenILS::Application::WoRM->in_transaction) {
-               OpenILS::Application::WoRM->begin_transaction || throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!");
+               OpenILS::Application::WoRM->begin_transaction($client) || throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!");
                $commit = 1;
        }
 
                $commit = 1;
        }
 
-       OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.authority.full_rec.mass_delete', { record => $rec } );
-       OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.authority.record_descriptor.mass_delete', { record => $rec } );
+       my $success = 1;
+       try {
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.set', 'scrub_authority_record' );
 
 
-       OpenILS::Application::WoRM->commit_transaction if ($commit);
-       return 1;
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.authority.full_rec.mass_delete', { record => $rec } );
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.authority.record_descriptor.mass_delete', { record => $rec } );
+
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.release', 'scrub_authority_record' );
+       } otherwise {
+               $log->debug('Scrubbing failed : '.shift(), ERROR);
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.rollback', 'scrub_authority_record' );
+               $success = 0;
+       };
+
+       OpenILS::Application::WoRM->commit_transaction if ($commit && $success);
+       OpenILS::Application::WoRM->rollback_transaction if ($commit && !$success);
+       return $success;
 }
 __PACKAGE__->register_method(  
        api_name        => "open-ils.worm.scrub.authority",
 }
 __PACKAGE__->register_method(  
        api_name        => "open-ils.worm.scrub.authority",
@@ -159,41 +193,59 @@ sub scrub_metabib_record {
 
        my $commit = 0;
        if (!OpenILS::Application::WoRM->in_transaction) {
 
        my $commit = 0;
        if (!OpenILS::Application::WoRM->in_transaction) {
-               OpenILS::Application::WoRM->begin_transaction || throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!");
+               OpenILS::Application::WoRM->begin_transaction($client) || throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!");
                $commit = 1;
        }
 
                $commit = 1;
        }
 
-       OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.full_rec.mass_delete', { record => $rec } );
-       OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.metarecord_source_map.mass_delete', { source => $rec } );
-       OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.record_descriptor.mass_delete', { record => $rec } );
-       OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.title_field_entry.mass_delete', { source => $rec } );
-       OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.author_field_entry.mass_delete', { source => $rec } );
-       OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.subject_field_entry.mass_delete', { source => $rec } );
-       OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.keyword_field_entry.mass_delete', { source => $rec } );
-       OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.series_field_entry.mass_delete', { source => $rec } );
-
-       my $mr = OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.metarecord.search_where', { master_record => $rec } );
-
-       if ($mr) {
-               my $others = OpenILS::Application::WoRM->storage_req(
-                               'open-ils.storage.direct.metabib.metarecord_source_map.search_where.atomic',
-                               { metarecord => $mr->id }
-               );
-
-               if (@$others) {
-                       $mr->master_record($others->[0]->source);
-                       OpenILS::Application::WoRM->storage_req(
-                               'open-ils.storage.direct.metabib.metarecord.remote_update',
-                               { id => $mr->id },
-                               { master_record => $others->[0]->source }
-                       );
-               } else {
-                       OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.metarecord.delete', $mr->id );
+       my $success = 1;
+       try {
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.set', 'scrub_metabib_record' );
+               
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.full_rec.mass_delete', { record => $rec } );
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.metarecord_source_map.mass_delete', { source => $rec } );
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.record_descriptor.mass_delete', { record => $rec } );
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.title_field_entry.mass_delete', { source => $rec } );
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.author_field_entry.mass_delete', { source => $rec } );
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.subject_field_entry.mass_delete', { source => $rec } );
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.keyword_field_entry.mass_delete', { source => $rec } );
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.series_field_entry.mass_delete', { source => $rec } );
+
+               $log->debug( "Looking for metarecords whose master is $rec", DEBUG);
+               my $masters = OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.metarecord.search.master_record.atomic', $rec );
+
+               for my $mr (@$masters) {
+                       $log->debug( "Found metarecord whose master is $rec", DEBUG);
+                       my $others = OpenILS::Application::WoRM->storage_req(
+                                       'open-ils.storage.direct.metabib.metarecord_source_map.search.metarecord.atomic', $mr->id );
+
+                       if (@$others) {
+                               $log->debug("Metarecord ".$mr->id." had master of $rec, setting to ".$others->[0]->source, DEBUG);
+                               $mr->master_record($others->[0]->source);
+                               OpenILS::Application::WoRM->storage_req(
+                                       'open-ils.storage.direct.metabib.metarecord.remote_update',
+                                       { id => $mr->id },
+                                       { master_record => $others->[0]->source }
+                               );
+                       } else {
+                               warn "Removing metarecord whose master is $rec";
+                               $log->debug( "Removing metarecord whose master is $rec", DEBUG);
+                               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.metarecord.delete', $mr->id );
+                               warn "Metarecord removed";
+                               $log->debug( "Metarecord removed", DEBUG);
+                       }
                }
                }
-       }
 
 
-       OpenILS::Application::WoRM->commit_transaction if ($commit);
-       return 1;
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.release', 'scrub_metabib_record' );
+
+       } otherwise {
+               $log->debug('Scrubbing failed : '.shift(), ERROR);
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.rollback', 'scrub_metabib_record' );
+               $success = 0;
+       };
+
+       OpenILS::Application::WoRM->commit_transaction if ($commit && $success);
+       OpenILS::Application::WoRM->rollback_transaction if ($commit && !$success);
+       return $success;
 }
 __PACKAGE__->register_method(  
        api_name        => "open-ils.worm.scrub.biblio",
 }
 __PACKAGE__->register_method(  
        api_name        => "open-ils.worm.scrub.biblio",
@@ -202,12 +254,206 @@ __PACKAGE__->register_method(
        argc            => 1,
 );                      
 
        argc            => 1,
 );                      
 
+sub wormize_biblio_record {
+       my $self = shift;
+       my $client = shift;
+       my $rec = shift;
+
+       my $commit = 0;
+       if (!OpenILS::Application::WoRM->in_transaction) {
+               OpenILS::Application::WoRM->begin_transaction($client) || throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!");
+               $commit = 1;
+       }
+
+       my $success = 1;
+       try {
+               # clean up the cruft
+               unless ($self->api_name =~ /noscrub/o) {
+                       $self->method_lookup( 'open-ils.worm.scrub.biblio' )->run( $rec ) || throw OpenSRF::EX::PANIC ("Couldn't scrub record $rec!");
+               }
+
+               # now redo 'em
+               my $bibs = OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.biblio.record_entry.search.id.atomic', $rec );
+
+               my @full_rec = ();
+               my @rec_descriptor = ();
+               my %field_entry = (
+                       title   => [],
+                       author  => [],
+                       subject => [],
+                       keyword => [],
+                       series  => [],
+               );
+               my @metarecord = ();
+               my @source_map = ();
+               for my $r (@$bibs) {
+                       my $xml = $parser->parse_string($r->marc);
+
+                       # the full_rec stuff
+                       for my $fr ( $self->method_lookup( 'open-ils.worm.flat_marc.biblio.xml' )->run( $xml ) ) {
+                               $fr->record( $r->id );
+                               push @full_rec, $fr;
+                       }
+
+                       # the rec_descriptor stuff
+                       my ($rd) = $self->method_lookup( 'open-ils.worm.biblio_leader.xml' )->run( $xml );
+                       $rd->record( $r->id );
+                       push @rec_descriptor, $rd;
+                       
+                       # the indexing field entry stuff
+                       for my $class ( qw/title author subject keyword series/ ) {
+                               for my $fe ( $self->method_lookup( 'open-ils.worm.field_entry.class.xml' )->run( $xml, $class ) ) {
+                                       $fe->source( $r->id );
+                                       push @{$field_entry{$class}}, $fe;
+                               }
+                       }
+
+                       #update the fingerprint
+                       my ($fp) = $self->method_lookup( 'open-ils.worm.fingerprint.marc' )->run( $xml );
+                       OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.biblio.record_entry.remote_update', { id => $r->id }, { fingerprint => $fp } );
+
+                       unless ($self->api_name =~ /nomap/o) {
+                               my $mr = OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.metarecord.search.fingerprint.atomic', $fp  )->[0];
+                               
+                               unless ($mr) {
+                                       $mr = Fieldmapper::metabib::metarecord->new;
+                                       $mr->fingerprint( $fp );
+                                       $mr->master_record( $r->id );
+                                       $mr->id( OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.metarecord.create', $mr) );
+                               }
+
+                               my $mr_map = Fieldmapper::metabib::metarecord_source_map->new;
+                               $mr_map->metarecord( $mr->id );
+                               $mr_map->source( $r->id );
+                               push @source_map, $mr_map;
+                       }
+
+               }
+
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.set', 'wormize_record' );
+
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.metarecord_source_map.batch.create', @source_map ) if (@source_map);
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.record_descriptor.batch.create', @rec_descriptor ) if (@rec_descriptor);
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.full_rec.batch.create', @full_rec ) if (@full_rec);
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.title_field_entry.batch.create', @{ $field_entry{title} } ) if (@{ $field_entry{title} });
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.author_field_entry.batch.create', @{ $field_entry{author} } ) if (@{ $field_entry{author} });
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.subject_field_entry.batch.create', @{ $field_entry{subject} } ) if (@{ $field_entry{subject} });
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.keyword_field_entry.batch.create', @{ $field_entry{keyword} } ) if (@{ $field_entry{keyword} });
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.series_field_entry.batch.create', @{ $field_entry{series} } ) if (@{ $field_entry{series} });
+
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.release', 'wormize_record' );
+
+       } otherwise {
+               $log->debug('Wormization failed : '.shift(), ERROR);
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.rollback', 'wormize_record' );
+               $success = 0;
+       };
+
+       OpenILS::Application::WoRM->commit_transaction if ($commit && $success);
+       OpenILS::Application::WoRM->rollback_transaction if ($commit && !$success);
+       return $success;
+}
+__PACKAGE__->register_method(
+       api_name        => "open-ils.worm.wormize.biblio",
+       method          => "wormize_biblio_record",
+       api_level       => 1,
+       argc            => 1,
+);
+__PACKAGE__->register_method(
+       api_name        => "open-ils.worm.wormize.biblio.nomap",
+       method          => "wormize_biblio_record",
+       api_level       => 1,
+       argc            => 1,
+);
+__PACKAGE__->register_method(
+       api_name        => "open-ils.worm.wormize.biblio.noscrub",
+       method          => "wormize_biblio_record",
+       api_level       => 1,
+       argc            => 1,
+);
+__PACKAGE__->register_method(
+       api_name        => "open-ils.worm.wormize.biblio.nomap.noscrub",
+       method          => "wormize_biblio_record",
+       api_level       => 1,
+       argc            => 1,
+);
+
+sub wormize_authority_record {
+       my $self = shift;
+       my $client = shift;
+       my $rec = shift;
+
+       my $commit = 0;
+       if (!OpenILS::Application::WoRM->in_transaction) {
+               OpenILS::Application::WoRM->begin_transaction($client) || throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!");
+               $commit = 1;
+       }
+
+       my $success = 1;
+       try {
+               # clean up the cruft
+               unless ($self->api_name =~ /noscrub/o) {
+                       $self->method_lookup( 'open-ils.worm.scrub.authority' )->run( $rec ) || throw OpenSRF::EX::PANIC ("Couldn't scrub record $rec!");
+               }
+
+               # now redo 'em
+               my $bibs = OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.authority.record_entry.search.id.atomic', $rec );
+
+               my @full_rec = ();
+               my @rec_descriptor = ();
+               for my $r (@$bibs) {
+                       my $xml = $parser->parse_string($r->marc);
+
+                       # the full_rec stuff
+                       for my $fr ( $self->method_lookup( 'open-ils.worm.flat_marc.authority.xml' )->run( $xml ) ) {
+                               $fr->record( $r->id );
+                               push @full_rec, $fr;
+                       }
+
+                       # the rec_descriptor stuff -- XXX What does this mean for authority records?
+                       #my ($rd) = $self->method_lookup( 'open-ils.worm.authority_leader.xml' )->run( $xml );
+                       #$rd->record( $r->id );
+                       #push @rec_descriptor, $rd;
+                       
+               }
+
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.set', 'wormize_authority_record' );
+
+               #OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.authority.record_descriptor.batch.create', @rec_descriptor ) if (@rec_descriptor);
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.authority.full_rec.batch.create', @full_rec ) if (@full_rec);
+
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.release', 'wormize_authority_record' );
+
+       } otherwise {
+               $log->debug('Wormization failed : '.shift(), ERROR);
+               OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.rollback', 'wormize_authority_record' );
+               $success = 0;
+       };
+
+       OpenILS::Application::WoRM->commit_transaction if ($commit && $success);
+       OpenILS::Application::WoRM->rollback_transaction if ($commit && !$success);
+       return $success;
+}
+__PACKAGE__->register_method(
+       api_name        => "open-ils.worm.wormize.authority",
+       method          => "wormize_authority_record",
+       api_level       => 1,
+       argc            => 1,
+);
+__PACKAGE__->register_method(
+       api_name        => "open-ils.worm.wormize.authority.noscrub",
+       method          => "wormize_authority_record",
+       api_level       => 1,
+       argc            => 1,
+);
+
 
 # --------------------------------------------------------------------------------
 # MARC index extraction
 
 package OpenILS::Application::WoRM::XPATH;
 use base qw/OpenILS::Application::WoRM/;
 
 # --------------------------------------------------------------------------------
 # MARC index extraction
 
 package OpenILS::Application::WoRM::XPATH;
 use base qw/OpenILS::Application::WoRM/;
+use Unicode::Normalize;
 
 # give this a MODS documentElement and an XPATH expression
 sub _xpath_to_string {
 
 # give this a MODS documentElement and an XPATH expression
 sub _xpath_to_string {
@@ -286,7 +532,7 @@ sub class_all_index_string_record {
        my $class = shift;
 
        OpenILS::Application::WoRM->post_init();
        my $class = shift;
 
        OpenILS::Application::WoRM->post_init();
-       my $r = OpenILS::Application::WoRM->st_sess->request( "open-ils.storage.direct.biblio.record_entry.retrieve" => $rec )->gather(1);
+       my $r = OpenILS::Application::WoRM->storage_req( "open-ils.storage.direct.biblio.record_entry.retrieve" => $rec );
 
        for my $fm ($self->method_lookup("open-ils.worm.field_entry.class.xml")->run($r->marc, $class)) {
                $fm->source($rec);
 
        for my $fm ($self->method_lookup("open-ils.worm.field_entry.class.xml")->run($r->marc, $class)) {
                $fm->source($rec);
@@ -329,7 +575,7 @@ sub class_index_string_record {
        my $type = shift;
 
        OpenILS::Application::WoRM->post_init();
        my $type = shift;
 
        OpenILS::Application::WoRM->post_init();
-       my $r = OpenILS::Application::WoRM->st_sess->request( "open-ils.storage.direct.biblio.record_entry.retrieve" => $rec )->gather(1);
+       my $r = OpenILS::Application::WoRM->storage_req( "open-ils.storage.direct.biblio.record_entry.retrieve" => $rec );
 
        my ($d) = $self->method_lookup("open-ils.worm.class.type.xml")->run($r->marc, $class => $type);
        $log->debug("XPath $class->$type for bib rec $rec returns ($d)", DEBUG);
 
        my ($d) = $self->method_lookup("open-ils.worm.class.type.xml")->run($r->marc, $class => $type);
        $log->debug("XPath $class->$type for bib rec $rec returns ($d)", DEBUG);
@@ -372,7 +618,7 @@ sub record_xpath {
        my $unique = shift;
 
        OpenILS::Application::WoRM->post_init();
        my $unique = shift;
 
        OpenILS::Application::WoRM->post_init();
-       my $r = OpenILS::Application::WoRM->st_sess->request( "open-ils.storage.direct.biblio.record_entry.retrieve" => $rec )->gather(1);
+       my $r = OpenILS::Application::WoRM->storage_req( "open-ils.storage.direct.biblio.record_entry.retrieve" => $rec );
 
        my ($d) = $self->method_lookup("open-ils.worm.xpath.xml")->run($r->marc, $xpath, $uri, $prefix, $unique );
        $log->debug("XPath [$xpath] bib rec $rec returns ($d)", DEBUG);
 
        my ($d) = $self->method_lookup("open-ils.worm.xpath.xml")->run($r->marc, $xpath, $uri, $prefix, $unique );
        $log->debug("XPath [$xpath] bib rec $rec returns ($d)", DEBUG);
@@ -391,8 +637,9 @@ __PACKAGE__->register_method(
 
 package OpenILS::Application::WoRM::Biblio::Leader;
 use base qw/OpenILS::Application::WoRM/;
 
 package OpenILS::Application::WoRM::Biblio::Leader;
 use base qw/OpenILS::Application::WoRM/;
+use Unicode::Normalize;
 
 
-our %descriptor_code = (
+our %biblio_descriptor_code = (
        item_type => sub { substr($ldr,6,1); },
        item_form => sub { (substr($ldr,6,1) =~ /^(?:f|g|i|m|o|p|r)$/o) ? substr($oo8,29,1) : substr($oo8,23,1); },
        bib_level => sub { substr($ldr,7,1); },
        item_type => sub { substr($ldr,6,1); },
        item_form => sub { (substr($ldr,6,1) =~ /^(?:f|g|i|m|o|p|r)$/o) ? substr($oo8,29,1) : substr($oo8,23,1); },
        bib_level => sub { substr($ldr,7,1); },
@@ -406,43 +653,43 @@ our %descriptor_code = (
        audience => sub { substr($oo8,22,1); },
 );
 
        audience => sub { substr($oo8,22,1); },
 );
 
-sub _extract_descriptors {
+sub _extract_biblio_descriptors {
        my $xml = shift;
 
        local $ldr = $xml->findvalue('//*[local-name()="leader"]');
        local $oo8 = $xml->findvalue('//*[local-name()="controlfield" and @tag="008"]');
 
        my $rd_obj = Fieldmapper::metabib::record_descriptor->new;
        my $xml = shift;
 
        local $ldr = $xml->findvalue('//*[local-name()="leader"]');
        local $oo8 = $xml->findvalue('//*[local-name()="controlfield" and @tag="008"]');
 
        my $rd_obj = Fieldmapper::metabib::record_descriptor->new;
-       for my $rd_field ( keys %descriptor_code ) {
-               $rd_obj->$rd_field( $descriptor_code{$rd_field}->() );
+       for my $rd_field ( keys %biblio_descriptor_code ) {
+               $rd_obj->$rd_field( $biblio_descriptor_code{$rd_field}->() );
        }
 
        return $rd_obj;
 }
 
        }
 
        return $rd_obj;
 }
 
-sub extract_desc_xml {
+sub extract_biblio_desc_xml {
        my $self = shift;
        my $client = shift;
        my $xml = shift;
 
        $xml = $parser->parse_string($xml) unless (ref $xml);
 
        my $self = shift;
        my $client = shift;
        my $xml = shift;
 
        $xml = $parser->parse_string($xml) unless (ref $xml);
 
-       return _extract_descriptors( $xml );
+       return _extract_biblio_descriptors( $xml );
 }
 __PACKAGE__->register_method(  
        api_name        => "open-ils.worm.biblio_leader.xml",
 }
 __PACKAGE__->register_method(  
        api_name        => "open-ils.worm.biblio_leader.xml",
-       method          => "extract_desc_xml",
+       method          => "extract_biblio_desc_xml",
        api_level       => 1,
        argc            => 1,
 );                      
 
        api_level       => 1,
        argc            => 1,
 );                      
 
-sub extract_desc_record {
+sub extract_biblio_desc_record {
        my $self = shift;
        my $client = shift;
        my $rec = shift;
 
        OpenILS::Application::WoRM->post_init();
        my $self = shift;
        my $client = shift;
        my $rec = shift;
 
        OpenILS::Application::WoRM->post_init();
-       my $r = OpenILS::Application::WoRM->st_sess->request( "open-ils.storage.direct.biblio.record_entry.retrieve" => $rec )->gather(1);
+       my $r = OpenILS::Application::WoRM->storage_req( "open-ils.storage.direct.biblio.record_entry.retrieve" => $rec );
 
        my ($d) = $self->method_lookup("open-ils.worm.biblio_leader.xml")->run($r->marc);
        $log->debug("Record descriptor for bib rec $rec is ".JSON->perl2JSON($d), DEBUG);
 
        my ($d) = $self->method_lookup("open-ils.worm.biblio_leader.xml")->run($r->marc);
        $log->debug("Record descriptor for bib rec $rec is ".JSON->perl2JSON($d), DEBUG);
@@ -450,7 +697,7 @@ sub extract_desc_record {
 }
 __PACKAGE__->register_method(  
        api_name        => "open-ils.worm.biblio_leader.record",
 }
 __PACKAGE__->register_method(  
        api_name        => "open-ils.worm.biblio_leader.record",
-       method          => "extract_desc_record",
+       method          => "extract_biblio_desc_record",
        api_level       => 1,
        argc            => 1,
 );                      
        api_level       => 1,
        argc            => 1,
 );                      
@@ -460,6 +707,7 @@ __PACKAGE__->register_method(
 
 package OpenILS::Application::WoRM::FlatMARC;
 use base qw/OpenILS::Application::WoRM/;
 
 package OpenILS::Application::WoRM::FlatMARC;
 use base qw/OpenILS::Application::WoRM/;
+use Unicode::Normalize;
 
 
 sub _marcxml_to_full_rows {
 
 
 sub _marcxml_to_full_rows {
@@ -479,7 +727,8 @@ sub _marcxml_to_full_rows {
                my $ns = $type->new;
 
                $ns->tag( 'LDR' );
                my $ns = $type->new;
 
                $ns->tag( 'LDR' );
-               my $val = NFD($tagline->textContent);
+               my $val = $tagline->textContent;
+               NFD($val);
                $val =~ s/(\pM+)//gso;
                $ns->value( $val );
 
                $val =~ s/(\pM+)//gso;
                $ns->value( $val );
 
@@ -492,7 +741,8 @@ sub _marcxml_to_full_rows {
                my $ns = $type->new;
 
                $ns->tag( $tagline->getAttribute( "tag" ) );
                my $ns = $type->new;
 
                $ns->tag( $tagline->getAttribute( "tag" ) );
-               my $val = NFD($tagline->textContent);
+               my $val = $tagline->textContent;
+               NFD($val);
                $val =~ s/(\pM+)//gso;
                $ns->value( $val );
 
                $val =~ s/(\pM+)//gso;
                $ns->value( $val );
 
@@ -515,7 +765,8 @@ sub _marcxml_to_full_rows {
                        $ns->ind1( $ind1 );
                        $ns->ind2( $ind2 );
                        $ns->subfield( $data->getAttribute( "code" ) );
                        $ns->ind1( $ind1 );
                        $ns->ind2( $ind2 );
                        $ns->subfield( $data->getAttribute( "code" ) );
-                       my $val = NFD($data->textContent);
+                       my $val = $data->textContent;
+                       NFD($val);
                        $val =~ s/(\pM+)//gso;
                        $ns->value( lc($val) );
 
                        $val =~ s/(\pM+)//gso;
                        $ns->value( lc($val) );
 
@@ -566,7 +817,7 @@ sub flat_marc_record {
        $type = 'authority' if ($self->api_name =~ /authority/o);
 
        OpenILS::Application::WoRM->post_init();
        $type = 'authority' if ($self->api_name =~ /authority/o);
 
        OpenILS::Application::WoRM->post_init();
-       my $r = OpenILS::Application::WoRM->st_sess->request( "open-ils.storage.direct.${type}.record_entry.retrieve" => $rec )->gather(1);
+       my $r = OpenILS::Application::WoRM->storage_req( "open-ils.storage.direct.${type}.record_entry.retrieve" => $rec );
 
        $client->respond($_) for ($self->method_lookup("open-ils.worm.flat_marc.$type.xml")->run($r->marc));
        return undef;
 
        $client->respond($_) for ($self->method_lookup("open-ils.worm.flat_marc.$type.xml")->run($r->marc));
        return undef;
@@ -592,6 +843,8 @@ __PACKAGE__->register_method(
 
 package OpenILS::Application::WoRM::Biblio::Fingerprint;
 use base qw/OpenILS::Application::WoRM/;
 
 package OpenILS::Application::WoRM::Biblio::Fingerprint;
 use base qw/OpenILS::Application::WoRM/;
+use Unicode::Normalize;
+use OpenSRF::EX qw/:try/;
 
 my @fp_mods_xpath = (
        '//mods:mods/mods:typeOfResource[text()="text"]' => [
 
 my @fp_mods_xpath = (
        '//mods:mods/mods:typeOfResource[text()="text"]' => [
@@ -751,6 +1004,41 @@ sub _fp_mods {
        return undef;
 }
 
        return undef;
 }
 
+sub refingerprint_bibrec {
+       my $self = shift;
+       my $client = shift;
+       my $rec = shift;
+
+       my $commit = 0;
+       if (!OpenILS::Application::WoRM->in_transaction) {
+               OpenILS::Application::WoRM->begin_transaction($client) || throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!");
+               $commit = 1;
+       }
+
+       my $success = 1;
+       try {
+               my $bibs = OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.biblio.record_entry.search.id.atomic', $rec );
+               OpenILS::Application::WoRM->storage_req(
+                       'open-ils.storage.direct.biblio.record_entry.remote_update',
+                       { id => $_->id },
+                       { fingerprint => $self->method_lookup( 'open-ils.worm.fingerprint.marc' )->run( $_->marc ) }
+               ) for (@$bibs);
+       } otherwise {
+               $log->debug('Fingerprinting failed : '.shift(), ERROR);
+               $success = 0;
+       };
+
+       OpenILS::Application::WoRM->commit_transaction if ($commit && $success);
+       OpenILS::Application::WoRM->rollback_transaction if ($commit && !$success);
+       return $success;
+}
+__PACKAGE__->register_method(  
+       api_name        => "open-ils.worm.fingerprint.record.update",
+       method          => "refingerprint_bibrec",
+       api_level       => 1,
+       argc            => 1,
+);                      
+
 
 sub fingerprint_bibrec {
        my $self = shift;
 
 sub fingerprint_bibrec {
        my $self = shift;
@@ -758,7 +1046,7 @@ sub fingerprint_bibrec {
        my $rec = shift;
 
        OpenILS::Application::WoRM->post_init();
        my $rec = shift;
 
        OpenILS::Application::WoRM->post_init();
-       my $r = OpenILS::Application::WoRM->st_sess->request( 'open-ils.storage.direct.biblio.record_entry.retrieve' => $rec )->gather(1);
+       my $r = OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.biblio.record_entry.retrieve' => $rec );
 
        my ($fp) = $self->method_lookup('open-ils.worm.fingerprint.marc')->run($r->marc);
        $log->debug("Returning [$fp] as fingerprint for record $rec", INFO);
 
        my ($fp) = $self->method_lookup('open-ils.worm.fingerprint.marc')->run($r->marc);
        $log->debug("Returning [$fp] as fingerprint for record $rec", INFO);
@@ -876,10 +1164,6 @@ sub wormize {
                unless ($mr_lookup);
        $mr_update = $self->method_lookup('open-ils.storage.direct.metabib.metarecord.batch.update')
                unless ($mr_update);
                unless ($mr_lookup);
        $mr_update = $self->method_lookup('open-ils.storage.direct.metabib.metarecord.batch.update')
                unless ($mr_update);
-       $mr_create = $self->method_lookup('open-ils.storage.direct.metabib.metarecord.create')
-               unless ($mr_create);
-       $create_source_map = $self->method_lookup('open-ils.storage.direct.metabib.metarecord_source_map.batch.create')
-               unless ($create_source_map);
        $lookup = $self->method_lookup('open-ils.storage.direct.biblio.record_entry.batch.retrieve')
                unless ($lookup);
        $update_entry = $self->method_lookup('open-ils.storage.direct.biblio.record_entry.batch.update')
        $lookup = $self->method_lookup('open-ils.storage.direct.biblio.record_entry.batch.retrieve')
                unless ($lookup);
        $update_entry = $self->method_lookup('open-ils.storage.direct.biblio.record_entry.batch.update')
@@ -900,6 +1184,10 @@ sub wormize {
                unless ($rm_old_kr);
        $rm_old_ser = $self->method_lookup( 'open-ils.storage.direct.metabib.series_field_entry.mass_delete')
                unless ($rm_old_ser);
                unless ($rm_old_kr);
        $rm_old_ser = $self->method_lookup( 'open-ils.storage.direct.metabib.series_field_entry.mass_delete')
                unless ($rm_old_ser);
+       $mr_create = $self->method_lookup('open-ils.storage.direct.metabib.metarecord.create')
+               unless ($mr_create);
+       $create_source_map = $self->method_lookup('open-ils.storage.direct.metabib.metarecord_source_map.batch.create')
+               unless ($create_source_map);
        $rd_create = $self->method_lookup( 'open-ils.storage.direct.metabib.record_descriptor.batch.create')
                unless ($rd_create);
        $fr_create = $self->method_lookup( 'open-ils.storage.direct.metabib.full_rec.batch.create')
        $rd_create = $self->method_lookup( 'open-ils.storage.direct.metabib.record_descriptor.batch.create')
                unless ($rd_create);
        $fr_create = $self->method_lookup( 'open-ils.storage.direct.metabib.full_rec.batch.create')