]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
uclient: implement readdir_r_cb (callback based readdir)
authorSage Weil <sage@newdream.net>
Wed, 8 Sep 2010 18:31:19 +0000 (11:31 -0700)
committerSage Weil <sage@newdream.net>
Wed, 8 Sep 2010 18:31:19 +0000 (11:31 -0700)
This lets us know whether the caller is able to consume an entry before
advancing our position.

src/client/Client.cc
src/client/Client.h

index 62340fd35ea81482229326ac50e9a3e0bf020c09..144717cb69d28fd4283ea544966147cdc7ba36db 100644 (file)
@@ -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<DirEntry> &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;
index 34129f09c16db680ab3a29f8044010159d7e63c1..c123a780fe0d7524c9b088a62df5ce96f294df12 100644 (file)
@@ -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);