Index: /branches/eam_branches/ipp-20191011/Nebulous-Server/lib/Nebulous/Server.pm
===================================================================
--- /branches/eam_branches/ipp-20191011/Nebulous-Server/lib/Nebulous/Server.pm	(revision 40979)
+++ /branches/eam_branches/ipp-20191011/Nebulous-Server/lib/Nebulous/Server.pm	(revision 40980)
@@ -15,5 +15,6 @@
 use Cache::Memcached;
 use DBI;
-use Digest::SHA1 qw( sha1_hex );
+## for gentoo: use Digest::SHA1 qw( sha1_hex );
+use Digest::SHA qw( sha1_hex );
 use Fcntl ':mode';
 use File::Basename qw( basename dirname fileparse );
@@ -77,6 +78,6 @@
         Cache::Memcached->new({
 	    servers => $config->memcached_servers,
-       })
-    );
+			      })
+	);
 #    $self->cache->set("foo", "bar") or die "set failed";
 #    $self->cache->get("foo") or die "get failed";
@@ -215,4 +216,6 @@
 }
 
+my $get_storage_volume_calls = 0;
+
 sub create_object
 {
@@ -252,6 +255,5 @@
     # 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 (defined $vol_name and not $self->_is_valid_volume_name($key, $key->volume)) {
         unless ($key->hard_volume) {
             $log->warn( "$vol_name is not a known volume name" );
@@ -262,4 +264,6 @@
     }
         
+    $get_storage_volume_calls = 0;
+
     my ($vol_id, $vol_host, $vol_path, $vol_xattr)
         = $self->_get_storage_volume($key, $vol_name, $key->hard_volume);
@@ -273,5 +277,7 @@
                 # create storage_object
                 my $query = $db->prepare_cached( $sql->new_object ); 
-                $query->execute('NULL', $key->path, basename($key->path), $parent_id);
+# bad syntax    $query->execute('NULL', $key->path, basename($key->path), $parent_id);
+                $query->execute(0, $key->path, basename($key->path), $parent_id);
+                $query->finish;
             }
 
@@ -292,4 +298,5 @@
                 my $query = $db->prepare_cached( $sql->new_object_attr ); 
                 $query->execute($so_id);
+                $query->finish;
             }
 
@@ -300,4 +307,5 @@
                 my $query = $db->prepare_cached( $sql->new_object_instance );
                 $query->execute($vol_id);
+                $query->finish;
             }
 
@@ -327,4 +335,5 @@
                 # vol_id, uri, ins_id
                 $query->execute($vol_id, "$uri", $ins_id);
+                $query->finish;
             }
 
@@ -421,4 +430,5 @@
                     }
                     $query->finish;
+		    $db->commit;
                 }
 
@@ -441,4 +451,6 @@
                     my $query = $db->prepare_cached($sql->new_directory);
                     $query->execute($dir, $parent_id);
+                    $query->finish;
+		    $db->commit;
                 }
 
@@ -452,9 +464,8 @@
                     ($parent_id) = $query->fetchrow_array;
                     $query->finish;
+		    $db->commit;
                 }
                 die("failed to get LAST_INSERT_ID()")
                     unless $parent_id;
-
-                $db->commit;
             }
         };
@@ -744,6 +755,5 @@
     # puke if the source volume is bogus, we may want to actually use this as
     # the instance to be copied later
-    if (defined $key->volume
-        and not $self->_is_valid_volume_name($key, $key->volume)) {
+    if (defined $key->volume and not $self->_is_valid_volume_name($key, $key->volume)) {
         unless ($key->hard_volume) {
             $log->warn($key->volume . " not a known volume name");
@@ -752,11 +762,12 @@
         }
     }
-    # puke if the source volume is bogus, we may want to actually use this as
-    # the instance to be copied later
+    # puke if the destination volume is bogus
     if (defined $dest_vol_name
         and not $self->_is_valid_volume_name($key, $dest_vol_name)) {
            $log->logdie($key->volume . " is not a valid volume name");
     }
-        
+
+    $get_storage_volume_calls = 0;
+
     my ($vol_id, $vol_host, $vol_path, $vol_xattr);
     if (defined $dest_vol_name) {
@@ -784,4 +795,5 @@
                 $so_id = $query->fetchrow_hashref->{ 'so_id' };
                 $query->finish;
+		$db->commit;
             }
 
@@ -800,4 +812,5 @@
                 # time LAST_INSERT_ID() is invoked
                 $query->finish;
+		$db->commit;
             }
 
@@ -841,6 +854,6 @@
     eval {
         my $mode = $self->getxattr_object("$key", 'user.mode');
-        if (defined $mode) {
-            $self->chmod_object("$key", $mode);
+        if (defined $mode && $mode ne "") {
+	    $self->chmod_object("$key", $mode);
         }
     };
@@ -852,5 +865,4 @@
 
     $log->debug("leaving");
-
     return "$uri";
 }
@@ -1323,4 +1335,5 @@
             die( "xattr $key:$name does not exist" );
         }
+
         # if we go more then one row bad something very bad has happened.
         unless ($rows == 1) {
@@ -1335,7 +1348,10 @@
         $value = $row->{ 'value' };
     };
+    $db->commit;
+
     if ($@) {
         if ($@ =~ /user\..*? does not exist/) {
             # do not log xattr does not exist messages
+	    # NOTE: the client is using the reported message to interpret the errors
             die $@;
         }
@@ -1386,4 +1402,5 @@
     };
     $log->logdie("database error: $@") if $@;
+    $db->commit;
 
     $log->debug("leaving");
@@ -1442,5 +1459,4 @@
                 die( "affected row count is $rows instead of 1" );
             }
-
             $db->commit;
             $log->debug("commit");
@@ -1545,6 +1561,5 @@
 	$work_dir = $pattern;
 	$file_pattern = '%';
-    }
-    else {
+    } else {
 	my $dir_plain = dirname($pattern);
 	if ($dir_plain eq 'neb:') {
@@ -1575,4 +1590,5 @@
         my $query = $db->prepare_cached( $sql->find_dir_by_parent_id . " AND dirname LIKE ? ");
         $query->execute( $dir_id, $file_pattern );
+	$db->commit;
 
         while ( my $row = $query->fetchrow_hashref ) {
@@ -1595,4 +1611,5 @@
         my $query = $db->prepare_cached( $sql->find_object_by_dir_id . " AND ext_id_basename LIKE ? ");
         $query->execute( $dir_id , $file_pattern);
+	$db->commit;
 
         while ( my $row = $query->fetchrow_hashref ) {
@@ -1624,5 +1641,4 @@
     my $sql = $self->sql;
     my $db  = $self->_db_for_index($index);
-
 
     # first check to see if the key is an exact match
@@ -1645,4 +1661,5 @@
         $log->logdie("database error: $@");
     }
+    $db->commit;
 
     if (scalar @keys) {
@@ -1678,4 +1695,5 @@
     };
     $log->logdie("database error: $@") if $@;
+    $db->commit;
 
     # find files under dir
@@ -1692,4 +1710,5 @@
     };
     $log->logdie("database error: $@") if $@;
+    $db->commit;
 
     $log->debug( "leaving" );
@@ -1753,4 +1772,5 @@
 }
 
+# sub find_instances
 sub find_instances_old
 {
@@ -1829,4 +1849,5 @@
             # ext_id, available
 	    if (defined($find_invalid)) {
+		# XXX returns instances which are NOT available
 		$rows = $query->execute($key->path, 0);
 	    }
@@ -1865,5 +1886,5 @@
 }
 
-#sub find_instances_by_proximity
+# sub find_instances_by_proximity
 sub find_instances
 {
@@ -1897,5 +1918,4 @@
         }, 
     );
-
     my $sql = $self->sql;
 
@@ -1932,6 +1952,4 @@
 	    }
 	}
-
-
     }
 
@@ -1972,8 +1990,10 @@
             # ext_id, name, available
 	    # host_vol_id host_cab_id host_site_id ext_id available
+
+	    ### XXX EAM if find_invalid is true, the last arguement here should be 0
             my $rows = $query->execute($h_vol_id, $h_cab_id, $h_site_id, $key->path, 1);
             unless ($rows > 0) {
                 $query->finish;
-                die("no instances on storage volume or volume is not avaiable for key: $key volume: $vol_name");
+                die("no instances on storage volume or volume is not available for key: $key volume: $vol_name");
             }
         } else {
@@ -1982,4 +2002,5 @@
             # ext_id, available
 	    if (defined($find_invalid)) {
+		# returns instances which are NOT available (volume not available)
 		$rows = $query->execute($key->path, 0);
 	    }
@@ -1992,4 +2013,7 @@
             }
         }
+	$db->commit;
+	## if we do not call commit here, the transaction stays
+	## open blocking some operations below. 
 
         while (my $row = $query->fetchrow_hashref) {
@@ -2018,4 +2042,8 @@
 }
 
+# this method returns instances on the specified volume
+# or a list of all available instances
+# it does NOT choose instances based on proximity
+# and it does NOT return invalid instances
 sub find_instances_for_cull
 {
@@ -2061,4 +2089,6 @@
     my $db  = $self->db($key);
 
+    ## XXX this method is missing the alias deference section (see find_instances)
+
     # the key's volume can't be validiated on input for this method so we have
     # to check it after parsing the key
@@ -2111,4 +2141,5 @@
         $log->logdie("database error: $@");
     }
+    $db->commit;
 
     # XXX remove this?
@@ -2222,5 +2253,4 @@
                 }
             }
-
             $db->commit;
             $log->debug("commit");
@@ -2282,4 +2312,5 @@
         $stat = $query->fetchrow_arrayref;
         $query->finish;
+	$db->commit;
     };
     $log->logdie("database error: $@") if $@;
@@ -2318,4 +2349,5 @@
     };
     $log->logdie("database error: $@") if $@;
+    $db->commit;
 
     $log->logdie("no mounted volumes found") unless (scalar @$stats);
@@ -2415,5 +2447,9 @@
     my ($key, $name, $hard_volume) = @_;
     
-#    $log->warn("_g_s_v: key:>$key< name:>$name< hard_vol:>$hard_volume<");
+    # track the number of calls to this function and
+    # give up after 10 attempts
+    $get_storage_volume_calls ++;
+
+#   $log->warn("_g_s_v: key:>$key< name:>$name< hard_vol:>$hard_volume<");
     my $sql = $self->sql;
     my $db  = $self->db($key);
@@ -2430,4 +2466,5 @@
             unless ($rows > 0) {
                 $query->finish;
+		$db->commit;
 
                 # if a volume name was specified, and is soft, and we failed to
@@ -2442,4 +2479,5 @@
             if ($rows > 1) {
                 $query->finish;
+		$db->commit;
                 die("affected row count is $rows instead of 1");
             }
@@ -2449,8 +2487,12 @@
             $rows = $query->execute($max_used_space, 1, 1, $topfew_count);
 #	    $log->warn("Storage_volume: $rows $topfew_count");
-            # there has to be atleast one storage volume
+            # there has to be at least one storage volume
             unless ($rows > 0) {
                 $query->finish;
-                die("no storage volume is available for key: $key volume: $name hard_volume: $hard_volume");
+		$db->commit;
+		# prevent failure in the die due to undefined variables
+		my $hard_volume_str = defined $hard_volume ? $hard_volume : "undefined";
+		my $name_str = defined $name ? $name : "undefined";
+                die("no storage volume is available for key: $key volume: $name_str hard_volume: $hard_volume_str");
             }
         }
@@ -2465,5 +2507,9 @@
             $log->error($@);
             $log->debug("retrying...");
-            return $self->_get_storage_volume(@_);
+	    if ($get_storage_volume_calls < 10) {
+		return $self->_get_storage_volume(@_);
+	    }
+	    # else
+	    $log->logdie("no available storage volume: $@");
         } 
         # else
@@ -2502,5 +2548,5 @@
 	unless ($rows > 0) {
 	    $query->finish;
-	    die("Requested key $key does not exist");
+	    die("Requested key $key does not exist (or cabinet is undefined)");
 	}
 	if ($rows == 1) {
@@ -2513,16 +2559,18 @@
 	    }
 	    $query->finish;
-	}
-	else {
+	} else {
+	    # if instances are spread across multiple cabinets, allow the next instance to go anywhere
+	    # NOTE: this does not prevent the new instance from going to the same volume as one of the existing instances
 	    $forbidden_cabinet = 0;
 	    $forbidden_site    = 0;
 	    $query->finish;
 	}
-	    
+	$db->commit;
 
         $query = $db->prepare_cached( $sql->get_replication_volume_for_ext_id );
-        # ext_id, %free, avaiable, allocate
+        # ext_id, %free, available, allocate
+
         $rows = $query->execute($key->path, $max_used_space, 1, 1, $forbidden_cabinet, $forbidden_site, $topfew_count);
-        # XXX destinguish between non-existant and unaviable
+        # XXX destinguish between non-existant and unavailable
         unless ($rows > 0) {
             $query->finish;
@@ -2544,4 +2592,5 @@
         ($vol_id, $vol_host, $vol_path, $xattr, $free) = $query->fetchrow_array;
         $query->finish;
+	$db->commit;
     };
     $log->logdie("database error: $@") if $@;
@@ -2590,4 +2639,6 @@
         ($ext_id) = $query->fetchrow_array;
         $query->finish;
+        $db->commit;
+	## if we do not call commit here, the transaction stays open blocking some operations below
     };
     if ($@) {
@@ -2612,5 +2663,6 @@
 }
 
-
+# in the past, _is_valid_volume_name returned 'undef'.  
+# now it either returns 1 (success) or 0 (failure)
 sub _is_valid_volume_name
 {
@@ -2650,4 +2702,5 @@
         ($vol_id, $vol_path, $free) = $query->fetchrow_array;
         $query->finish;
+        $db->commit;
     };
     $log->logdie("database error: $@") if $@;
