void _applyOpToDataFiles( const string& database, FileOp &fo, bool afterAllocator, const string& path ) { if ( afterAllocator ) FileAllocator::get()->waitUntilFinished(); string c = database; c += '.'; boost::filesystem::path p(path); if (storageGlobalParams.directoryperdb) p /= database; boost::filesystem::path q; q = p / (c+"ns"); bool ok = false; MONGO_ASSERT_ON_EXCEPTION( ok = fo.apply( q ) ); if ( ok ) { LOG(2) << fo.op() << " file " << q.string() << endl; } int i = 0; int extra = 10; // should not be necessary, this is defensive in case there are missing files while ( 1 ) { verify( i <= DiskLoc::MaxFiles ); stringstream ss; ss << c << i; q = p / ss.str(); MONGO_ASSERT_ON_EXCEPTION( ok = fo.apply(q) ); if ( ok ) { if ( extra != 10 ) { LOG(1) << fo.op() << " file " << q.string() << endl; log() << " _applyOpToDataFiles() warning: extra == " << extra << endl; } } else if ( --extra <= 0 ) break; i++; } }
// this function is shared by chmod/utime/chown maybe others // it's here for directories which may span multiple backends // returns PLFS_SUCCESS or PLFS_E* static plfs_error_t plfs_flatfile_operation(struct plfs_physpathinfo *ppip, FileOp& op, IOStore *ios) { plfs_error_t ret = PLFS_SUCCESS; vector<plfs_pathback> dirs; struct stat st; mode_t mode = 0; ret = ppip->canback->store->Lstat(ppip->canbpath.c_str(), &st); if (ret != PLFS_SUCCESS){ mode = 0; } else { mode = st.st_mode; } //perform operation on ALL directories if (S_ISDIR(mode)){ ret = generate_backpaths(ppip, dirs); vector<plfs_pathback>::reverse_iterator ritr; for(ritr = dirs.rbegin(); ritr != dirs.rend() && ret == PLFS_SUCCESS; ++ritr) { ret = op.op(ritr->bpath.c_str(),DT_DIR,ritr->back->store); } } //we hit a regular flat file else if(S_ISREG(mode)){ ret = op.op(ppip->canbpath.c_str(), DT_REG, ios); } //symlink else if (S_ISLNK(mode)){ ret = op.op(ppip->canbpath.c_str(), DT_LNK, ios); } return(ret); }
/** * plfs_backends_op: apply a fileop to all the backends in a mount. * currently used by readdir, rmdir, mkdir * this doesn't require the dires to already exist * * @param ppip the phyiscal path we are operating on * @param op the file op to apply * @return PLFS_SUCCESS or PLFS_E* */ plfs_error_t plfs_backends_op(struct plfs_physpathinfo *ppip, FileOp& op) { plfs_error_t ret = PLFS_SUCCESS; vector<plfs_pathback> exps; vector<plfs_pathback>::iterator itr; if ( (ret = generate_backpaths(ppip, exps)) != PLFS_SUCCESS ) { return(ret); } for(itr = exps.begin(); itr != exps.end() && ret == PLFS_SUCCESS; itr++ ) { ret = op.op(itr->bpath.c_str(),DT_DIR,itr->back->store); mlog(INT_DCOMMON, "%s on %s: %d",op.name(),itr->bpath.c_str(),ret); } return(ret); }
// this function is shared by chmod/utime/chown maybe others // it's here for directories which may span multiple backends // returns 0 or -err int plfs_flatfile_operation(const char *logical, FileOp& op, IOStore *ios) { FLAT_ENTER; vector<plfs_pathback> dirs; mode_t mode = 0; ret = is_plfs_file(logical, &mode); //perform operation on ALL directories if (S_ISDIR(mode)){ ret = find_all_expansions(logical, dirs); vector<plfs_pathback>::reverse_iterator ritr; for(ritr = dirs.rbegin(); ritr != dirs.rend() && ret == 0; ++ritr) { ret = op.op(ritr->bpath.c_str(),DT_DIR,ritr->back->store); } } //we hit a regular flat file else if(S_ISREG(mode)){ ret = op.op(path.c_str(), DT_REG, ios); } //symlink else{ ret = op.op(path.c_str(), DT_LNK, ios); } FLAT_EXIT(ret); }
/** * plfs_file_operation: this function is shared by * chmod/utime/chown/etc. anything that needs to operate on possibly * a lot of items either on a bunch of dirs across the backends or on * a bunch of entries within a container Be careful. This performs a * stat. Do not use for performance critical operations. If needed, * then you'll have to figure out how to cheaply pass the mode_t in * * @param ppip the phyiscal path we are working with * @param op the FileOp operation we are going to perform * @return PLFS_SUCCESS or PLFS_E* */ static plfs_error_t plfs_file_operation(struct plfs_physpathinfo *ppip, FileOp& op) { plfs_error_t ret = PLFS_SUCCESS; vector<plfs_pathback> files, dirs, links; string accessfile; struct plfs_pathback pb; // first go through and find the set of physical files and dirs // that need to be operated on // if it's a PLFS file, then maybe we just operate on // the access file, or maybe on all subentries // if it's a directory, then we operate on all backend copies // else just operate on whatever it is (ENOENT, symlink) mode_t mode = 0; ret = (is_container_file(ppip,&mode) == false) ? PLFS_SUCCESS : PLFS_TBD; bool is_container = false; // differentiate btwn logical dir and container if (S_ISREG(mode)) { // it's a PLFS file if (op.onlyAccessFile()) { pb.bpath = Container::getAccessFilePath(ppip->canbpath); pb.back = ppip->canback; files.push_back(pb); ret = PLFS_SUCCESS; // ret was one from is_container_file } else { // everything is_container = true; accessfile = Container::getAccessFilePath(ppip->canbpath); ret = plfs_collect_from_containers(ppip,files,dirs,links); } } else if (S_ISDIR(mode)) { // need to iterate across dirs ret = generate_backpaths(ppip, dirs); } else { // ENOENT, a symlink, somehow a flat file in here pb.bpath = ppip->canbpath; pb.back = ppip->canback; files.push_back(pb); // we might want to reset ret to 0 here } // now apply the operation to each operand so long as ret==0. dirs must be // done in reverse order and files must be done first. This is necessary // for when op is unlink since children must be unlinked first. for the // other ops, order doesn't matter. vector<plfs_pathback>::reverse_iterator ritr; for(ritr = files.rbegin(); ritr != files.rend() && ret == PLFS_SUCCESS; ++ritr) { // In container mode, we want to special treat accessfile deletion, // because once accessfile deleted, the top directory will no longer // be viewed as a container. Defer accessfile deletion until last moment // so that if anything fails in the middle, the container information // remains. if (is_container && accessfile == ritr->bpath) { mlog(INT_DCOMMON, "%s skipping accessfile %s", __FUNCTION__, ritr->bpath.c_str()); continue; } mlog(INT_DCOMMON, "%s on %s",__FUNCTION__,ritr->bpath.c_str()); ret = op.op(ritr->bpath.c_str(),DT_REG,ritr->back->store); } for(ritr = links.rbegin(); ritr != links.rend() && ret == PLFS_SUCCESS; ++ritr) { op.op(ritr->bpath.c_str(),DT_LNK,ritr->back->store); } for(ritr = dirs.rbegin(); ritr != dirs.rend() && ret == PLFS_SUCCESS; ++ritr) { if (is_container && ritr->bpath == ppip->canbpath) { mlog(INT_DCOMMON, "%s skipping canonical top directory%s", __FUNCTION__, ppip->canbpath.c_str()); continue; } ret = op.op(ritr->bpath.c_str(), is_container?(unsigned char)DT_CONTAINER:(unsigned char)DT_DIR, ritr->back->store); } if (is_container) { mlog(INT_DCOMMON, "%s processing access file and canonical top dir", __FUNCTION__); ret = op.op(accessfile.c_str(), DT_REG, ppip->canback->store); if (ret == PLFS_SUCCESS) ret = op.op(ppip->canbpath.c_str(), DT_CONTAINER, ppip->canback->store); } mlog(INT_DAPI, "%s: ret %d", __FUNCTION__,ret); return(ret); }