Index: trunk/Nebulous/lib/Nebulous/Server.pm
===================================================================
--- trunk/Nebulous/lib/Nebulous/Server.pm	(revision 13072)
+++ trunk/Nebulous/lib/Nebulous/Server.pm	(revision 13087)
@@ -1,5 +1,5 @@
 # Copyright (c) 2004  Joshua Hoblitt
 #
-# $Id: Server.pm,v 1.26 2007-04-28 00:44:38 jhoblitt Exp $
+# $Id: Server.pm,v 1.27 2007-05-01 02:00:07 jhoblitt Exp $
 
 package Nebulous::Server;
@@ -614,4 +614,207 @@
 
 
+sub setxattr_object
+{
+    my $self = shift;
+
+    my ($key, $name, $value, $flags) = validate_pos(@_,
+        {
+            type        => SCALAR,
+        },
+        {
+            type        => SCALAR,
+        },
+        {
+            type        => SCALAR,
+        },
+        {
+            type        => SCALAR,
+            callbacks   => {
+                'is read or write' => sub { $_[0] =~ /^(?:create|replace)$/i },
+            },
+        },
+    );
+
+    my $log = $self->log;
+    my $sql = $self->sql;
+    my $db  =$self->db;
+
+    $log->debug("entered - @_");
+
+    eval {
+        my $query;
+
+        if ($flags eq 'create') {
+            $query = $db->prepare_cached( $sql->new_object_xattr );
+        } else {
+            # replace
+            $query = $db->prepare_cached( $sql->replace_object_xattr );
+        }
+
+        # name, value, ext_id
+        my $rows = $query->execute($name, $value, $key);
+
+        # if we affected more then one row something very bad has happened.
+        if ($flags eq 'create') {
+            unless ($rows == 1) {
+                $log->logdie( "affected row count is $rows instead of 1" );
+            }
+        } else {
+            unless ($rows == 2) {
+                $log->logdie( "affected row count is $rows instead of 2" );
+            }
+        }
+    };
+    if ($@) {
+        $db->rollback;
+        $log->logdie("database error: $@");
+    }
+
+    eval { 
+        $db->commit;
+    };
+    if ($@) {
+        $db->rollback;
+        $log->logdie("database error: $@");
+    }
+
+    $log->debug("leaving");
+
+    return 1;
+}
+
+
+sub getxattr_object
+{
+    my $self = shift;
+
+    my ($key, $name) = validate_pos(@_,
+        {
+            type        => SCALAR,
+        },
+        {
+            type        => SCALAR,
+        },
+    );
+
+    my $log = $self->log;
+    my $sql = $self->sql;
+    my $db  =$self->db;
+
+    $log->debug("entered - @_");
+
+    my $query;
+    eval {
+        $query = $db->prepare_cached( $sql->get_object_xattr );
+        # ext_id, name
+        my $rows = $query->execute($key, $name);
+
+        # if we affected more then one row something very bad has happened.
+        unless ($rows == 1) {
+            $log->logdie( "affected row count is $rows instead of 1" );
+        }
+    };
+    if ($@) {
+        $db->rollback;
+        $log->logdie("database error: $@");
+    }
+
+    my $row = $query->fetchrow_hashref;
+    my $value = $row->{ 'value' };
+    $query->finish;
+
+    $log->debug("leaving");
+
+    return $value;
+}
+
+
+sub listxattr_object
+{
+    my $self = shift;
+
+    my ($key) = validate_pos(@_,
+        {
+            type        => SCALAR,
+        },
+    );
+
+    my $log = $self->log;
+    my $sql = $self->sql;
+    my $db  =$self->db;
+
+    $log->debug("entered - @_");
+
+    my $query;
+    eval {
+        $query = $db->prepare_cached( $sql->list_object_xattr );
+        # ext_id
+        my $rows = $query->execute($key);
+    };
+    if ($@) {
+        $db->rollback;
+        $log->logdie("database error: $@");
+    }
+
+    my @xattrs;
+    while (my $row = $query->fetchrow_hashref) {
+        push @xattrs, $row->{ 'name' };
+    }
+
+    $log->debug("leaving");
+
+    return @xattrs;
+}
+
+
+sub removexattr_object
+{
+    my $self = shift;
+
+    my ($key, $name) = validate_pos(@_,
+        {
+            type        => SCALAR,
+        },
+        {
+            type        => SCALAR,
+        },
+    );
+
+    my $log = $self->log;
+    my $sql = $self->sql;
+    my $db  =$self->db;
+
+    $log->debug("entered - @_");
+
+    my $query;
+    eval {
+        $query = $db->prepare_cached( $sql->remove_object_xattr );
+        # ext_id, name
+        my $rows = $query->execute($key, $name);
+
+        # if we affected more then one row something very bad has happened.
+        unless ($rows == 1) {
+            $log->logdie( "affected row count is $rows instead of 1" );
+        }
+    };
+    if ($@) {
+        $db->rollback;
+        $log->logdie("database error: $@");
+    }
+
+    eval { 
+        $db->commit;
+    };
+    if ($@) {
+        $db->rollback;
+        $log->logdie("database error: $@");
+    }
+
+    $log->debug("leaving");
+
+    return 1;
+}
+
+
 sub find_objects {
     my $self = shift;
Index: trunk/Nebulous/lib/Nebulous/Server/SQL.pm
===================================================================
--- trunk/Nebulous/lib/Nebulous/Server/SQL.pm	(revision 13072)
+++ trunk/Nebulous/lib/Nebulous/Server/SQL.pm	(revision 13087)
@@ -1,5 +1,5 @@
 # Copyright (c) 2004  Joshua Hoblitt
 #
-# $Id: SQL.pm,v 1.28 2007-04-28 00:44:38 jhoblitt Exp $
+# $Id: SQL.pm,v 1.29 2007-05-01 02:00:07 jhoblitt Exp $
 
 package Nebulous::Server::SQL;
@@ -63,4 +63,42 @@
         WHERE ext_id = ?
         FOR UPDATE
+    },
+    new_object_xattr  => qq{
+        INSERT INTO storage_object_xattr
+            SELECT
+                so_id,
+                ?,
+                ?        
+            FROM storage_object
+            WHERE ext_id = ?
+    },
+    replace_object_xattr  => qq{
+        REPLACE INTO storage_object_xattr
+            SELECT
+                so_id,
+                ?,
+                ?        
+            FROM storage_object
+            WHERE ext_id = ?
+    },
+    list_object_xattr    => qq{
+        SELECT storage_object_xattr.name
+        FROM storage_object
+        JOIN storage_object_xattr
+        USING (so_id)
+        WHERE ext_id = ?
+    },
+    get_object_xattr    => qq{
+        SELECT storage_object_xattr.value
+        FROM storage_object
+        JOIN storage_object_xattr
+        USING (so_id)
+        WHERE ext_id = ?
+            AND name = ?
+    },
+    remove_object_xattr    => qq{
+        DELETE FROM storage_object_xattr
+        WHERE so_id = (SELECT so_id from storage_object where ext_id = ?)
+            AND name = ?
     },
     set_write_lock      => qq{
@@ -179,4 +217,5 @@
 DROP TABLE IF EXISTS storage_object;
 DROP TABLE IF EXISTS storage_object_attr;
+DROP TABLE IF EXISTS storage_object_xattr;
 DROP TABLE IF EXISTS instance;
 DROP TABLE IF EXISTS lock_record;
@@ -226,4 +265,13 @@
     PRIMARY KEY(so_id),
     KEY(class_id)
+) ENGINE=innodb;
+
+###
+
+CREATE TABLE storage_object_xattr (
+    so_id BIGINT NOT NULL AUTO_INCREMENT,
+    name VARCHAR(255),
+    value BLOB,
+    PRIMARY KEY(so_id, name)
 ) ENGINE=innodb;
 
