Index: trunk/Nebulous-Server/lib/Nebulous/Server.pm
===================================================================
--- trunk/Nebulous-Server/lib/Nebulous/Server.pm	(revision 24995)
+++ trunk/Nebulous-Server/lib/Nebulous/Server.pm	(revision 26292)
@@ -35,4 +35,10 @@
 use constant NFS_RETRY_WAIT 	=> 1;
 use constant TRANS_RETRY_WAIT 	=> 1;
+
+# This is the umask hack.
+umask(0002);
+
+# This determines how many entries from the list of volumes sorted by free space are randomized.
+my $topfew_count = 3;
 
 # transaction restart/retry regex
@@ -905,13 +911,15 @@
             }
 
-            # In MySQL you can't select from a table your deleting rows from so
+            # In MySQL you can't select from a table you're deleting rows from so
             # we first have to get a list of instances to be removed, and then
-            # removed them.
+            # remove them.
             my $rows_found;
             {
                 my $query = $db->prepare_cached( $sql->find_dead_instances_by_so_id );
                 $rows_found = $query->execute( $so_id );
-                foreach my $row ($query->fetchrow_hashref) {
+		my $i = 0;
+		while (my $row = $query->fetchrow_hashref) {
                     # remove dead instances
+#		    $log->warn("copied: $rows_copied found: $rows_found removed: $rows_removed");
                     my $query = $db->prepare_cached( $sql->delete_instance_by_ins_id);
                     $rows_removed += $query->execute( $row->{ins_id} );
@@ -919,5 +927,5 @@
                 $query->finish;
             }
-
+#	    $log->warn("copied: $rows_copied found: $rows_found removed: $rows_removed");
             # sanity check
             die("instances inaccessible ($rows_copied) != instances removed ($rows_removed)")
@@ -1692,4 +1700,108 @@
 }
 
+sub find_instances_for_cull
+{
+    my $self = shift;
+
+    my $log = $self->log;
+    $log->debug("entered - @_");
+
+    my ($key, $vol_name) = validate_pos(@_,
+        {
+            type        => SCALAR,
+            callbacks   => {
+                'is valid object key' => sub { $self->_is_valid_object_key($_[0]) },
+            },
+        },
+        {
+            type        => SCALAR|UNDEF,
+#            callbacks   => {
+#                # check that the volume name requested is valid
+#                'is valid volume name' => sub {
+#                    return 1 if not defined $_[0];
+#                    $self->_is_valid_volume_name($_[0])
+#                },
+#            },
+            optional    => 1,
+        },
+    );
+
+    my $sql = $self->sql;
+
+#    unless ($key) {
+#        $log->warn("key was undefined after validate_pos(), trying again...");
+#        return $self->find_instances(@_);
+#    }
+
+    # vol_name overrides the key implied volume
+    eval {
+        $key = parse_neb_key($key, $vol_name);
+    };
+    $log->logdie("$@") if $@;
+    $vol_name = $key->volume;
+
+    my $db  = $self->db($key);
+
+    # the key's volume can't be validiated on input for this method so we have
+    # to check it after parsing the key
+    if (defined $vol_name
+        and not $self->_is_valid_volume_name($key, $key->volume)) {
+        if ($key->hard_volume) {
+            $log->logdie("$vol_name is not a valid volume name");
+        } else {
+            $log->warn( "$vol_name is not a known volume name" );
+            $vol_name = undef;
+        }
+    }
+
+    my @locations;
+    eval {
+        my $query;
+        if ($vol_name) {
+            $query = $db->prepare_cached( $sql->get_object_instances_by_vol_name );
+            # ext_id, name, available
+            my $rows = $query->execute($key->path, $vol_name, 1);
+            unless ($rows > 0) {
+                $query->finish;
+                die("no instances on storage volume or volume is not avaiable for key: $key volume: $vol_name");
+            }
+        } else {
+            $query = $db->prepare_cached( $sql->get_object_instances );
+            # ext_id, available
+            my $rows = $query->execute($key->path, 1);
+            unless ($rows > 0) {
+                $query->finish;
+                die("no instances available for key: $key");
+            }
+        }
+	
+        while (my $row = $query->fetchrow_hashref) {
+#	    my $instance_hash  = { uri => $row->{ 'uri' }, 
+#				   vol_id => $row->{ 'vol_id' }, 
+#				   cab_id => $row->{ 'cab_id'} };
+	    my $instance = $row->{ 'uri' };
+            push @locations, $row if $instance;
+        }
+    };
+    if ($@) {
+        $db->rollback;
+        # handle soft volumes
+        if (defined $vol_name and not defined $key->hard_volume) {
+            $log->debug("retrying with 'any' volume");
+            return $self->find_instances($key->path, 'any');
+        }
+        $log->logdie("database error: $@");
+    }
+
+    # XXX remove this?
+    $log->logdie("no instances found") unless (scalar @locations);
+
+    $log->debug("found: @locations");
+
+    $log->debug("leaving");
+
+    return \@locations;
+}
+
 
 sub delete_instance
@@ -1984,5 +2096,6 @@
 
     my ($key, $name, $hard_volume) = @_;
-
+    
+#    $log->warn("_g_s_v: key:>$key< name:>$name< hard_vol:>$hard_volume<");
     my $sql = $self->sql;
     my $db  = $self->db($key);
@@ -1996,5 +2109,5 @@
             # %free, name, avaiable, allocate
             $rows = $query->execute(0.95, $name, 1, 1);
-            # XXX destinguish between non-existant and unaviable
+            # XXX destinguish between non-existant and unavailable
             unless ($rows > 0) {
                 $query->finish;
@@ -2016,5 +2129,5 @@
             $query = $db->prepare_cached( $sql->get_storage_volume );
             # %free, avaiable, allocate
-            $rows = $query->execute(0.95, 1, 1);
+            $rows = $query->execute(0.95, 1, 1, $topfew_count);
             # there has to be atleast one storage volume
             unless ($rows > 0) {
@@ -2062,10 +2175,30 @@
     my $db  = $self->db($key);
 
-    my ($vol_id, $vol_host, $vol_path, $xattr);
+    my ($vol_id, $vol_host, $vol_path, $xattr, $forbidden_cabinet);
     eval {
         my $rows;
-        my $query = $db->prepare_cached( $sql->get_replication_volume_for_ext_id );
+	
+	my $query = $db->prepare_cached( $sql->get_cabinets_for_ext_id );
+	$rows = $query->execute($key->path);
+	unless ($rows > 0) {
+	    $query->finish;
+	    die("Requested key $key does not exist");
+	}
+	if ($rows == 1) {
+	    ($forbidden_cabinet) = $query->fetchrow_array;
+	    unless (defined($forbidden_cabinet)) {
+		$forbidden_cabinet = 0;
+	    }
+	    $query->finish;
+	}
+	else {
+	    $forbidden_cabinet = 0;
+	    $query->finish;
+	}
+	    
+
+        $query = $db->prepare_cached( $sql->get_replication_volume_for_ext_id );
         # ext_id, %free, avaiable, allocate
-        $rows = $query->execute($key->path, 0.95, 1, 1);
+        $rows = $query->execute($key->path, 0.95, 1, 1, $forbidden_cabinet, $topfew_count);
         # XXX destinguish between non-existant and unaviable
         unless ($rows > 0) {
@@ -2175,5 +2308,5 @@
 
     # handle "any" volume
-    if ($vol_name eq 'any') {
+    if (($vol_name eq 'any')||($vol_name eq 'any.0')) {
         $log->debug( "found volume name $vol_name" );
         $log->debug( "leaving" );
@@ -2200,5 +2333,5 @@
     $log->debug( "leaving" );
 
-    return;
+    return 0;
 }
 
