Commit 58059b6e authored by Tudor Bosman's avatar Tudor Bosman Committed by Sara Golemon

Add isManaged / makeManaged

Summary: Add a way to tell whether an IOBuf (either indvidually or the whole chain)
refers to memory that's outside of IOBuf's control (via WRAP_BUFFER). That is,
can you assume that clone() will extend the lifetime of the memory? Is it safe
to use clone() instead of copying the data (and avoid a copy)?

Reviewed By: @simpkins

Differential Revision: D2191883
parent 6caa6956
main 2016.07.26 v2022.02.14.00 v2022.02.07.00 v2022.01.31.00 v2022.01.24.00 v2022.01.17.00 v2022.01.10.00 v2022.01.03.00 v2021.12.27.00 v2021.12.20.00 v2021.12.13.00 v2021.12.06.00 v2021.11.29.00 v2021.11.15.00 v2021.11.08.00 v2021.11.01.00 v2021.10.25.00 v2021.10.18.00 v2021.10.11.00 v2021.10.04.00 v2021.09.27.00 v2021.09.20.00 v2021.09.13.00 v2021.09.06.00 v2021.08.30.00 v2021.08.23.00 v2021.08.02.00 v2021.07.22.00 v2021.07.20.01 v2021.07.20.00 v2021.06.28.00 v2021.06.14.00 v2021.06.07.00 v2021.05.31.00 v2021.05.24.00 v2021.05.17.00 v2021.05.10.00 v2021.05.03.00 v2021.04.26.00 v2021.04.19.00 v2021.04.12.00 v2021.04.05.00 v2021.03.29.00 v2021.03.22.00 v2021.03.15.00 v2021.03.08.00 v2021.03.01.00 v2021.02.22.00 v2021.02.15.00 v2021.02.08.00 v2021.02.01.00 v2021.01.25.00 v2021.01.18.01 v2021.01.18.00 v2021.01.11.00 v2021.01.04.00 v2020.12.28.00 v2020.12.21.00 v2020.12.14.00 v2020.12.07.00 v2020.11.30.00 v2020.11.23.00 v2020.11.16.00 v2020.11.09.00 v2020.11.02.00 v2020.10.26.00 v2020.10.19.00 v2020.10.12.00 v2020.10.05.00 v2020.09.28.00 v2020.09.21.00 v2020.09.14.00 v2020.09.07.00 v2020.08.31.00 v2020.08.24.00 v2020.08.17.00 v2020.08.10.00 v2020.08.03.00 v2020.07.27.00 v2020.07.20.00 v2020.07.13.00 v2020.07.06.00 v2020.06.29.00 v2020.06.15.00 v2020.06.08.00 v2020.06.01.00 v2020.05.25.00 v2020.05.18.00 v2020.05.11.00 v2020.05.04.00 v2020.04.27.00 v2020.04.20.00 v2020.04.13.00 v2020.04.06.00 v2020.03.30.00 v2020.03.23.00 v2020.03.16.00 v2020.03.09.00 v2020.03.02.00 v2020.02.24.00 v2020.02.17.00 v2020.02.10.00 v2020.02.03.00 v2020.01.27.00 v2020.01.20.00 v2020.01.13.00 v2020.01.06.00 v2019.12.30.00 v2019.12.23.00 v2019.12.16.00 v2019.12.09.00 v2019.12.06.00 v2019.12.02.00 v2019.11.11.00 v2019.11.04.00 v2019.10.28.00 v2019.10.21.00 v2019.10.14.00 v2019.10.07.00 v2019.09.30.00 v2019.09.23.00 v2019.09.16.00 v2019.09.09.00 v2019.09.02.00 v2019.08.26.00 v2019.08.19.00 v2019.08.12.00 v2019.08.05.00 v2019.07.29.00 v2019.07.22.00 v2019.06.17.00 v2019.06.10.00 v2019.06.03.00 v2019.05.27.00 v2019.05.20.00 v2019.05.13.00 v2019.05.06.00 v2019.04.29.00 v2019.04.22.00 v2019.04.15.00 v2019.04.08.00 v2019.04.01.00 v2019.03.25.00 v2019.03.18.00 v2019.03.04.00 v2019.02.25.00 v2019.02.18.00 v2019.02.11.00 v2019.02.04.00 v2019.01.28.00 v2019.01.21.00 v2019.01.14.00 v2019.01.07.00 v2018.12.31.00 v2018.12.24.00 v2018.12.17.00 v2018.12.10.00 v2018.12.03.00 v2018.11.26.00 v2018.11.19.00 v2018.11.12.00 v2018.11.05.00 v2018.10.29.00 v2018.10.22.00 v2018.10.15.00 v2018.10.08.00 v2018.10.01.00 v2018.09.24.00 v2018.09.17.00 v2018.09.10.01 v2018.09.10.00 v2018.09.03.01 v2018.09.03.00 v2018.08.27.00 v2018.08.20.00 v2018.08.13.00 v2018.08.09.00 v2018.08.06.00 v2018.07.30.00 v2018.07.23.00 v2018.07.16.00 v2018.07.09.00 v2018.07.02.00 v2018.06.25.00 v2018.06.18.00 v2018.06.11.00 v2018.06.04.00 v2018.05.28.00 v2018.05.21.00 v2018.05.14.00 v2018.05.07.00 v2018.04.30.00 v2018.04.23.00 v2018.04.16.00 v2018.04.09.00 v2018.04.02.00 v2018.03.26.00 v2018.03.19.00 v2018.03.12.00 v2018.03.05.00 v2018.02.26.00 v2018.02.19.00 v2018.02.12.00 v2018.02.05.00 v2018.01.29.00 v2018.01.22.00 v2018.01.15.00 v2018.01.08.00 v2018.01.01.00 v2017.12.25.00 v2017.12.18.00 v2017.12.11.00 v2017.12.04.00 v2017.11.27.00 v2017.11.20.00 v2017.11.13.00 v2017.11.06.00 v2017.10.30.00 v2017.10.23.00 v2017.10.16.00 v2017.10.09.00 v2017.10.02.00 v2017.09.25.00 v2017.09.18.00 v2017.09.11.00 v2017.09.04.00 v2017.08.28.00 v2017.08.21.00 v2017.08.14.00 v2017.08.07.00 v2017.07.31.00 v2017.07.24.00 v2017.07.17.01 v2017.07.17.00 v2017.07.10.00 v2017.07.03.00 v2017.06.26.01 v2017.06.26.00 v2017.06.19.00 v2017.06.12.00 v2017.06.05.00 v2017.05.29.00 v2017.05.22.00 v2017.05.15.00 v2017.05.08.00 v2017.05.01.00 v2017.04.24.00 v2017.04.17.00 v2017.04.10.00 v2017.04.03.00 v2017.03.27.00 v2017.03.20.00 v2017.03.13.00 v2017.03.06.00 v2016.12.19.00 v2016.12.12.00 v2016.12.05.00 v2016.11.28.00 v2016.11.21.00 v2016.11.14.00 v2016.11.07.00 v2016.10.31.00 v2016.10.24.00 v2016.10.17.00 v2016.10.10.00 v2016.10.03.00 v2016.09.26.00 v2016.09.19.00 v2016.09.12.01 v2016.09.12.00 v2016.09.05.00 v2016.08.29.00 v2016.08.22.00 v2016.08.15.00 v2016.08.08.00 v2016.08.01.00 v2016.07.29.00 v0.57.0 v0.56.0 v0.55.0 v0.54.0 v0.53.0 v0.52.0 v0.51.0 v0.50.0 deprecate-dynamic-initializer
No related merge requests found
...@@ -552,6 +552,19 @@ void IOBuf::unshareChained() { ...@@ -552,6 +552,19 @@ void IOBuf::unshareChained() {
coalesceSlow(); coalesceSlow();
} }
void IOBuf::makeManagedChained() {
assert(isChained());
IOBuf* current = this;
while (true) {
current->makeManagedOne();
current = current->next_;
if (current == this) {
break;
}
}
}
void IOBuf::coalesceSlow() { void IOBuf::coalesceSlow() {
// coalesceSlow() should only be called if we are part of a chain of multiple // coalesceSlow() should only be called if we are part of a chain of multiple
// IOBufs. The caller should have already verified this. // IOBufs. The caller should have already verified this.
......
...@@ -871,6 +871,33 @@ class IOBuf { ...@@ -871,6 +871,33 @@ class IOBuf {
} }
} }
/**
* Return true if all IOBufs in this chain are managed by the usual
* refcounting mechanism (and so the lifetime of the underlying memory
* can be extended by clone()).
*/
bool isManaged() const {
const IOBuf* current = this;
while (true) {
if (!current->isManagedOne()) {
return false;
}
current = current->next_;
if (current == this) {
return true;
}
}
}
/**
* Return true if this IOBuf is managed by the usual refcounting mechanism
* (and so the lifetime of the underlying memory can be extended by
* cloneOne()).
*/
bool isManagedOne() const {
return sharedInfo();
}
/** /**
* Return true if other IOBufs are also pointing to the buffer used by this * Return true if other IOBufs are also pointing to the buffer used by this
* IOBuf, and false otherwise. * IOBuf, and false otherwise.
...@@ -946,6 +973,39 @@ class IOBuf { ...@@ -946,6 +973,39 @@ class IOBuf {
} }
} }
/**
* Ensure that the memory that IOBufs in this chain refer to will continue to
* be allocated for as long as the IOBufs of the chain (or any clone()s
* created from this point onwards) is alive.
*
* This only has an effect for user-owned buffers (created with the
* WRAP_BUFFER constructor or wrapBuffer factory function), in which case
* those buffers are unshared.
*/
void makeManaged() {
if (isChained()) {
makeManagedChained();
} else {
makeManagedOne();
}
}
/**
* Ensure that the memory that this IOBuf refers to will continue to be
* allocated for as long as this IOBuf (or any clone()s created from this
* point onwards) is alive.
*
* This only has an effect for user-owned buffers (created with the
* WRAP_BUFFER constructor or wrapBuffer factory function), in which case
* those buffers are unshared.
*/
void makeManagedOne() {
if (!isManagedOne()) {
// We can call the internal function directly; unmanaged implies shared.
unshareOneSlow();
}
}
/** /**
* Coalesce this IOBuf chain into a single buffer. * Coalesce this IOBuf chain into a single buffer.
* *
...@@ -1158,6 +1218,7 @@ class IOBuf { ...@@ -1158,6 +1218,7 @@ class IOBuf {
void unshareOneSlow(); void unshareOneSlow();
void unshareChained(); void unshareChained();
void makeManagedChained();
void coalesceSlow(); void coalesceSlow();
void coalesceSlow(size_t maxLength); void coalesceSlow(size_t maxLength);
// newLength must be the entire length of the buffers between this and // newLength must be the entire length of the buffers between this and
......
...@@ -1152,6 +1152,91 @@ TEST(IOBuf, CopyConstructorAndAssignmentOperator) { ...@@ -1152,6 +1152,91 @@ TEST(IOBuf, CopyConstructorAndAssignmentOperator) {
EXPECT_FALSE(buf->isShared()); EXPECT_FALSE(buf->isShared());
} }
namespace {
// Use with string literals only
std::unique_ptr<IOBuf> wrap(const char* str) {
return IOBuf::wrapBuffer(str, strlen(str));
}
std::unique_ptr<IOBuf> copy(const char* str) {
// At least 1KiB of tailroom, to ensure an external buffer
return IOBuf::copyBuffer(str, strlen(str), 0, 1024);
}
std::string toString(const folly::IOBuf& buf) {
std::string result;
result.reserve(buf.computeChainDataLength());
for (auto& b : buf) {
result.append(reinterpret_cast<const char*>(b.data()), b.size());
}
return result;
}
char* writableStr(folly::IOBuf& buf) {
return reinterpret_cast<char*>(buf.writableData());
}
} // namespace
TEST(IOBuf, Managed) {
auto hello = "hello";
auto buf1UP = wrap(hello);
auto buf1 = buf1UP.get();
EXPECT_FALSE(buf1->isManagedOne());
auto buf2UP = copy("world");
auto buf2 = buf2UP.get();
EXPECT_TRUE(buf2->isManagedOne());
auto buf3UP = wrap(hello);
auto buf3 = buf3UP.get();
auto buf4UP = buf2->clone();
auto buf4 = buf4UP.get();
// buf1 and buf3 share the same memory (but are unmanaged)
EXPECT_FALSE(buf1->isManagedOne());
EXPECT_FALSE(buf3->isManagedOne());
EXPECT_TRUE(buf1->isSharedOne());
EXPECT_TRUE(buf3->isSharedOne());
EXPECT_EQ(buf1->data(), buf3->data());
// buf2 and buf4 share the same memory (but are managed)
EXPECT_TRUE(buf2->isManagedOne());
EXPECT_TRUE(buf4->isManagedOne());
EXPECT_TRUE(buf2->isSharedOne());
EXPECT_TRUE(buf4->isSharedOne());
EXPECT_EQ(buf2->data(), buf4->data());
buf1->prependChain(std::move(buf2UP));
buf1->prependChain(std::move(buf3UP));
buf1->prependChain(std::move(buf4UP));
EXPECT_EQ("helloworldhelloworld", toString(*buf1));
EXPECT_FALSE(buf1->isManaged());
buf1->makeManaged();
EXPECT_TRUE(buf1->isManaged());
// buf1 and buf3 are now unshared (because they were unmanaged)
EXPECT_TRUE(buf1->isManagedOne());
EXPECT_TRUE(buf3->isManagedOne());
EXPECT_FALSE(buf1->isSharedOne());
EXPECT_FALSE(buf3->isSharedOne());
EXPECT_NE(buf1->data(), buf3->data());
// buf2 and buf4 are still shared
EXPECT_TRUE(buf2->isManagedOne());
EXPECT_TRUE(buf4->isManagedOne());
EXPECT_TRUE(buf2->isSharedOne());
EXPECT_TRUE(buf4->isSharedOne());
EXPECT_EQ(buf2->data(), buf4->data());
// And verify that the truth is what we expect: modify a byte in buf1 and
// buf2, see that the change from buf1 is *not* reflected in buf3, but the
// change from buf2 is reflected in buf4.
writableStr(*buf1)[0] = 'j';
writableStr(*buf2)[0] = 'x';
EXPECT_EQ("jelloxorldhelloxorld", toString(*buf1));
}
int main(int argc, char** argv) { int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv); testing::InitGoogleTest(&argc, argv);
gflags::ParseCommandLineFlags(&argc, &argv, true); gflags::ParseCommandLineFlags(&argc, &argv, true);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment