Index: trunk/Nebulous-Server/Changes
===================================================================
--- trunk/Nebulous-Server/Changes	(revision 18389)
+++ trunk/Nebulous-Server/Changes	(revision 18400)
@@ -2,4 +2,5 @@
 
 0.13
+    - add "smart" storage volume selection when ->replicate_object() is invoked without a target volume name
     - add volume.host field
     - add --host option to neb-initdb
Index: trunk/Nebulous-Server/lib/Nebulous/Server.pm
===================================================================
--- trunk/Nebulous-Server/lib/Nebulous/Server.pm	(revision 18389)
+++ trunk/Nebulous-Server/lib/Nebulous/Server.pm	(revision 18400)
@@ -1,5 +1,5 @@
 # Copyright (c) 2004-2008  Joshua Hoblitt
 #
-# $Id: Server.pm,v 1.78 2008-07-01 00:28:06 jhoblitt Exp $
+# $Id: Server.pm,v 1.79 2008-07-02 03:40:10 jhoblitt Exp $
 
 package Nebulous::Server;
@@ -320,5 +320,6 @@
             type        => SCALAR,
             callbacks   => {
-                'is valid object key' => sub { $self->_is_valid_object_key($_[0]) },
+                'is valid object key'
+                    => sub { $self->_is_valid_object_key($_[0]) },
             },
         },
@@ -336,4 +337,12 @@
     );
 
+    # if a volume name is explicity specified then we should make the
+    # replication onto that volume (even if there is alread an instance on that
+    # volume) if at all possible and throw an error if we can not.
+    # if a volume name IS NOT specified then we should make the replication
+    # onto any (hopefully the best) volume that DOES NOT already have an
+    # instance on it.  If all avilable volume already have an instance on them
+    # then we should throw an error 
+
     my $log = $self->log;
     my $sql = $self->sql;
@@ -353,5 +362,12 @@
     }
         
-    my ($vol_id, $vol_host, $vol_path, $vol_xattr) = $self->_get_storage_volume($vol_name);
+    my ($vol_id, $vol_host, $vol_path, $vol_xattr);
+    if (defined $vol_name) {
+        ($vol_id, $vol_host, $vol_path, $vol_xattr)
+            = $self->_get_storage_volume($vol_name);
+    } else {
+        ($vol_id, $vol_host, $vol_path, $vol_xattr)
+            = $self->_get_replication_volume($key);
+    }
 
     my $uri;
@@ -359,4 +375,5 @@
         my $so_id;
         {
+            # verify that at least one instance is currently available
             my $query = $db->prepare_cached( $sql->get_object_instances );
             my $rows = $query->execute($key, 1);
@@ -382,5 +399,5 @@
             ($ins_id) = $query->fetchrow_array;
             # XXX finish seems to be required when using LAST_INSERT_ID() or we
-            # get a warning about the stmt handling still be active the next
+            # get a warning about the stmt handling still being active the next
             # time LAST_INSERT_ID() is invoked
             $query->finish;
@@ -1197,4 +1214,53 @@
 
 
+sub _get_replication_volume
+{
+    my $self = shift;
+
+    my $log = $self->log;
+    my $sql = $self->sql;
+    my $db  =$self->db;
+
+    no warnings qw( uninitialized );
+    $log->debug( "entered - @_" );
+    use warnings;
+
+    my $key = shift;
+
+    my $volume;
+    ($volume, $key) = parse_neb_key($key);
+
+    my ($vol_id, $vol_host, $vol_path, $xattr);
+    eval {
+        my $rows;
+        my $query = $db->prepare_cached( $sql->get_replication_volume_for_ext_id );
+        # ext_id, %free, avaiable, allocate
+        $rows = $query->execute($key, 0.95, 1, 1);
+        # XXX destinguish between non-existant and unaviable
+        unless ($rows > 0) {
+            $query->finish;
+            $log->logdie("can't find a suitable storage volume to replicate $key too");
+        }
+        # when matching by name we shouldn't ever match more than once
+        if ($rows > 1) {
+            $query->finish;
+            $log->logdie("affected row count is $rows instead of 1");
+        }
+
+        my $free;
+        ($vol_id, $vol_host, $vol_path, $xattr, $free) = $query->fetchrow_array;
+        $query->finish;
+    };
+    $log->logdie("database error: $@") if $@;
+
+    $log->logdie("failed to find a suitable volume" )
+        unless defined $vol_id and defined $vol_path;
+
+    $log->debug( "leaving" );
+
+    return ($vol_id, $vol_host, $vol_path, $xattr);
+}
+
+
 sub _is_valid_object_key
 {
Index: trunk/Nebulous-Server/lib/Nebulous/Server/SQL.pm
===================================================================
--- trunk/Nebulous-Server/lib/Nebulous/Server/SQL.pm	(revision 18389)
+++ trunk/Nebulous-Server/lib/Nebulous/Server/SQL.pm	(revision 18400)
@@ -1,5 +1,5 @@
 # Copyright (c) 2004  Joshua Hoblitt
 #
-# $Id: SQL.pm,v 1.59 2008-06-30 23:26:16 jhoblitt Exp $
+# $Id: SQL.pm,v 1.60 2008-07-02 03:40:10 jhoblitt Exp $
 
 package Nebulous::Server::SQL;
@@ -211,4 +211,44 @@
             AND available = ?
             AND allocate = ?
+        ORDER BY free DESC
+        LIMIT 1
+    },
+    get_replication_volume_for_ext_id   => qq{
+        SELECT
+            vol_id,
+            host,
+            path,
+            xattr,
+            total - used as free
+        FROM (
+-- This query works but is slow...
+--             SELECT
+--                  mountedvol.*
+--             FROM mountedvol
+--             WHERE
+--                 vol_id NOT IN(
+--                     SELECT vol_id
+--                     FROM storage_object
+--                     JOIN instance
+--                         USING(so_id)
+--                     WHERE ext_id = --
+--                  )
+                SELECT
+                    m.*
+                FROM mountedvol AS m
+                LEFT JOIN instance AS i
+                    ON m.vol_id = i.vol_id
+                    AND i.so_id = (
+                        SELECT so_id
+                        FROM storage_object
+                        WHERE ext_id = ?
+                    )
+                WHERE
+                    i.vol_id IS NULL
+        ) as Foo 
+        WHERE
+            used / total < ? 
+            AND available = ? 
+            AND allocate = ? 
         ORDER BY free DESC
         LIMIT 1
Index: trunk/Nebulous-Server/t/07_server_find_instances.t
===================================================================
--- trunk/Nebulous-Server/t/07_server_find_instances.t	(revision 18389)
+++ trunk/Nebulous-Server/t/07_server_find_instances.t	(revision 18400)
@@ -3,5 +3,5 @@
 # Copryight (C) 2004-2005  Joshua Hoblitt
 #
-# $Id: 07_server_find_instances.t,v 1.12 2008-05-20 01:47:08 jhoblitt Exp $
+# $Id: 07_server_find_instances.t,v 1.13 2008-07-02 03:40:10 jhoblitt Exp $
 
 use strict;
@@ -91,5 +91,5 @@
     my $uri2 = $neb->replicate_object("foo");
 
-    my $locations = $neb->find_instances("foo", "node01");
+    my $locations = $neb->find_instances("foo", ":any");
 
     uri_scheme_ok($locations->[0], 'file');
