Changeset 26292
- Timestamp:
- Nov 30, 2009, 1:54:49 PM (16 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 7 edited
-
Nebulous-Server/Build.PL (modified) (1 diff)
-
Nebulous-Server/MANIFEST (modified) (1 diff)
-
Nebulous-Server/bin/neb-cabadd (added)
-
Nebulous-Server/bin/neb-voladm (modified) (9 diffs)
-
Nebulous-Server/bin/nebdiskd (modified) (4 diffs)
-
Nebulous-Server/lib/Nebulous/Server.pm (modified) (10 diffs)
-
Nebulous-Server/lib/Nebulous/Server/SQL.pm (modified) (10 diffs)
-
Nebulous/lib/Nebulous/Client.pm (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Nebulous-Server/Build.PL
r24488 r26292 46 46 bin/neb-fsck 47 47 bin/neb-initdb 48 bin/neb-cabadd 48 49 bin/neb-voladd 49 50 bin/neb-voladm -
trunk/Nebulous-Server/MANIFEST
r24915 r26292 8 8 bin/neb-initdb 9 9 bin/neb-voladd 10 bin/neb-cabadd 11 bin/neb-voladm 10 12 bin/nebdiskd 11 13 docs/database_setup.txt -
trunk/Nebulous-Server/bin/neb-voladm
r24842 r26292 23 23 $allocate, 24 24 $available, 25 $mounted, 25 26 $db, 26 27 $dbhost, … … 31 32 $vname, 32 33 $xattr, 34 $cab_id, 33 35 ); 34 36 … … 41 43 'allocate=i' => \$allocate, 42 44 'available=i' => \$available, 45 'mounted' => \$mounted, 43 46 'db|d=s' => \$db, 44 47 'debug' => \$debug, … … 48 51 'vhost=s' => \$vhost, 49 52 'vname|n=s' => \$vname, 53 'cab_id|c=i' => \$cab_id, 50 54 'xattr=i' => \$xattr, 51 55 ) || pod2usage( 2 ); … … 56 60 57 61 # are we listing the volumes or updating? 58 if (defined $allocate or defined $available or defined $xattr ) {59 pod2usage( -msg => "Options: --allocate, --available, and --xattrRequire options --vhost or --vname", -exitval => 2 )62 if (defined $allocate or defined $available or defined $xattr or defined $cab_id) { 63 pod2usage( -msg => "Options: --allocate, --available, --xattr, and --cab_id Require options --vhost or --vname", -exitval => 2 ) 60 64 unless defined $vhost or defined $vname; 61 65 pod2usage( -msg => "Options: --allocate, --available, and --xattr Must be 0 or 1", -exitval => 2) … … 84 88 $set{'v.available'} = $available if defined $available; 85 89 $set{'v.xattr'} = $xattr if defined $xattr; 90 $set{'v.cab_id'} = $cab_id if defined $cab_id; 86 91 87 92 if (%set) { … … 97 102 die $@; 98 103 } 104 if ($mounted) { 105 eval { 106 my ($q, @bind) = sql_interp("UPDATE mountedvol AS v SET", \%set, "WHERE", \%constraint); 107 warn "$q\n" if $debug; 108 my $query = $dbh->prepare($q); 109 $query->execute(@bind); 110 $dbh->commit; 111 }; 112 if ($@) { 113 $dbh->rollback; 114 die $@; 115 } 116 } 99 117 } 100 118 … … 132 150 neb-voladm [--vname <volume name>] [--vhost <volume host>] 133 151 [--allocate <0|1>] [--available <0|1>] [--xattr <0|1>] 152 [--cab_id <cab_id>] 134 153 [--host <database host> ] [--db <database name>] 135 154 [--user <database username>] [--pass <database password>] … … 164 183 165 184 Enables/Disables these flags on the storage volume. 185 186 Requires either the C<--vname> or c<--vhost> options. 187 188 =item * --cab_id <cab_id> 189 190 Sets the cabinet id for this storage volume. 166 191 167 192 Requires either the C<--vname> or c<--vhost> options. -
trunk/Nebulous-Server/bin/nebdiskd
r24617 r26292 177 177 178 178 eval { 179 my $r_query = $dbh->prepare_cached("REPLACE INTO mountedvol SELECT *, ?, ? FROM volume WHERE mountpoint = ?"); 179 my $r_query = $dbh->prepare_cached("REPLACE INTO mountedvol SELECT vol_id,name,host,path,allocate,available,xattr,mountpoint, ?, ? FROM volume WHERE mountpoint = ?"); 180 # my $d_query = $dbh->prepare_cached("UPDATE mountedvol SET allocate = ?, available = ? WHERE mountpoint = ?"); 180 181 my $d_query = $dbh->prepare_cached("DELETE FROM mountedvol WHERE mountpoint = ?"); 181 182 … … 185 186 # there may be multiple vol_ids per mountpoint but we only need to 186 187 # check each mointpont once 187 my $query = $dbh->prepare_cached("SELECT DISTINCT mountpoint FROM volume WHERE available = 1");188 my $query = $dbh->prepare_cached("SELECT DISTINCT mountpoint FROM volume"); 188 189 $query->execute; 189 190 while (my $row = $query->fetchrow_hashref) { … … 200 201 # automounter and it fails to mount 201 202 my $tries = 0; 203 my $valid_mountpoint = 1; 202 204 TEST: eval { 203 205 $tries++; 204 206 unless (is_mountpoint($mountpoint)) { 205 $log->warn("$mnt is not a valid mountpoint"); 207 $log->warn("$mountpoint is not a valid mountpoint ($tries)"); 208 $valid_mountpoint = 0; 206 209 } 207 210 }; 208 if ( $@) {211 if (!$valid_mountpoint) { 209 212 # try is_mountpoint() again if $retry > 1 210 213 if ($tries < $retry) { … … 212 215 goto TEST; 213 216 } 214 $log->warn($@); 217 $log->warn("Removing $mountpoint from the mountedvol table ($tries > $retry)"); 218 # $log->warn($@); 219 215 220 $d_query->execute($mountpoint); 216 221 next; -
trunk/Nebulous-Server/lib/Nebulous/Server.pm
r24995 r26292 35 35 use constant NFS_RETRY_WAIT => 1; 36 36 use constant TRANS_RETRY_WAIT => 1; 37 38 # This is the umask hack. 39 umask(0002); 40 41 # This determines how many entries from the list of volumes sorted by free space are randomized. 42 my $topfew_count = 3; 37 43 38 44 # transaction restart/retry regex … … 905 911 } 906 912 907 # In MySQL you can't select from a table you rdeleting rows from so913 # In MySQL you can't select from a table you're deleting rows from so 908 914 # we first have to get a list of instances to be removed, and then 909 # remove dthem.915 # remove them. 910 916 my $rows_found; 911 917 { 912 918 my $query = $db->prepare_cached( $sql->find_dead_instances_by_so_id ); 913 919 $rows_found = $query->execute( $so_id ); 914 foreach my $row ($query->fetchrow_hashref) { 920 my $i = 0; 921 while (my $row = $query->fetchrow_hashref) { 915 922 # remove dead instances 923 # $log->warn("copied: $rows_copied found: $rows_found removed: $rows_removed"); 916 924 my $query = $db->prepare_cached( $sql->delete_instance_by_ins_id); 917 925 $rows_removed += $query->execute( $row->{ins_id} ); … … 919 927 $query->finish; 920 928 } 921 929 # $log->warn("copied: $rows_copied found: $rows_found removed: $rows_removed"); 922 930 # sanity check 923 931 die("instances inaccessible ($rows_copied) != instances removed ($rows_removed)") … … 1692 1700 } 1693 1701 1702 sub find_instances_for_cull 1703 { 1704 my $self = shift; 1705 1706 my $log = $self->log; 1707 $log->debug("entered - @_"); 1708 1709 my ($key, $vol_name) = validate_pos(@_, 1710 { 1711 type => SCALAR, 1712 callbacks => { 1713 'is valid object key' => sub { $self->_is_valid_object_key($_[0]) }, 1714 }, 1715 }, 1716 { 1717 type => SCALAR|UNDEF, 1718 # callbacks => { 1719 # # check that the volume name requested is valid 1720 # 'is valid volume name' => sub { 1721 # return 1 if not defined $_[0]; 1722 # $self->_is_valid_volume_name($_[0]) 1723 # }, 1724 # }, 1725 optional => 1, 1726 }, 1727 ); 1728 1729 my $sql = $self->sql; 1730 1731 # unless ($key) { 1732 # $log->warn("key was undefined after validate_pos(), trying again..."); 1733 # return $self->find_instances(@_); 1734 # } 1735 1736 # vol_name overrides the key implied volume 1737 eval { 1738 $key = parse_neb_key($key, $vol_name); 1739 }; 1740 $log->logdie("$@") if $@; 1741 $vol_name = $key->volume; 1742 1743 my $db = $self->db($key); 1744 1745 # the key's volume can't be validiated on input for this method so we have 1746 # to check it after parsing the key 1747 if (defined $vol_name 1748 and not $self->_is_valid_volume_name($key, $key->volume)) { 1749 if ($key->hard_volume) { 1750 $log->logdie("$vol_name is not a valid volume name"); 1751 } else { 1752 $log->warn( "$vol_name is not a known volume name" ); 1753 $vol_name = undef; 1754 } 1755 } 1756 1757 my @locations; 1758 eval { 1759 my $query; 1760 if ($vol_name) { 1761 $query = $db->prepare_cached( $sql->get_object_instances_by_vol_name ); 1762 # ext_id, name, available 1763 my $rows = $query->execute($key->path, $vol_name, 1); 1764 unless ($rows > 0) { 1765 $query->finish; 1766 die("no instances on storage volume or volume is not avaiable for key: $key volume: $vol_name"); 1767 } 1768 } else { 1769 $query = $db->prepare_cached( $sql->get_object_instances ); 1770 # ext_id, available 1771 my $rows = $query->execute($key->path, 1); 1772 unless ($rows > 0) { 1773 $query->finish; 1774 die("no instances available for key: $key"); 1775 } 1776 } 1777 1778 while (my $row = $query->fetchrow_hashref) { 1779 # my $instance_hash = { uri => $row->{ 'uri' }, 1780 # vol_id => $row->{ 'vol_id' }, 1781 # cab_id => $row->{ 'cab_id'} }; 1782 my $instance = $row->{ 'uri' }; 1783 push @locations, $row if $instance; 1784 } 1785 }; 1786 if ($@) { 1787 $db->rollback; 1788 # handle soft volumes 1789 if (defined $vol_name and not defined $key->hard_volume) { 1790 $log->debug("retrying with 'any' volume"); 1791 return $self->find_instances($key->path, 'any'); 1792 } 1793 $log->logdie("database error: $@"); 1794 } 1795 1796 # XXX remove this? 1797 $log->logdie("no instances found") unless (scalar @locations); 1798 1799 $log->debug("found: @locations"); 1800 1801 $log->debug("leaving"); 1802 1803 return \@locations; 1804 } 1805 1694 1806 1695 1807 sub delete_instance … … 1984 2096 1985 2097 my ($key, $name, $hard_volume) = @_; 1986 2098 2099 # $log->warn("_g_s_v: key:>$key< name:>$name< hard_vol:>$hard_volume<"); 1987 2100 my $sql = $self->sql; 1988 2101 my $db = $self->db($key); … … 1996 2109 # %free, name, avaiable, allocate 1997 2110 $rows = $query->execute(0.95, $name, 1, 1); 1998 # XXX destinguish between non-existant and unav iable2111 # XXX destinguish between non-existant and unavailable 1999 2112 unless ($rows > 0) { 2000 2113 $query->finish; … … 2016 2129 $query = $db->prepare_cached( $sql->get_storage_volume ); 2017 2130 # %free, avaiable, allocate 2018 $rows = $query->execute(0.95, 1, 1 );2131 $rows = $query->execute(0.95, 1, 1, $topfew_count); 2019 2132 # there has to be atleast one storage volume 2020 2133 unless ($rows > 0) { … … 2062 2175 my $db = $self->db($key); 2063 2176 2064 my ($vol_id, $vol_host, $vol_path, $xattr );2177 my ($vol_id, $vol_host, $vol_path, $xattr, $forbidden_cabinet); 2065 2178 eval { 2066 2179 my $rows; 2067 my $query = $db->prepare_cached( $sql->get_replication_volume_for_ext_id ); 2180 2181 my $query = $db->prepare_cached( $sql->get_cabinets_for_ext_id ); 2182 $rows = $query->execute($key->path); 2183 unless ($rows > 0) { 2184 $query->finish; 2185 die("Requested key $key does not exist"); 2186 } 2187 if ($rows == 1) { 2188 ($forbidden_cabinet) = $query->fetchrow_array; 2189 unless (defined($forbidden_cabinet)) { 2190 $forbidden_cabinet = 0; 2191 } 2192 $query->finish; 2193 } 2194 else { 2195 $forbidden_cabinet = 0; 2196 $query->finish; 2197 } 2198 2199 2200 $query = $db->prepare_cached( $sql->get_replication_volume_for_ext_id ); 2068 2201 # ext_id, %free, avaiable, allocate 2069 $rows = $query->execute($key->path, 0.95, 1, 1 );2202 $rows = $query->execute($key->path, 0.95, 1, 1, $forbidden_cabinet, $topfew_count); 2070 2203 # XXX destinguish between non-existant and unaviable 2071 2204 unless ($rows > 0) { … … 2175 2308 2176 2309 # handle "any" volume 2177 if ( $vol_name eq 'any') {2310 if (($vol_name eq 'any')||($vol_name eq 'any.0')) { 2178 2311 $log->debug( "found volume name $vol_name" ); 2179 2312 $log->debug( "leaving" ); … … 2200 2333 $log->debug( "leaving" ); 2201 2334 2202 return ;2335 return 0; 2203 2336 } 2204 2337 -
trunk/Nebulous-Server/lib/Nebulous/Server/SQL.pm
r24915 r26292 237 237 storage_object.so_id, 238 238 uri, 239 available 239 mountedvol.available, 240 vol_id, 241 cab_id 240 242 FROM storage_object 241 243 JOIN instance … … 243 245 JOIN mountedvol 244 246 USING(vol_id) 245 WHERE ext_id = ? 246 AND available = ? 247 JOIN volume 248 USING(vol_id) 249 WHERE ext_id = ? 250 AND mountedvol.available = ? 247 251 }, 248 252 get_object_instances_by_vol_name => qq{ 249 253 SELECT 250 254 storage_object.so_id, 251 uri 255 uri, 256 vol_id, 257 cab_id 252 258 FROM storage_object 253 259 JOIN instance … … 255 261 JOIN mountedvol 256 262 USING(vol_id) 257 WHERE ext_id = ? 258 AND name = ? 259 AND available = ? 260 }, 263 JOIN volume 264 USING(vol_id) 265 WHERE ext_id = ? 266 AND mountedvol.name = ? 267 AND mountedvol.available = ? 268 }, 269 # volume handler 261 270 get_storage_volume_by_name => qq{ 262 271 SELECT … … 275 284 LIMIT 1 276 285 }, 277 get_replication_volume_for_ext_id => qq{ 286 # volume handler 287 get_cabinets_for_ext_id => qq{ 288 SELECT DISTINCT 289 cab_id 290 FROM instance 291 JOIN volume ON instance.vol_id = volume.vol_id 292 JOIN storage_object USING(so_id) 293 WHERE ext_id = ? 294 }, 295 get_replication_volume_for_ext_id => qq{ 296 SELECT * FROM ( 278 297 SELECT 279 298 m.vol_id, 280 host,281 path,282 xattr,299 m.host, 300 m.path, 301 m.xattr, 283 302 total - used as free 284 303 FROM mountedvol AS m 285 LEFT JOIN instance AS i 304 JOIN volume AS v USING(vol_id) 305 LEFT JOIN ( 306 SELECT 307 instance.vol_id, 308 so_id 309 FROM instance 310 JOIN volume 311 ON instance.vol_id = volume.vol_id 312 ) AS i 286 313 ON m.vol_id = i.vol_id 287 314 AND i.so_id = ( … … 290 317 WHERE ext_id = ? 291 318 ) 292 WHERE 293 i.vol_id IS NULL 294 AND used / total < ? 295 AND available = ? 296 AND allocate = ? 297 ORDER BY RAND() 298 LIMIT 1 299 }, 319 WHERE 320 i.vol_id IS NULL 321 AND used / total < ? 322 AND m.available = ? 323 AND m.allocate = ? 324 AND ( (v.cab_id IS NULL) || 325 (v.cab_id != ?) ) 326 ORDER BY free DESC 327 LIMIT ?) as topfew 328 ORDER BY RAND() 329 LIMIT 1 330 }, 331 # volume handler 300 332 get_storage_volume => qq{ 333 SELECT * from ( 301 334 SELECT 302 335 vol_id, … … 311 344 AND allocate = ? 312 345 ORDER BY free DESC 346 LIMIT ?) as topfew 347 ORDER BY RAND() 313 348 LIMIT 1 314 349 }, 350 new_cabinet => qq{ 351 INSERT INTO cabinet (name, location, cab_id) 352 VALUES (?, ?, NULL) 353 }, 315 354 new_volume => qq{ 316 INSERT INTO volume (name, host, path, allocate, available, xattr, mountpoint )317 VALUES (?, ?, ?, TRUE, TRUE, FALSE, ? )355 INSERT INTO volume (name, host, path, allocate, available, xattr, mountpoint, cab_id) 356 VALUES (?, ?, ?, TRUE, TRUE, FALSE, ?, NULL) 318 357 }, 319 358 get_volume_by_name => qq{ … … 331 370 v.available, 332 371 v.xattr, 333 mountedvol.vol_id IS NOT NULL as mounted 372 mountedvol.vol_id IS NOT NULL as mounted, 373 v.cab_id 334 374 FROM volume AS v 335 375 LEFT JOIN mountedvol … … 614 654 ### 615 655 656 CREATE TABLE cabinet ( 657 cab_id INT NOT NULL AUTO_INCREMENT, 658 name VARCHAR(255) NOT NULL, 659 location VARCHAR(255), 660 PRIMARY KEY(cab_id), 661 UNIQUE KEY(name), 662 KEY (location) 663 ) ENGINE=innodb DEFAULT CHARSET=latin1; 664 665 ### 666 616 667 CREATE TABLE volume ( 617 668 vol_id INT NOT NULL AUTO_INCREMENT, … … 623 674 xattr BOOLEAN DEFAULT FALSE, 624 675 mountpoint VARCHAR(255) NOT NULL, 676 cab_id INT, 625 677 PRIMARY KEY(vol_id), 626 678 UNIQUE KEY(name), … … 629 681 KEY(allocate), 630 682 KEY(available), 683 FOREIGN KEY(cab_id) REFERENCES cabinet(cab_id), 631 684 KEY(mountpoint(255)) 632 685 ) ENGINE=innodb DEFAULT CHARSET=latin1; -
trunk/Nebulous/lib/Nebulous/Client.pm
r25121 r26292 315 315 my $locations; 316 316 if (defined $vol_name) { 317 $locations = $self->find_instances ($key, $vol_name);317 $locations = $self->find_instances_for_cull($key, $vol_name); 318 318 } else { 319 $locations = $self->find_instances ($key);319 $locations = $self->find_instances_for_cull($key); 320 320 } 321 321 … … 326 326 return; 327 327 } 328 329 my $uri = $self->delete_instance($key, @$locations[0]); 328 329 # Calculate which is the best instance to remove. First, see if we have two copies 330 # on one volume, if so, delete the first of those copies. 331 my $delete_index = -1; 332 333 for (my $i = 0 ; $i <= $#{ $locations }; $i++) { 334 for (my $j = $i + 1; $j <= $#{ $locations }; $j++) { 335 if (@$locations[$i]->{vol_id} eq @$locations[$j]->{vol_id}) { 336 $delete_index = $i; 337 } 338 } 339 } 340 # If we don't have two copies on one volume, see if we have two copies on a single 341 # cabinet. If so, delete the first of those copies. 342 if ($delete_index == -1) { 343 for (my $i = 0 ; $i <= $#{ $locations }; $i++) { 344 for (my $j = $i + 1; $j <= $#{ $locations }; $j++) { 345 if (@$locations[$i]->{cab_id} eq @$locations[$j]->{cab_id}) { 346 $delete_index = $i; 347 } 348 } 349 } 350 } 351 # Fail-safe. We didn't have any duplicates (the instances are "well-mixed"), so 352 # delete the first. 353 if ($delete_index == -1) { 354 $delete_index = 0; 355 } 356 my $uri = $self->delete_instance($key, @$locations[$delete_index]->{uri}); 330 357 331 358 eval { 332 _nuke_file(_get_file_path(@$locations[ 0]));359 _nuke_file(_get_file_path(@$locations[$delete_index]->{uri})); 333 360 }; 334 361 if ($@) { … … 758 785 } 759 786 787 sub find_instances_for_cull 788 { 789 my $self = shift; 790 791 my ( $key, @params ) = validate_pos( @_, 792 { 793 type => SCALAR, 794 }, 795 { 796 #volume 797 type => SCALAR|UNDEF, 798 optional => 1, 799 }, 800 ); 801 802 $log->debug( "entered - @_" ); 803 804 my $response = $self->{ 'server' }->find_instances_for_cull( $key, @params ); 805 if ( $response->fault ) { 806 $self->set_err($response->faultstring); 807 # check to see if this failure is because $key doesn't exist 808 if ($response->faultstring =~ /is valid object key/) { 809 $log->debug( "leaving" ); 810 return; 811 } 812 # key is valid but no instances are on the specified volume 813 if ($response->faultstring =~ /no instances on storage volume/) { 814 $log->debug( "leaving" ); 815 return; 816 } 817 818 $log->logdie("unhandled fault - ", $self->err); 819 } 820 821 my $uris = $response->result; 822 823 $log->debug( "server found: @$uris" ); 824 825 $log->debug( "leaving" ); 826 827 return $uris; 828 } 829 760 830 761 831 sub find
Note:
See TracChangeset
for help on using the changeset viewer.
