]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd: harder-working sparse import from stdin
authorDan Mick <dan.mick@inktank.com>
Sat, 8 Dec 2012 06:57:06 +0000 (22:57 -0800)
committerDan Mick <dan.mick@inktank.com>
Sat, 22 Dec 2012 01:03:38 +0000 (17:03 -0800)
Try to accumulate image-sized blocks when importing from stdin, even if
each read is shorter than requested; if we get a full block, and it's
all zeroes, we can seek and make a sparse output file

Signed-off-by: Dan Mick <dan.mick@inktank.com>
Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
src/rbd.cc

index f38a01e237d22dfd763055d5904f8b860ddb12ab..2b098b3d983ecad222cee227730063ff7dcf90e5 100644 (file)
@@ -852,16 +852,27 @@ static int do_import_from_stdin(librbd::RBD &rbd, librados::IoCtx& io_ctx,
     return r;
   }
 
-  size_t readlen;
-  off_t file_pos = 0;
-
-  size_t len = 1 << *order;
-  bufferptr p(len);
+  off_t image_pos = 0;
+
+  // try to fill whole imgblklen blocks for sparsification
+
+  size_t imgblklen = 1 << *order;
+  char *p = new char[imgblklen];
+  size_t reqlen = imgblklen;   // amount requested from read
+  ssize_t readlen;             // amount received from one read
+  size_t blklen = 0;           // amount accumulated from reads to fill blk
+
+  // loop body handles 0 return, as we may have a block to flush
+  while ((readlen = ::read(0, p + blklen, reqlen)) >= 0) {
+    blklen += readlen;
+    // if read was short, try again to fill the block before writing
+    if (readlen && ((size_t)readlen < reqlen)) {
+      reqlen -= readlen;
+      continue;
+    }
 
-  while ((readlen = ::read(0, p.c_str(), len)) > 0) {
-    bufferlist bl;
-    bl.append(p);
-    if ((file_pos + readlen) > cur_size) {
+    // resize output image by binary expansion as we go
+    if ((image_pos + (size_t)blklen) > cur_size) {
       cur_size *= 2;
       r = image.resize(cur_size);
       if (r < 0) {
@@ -869,19 +880,32 @@ static int do_import_from_stdin(librbd::RBD &rbd, librados::IoCtx& io_ctx,
        return r;
       }
     }
-    r = image.write(file_pos, readlen, bl);
-    if (r < 0) {
-      cerr << "rbd: error writing to image block" << std::endl;
-      return r;
+
+    // write as much as we got; perhaps less than imgblklen
+    bufferlist bl(blklen);
+    bl.append(p, blklen);
+    // but skip writing zeros to create sparse images
+    if (!bl.is_zero()) {
+      r = image.write(image_pos, blklen, bl);
+      if (r < 0) {
+       cerr << "rbd: error writing to image block" << cpp_strerror(r) << std::endl;
+       return r;
+      }
     }
-    file_pos += readlen;
+    // done with whole block, whether written or not 
+    image_pos += blklen;
+    // if read had returned 0, we're at EOF and should quit
+    if (readlen == 0)
+      break;
+    blklen = 0;
+    reqlen = imgblklen;
   }
-  r = image.resize(file_pos);
+  r = image.resize(image_pos);
   if (r < 0) {
     cerr << "rbd: final image resize failed" << std::endl;
     return r;
   }
-  return readlen;      // 0 or error
+  return readlen;      // 0 or -error
 }
 
 static int do_import(librbd::RBD &rbd, librados::IoCtx& io_ctx,