[Koha-patches] [PATCH] Items modification Performance improvement

Henri-Damien LAURENT henridamien.laurent at biblibre.com
Thu Nov 5 16:16:26 CET 2009


Adding a _field_xml_output to C4::Biblio
Replacing all the manipulations of MARC::Record by string manipulation of marcxml
This is a Proof Of Concept.
This is for comments.

But I think performance is highly improved in dealing with items as such.
What looks quite clumsy is that marc blob is not synched.
And also, zebra queue is not updated at the moment.
But It seems a good first step.
Will post some more heavy tests.
---
 C4/Biblio.pm           |   36 ++++++++++++++++++++-
 C4/Items.pm            |   84 +++++++++++++++++++++++++----------------------
 t/db_dependent/Items.t |   33 +++++++++++++++++++
 3 files changed, 113 insertions(+), 40 deletions(-)
 create mode 100755 t/db_dependent/Items.t

diff --git a/C4/Biblio.pm b/C4/Biblio.pm
index 7b83d61..7bbec7c 100755
--- a/C4/Biblio.pm
+++ b/C4/Biblio.pm
@@ -3510,8 +3510,42 @@ sub get_biblio_authorised_values {
     return $authorised_values;
 }
 
-1;
 
+
+=head3 _field_xml_output
+
+  prints a MARC::Field as xml
+
+  parameters:
+    
+    MARC::Field
+
+  returns: a string describing the MARC Field with MARCXML
+
+  Notes: forlibrarian should probably be passed in, and called something different.
+
+
+=cut
+
+sub _field_xml_output{
+	my $field=shift;
+	return unless ($field);
+	if ($field->tag()>"010"){
+		my $xml_field=sprintf(qq{<datafield tag="%s" ind1="%s" ind2="%s">},$field->tag(),$field->indicator(1), $field->indicator(2));
+		my @xml_subfields=map{_subfield_xml_output($_)}$field->subfields();
+		my $xml_string=$xml_field.join("", at xml_subfields).qq{</datafield>};
+		return $xml_string;
+	}
+	else {
+		return sprintf(qq{<controlfield tag="%s">%s</controlfield>},$field->tag(), $field->data());
+	}
+}
+
+sub _subfield_xml_output{
+	my $subfield=shift;
+	return sprintf(qq{<subfield code="%s">%s</subfield>},map{StripNonXmlChars($_)}@$subfield);
+}
+1;
 __END__
 
 =head1 AUTHOR
diff --git a/C4/Items.pm b/C4/Items.pm
index 61126d9..9a1e81f 100644
--- a/C4/Items.pm
+++ b/C4/Items.pm
@@ -604,25 +604,20 @@ sub DelItem {
     
     _koha_delete_item( $dbh, $itemnumber );
 
-    # get the MARC record
-    my $record = GetMarcBiblio($biblionumber);
-    my $frameworkcode = GetFrameworkCode($biblionumber);
-
-    # backup the record
-    my $copy2deleted = $dbh->prepare("UPDATE deleteditems SET marc=? WHERE itemnumber=?");
-    $copy2deleted->execute( $record->as_usmarc(), $itemnumber );
-
+#This looks quite odd to me Why would we need to save the whole bibliorecord ?
+#    # get the MARC record
+#    my $record = GetMarcBiblio($biblionumber);
+#
+#    # backup the record
+#    my $copy2deleted = $dbh->prepare("UPDATE deleteditems SET marc=? WHERE itemnumber=?");
+#    $copy2deleted->execute( $record->as_usmarc(), $itemnumber );
+#
     #search item field code
-    my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField("items.itemnumber",$frameworkcode);
-    my @fields = $record->field($itemtag);
+#    my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField("items.itemnumber",$frameworkcode);
 
     # delete the item specified
-    foreach my $field (@fields) {
-        if ( $field->subfield($itemsubfield) eq $itemnumber ) {
-            $record->delete_field($field);
-        }
-    }
-    &ModBiblioMarc( $record, $biblionumber, $frameworkcode );
+    my $frameworkcode = GetFrameworkCode($biblionumber);
+    _replace_item_field_in_biblio( undef, $biblionumber,$itemnumber, $frameworkcode );
     logaction("CATALOGUING", "DELETE", $itemnumber, "item") if C4::Context->preference("CataloguingLog");
 }
 
@@ -2268,13 +2263,15 @@ item information field.
 
 sub _add_item_field_to_biblio {
     my ($item_marc, $biblionumber, $frameworkcode) = @_;
+    my $dbh = C4::Context->dbh;
 
-    my $biblio_marc = GetMarcBiblio($biblionumber);
-    foreach my $field ($item_marc->fields()) {
-        $biblio_marc->append_fields($field);
-    }
+    my $biblio_xml = GetXmlBiblio($biblionumber);
+    my ($itemtag,$itemsubfield) = GetMarcFromKohaField("items.itemnumber",$frameworkcode);
+    my $itemField = $item_marc->field($itemtag);
+  	my $itemXML = C4::Biblio::_field_xml_output($itemField);
+	substr($biblio_xml,-10,0,$itemXML);
+	$dbh->do(qq{UPDATE biblioitems set marcxml=? WHERE biblionumber=?},undef, $biblio_xml, $biblionumber);
 
-    ModBiblioMarc($biblio_marc, $biblionumber, $frameworkcode);
 }
 
 =head2 _replace_item_field_in_biblio
@@ -2297,27 +2294,36 @@ sub _replace_item_field_in_biblio {
     my $dbh = C4::Context->dbh;
     
     # get complete MARC record & replace the item field by the new one
-    my $completeRecord = GetMarcBiblio($biblionumber);
+    my $completeRecord = GetXmlBiblio($biblionumber);
     my ($itemtag,$itemsubfield) = GetMarcFromKohaField("items.itemnumber",$frameworkcode);
-    my $itemField = $ItemRecord->field($itemtag);
-    my @items = $completeRecord->field($itemtag);
-    my $found = 0;
-    foreach (@items) {
-        if ($_->subfield($itemsubfield) eq $itemnumber) {
-            $_->replace_with($itemField);
-            $found = 1;
-        }
-    }
+	my $itemXML;
+	if ($ItemRecord){
+	    my $itemField = $ItemRecord->field($itemtag);
+  		$itemXML = C4::Biblio::_field_xml_output($itemField);
+	}
+	my $done=0;
+	my $ofset_itemfield=0;
+  	while (($ofset_itemfield=index($completeRecord,qq{<datafield tag="$itemtag" ind1=" " ind2=" ">},$ofset_itemfield ))>0){
+		my $ofset_itemfield_end=index(substr($completeRecord,$ofset_itemfield),qq{</datafield>});
+		warn "$ofset_itemfield $ofset_itemfield_end";
+		my $field_string=substr($completeRecord,$ofset_itemfield,$ofset_itemfield_end);
+		if (my $index=index($field_string,qq{code="$itemsubfield">$itemnumber</subfield})>0){
+			substr($completeRecord,$ofset_itemfield,$ofset_itemfield_end+length(qq{</datafield>}),"".$itemXML) and $done=1;
+			$dbh->do(qq{UPDATE biblioitems set marcxml=? WHERE biblionumber=?},undef, $completeRecord, $biblionumber);
+			return;
+		}
+		if ($ofset_itemfield_end>-1){
+			$ofset_itemfield+= $ofset_itemfield_end+length(qq{</datafield>});
+		}
+		else {
+			$ofset_itemfield=length($completeRecord); 
+		}
+	}
   
-    unless ($found) { 
-        # If we haven't found the matching field,
-        # just add it.  However, this means that
-        # there is likely a bug.
-        $completeRecord->append_fields($itemField);
+    unless ($done) { 
+		#Add XML at the end of record
+		_add_item_field_to_biblio($ItemRecord,$biblionumber,$frameworkcode)
     }
-
-    # save the record
-    ModBiblioMarc($completeRecord, $biblionumber, $frameworkcode);
 }
 
 =head2 _repack_item_errors
diff --git a/t/db_dependent/Items.t b/t/db_dependent/Items.t
new file mode 100755
index 0000000..c3b4788
--- /dev/null
+++ b/t/db_dependent/Items.t
@@ -0,0 +1,33 @@
+use strict;
+use warnings;
+use Test::More tests=>18;
+
+BEGIN {use_ok('C4::Items') }
+use C4::Biblio;
+use C4::Dates;
+use C4::Debug;
+
+print "ok 1\n";
+use YAML;
+
+#
+# Budget Periods :
+#
+my $field=MARC::Field->new('200'," "," ",a=>"Title",b=>'itemtype');
+my $biblio=MARC::Record->new();
+$biblio->append_fields($field);
+my ($biblionumber)=AddBiblio($biblio,'');
+my ($biblionumber,$biblioitemnumber,$itemnumber)=AddItem({barcode=>1231241,location=>"MyLOC"},$biblionumber);
+$debug && warn Dump(GetItem($itemnumber));
+my ($biblionumber,$biblioitemnumber,$itemnumber2)=AddItem({barcode=>'ACAD',location=>"MyLOC2"},$biblionumber);
+$debug && warn Dump(GetItem($itemnumber2));
+my $bibliorecord=GetMarcBiblio($biblionumber);
+$debug && warn $bibliorecord->as_formatted;
+ModItem({dateaccessioned=>2009-01-01,location=>'TESTS2'},$biblionumber,$itemnumber);
+my $bibliorecord=GetMarcBiblio($biblionumber);
+$debug && warn $bibliorecord->as_formatted;
+print localtime;
+for (my $i=1;$i<10000;$i++){
+ModItem({location=>"TEST$i"},$biblionumber,$itemnumber2);
+}
+print localtime
-- 
1.6.3.3




More information about the Koha-patches mailing list