From 561f302207a4ad1c7a1afeb95b49f22a19a6727a Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 8 Sep 2010 11:31:19 -0700 Subject: [PATCH] uclient: implement readdir_r_cb (callback based readdir) This lets us know whether the caller is able to consume an entry before advancing our position. --- src/client/Client.cc | 62 ++++++++++++++++++++++++++++++++++++++++++++ src/client/Client.h | 3 +++ 2 files changed, 65 insertions(+) diff --git a/src/client/Client.cc b/src/client/Client.cc index 62340fd35ea..144717cb69d 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -4003,6 +4003,68 @@ int Client::readdirplus_r(DIR *d, struct dirent *de, struct stat *st, int *stmas assert(0); } +int Client::readdir_r_cb(DIR *d, add_dirent_cb_t cb, void *p) +{ + DirResult *dirp = (DirResult*)d; + + dout(10) << "readdir_r_cb " << *dirp->inode << " offset " << dirp->offset + << " frag " << dirp->frag() << " fragpos " << dirp->fragpos() + << " at_end=" << dirp->at_end() + << dendl; + + struct dirent de; + struct stat st; + memset(&de, 0, sizeof(de)); + memset(&st, 0, sizeof(st)); + + while (1) { + if (dirp->at_end()) + return 0; + + if (dirp->buffer.count(dirp->frag()) == 0) { + Mutex::Locker lock(client_lock); + _readdir_get_frag(dirp); + if (dirp->at_end()) + return 0; + } + + frag_t fg = dirp->frag(); + uint32_t pos = dirp->fragpos(); + assert(dirp->buffer.count(fg)); + vector &ent = dirp->buffer[fg]; + + if (ent.empty() || + pos >= ent.size()) { + dout(10) << "empty frag " << fg << ", moving on to next" << dendl; + _readdir_next_frag(dirp); + continue; + } + + assert(pos < ent.size()); + _readdir_fill_dirent(&de, &ent[pos], dirp->offset); + st = ent[pos].st; + int stmask = ent[pos].stmask; + + int r = cb(p, &de, &st, stmask, dirp->offset + 1); // _next_ offset + if (r < 0) + break; + + dout(15) << " de " << de.d_name << " off " << dirp->offset + << " = " << r + << dendl; + + pos++; + dirp->offset++; + + if (pos == ent.size()) + _readdir_next_frag(dirp); + + return 1; + } + + return 0; +} + int Client::_getdents(DIR *dir, char *buf, int buflen, bool fullent) { DirResult *dirp = (DirResult *)dir; diff --git a/src/client/Client.h b/src/client/Client.h index 34129f09c16..c123a780fe0 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -1173,6 +1173,9 @@ public: int readdir_r(DIR *dirp, struct dirent *de); int readdirplus_r(DIR *dirp, struct dirent *de, struct stat *st, int *stmask); + typedef int (*add_dirent_cb_t)(void *p, struct dirent *de, struct stat *st, int stmask, off_t off); + int readdir_r_cb(DIR *dirp, add_dirent_cb_t cb, void *p); + int _getdents(DIR *dirp, char *buf, int buflen, bool ful); // get a bunch of dentries at once int getdents(DIR *dirp, char *buf, int buflen) { return _getdents(dirp, buf, buflen, true);