Commit f0f635c7 authored by Mike Hibler's avatar Mike Hibler

Deal with a nasty circular dependency when destroying a blockstore.

If we destroy the Blockstore DB state first and then the server-side object
destruction fails, we leave behind a dangling object and potentially Lease DB
state. But if we destroy the object first and the DB state removal fails,
we are left with a blockstore with no server-side object and thus we cannot
look it up in the future to retry the destruction.

We choose to go with the latter and just create a tiny server-side stub
object if the DB state removal fails.
parent efc4eb8d
......@@ -45,24 +45,24 @@ use Getopt::Std;
# The following commands are for persistent blockstores.
# For these, a blockstore name, "bsname", had better be unique.
#
# bscontrol [ -S server [ -P pool ] ] [-l leaseidx] [-f fstype] -s size -t type create bsname
# bscontrol [ -S server [ -P pool ] ] [-f fstype] -l leaseidx -s size -t type create bsname
# Create a blockstore of the given size with the given name.
# If the server is not specified, we pick the "best" server,
# based on availability of space.
#
# bscontrol snapshot [ -S server -P pool ] bsname [ tstamp ]
# bscontrol snapshot [ -S server [ -P pool ] ] bsname [ tstamp ]
# Create a snapshot of the named blockstore with the indicated
# timestamp. If timestamp is not provided, it will use the
# current time. bsname needs to be unique across all servers
# or the server and pool need to be explicitly specified.
#
# bscontrol desnapshot [ -S server -P pool ] bsname [ tstamp ]
# bscontrol desnapshot [ -S server [ -P pool ] ] bsname [ tstamp ]
# Delete the snapshot of the named blockstore with the indicated
# timestamp. If timestamp is not provided, delete all snapshots
# associated with the blockstore. bsname needs to be unique across
# all servers or the server and pool need to be explicitly specified.
#
# bscontrol destroy [ -S server -P pool ] bsname
# bscontrol destroy [ -S server [ -P pool ] ] bsname
# Destroy the named blockstore freeing up the space. Also destroys
# any associated snapshots. bsname needs to be unique across all
# servers or the server and pool need to be explicitly specified.
......@@ -73,13 +73,18 @@ use Getopt::Std;
#
sub usage()
{
print STDERR "Usage: bscontrol command args\n";
print STDERR "Usage: bscontrol [-hd] command args\n";
print STDERR " -h This message\n";
print STDERR " -d Print additional debug info\n";
print STDERR "commands:\n";
print STDERR " list List all blockstore servers\n";
print STDERR " avail For each server, show available storage\n";
print STDERR " info For each server, show all extant volumes\n";
print STDERR "\nAdditional persistent blockstore commands.\n";
print STDERR "bscontrol [-S server [-P pool]] [-f fstype] -l leaseidx -s size -t type create bsname\n";
print STDERR "bscontrol [-S server -P pool] destroy bsname\n";
print STDERR "bscontrol [-S server [-P pool]] snapshot bsname [tstamp]\n";
print STDERR "bscontrol [-S server [-P pool]] desnapshot bsname [tstamp]\n";
exit(-1);
}
my $optlist = "hds:t:l:S:P:Ff:I";
......@@ -560,6 +565,19 @@ sub getvolumes($$)
}
}
if ($debug && keys(%volumes) > 0) {
print STDERR "Found volumes:\n";
foreach my $v (keys(%volumes)) {
my $attrs = $volumes{$v};
print STDERR " $v: ";
foreach my $k (keys(%$attrs)) {
my $v = $attrs->{$k};
print STDERR "$k=$v ";
}
print STDERR "\n";
}
}
return \%volumes;
}
......@@ -963,7 +981,9 @@ sub bs_destroy($$$@)
}
#
# Delete the blockstore object
# Verify that the blockstore object exists and is of the right type.
# We will delete the blockstore object *after* we destroy the server-side
# object. See XXX below for rationale.
#
my $bstore = Blockstore->Lookup($srv, $name);
if (!$bstore && !$ignoredb) {
......@@ -972,9 +992,6 @@ sub bs_destroy($$$@)
if ($bstore && $bstore->role() ne "partition") {
fatal("destroy: wrong type of blockstore '$srv/$name'");
}
if ($bstore && $bstore->Delete()) {
fatal("destroy: could not delete blockstore '$srv/$name' from DB");
}
#
# Call out to the server to delete the storage.
......@@ -1003,15 +1020,41 @@ sub bs_destroy($$$@)
goto fail;
}
#
# After everything else works, delete the actual blockstore object.
#
# XXX There is a nasty circular dependency here where if we were to
# destroy the blockstore DB state first and then the object destruction
# fails, we leave behind a dangling object and potentially Lease DB
# state. But if we destroy the object first and the DB state removal
# fails, we are left with a blockstore with no server object and thus
# we cannot look it up in the future to retry the destruction.
#
# We choose to go with the latter and just create a tiny server-side
# stub object if the DB state removal fails.
#
if ($bstore && $bstore->Delete()) {
print STDERR "*** destroy: ".
"could not destroy Blockstore DB state, ".
"recreating a stub server-side object.\n";
if (bsserver_cmd($srv, "$PROXYCMD create $pool $name 1", \$outref)) {
print STDERR "*** destroy: ".
"re-creation of server-side object failed, ".
"before you can destroy this blockstore ".
"you must manually re-create the object with:\n";
print STDERR " $PROXYCMD create $pool $name 1\n";
goto fail;
}
fatal("destroy: could not delete blockstore '$srv/$name' from DB");
}
return 0;
fail:
foreach my $str (@$outref) {
print STDERR " $str\n";
}
print STDERR "*** blockstore has been removed from DB, ".
"to remove residual state do:\n".
" $0 -I -S srv -P $pool destroy $name\n";
exit(-1);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment