You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by al...@apache.org on 2017/05/11 18:23:11 UTC

[3/4] kudu git commit: faststring: add shrink_to_fit()

faststring: add shrink_to_fit()

This adds a shrink_to_fit() method which reallocates the underlying buffer of a
faststring to match its current length. This is useful in the case where a
faststring acts as a long-lived buffer which occasionally gets large values,
but often contains small ones.

Change-Id: I0e437ff180fccd1957d252fb9a3551bb91ba7917
Reviewed-on: http://gerrit.cloudera.org:8080/6835
Reviewed-by: David Ribeiro Alves <da...@gmail.com>
Tested-by: Kudu Jenkins


Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/dce25916
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/dce25916
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/dce25916

Branch: refs/heads/master
Commit: dce25916f428659072fd1e140a9081829956468e
Parents: 43fbfdf
Author: Todd Lipcon <to...@cloudera.com>
Authored: Tue May 9 14:30:41 2017 -0700
Committer: Todd Lipcon <to...@apache.org>
Committed: Thu May 11 16:25:10 2017 +0000

----------------------------------------------------------------------
 src/kudu/util/CMakeLists.txt     |  1 +
 src/kudu/util/faststring-test.cc | 60 +++++++++++++++++++++++++++++++++++
 src/kudu/util/faststring.cc      | 21 ++++++++++--
 src/kudu/util/faststring.h       | 20 ++++++++++--
 4 files changed, 96 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kudu/blob/dce25916/src/kudu/util/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/kudu/util/CMakeLists.txt b/src/kudu/util/CMakeLists.txt
index d9a37cd..e4fff0c 100644
--- a/src/kudu/util/CMakeLists.txt
+++ b/src/kudu/util/CMakeLists.txt
@@ -339,6 +339,7 @@ ADD_KUDU_TEST(env-test LABELS no_tsan)
 ADD_KUDU_TEST(env_util-test)
 ADD_KUDU_TEST(errno-test)
 ADD_KUDU_TEST(failure_detector-test)
+ADD_KUDU_TEST(faststring-test)
 ADD_KUDU_TEST(file_cache-test)
 ADD_KUDU_TEST(file_cache-stress-test RUN_SERIAL true)
 ADD_KUDU_TEST(flag_tags-test)

http://git-wip-us.apache.org/repos/asf/kudu/blob/dce25916/src/kudu/util/faststring-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/util/faststring-test.cc b/src/kudu/util/faststring-test.cc
new file mode 100644
index 0000000..c57cb41
--- /dev/null
+++ b/src/kudu/util/faststring-test.cc
@@ -0,0 +1,60 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <algorithm>
+#include "kudu/util/faststring.h"
+#include "kudu/util/random.h"
+#include "kudu/util/random_util.h"
+#include "kudu/util/test_util.h"
+
+namespace kudu {
+class FaststringTest : public KuduTest {};
+
+TEST_F(FaststringTest, TestShrinkToFit_Empty) {
+  faststring s;
+  s.shrink_to_fit();
+  ASSERT_EQ(faststring::kInitialCapacity, s.capacity());
+}
+
+// Test that, if the string contents is shorter than the initial capacity
+// of the faststring, shrink_to_fit() leaves the string in the built-in
+// array.
+TEST_F(FaststringTest, TestShrinkToFit_SmallerThanInitialCapacity) {
+  faststring s;
+  s.append("hello");
+  s.shrink_to_fit();
+  ASSERT_EQ(faststring::kInitialCapacity, s.capacity());
+}
+
+TEST_F(FaststringTest, TestShrinkToFit_Random) {
+  Random r(GetRandomSeed32());
+  int kMaxSize = faststring::kInitialCapacity * 2;
+  std::unique_ptr<char[]> random_bytes(new char[kMaxSize]);
+  RandomString(random_bytes.get(), kMaxSize, &r);
+
+  faststring s;
+  for (int i = 0; i < 100; i++) {
+    int new_size = r.Uniform(kMaxSize);
+    s.resize(new_size);
+    memcpy(s.data(), random_bytes.get(), new_size);
+    s.shrink_to_fit();
+    ASSERT_EQ(0, memcmp(s.data(), random_bytes.get(), new_size));
+    ASSERT_EQ(std::max<int>(faststring::kInitialCapacity, new_size), s.capacity());
+  }
+}
+
+} // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/dce25916/src/kudu/util/faststring.cc
----------------------------------------------------------------------
diff --git a/src/kudu/util/faststring.cc b/src/kudu/util/faststring.cc
index cf5dbd1..a1cd26b 100644
--- a/src/kudu/util/faststring.cc
+++ b/src/kudu/util/faststring.cc
@@ -18,8 +18,7 @@
 #include "kudu/util/faststring.h"
 
 #include <glog/logging.h>
-
-#include "kudu/gutil/gscoped_ptr.h"
+#include <memory>
 
 namespace kudu {
 
@@ -38,7 +37,7 @@ void faststring::GrowByAtLeast(size_t count) {
 
 void faststring::GrowArray(size_t newcapacity) {
   DCHECK_GE(newcapacity, capacity_);
-  gscoped_array<uint8_t> newdata(new uint8_t[newcapacity]);
+  std::unique_ptr<uint8_t[]> newdata(new uint8_t[newcapacity]);
   if (len_ > 0) {
     memcpy(&newdata[0], &data_[0], len_);
   }
@@ -53,5 +52,21 @@ void faststring::GrowArray(size_t newcapacity) {
   ASAN_POISON_MEMORY_REGION(data_ + len_, capacity_ - len_);
 }
 
+void faststring::ShrinkToFitInternal() {
+  DCHECK_NE(data_, initial_data_);
+  if (len_ <= kInitialCapacity) {
+    ASAN_UNPOISON_MEMORY_REGION(initial_data_, len_);
+    memcpy(initial_data_, &data_[0], len_);
+    delete[] data_;
+    data_ = initial_data_;
+    capacity_ = kInitialCapacity;
+  } else {
+    std::unique_ptr<uint8_t[]> newdata(new uint8_t[len_]);
+    memcpy(&newdata[0], &data_[0], len_);
+    delete[] data_;
+    data_ = newdata.release();
+    capacity_ = len_;
+  }
+}
 
 } // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/dce25916/src/kudu/util/faststring.h
----------------------------------------------------------------------
diff --git a/src/kudu/util/faststring.h b/src/kudu/util/faststring.h
index 5bd003a..3d25c84 100644
--- a/src/kudu/util/faststring.h
+++ b/src/kudu/util/faststring.h
@@ -30,6 +30,10 @@ namespace kudu {
 // instead of memsetting to \0)
 class faststring {
  public:
+  enum {
+    kInitialCapacity = 32
+  };
+
   faststring() :
     data_(initial_data_),
     len_(0),
@@ -198,6 +202,18 @@ class faststring {
                 str.size());
   }
 
+  // Reallocates the internal storage to fit only the current data.
+  //
+  // This may revert to using internal storage if the current length is shorter than
+  // kInitialCapacity. Note that, in that case, after this call, capacity() will return
+  // a capacity larger than the data length.
+  //
+  // Any pointers within this instance are invalidated.
+  void shrink_to_fit() {
+    if (data_ == initial_data_ || capacity_ == len_) return;
+    ShrinkToFitInternal();
+  }
+
   // Return a copy of this string as a std::string.
   std::string ToString() const {
     return std::string(reinterpret_cast<const char *>(data()),
@@ -227,9 +243,7 @@ class faststring {
   // the current capacity.
   void GrowArray(size_t newcapacity);
 
-  enum {
-    kInitialCapacity = 32
-  };
+  void ShrinkToFitInternal();
 
   uint8_t* data_;
   uint8_t initial_data_[kInitialCapacity];