]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: lay groundwork for chunky read/write
authorYehuda Sadeh <yehuda@hq.newdream.net>
Mon, 19 Jul 2010 23:20:34 +0000 (16:20 -0700)
committerYehuda Sadeh <yehuda@hq.newdream.net>
Mon, 19 Jul 2010 23:20:54 +0000 (16:20 -0700)
src/rgw/rgw_access.h
src/rgw/rgw_fs.cc
src/rgw/rgw_fs.h
src/rgw/rgw_op.cc
src/rgw/rgw_op.h
src/rgw/rgw_rados.cc
src/rgw/rgw_rados.h
src/rgw/rgw_rest.cc
src/rgw/rgw_rest.h
src/rgw/rgw_user.cc

index 210d86f861feaae7ddb666736a0a4e4c95382c3d..d4862191580935ca6dfc1bb552c8566f65a8338a 100644 (file)
@@ -43,9 +43,19 @@ public:
   virtual int create_bucket(std::string& id, std::string& bucket, map<std::string, bufferlist>& attrs, uint64_t auid=0) = 0;
   /** write an object to the storage device in the appropriate pool
     with the given stats */
-  virtual int put_obj(std::string& id, std::string& bucket, std::string& obj, const char *data, size_t size,
-                      time_t *mtime,
+  virtual int put_obj_meta(std::string& id, std::string& bucket, std::string& obj, time_t *mtime,
                       map<std::string, bufferlist>& attrs) = 0;
+  virtual int put_obj_data(std::string& id, std::string& bucket, std::string& obj, const char *data,
+                      off_t ofs, size_t len, time_t *mtime) = 0;
+
+  int put_obj(std::string& id, std::string& bucket, std::string& obj, const char *data, size_t len,
+              time_t *mtime, map<std::string, bufferlist>& attrs) {
+    int ret = put_obj_meta(id, bucket, obj, NULL, attrs);
+    if (ret >= 0)
+      ret = put_obj_data(id, bucket, obj, data, 0, len, mtime);
+    return ret;
+  }
+
   /**
    * Copy an object.
    * id: unused (well, it's passed to put_obj)
@@ -108,15 +118,19 @@ public:
  *          (if get_data==true) length of read data,
  *          (if get_data==false) length of the object
  */
-  virtual int get_obj(std::string& bucket, std::string& obj, 
-                     char **data, off_t ofs, off_t end,
-                     map<std::string, bufferlist> *attrs,
-                     const time_t *mod_ptr,
-                     const time_t *unmod_ptr,
-                     const char *if_match,
-                     const char *if_nomatch,
-                     bool get_data,
-                     struct rgw_err *err) = 0;
+  virtual int prepare_get_obj(std::string& bucket, std::string& obj, 
+            off_t ofs, off_t *end,
+            map<string, bufferlist> *attrs,
+            const time_t *mod_ptr,
+            const time_t *unmod_ptr,
+            const char *if_match,
+            const char *if_nomatch,
+            bool get_data,
+            void **handle,
+            struct rgw_err *err) = 0;
+
+  virtual int get_obj(void *handle, std::string& bucket, std::string& oid, 
+            char **data, off_t ofs, off_t end) = 0;
 
   /**
    * Get the attributes for an object.
index aa4c9a9f6490a9eab525cb16d071c37a4e57a387..a8a3106f427183bc45b3c4bf265f821d887109d0 100644 (file)
@@ -172,9 +172,8 @@ int RGWFS::create_bucket(std::string& id, std::string& bucket, map<std::string,
   return 0;
 }
 
-int RGWFS::put_obj(std::string& id, std::string& bucket, std::string& obj, const char *data, size_t size,
-                  time_t *mtime,
-                  map<string, bufferlist>& attrs)
+int RGWFS::put_obj_meta(std::string& id, std::string& bucket, std::string& obj,
+                  time_t *mtime, map<string, bufferlist>& attrs)
 {
   int len = strlen(DIR_NAME) + 1 + bucket.size() + 1 + obj.size() + 1;
   char buf[len];
@@ -193,31 +192,58 @@ int RGWFS::put_obj(std::string& id, std::string& bucket, std::string& obj, const
     
     if (bl.length()) {
       r = fsetxattr(fd, name.c_str(), bl.c_str(), bl.length(), 0);
-      if (r < 0) {
-        r = -errno;
-        close(fd);
-        return r;
-      }
+      if (r < 0)
+        goto done_err;
     }
   }
 
-  r = write(fd, data, size);
-  if (r < 0) {
-    r = -errno;
-    close(fd);
-    unlink(buf);
-    return r;
+  if (mtime) {
+    struct stat st;
+    r = fstat(fd, &st);
+    if (r < 0)
+      goto done_err;
+    *mtime = st.st_mtime;
   }
 
+  r = close(fd);
+  if (r < 0)
+    return -errno;
+
+  return 0;
+done_err:
+  r = -errno;
+  close(fd);
+  unlink(buf);
+  return -errno;
+}
+
+int RGWFS::put_obj_data(std::string& id, std::string& bucket, std::string& obj, const char *data,
+                  off_t ofs, size_t size, time_t *mtime)
+{
+  int len = strlen(DIR_NAME) + 1 + bucket.size() + 1 + obj.size() + 1;
+  char buf[len];
+  snprintf(buf, len, "%s/%s/%s", DIR_NAME, bucket.c_str(), obj.c_str());
+  int fd;
+
+  fd = open(buf, O_CREAT | O_WRONLY, 0755);
+  if (fd < 0)
+    return -errno;
+
+  int r;
+
+  r = lseek(fd, ofs, SEEK_SET);
+  if (r < 0)
+    goto done_err;
+
+  r = write(fd, data, size);
+  if (r < 0)
+    goto done_err;
+
   if (mtime) {
     struct stat st;
     r = fstat(fd, &st);
-    if (r < 0) {
-      r = -errno;
-      close(fd);
-      unlink(buf);
-      return -errno;
-    }
+    if (r < 0)
+      goto done_err;
     *mtime = st.st_mtime;
   }
 
@@ -226,6 +252,11 @@ int RGWFS::put_obj(std::string& id, std::string& bucket, std::string& obj, const
     return -errno;
 
   return 0;
+done_err:
+  r = -errno;
+  close(fd);
+  unlink(buf);
+  return r;
 }
 
 int RGWFS::copy_obj(std::string& id, std::string& dest_bucket, std::string& dest_obj,
@@ -240,12 +271,21 @@ int RGWFS::copy_obj(std::string& id, std::string& dest_bucket, std::string& dest
 {
   int ret;
   char *data;
+  void *handle;
+  off_t ofs = 0, end = -1;
 
   map<string, bufferlist> attrset;
-  ret = get_obj(src_bucket, src_obj, &data, 0, -1, &attrset,
-                mod_ptr, unmod_ptr, if_match, if_nomatch, true, err);
+  ret = prepare_get_obj(src_bucket, src_obj, 0, &end, &attrset, mod_ptr, unmod_ptr,
+                        if_match, if_nomatch, true, &handle, err);
   if (ret < 0)
     return ret;
+  do { 
+    ret = get_obj(handle, src_bucket, src_obj, &data, ofs, end);
+    if (ret < 0)
+      return ret;
+    ofs += ret;
+  } while (ofs <= end);
 
   map<string, bufferlist>::iterator iter;
   for (iter = attrs.begin(); iter != attrs.end(); ++iter) {
@@ -375,14 +415,15 @@ int RGWFS::set_attr(std::string& bucket, std::string& obj,
   return ret;
 }
 
-int RGWFS::get_obj(std::string& bucket, std::string& obj, 
-            char **data, off_t ofs, off_t end,
+int RGWFS::prepare_get_obj(std::string& bucket, std::string& obj, 
+            off_t ofs, off_t *end,
             map<string, bufferlist> *attrs,
             const time_t *mod_ptr,
             const time_t *unmod_ptr,
             const char *if_match,
             const char *if_nomatch,
             bool get_data,
+            void **handle,
             struct rgw_err *err)
 {
   int len = strlen(DIR_NAME) + 1 + bucket.size() + 1 + obj.size() + 1;
@@ -390,31 +431,43 @@ int RGWFS::get_obj(std::string& bucket, std::string& obj,
   int fd;
   struct stat st;
   int r = -EINVAL;
-  size_t max_len, pos;
+  size_t max_len;
   char *etag = NULL;
+  off_t size;
+
+
+  GetObjState *state = new GetObjState;
+  if (!state)
+    return -ENOMEM;
 
   snprintf(buf, len, "%s/%s/%s", DIR_NAME, bucket.c_str(), obj.c_str());
 
   fd = open(buf, O_RDONLY, 0755);
 
-  if (fd < 0)
-    return -errno;
+  if (fd < 0) {
+    r = -errno;
+    goto done_err;
+  }
+
+  state->fd = fd;
 
   r = fstat(fd, &st);
   if (r < 0)
     return -errno;
 
-  if (end < 0)
-    end = st.st_size - 1;
+  size = st.st_size;
+
+  if (*end < 0)
+    *end = size - 1;
 
-  max_len = end - ofs + 1;
+  max_len = *end + 1 - ofs;
 
   r = -ECANCELED;
   if (mod_ptr) {
     if (st.st_mtime < *mod_ptr) {
       err->num = "304";
       err->code = "PreconditionFailed";
-      goto done;
+      goto done_err;
     }
   }
 
@@ -422,13 +475,13 @@ int RGWFS::get_obj(std::string& bucket, std::string& obj,
     if (st.st_mtime >= *mod_ptr) {
       err->num = "412";
       err->code = "PreconditionFailed";
-      goto done;
+      goto done_err;
     }
   }
   if (if_match || if_nomatch) {
     r = get_attr(RGW_ATTR_ETAG, fd, &etag);
     if (r < 0)
-      goto done;
+      goto done_err;
  
     r = -ECANCELED;
     if (if_match) {
@@ -436,7 +489,7 @@ int RGWFS::get_obj(std::string& bucket, std::string& obj,
       if (strcmp(if_match, etag)) {
         err->num = "412";
         err->code = "PreconditionFailed";
-        goto done;
+        goto done_err;
       }
     }
 
@@ -445,48 +498,72 @@ int RGWFS::get_obj(std::string& bucket, std::string& obj,
       if (strcmp(if_nomatch, etag) == 0) {
         err->num = "412";
         err->code = "PreconditionFailed";
-        goto done;
+        goto done_err;
       }
     }
   }
 
+  free(etag);
+
   if (!get_data) {
     r = max_len;
     goto done;
   }
-  *data = (char *)malloc(max_len);
-  if (!*data) {
-    r = -ENOMEM;
-    goto done;
-  }
 
-  pos = 0;
-  while (pos < max_len) {
-    r = read(fd, (*data) + pos, max_len);
+  r = 0;
+done:
+  return r;
+
+done_err:
+  delete state;
+  if (fd >= 0)
+    close(fd);
+  return r;
+}
+
+int RGWFS::get_obj(void *handle, std::string& bucket, std::string& obj, 
+            char **data, off_t ofs, off_t end)
+{
+  uint64_t len;
+  bufferlist bl;
+  int r = 0;
+
+  GetObjState *state = (GetObjState *)handle;
+
+  if (end <= 0)
+    len = 0;
+  else
+    len = end - ofs + 1;
+  off_t pos = 0;
+
+  while (pos < (off_t)len) {
+    r = read(state->fd, (*data) + pos, len - pos);
     if (r > 0) {
       pos += r;
     } else {
       if (!r) {
-        cerr << "pos=" << pos << " r=" << r << " max_len=" << max_len << endl;
+        cerr << "pos=" << pos << " r=" << r << " len=" << len << endl;
         r = -EIO; /* should not happen as we validated file size earlier */
-        goto done;
+        break;
       }
       switch (errno) {
       case EINTR:
         break;
       default:
         r = -errno;
-        goto done;
+        break;
       }
     }
-  } 
+  }
 
-  r = max_len;
-done:
-  free(etag);
-  close(fd);  
+  if (r >= 0)
+    r = len;
+
+  if (r < 0 || !len || (off_t)(ofs + len - 1) == end) {
+    close(state->fd);
+    delete state;
+  }
 
   return r;
 }
 
-
index 702fae24705be5351f13a523250a87436b1dd621..95cedfbc17fe1c2a157242eb1822337beff479e1 100644 (file)
@@ -6,6 +6,9 @@
 
 class RGWFS  : public RGWAccess
 {
+  struct GetObjState {
+    int fd;
+  };
 public:
   int list_buckets_init(std::string& id, RGWAccessHandle *handle);
   int list_buckets_next(std::string& id, RGWObjEnt& obj, RGWAccessHandle *handle);
@@ -14,9 +17,10 @@ public:
                    std::string& marker, std::vector<RGWObjEnt>& result, map<string, bool>& common_prefixes);
 
   int create_bucket(std::string& id, std::string& bucket, map<std::string, bufferlist>& attrs, uint64_t auid=0);
-  int put_obj(std::string& id, std::string& bucket, std::string& obj, const char *data, size_t size,
-              time_t *mtime,
+  int put_obj_meta(std::string& id, std::string& bucket, std::string& obj, time_t *mtime,
              map<std::string, bufferlist>& attrs);
+  int put_obj_data(std::string& id, std::string& bucket, std::string& obj, const char *data,
+              off_t ofs, size_t size, time_t *mtime);
   int copy_obj(std::string& id, std::string& dest_bucket, std::string& dest_obj,
                std::string& src_bucket, std::string& src_obj,
                time_t *mtime,
@@ -36,15 +40,19 @@ public:
   int set_attr(std::string& bucket, std::string& obj,
                        const char *name, bufferlist& bl);
 
- int get_obj(std::string& bucket, std::string& obj, 
-            char **data, off_t ofs, off_t end,
-            map<std::string, bufferlist> *attrs,
+ int prepare_get_obj(std::string& bucket, std::string& obj, 
+            off_t ofs, off_t *end,
+           map<std::string, bufferlist> *attrs,
             const time_t *mod_ptr,
             const time_t *unmod_ptr,
             const char *if_match,
             const char *if_nomatch,
             bool get_data,
+            void **handle,
             struct rgw_err *err);
+
+ int get_obj(void *handle, std::string& bucket, std::string& obj, 
+            char **data, off_t ofs, off_t end);
 };
 
 #endif
index 68406ce1558ef68087c39330ef39cc03f39fad5b..fae8c62d0140d76c9dbf06584dd5a316d0606c5b 100644 (file)
@@ -123,6 +123,8 @@ int read_acls(struct req_state *s, bool only_bucket)
 
 void RGWGetObj::execute()
 {
+  void *handle;
+
   if (!verify_permission(s, RGW_PERM_READ)) {
     ret = -EACCES;
     goto done;
@@ -134,13 +136,34 @@ void RGWGetObj::execute()
 
   init_common();
 
-  len = rgwstore->get_obj(s->bucket_str, s->object_str, &data, ofs, end, &attrs,
-                         mod_ptr, unmod_ptr, if_match, if_nomatch, get_data, &err);
-  if (len < 0)
+  len = rgwstore->prepare_get_obj(s->bucket_str, s->object_str, ofs, &end, &attrs, mod_ptr,
+                                  unmod_ptr, if_match, if_nomatch, get_data, &handle, &err);
+
+  if (len < 0) {
     ret = len;
+    goto done;
+  }
+
+  if (!get_data)
+    goto done;
+
+  while (ofs <= end) {
+    len = rgwstore->get_obj(handle, s->bucket_str, s->object_str, &data, ofs, end);
+    if (len < 0) {
+      ret = len;
+      goto done;
+    }
+
+    ofs += len;
+    send_response(handle);
+    free(data);
+  }
+
+  return;
 
 done:
-  send_response();
+  send_response(handle);
+  free(data);
 }
 
 int RGWGetObj::init_common()
index 36ea6d552a891b11bb413e55bd45e17bf418401f..8bf432044c745951c717fcf61f1fb409cc3942d9 100644 (file)
@@ -81,7 +81,7 @@ public:
   void execute();
 
   virtual int get_params() = 0;
-  virtual int send_response() = 0;
+  virtual int send_response(void *handle) = 0;
 };
 
 class RGWListBuckets : public RGWOp {
index af026959de209e193bd387d16594251f5181eada..bbcc619774857f5ef19d4389d4f1b617d1e5f856 100644 (file)
@@ -117,6 +117,11 @@ static int open_pool(string& bucket, rados_pool_t *pool)
 {
   return rados->open_pool(bucket.c_str(), pool);
 }
+
+static int close_pool(rados_pool_t pool)
+{
+  return rados->close_pool(pool);
+}
 /** 
  * get listing of the objects in a bucket.
  * id: ignored.
@@ -244,9 +249,8 @@ int RGWRados::create_bucket(std::string& id, std::string& bucket, map<std::strin
  * attrs: all the given attrs are written to bucket storage for the given object
  * Returns: 0 on success, -ERR# otherwise.
  */
-int RGWRados::put_obj(std::string& id, std::string& bucket, std::string& oid, const char *data, size_t size,
-                  time_t *mtime,
-                  map<string, bufferlist>& attrs)
+int RGWRados::put_obj_meta(std::string& id, std::string& bucket, std::string& oid,
+                  time_t *mtime, map<string, bufferlist>& attrs)
 {
   rados_pool_t pool;
 
@@ -266,9 +270,40 @@ int RGWRados::put_obj(std::string& id, std::string& bucket, std::string& oid, co
     }
   }
 
+  if (mtime) {
+    r = rados->stat(pool, oid, NULL, mtime);
+    if (r < 0)
+      return r;
+  }
+
+  close_pool(pool);
+
+  return 0;
+}
+
+/**
+ * Write/overwrite an object to the bucket storage.
+ * id: ignored
+ * bucket: the bucket to store the object in
+ * obj: the object name/key
+ * data: the object contents/value
+ * size: the amount of data to write (data must be this long)
+ * mtime: if non-NULL, writes the given mtime to the bucket storage
+ * attrs: all the given attrs are written to bucket storage for the given object
+ * Returns: 0 on success, -ERR# otherwise.
+ */
+int RGWRados::put_obj_data(std::string& id, std::string& bucket, std::string& oid, const char *data, off_t ofs, size_t len,
+                  time_t *mtime)
+{
+  rados_pool_t pool;
+
+  int r = open_pool(bucket, &pool);
+  if (r < 0)
+    return r;
+
   bufferlist bl;
-  bl.append(data, size);
-  r = rados->write_full(pool, oid, bl);
+  bl.append(data, len);
+  r = rados->write(pool, oid, ofs, bl, len);
   if (r < 0)
     return r;
 
@@ -278,6 +313,8 @@ int RGWRados::put_obj(std::string& id, std::string& bucket, std::string& oid, co
       return r;
   }
 
+  close_pool(pool);
+
   return 0;
 }
 /**
@@ -303,27 +340,46 @@ int RGWRados::copy_obj(std::string& id, std::string& dest_bucket, std::string& d
                map<string, bufferlist>& attrs,  /* in/out */
                struct rgw_err *err)
 {
-  int ret;
+  int ret, r;
   char *data;
+  off_t ofs = 0, end = -1;
+  map<string, bufferlist>::iterator iter;
 
   cerr << "copy " << src_bucket << ":" << src_obj << " => " << dest_bucket << ":" << dest_obj << std::endl;
 
+  void *handle;
+
   map<string, bufferlist> attrset;
-  ret = get_obj(src_bucket, src_obj, &data, 0, -1, &attrset,
-                mod_ptr, unmod_ptr, if_match, if_nomatch, true, err);
+  ret = prepare_get_obj(src_bucket, src_obj, ofs, &end, &attrset,
+                mod_ptr, unmod_ptr, if_match, if_nomatch, true, &handle, err);
 
   if (ret < 0)
     return ret;
 
-  map<string, bufferlist>::iterator iter;
+  do {
+    ret = get_obj(&handle, src_bucket, src_obj, &data, ofs, end);
+    if (ret < 0)
+      return ret;
+
+    r = put_obj_data(id, dest_bucket, dest_obj, data, ofs, ret, NULL);
+    free(data);
+    if (r < 0)
+      goto done_err;
+
+    ofs += ret;
+  } while (ofs <= end);
+
   for (iter = attrs.begin(); iter != attrs.end(); ++iter) {
     attrset[iter->first] = iter->second;
   }
   attrs = attrset;
 
-  ret =  put_obj(id, dest_bucket, dest_obj, data, ret, mtime, attrs);
+  ret = put_obj_meta(id, dest_bucket, dest_obj, mtime, attrs);
 
   return ret;
+done_err:
+  /* FIXME: need to free handle */
+  return r;
 }
 
 /**
@@ -447,40 +503,45 @@ int RGWRados::set_attr(std::string& bucket, std::string& oid,
  *          (if get_data==true) length of read data,
  *          (if get_data==false) length of the object
  */
-int RGWRados::get_obj(std::string& bucket, std::string& oid, 
-            char **data, off_t ofs, off_t end,
+int RGWRados::prepare_get_obj(std::string& bucket, std::string& oid, 
+            off_t ofs, off_t *end,
             map<string, bufferlist> *attrs,
             const time_t *mod_ptr,
             const time_t *unmod_ptr,
             const char *if_match,
             const char *if_nomatch,
             bool get_data,
+            void **handle,
             struct rgw_err *err)
 {
   int r = -EINVAL;
-  uint64_t size, len;
+  uint64_t size;
   bufferlist etag;
   time_t mtime;
-  bufferlist bl;
 
-  rados_pool_t pool;
   map<string, bufferlist>::iterator iter;
 
-  r = open_pool(bucket, &pool);
+  GetObjState *state = new GetObjState;
+  if (!state)
+    return -ENOMEM;
+
+  *handle = state;
+
+  r = open_pool(bucket, &state->pool);
   if (r < 0)
-    return r;
+    goto done_err;
 
-  r = rados->stat(pool, oid, &size, &mtime);
+  r = rados->stat(state->pool, oid, &size, &mtime);
   if (r < 0)
-    return r;
+    goto done_err;
 
   if (attrs) {
-    r = rados->getxattrs(pool, oid, *attrs);
+    r = rados->getxattrs(state->pool, oid, *attrs);
     for (iter = attrs->begin(); iter != attrs->end(); ++iter) {
       cerr << "xattr: " << iter->first << std::endl;
     }
     if (r < 0)
-      return r;
+      goto done_err;
   }
 
 
@@ -489,7 +550,7 @@ int RGWRados::get_obj(std::string& bucket, std::string& oid,
     if (mtime < *mod_ptr) {
       err->num = "304";
       err->code = "PreconditionFailed";
-      goto done;
+      goto done_err;
     }
   }
 
@@ -497,13 +558,13 @@ int RGWRados::get_obj(std::string& bucket, std::string& oid,
     if (mtime >= *mod_ptr) {
       err->num = "412";
       err->code = "PreconditionFailed";
-      goto done;
+      goto done_err;
     }
   }
   if (if_match || if_nomatch) {
     r = get_attr(bucket, oid, RGW_ATTR_ETAG, etag);
     if (r < 0)
-      goto done;
+      goto done_err;
 
     r = -ECANCELED;
     if (if_match) {
@@ -511,7 +572,7 @@ int RGWRados::get_obj(std::string& bucket, std::string& oid,
       if (strcmp(if_match, etag.c_str())) {
         err->num = "412";
         err->code = "PreconditionFailed";
-        goto done;
+        goto done_err;
       }
     }
 
@@ -520,15 +581,33 @@ int RGWRados::get_obj(std::string& bucket, std::string& oid,
       if (strcmp(if_nomatch, etag.c_str()) == 0) {
         err->num = "412";
         err->code = "PreconditionFailed";
-        goto done;
+        goto done_err;
       }
     }
   }
 
-  if (!get_data) {
-    r = size;
-    goto done;
-  }
+  if (*end < 0)
+    *end = size - 1;
+
+  if (!get_data)
+    return size;
+
+  return 0;
+
+done_err:
+  delete state;
+  *handle = NULL;
+  return r;
+}
+
+int RGWRados::get_obj(void *handle,
+            std::string& bucket, std::string& oid, 
+            char **data, off_t ofs, off_t end)
+{
+  uint64_t len;
+  bufferlist bl;
+
+  GetObjState *state = (GetObjState *)handle;
 
   if (end <= 0)
     len = 0;
@@ -536,18 +615,20 @@ int RGWRados::get_obj(std::string& bucket, std::string& oid,
     len = end - ofs + 1;
 
   cout << "rados->read ofs=" << ofs << " len=" << len << std::endl;
-  r = rados->read(pool, oid, ofs, bl, len);
+  int r = rados->read(state->pool, oid, ofs, bl, len);
   cout << "rados->read r=" << r << std::endl;
-  if (r < 0)
-    return r;
 
   if (r > 0) {
     *data = (char *)malloc(r);
     memcpy(*data, bl.c_str(), bl.length());
   }
 
-done:
+  if (r < 0 || !len || (ofs + len - 1 == end)) {
+    rados->close_pool(state->pool);
+    delete state;
+  }
 
   return r;
+
 }
 
index 27552177772b94e64a9b7ace0a9b35c4add844ca..3684a91458469525a6bb3f1af11eb75fb81de0e3 100644 (file)
@@ -9,6 +9,14 @@ class RGWRados  : public RGWAccess
 {
   /** Open the pool used as root for this gateway */
   int open_root_pool(rados_pool_t *pool);
+
+  struct GetObjState {
+    rados_pool_t pool;
+    bool sent_data;
+
+    GetObjState() : pool(0), sent_data(false) {}
+  };
+
 public:
   /** Initialize the RADOS instance and prepare to do other ops */
   int initialize(int argc, char *argv[]);
@@ -31,9 +39,10 @@ public:
   int create_bucket(std::string& id, std::string& bucket, map<std::string,bufferlist>& attrs, uint64_t auid=0);
 
   /** Write/overwrite an object to the bucket storage. */
-  int put_obj(std::string& id, std::string& bucket, std::string& obj, const char *data, size_t size,
-              time_t *mtime,
+  int put_obj_meta(std::string& id, std::string& bucket, std::string& obj, time_t *mtime,
               map<std::string, bufferlist>& attrs);
+  int put_obj_data(std::string& id, std::string& bucket, std::string& obj, const char *data,
+              off_t ofs, size_t len, time_t *mtime);
   /** Copy an object, with many extra options */
   int copy_obj(std::string& id, std::string& dest_bucket, std::string& dest_obj,
                std::string& src_bucket, std::string& src_obj,
@@ -59,15 +68,19 @@ public:
                        const char *name, bufferlist& bl);
 
   /** Get data about an object out of RADOS and into memory. */
-  int get_obj(std::string& bucket, std::string& obj, 
-            char **data, off_t ofs, off_t end,
+  int prepare_get_obj(std::string& bucket, std::string& obj, 
+            off_t ofs, off_t *end,
             map<string, bufferlist> *attrs,
             const time_t *mod_ptr,
             const time_t *unmod_ptr,
             const char *if_match,
             const char *if_nomatch,
             bool get_data,
+            void **handle,
             struct rgw_err *err);
+
+  int get_obj(void *handle, std::string& bucket, std::string& oid, 
+            char **data, off_t ofs, off_t end);
 };
 
 #endif
index ede6bbcfa38a2e96bbec8e41ca5e6249c29bedf5..f34d1ff6ab68da800728eb0aa8536b502235cd18 100644 (file)
@@ -194,10 +194,13 @@ int RGWGetObj_REST::get_params()
   return 0;
 }
 
-int RGWGetObj_REST::send_response()
+int RGWGetObj_REST::send_response(void *handle)
 {
   const char *content_type = NULL;
 
+  if (sent_header)
+    goto send_data;
+
   if (get_data && !ret) {
     dump_content_length(s, len);
   }
@@ -222,6 +225,10 @@ int RGWGetObj_REST::send_response()
   }
   dump_errno(s, ret, &err);
   end_header(s, content_type);
+
+  sent_header = true;
+
+send_data:
   if (get_data && !ret) {
     FCGX_PutStr(data, len, s->fcgx->out); 
   }
index 6f0b167af36862c4bb1b18fec5886bb112464ac9..20e5f8e9f021bb213290f2bf21595b617d254465 100644 (file)
@@ -5,11 +5,18 @@
 
 class RGWGetObj_REST : public RGWGetObj
 {
+  bool sent_header;
 public:
   RGWGetObj_REST() {}
   ~RGWGetObj_REST() {}
+
+  virtual void init(struct req_state *s) {
+    RGWGetObj::init(s);
+    sent_header = false;
+  }
+
   int get_params();
-  int send_response();
+  int send_response(void *handle);
 };
 
 class RGWListBuckets_REST : public RGWListBuckets {
index 5152b95fb2b831cbfaf0375766bbb16d16485c02..07f68f867e54ab355ac7f0073a4c0621cb8c8c8e 100644 (file)
@@ -25,15 +25,24 @@ int rgw_get_user_info(string user_id, RGWUserInfo& info)
   int ret;
   char *data;
   struct rgw_err err;
+  void *handle;
+  off_t ofs = 0, end = -1;
 
-  ret = rgwstore->get_obj(ui_bucket, user_id, &data, 0, -1, NULL, NULL, NULL, NULL, NULL, true, &err);
-  if (ret < 0) {
+  ret = rgwstore->prepare_get_obj(ui_bucket, user_id, ofs, &end, NULL, NULL, NULL, NULL, NULL, true, &handle, &err);
+  if (ret < 0)
     return ret;
-  }
-  bl.append(data, ret);
+  do {
+    ret = rgwstore->get_obj(handle, ui_bucket, user_id, &data, ofs, end);
+    if (ret < 0) {
+      return ret;
+    }
+    bl.append(data, ret);
+    free(data);
+    ofs += ret;
+  } while (ofs <= end);
+
   bufferlist::iterator iter = bl.begin();
   info.decode(iter); 
-  free(data);
   return 0;
 }
 
@@ -100,16 +109,25 @@ int rgw_get_uid_by_email(string& email, string& user_id)
   char *data;
   struct rgw_err err;
   RGWUID uid;
+  void *handle;
+  off_t ofs = 0, end = -1;
 
-  ret = rgwstore->get_obj(ui_email_bucket, email, &data, 0, -1, NULL, NULL, NULL, NULL, NULL, true, &err);
-  if (ret < 0) {
+  ret = rgwstore->prepare_get_obj(ui_email_bucket, email, ofs, &end, NULL, NULL,
+                                  NULL, NULL, NULL, true, &handle, &err);
+  if (ret < 0)
     return ret;
-  }
-  bl.append(data, ret);
+  do {
+    ret = rgwstore->get_obj(handle, ui_email_bucket, email, &data, ofs, end);
+    if (ret < 0)
+      return ret;
+    ofs += ret;
+    bl.append(data, ret);
+    free(data);
+  } while (ofs <= end);
+
   bufferlist::iterator iter = bl.begin();
   uid.decode(iter); 
   user_id = uid.user_id;
-  free(data);
   return 0;
 }