Index: trunk/Nebulous/lib/Nebulous/Client.pm
===================================================================
--- trunk/Nebulous/lib/Nebulous/Client.pm	(revision 13177)
+++ trunk/Nebulous/lib/Nebulous/Client.pm	(revision 13180)
@@ -1,5 +1,5 @@
 # Copyright (c) 2004  Joshua Hoblitt
 #
-# $Id: Client.pm,v 1.29 2007-05-01 02:52:04 jhoblitt Exp $
+# $Id: Client.pm,v 1.30 2007-05-03 03:21:28 jhoblitt Exp $
 
 package Nebulous::Client;
@@ -227,5 +227,5 @@
     my $self = shift;
 
-    my ( $key, @params ) = validate_pos( @_,
+    my ($key, $vol_name) = validate_pos(@_,
         {
             type => SCALAR,
@@ -240,23 +240,46 @@
     $log->debug( "entered - @_" );
 
-    # need some way to determine which is the best instance to remove
-    my $locations = $self->find_instances( $key, @params );
-    unless ( $locations ) {
+    my $locations;
+    # if vol_name is specified we need to stat the file to find out how many
+    # instances there are on all volumes.  Otherwise we wouldn't know if it's
+    # safe to remove the last instance on the specified volume.
+    # XXX We need some way to determine which is the best instance to remove
+    if (defined $vol_name) {
+        my @stats = $self->stat($key);
+        my $instances = $stats[6];
+        if (defined $instances and $instances < 2) {
+            $log->debug("can not cull - not enough instances");
+            $log->debug("leaving");
+
+            return;
+        }
+
+        $locations = $self->find_instances($key, $vol_name);
+        unless (scalar @{ $locations }) {
             $log->debug( "no instances" );
             $log->debug( "leaving" );
 
-            return undef;
-    }
-
-    if ( scalar @{ $locations } < 2 ) {
-        $log->debug( "can not cull - not enough instances" );
-        $log->debug( "leaving" );
-
-        return undef;
-    }
-
-    my $uri = $self->delete_instance( $locations->[0] );
-
-    $log->debug( "leaving" );
+            return;
+        }
+    } else {
+        $locations = $self->find_instances($key);
+        unless ($locations) {
+            $log->debug("no instances");
+            $log->debug("leaving");
+
+            return;
+        }
+
+        if (scalar @{ $locations } < 2) {
+            $log->debug("can not cull - not enough instances");
+            $log->debug("leaving");
+
+            return;
+        }
+    }
+
+    my $uri = $self->delete_instance( @$locations[0] );
+
+    $log->debug("leaving");
 
     return $uri;
@@ -638,5 +661,5 @@
     my $self = shift;
 
-    my ( $uri ) = validate_pos( @_,
+    my ($uri) = validate_pos(@_,
         {
             type => SCALAR,
Index: trunk/Nebulous/lib/Nebulous/Server.pm
===================================================================
--- trunk/Nebulous/lib/Nebulous/Server.pm	(revision 13177)
+++ trunk/Nebulous/lib/Nebulous/Server.pm	(revision 13180)
@@ -1,5 +1,5 @@
 # Copyright (c) 2004  Joshua Hoblitt
 #
-# $Id: Server.pm,v 1.32 2007-05-03 01:44:23 jhoblitt Exp $
+# $Id: Server.pm,v 1.33 2007-05-03 03:21:28 jhoblitt Exp $
 
 package Nebulous::Server;
@@ -1021,34 +1021,35 @@
     my ( $key ) = validate_pos( @_,
         {
-            type => SCALAR,
-        },
-    );
-
-    my $log = $self->log;
-    my $sql = $self->sql;
-    my $db  =$self->db;
-
-    $log->debug( "entered - @_" );
+            type        => SCALAR,
+            callbacks   => {
+                'is valid object key' => sub { $self->_is_valid_object_key($_[0]) },
+            },
+        },
+    );
+
+    my $log = $self->log;
+    my $sql = $self->sql;
+    my $db  =$self->db;
+
+    $log->debug("entered - @_");
 
     my $stat;
     eval {
-        my $query = $db->prepare_cached( $sql->get_object );
-        my $rows = $query->execute( $key );
-
-        unless ( $rows == 1 ) {
-            $log->logdie( "no storage object found" );
+        my $query = $db->prepare_cached( $sql->stat_object );
+        my $rows = $query->execute($key);
+
+        unless ($rows == 1) {
+            $log->logdie("no storage object found");
         }
 
         $stat = $query->fetchrow_arrayref;
         $query->finish;
-
-        $db->commit;
     };
     if ( $@ ) {
         $db->rollback;
-        $log->logdie( "database error: $@" );
-    }
-
-    $log->debug( "leaving" );
+        $log->logdie("database error: $@");
+    }
+
+    $log->debug("leaving");
 
     return $stat;
Index: trunk/Nebulous/lib/Nebulous/Server/SQL.pm
===================================================================
--- trunk/Nebulous/lib/Nebulous/Server/SQL.pm	(revision 13177)
+++ trunk/Nebulous/lib/Nebulous/Server/SQL.pm	(revision 13180)
@@ -1,5 +1,5 @@
 # Copyright (c) 2004  Joshua Hoblitt
 #
-# $Id: SQL.pm,v 1.35 2007-05-03 01:49:55 jhoblitt Exp $
+# $Id: SQL.pm,v 1.36 2007-05-03 03:21:28 jhoblitt Exp $
 
 package Nebulous::Server::SQL;
@@ -53,5 +53,5 @@
     get_object          => qq{
         SELECT
-            storage_object.so_id,
+            so_id,
             ext_id,
             read_lock,
@@ -63,4 +63,21 @@
         USING (so_id)
         WHERE ext_id = ?
+    },
+    stat_object          => qq{
+        SELECT
+            storage_object.so_id,
+            storage_object.ext_id,
+            read_lock,
+            write_lock,
+            storage_object_attr.epoch,
+            storage_object_attr.mtime,
+            COUNT(instance.so_id) as instances
+        FROM storage_object
+        JOIN storage_object_attr
+            USING (so_id)
+        JOIN instance
+            USING (so_id)
+        WHERE ext_id = ?
+        GROUP BY storage_object.so_id
     },
     # Note: this sets an update lock
