os/: Add CollectionIndex::prep_delete

If an unlink is interupted between removing the file
and updating the subdir attribute, the attribute will
overestimate the number of files in the directory.  This
is by design, at worst we will merge the collection later
than intended, but closing the gap would require a second
subdir xattr update.  However, this can in extreme cases
result in a collection with subdirectories but no objects.
FileStore::_destry_collection would therefore see an
erroneous -ENOTEMPTY.

prep_delete allows the CollectionIndex implementation to
clean up state prior to removal.

Signed-off-by: Samuel Just <sam.just@inktank.com>
This commit is contained in:
Samuel Just 2012-11-17 18:18:23 -08:00
parent a48dee547c
commit fdc5e5d187
4 changed files with 47 additions and 0 deletions

View File

@ -180,6 +180,9 @@ protected:
vector<hobject_t> *ls ///< [out] Listed Objects
) = 0;
/// Call prior to removing directory
virtual int prep_delete() { return 0; }
/// Virtual destructor
virtual ~CollectionIndex() {}
};

View File

@ -4464,6 +4464,15 @@ int FileStore::_create_collection(coll_t c)
int FileStore::_destroy_collection(coll_t c)
{
{
Index from;
int r = get_index(c, &from);
if (r < 0)
return r;
r = from->prep_delete();
if (r < 0)
return r;
}
char fn[PATH_MAX];
get_cdir(c, fn, sizeof(fn));
dout(15) << "_destroy_collection " << fn << dendl;

View File

@ -333,6 +333,34 @@ int HashIndex::_collection_list_partial(const hobject_t &start,
return list_by_hash(path, min_count, max_count, seq, next, ls);
}
int HashIndex::prep_delete() {
return recursive_remove(vector<string>());
}
int HashIndex::recursive_remove(const vector<string> &path) {
set<string> subdirs;
int r = list_subdirs(path, &subdirs);
if (r < 0)
return r;
map<string, hobject_t> objects;
r = list_objects(path, 0, 0, &objects);
if (r < 0)
return r;
if (objects.size())
return -ENOTEMPTY;
vector<string> subdir(path);
for (set<string>::iterator i = subdirs.begin();
i != subdirs.end();
++i) {
subdir.push_back(*i);
r = recursive_remove(subdir);
if (r < 0)
return r;
subdir.pop_back();
}
return remove_path(path);
}
int HashIndex::start_col_split(const vector<string> &path) {
bufferlist bl;
InProgressOp op_tag(InProgressOp::COL_SPLIT, path);

View File

@ -148,6 +148,9 @@ public:
/// @see CollectionIndex
int cleanup();
/// @see CollectionIndex
int prep_delete();
/// @see CollectionIndex
int _split(
uint32_t match,
@ -186,6 +189,10 @@ protected:
hobject_t *next
);
private:
/// Recursively remove path and its subdirs
int recursive_remove(
const vector<string> &path ///< [in] path to remove
); /// @return Error Code, 0 on success
/// Tag root directory at beginning of col_split
int start_col_split(
const vector<string> &path ///< [in] path to split