You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by ma...@apache.org on 2009/12/03 21:24:36 UTC

svn commit: r886907 - in /lucene/lucy/trunk: core/Lucy/Object/Obj.bp core/Lucy/Object/Obj.c perl/lib/Lucy/Object/Obj.pm perl/t/binding/019-obj.t

Author: marvin
Date: Thu Dec  3 20:24:35 2009
New Revision: 886907

URL: http://svn.apache.org/viewvc?rev=886907&view=rev
Log:
Commit obj_serialize.diff from LUCY-81, adding the base routines for Lucy
object serialization and hooks for Perl Storable module.

Modified:
    lucene/lucy/trunk/core/Lucy/Object/Obj.bp
    lucene/lucy/trunk/core/Lucy/Object/Obj.c
    lucene/lucy/trunk/perl/lib/Lucy/Object/Obj.pm
    lucene/lucy/trunk/perl/t/binding/019-obj.t

Modified: lucene/lucy/trunk/core/Lucy/Object/Obj.bp
URL: http://svn.apache.org/viewvc/lucene/lucy/trunk/core/Lucy/Object/Obj.bp?rev=886907&r1=886906&r2=886907&view=diff
==============================================================================
--- lucene/lucy/trunk/core/Lucy/Object/Obj.bp (original)
+++ lucene/lucy/trunk/core/Lucy/Object/Obj.bp Thu Dec  3 20:24:35 2009
@@ -131,6 +131,21 @@
     public abstract double
     To_F64(Obj *self);
 
+    /** Serialize the object by writing to the supplied OutStream.
+     */
+    public void
+    Serialize(Obj *self, OutStream *outstream);
+
+    /** Inflate an object by reading the serialized form from the instream.
+     * The assumption is that the object has been allocated, assigned a
+     * refcount and a vtable, but that everything else is uninitialized.  
+     * 
+     * Implementations should also be prepared to handle NULL as an argument,
+     * in which case they should create the object from nothing.
+     */
+    public incremented Obj*
+    Deserialize(Obj *self, InStream *instream);
+
     /** Return a representation of the object using only scalars, hashes, and
      * arrays.  Some implementations support JSON serialization via Dump() and
      * its companion method, Load(); for others, Dump() is only a debugging

Modified: lucene/lucy/trunk/core/Lucy/Object/Obj.c
URL: http://svn.apache.org/viewvc/lucene/lucy/trunk/core/Lucy/Object/Obj.c?rev=886907&r1=886906&r2=886907&view=diff
==============================================================================
--- lucene/lucy/trunk/core/Lucy/Object/Obj.c (original)
+++ lucene/lucy/trunk/core/Lucy/Object/Obj.c Thu Dec  3 20:24:35 2009
@@ -12,6 +12,8 @@
 #include "Lucy/Object/Err.h"
 #include "Lucy/Object/Hash.h"
 #include "Lucy/Object/VTable.h"
+#include "Lucy/Store/InStream.h"
+#include "Lucy/Store/OutStream.h"
 #include "Lucy/Util/Memory.h"
 
 Obj*
@@ -54,6 +56,35 @@
     return (self == other);
 }
 
+void
+Obj_serialize(Obj *self, OutStream *outstream)
+{
+    CharBuf *class_name = Obj_Get_Class_Name(self);
+    size_t size = CB_Get_Size(class_name);
+    OutStream_Write_C32(outstream, size);
+    OutStream_Write_Bytes(outstream, CB_Get_Ptr8(class_name), size);
+}
+
+Obj*
+Obj_deserialize(Obj *self, InStream *instream)
+{
+    size_t size = InStream_Read_C32(instream);
+    CharBuf *class_name = CB_new(size);
+    CB_Set_Size(class_name, size);
+    InStream_Read_Bytes(instream, CB_Get_Ptr8(class_name), size);
+    if (!self) {
+        VTable *vtable = VTable_singleton(class_name, OBJ);
+        self = VTable_Make_Obj(vtable);
+    }
+    else {
+        CharBuf *my_class = VTable_Get_Name(self->vtable);
+        if (!CB_Equals(class_name, (Obj*)my_class)) 
+            THROW(ERR, "Class mismatch: %o %o", class_name, my_class);
+    }
+    DECREF(class_name);
+    return Obj_init(self);
+}
+
 CharBuf*
 Obj_to_string(Obj *self)
 {

Modified: lucene/lucy/trunk/perl/lib/Lucy/Object/Obj.pm
URL: http://svn.apache.org/viewvc/lucene/lucy/trunk/perl/lib/Lucy/Object/Obj.pm?rev=886907&r1=886906&r2=886907&view=diff
==============================================================================
--- lucene/lucy/trunk/perl/lib/Lucy/Object/Obj.pm (original)
+++ lucene/lucy/trunk/perl/lib/Lucy/Object/Obj.pm Thu Dec  3 20:24:35 2009
@@ -21,6 +21,78 @@
 OUTPUT: RETVAL
 
 void
+STORABLE_freeze(self, ...)
+    lucy_Obj *self;
+PPCODE:
+{
+    CHY_UNUSED_VAR(self);
+    if (items < 2 || !SvTRUE(ST(1))) {
+        SV *retval;
+        lucy_ByteBuf *serialized_bb;
+        lucy_RAMFileHandle *file_handle = lucy_RAMFH_open(NULL, 
+            LUCY_FH_WRITE_ONLY | LUCY_FH_CREATE, NULL);
+        lucy_OutStream *target = lucy_OutStream_open((lucy_Obj*)file_handle);
+
+        Lucy_Obj_Serialize(self, target);
+
+        Lucy_OutStream_Close(target);
+        serialized_bb = Lucy_RAMFile_Get_Contents(
+            Lucy_RAMFH_Get_File(file_handle));
+        retval = XSBind_bb_to_sv(serialized_bb);
+        LUCY_DECREF(file_handle);
+        LUCY_DECREF(target);
+
+        if (SvCUR(retval) == 0) { /* Thwart Storable bug */
+            THROW(LUCY_ERR, "Calling serialize produced an empty string");
+        }
+        ST(0) = sv_2mortal(retval);
+        XSRETURN(1);
+    }
+}
+
+=begin comment
+
+Calls deserialize(), and copies the object pointer.  Since deserialize is an
+abstract method, it will confess() unless implemented.
+
+=end comment
+=cut
+
+void
+STORABLE_thaw(blank_obj, cloning, serialized_sv)
+    SV *blank_obj;
+    SV *cloning;
+    SV *serialized_sv;
+PPCODE:
+{
+    char *class_name = HvNAME(SvSTASH(SvRV(blank_obj)));
+    lucy_ZombieCharBuf klass 
+        = lucy_ZCB_make_str(class_name, strlen(class_name));
+    lucy_VTable *vtable = (lucy_VTable*)lucy_VTable_singleton(
+        (lucy_CharBuf*)&klass, NULL);
+    STRLEN len;
+    char *ptr = SvPV(serialized_sv, len);
+    lucy_ViewByteBuf *contents = lucy_ViewBB_new(ptr, len);
+    lucy_RAMFile *ram_file = lucy_RAMFile_new((lucy_ByteBuf*)contents, true);
+    lucy_RAMFileHandle *file_handle 
+        = lucy_RAMFH_open(NULL, LUCY_FH_READ_ONLY, ram_file);
+    lucy_InStream *instream = lucy_InStream_open((lucy_Obj*)file_handle);
+    lucy_Obj *self = Lucy_VTable_Foster_Obj(vtable, blank_obj);
+    lucy_Obj *deserialized = Lucy_Obj_Deserialize(self, instream);
+
+    CHY_UNUSED_VAR(cloning);
+    LUCY_DECREF(contents);
+    LUCY_DECREF(ram_file);
+    LUCY_DECREF(file_handle);
+    LUCY_DECREF(instream);
+
+    /* Catch bad deserialize() override. */
+    if (deserialized != self) {
+        THROW(LUCY_ERR, "Error when deserializing obj of class %o", &klass);
+    }
+}
+
+void
 DESTROY(self)
     lucy_Obj *self;
 PPCODE:
@@ -52,6 +124,8 @@
             Mimic
             Equals
             Hash_Code
+            Serialize
+            Deserialize
             Destroy
             )
     ],

Modified: lucene/lucy/trunk/perl/t/binding/019-obj.t
URL: http://svn.apache.org/viewvc/lucene/lucy/trunk/perl/t/binding/019-obj.t?rev=886907&r1=886906&r2=886907&view=diff
==============================================================================
--- lucene/lucy/trunk/perl/t/binding/019-obj.t (original)
+++ lucene/lucy/trunk/perl/t/binding/019-obj.t Thu Dec  3 20:24:35 2009
@@ -1,7 +1,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 16;
+use Test::More tests => 19;
 
 package TestObj;
 use base qw( Lucy::Object::Obj );
@@ -15,9 +15,29 @@
         my $self = shift;
         return "STRING: " . $self->SUPER::to_string;
     }
+
+    sub serialize {
+        my ( $self, $outstream ) = @_;
+        $self->SUPER::serialize($outstream);
+        $outstream->write_string("zowie");
+    }
+
+    sub deserialize {
+        my ( $self, $instream ) = @_;
+        $self = $self->SUPER::deserialize($instream);
+        $instream->read_string;
+        return $self;
+    }
+}
+
+package BadSerialize;
+use base qw( Lucy::Object::Obj );
+{
+    sub serialize { }
 }
 
 package main;
+use Storable qw( freeze thaw );
 
 ok( defined $TestObj::version,
     "Using base class should grant access to "
@@ -39,8 +59,8 @@
 ok( $object->is_a("Lucy::Object::Obj"), "custom is_a correct" );
 ok( !$object->is_a("Lucy::Object"),     "custom is_a too long" );
 ok( !$object->is_a("Lucy"),             "custom is_a substring" );
-ok( !$object->is_a(""),                 "custom is_a blank" );
-ok( !$object->is_a("thing"),            "custom is_a wrong" );
+ok( !$object->is_a(""),                       "custom is_a blank" );
+ok( !$object->is_a("thing"),                  "custom is_a wrong" );
 
 eval { my $another_obj = TestObj->new( kill_me_now => 1 ) };
 like( $@, qr/kill_me_now/, "reject bad param" );
@@ -60,7 +80,22 @@
 is( $object->get_refcount, 1,
     "correct refcount after destruction of ref" );
 
+my $copy = thaw( freeze($object) );
+is( ref($copy), ref($object), "freeze/thaw" );
+
 $object = SonOfTestObj->new;
 like( $object->to_string, qr/STRING:.*?SonOfTestObj/,
     "overridden XS bindings can be called via SUPER" );
 
+my $frozen = freeze($object);
+my $dupe   = thaw($frozen);
+is( ref($dupe), ref($object), "override serialize/deserialize" );
+
+SKIP: {
+    skip( "Invalid serialization causes leaks", 1 ) if $ENV{LUCY_VALGRIND};
+    my $bad = BadSerialize->new;
+    eval { my $froze = freeze($bad); };
+    like( $@, qr/empty/i,
+        "Don't allow subclasses to perform invalid serialization" );
+}
+