diff options
author | Henrik Edin <henrik.edin@mongodb.com> | 2021-11-12 15:34:18 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-11-12 16:31:52 +0000 |
commit | 9546646fd4ab6225c49c58b01c924eb0023085a6 (patch) | |
tree | 91642946962c099ca6b2d62e7cf7c49aa79aac3a /src/mongo/bson/util | |
parent | 748f177e840861c374d2735fc5cbc5418589ad11 (diff) | |
download | mongo-9546646fd4ab6225c49c58b01c924eb0023085a6.tar.gz |
SERVER-61436 Compare bit pattern when encoding doubles in BSONColumn
So we can detect differences between 0.0 and -0.0 for example.
Diffstat (limited to 'src/mongo/bson/util')
-rw-r--r-- | src/mongo/bson/util/bsoncolumn_test.cpp | 24 | ||||
-rw-r--r-- | src/mongo/bson/util/simple8b_type_util.cpp | 13 |
2 files changed, 34 insertions, 3 deletions
diff --git a/src/mongo/bson/util/bsoncolumn_test.cpp b/src/mongo/bson/util/bsoncolumn_test.cpp index 386d824a8cc..215b4bc1eac 100644 --- a/src/mongo/bson/util/bsoncolumn_test.cpp +++ b/src/mongo/bson/util/bsoncolumn_test.cpp @@ -1188,6 +1188,30 @@ TEST_F(BSONColumnTest, DoubleIntegerOverflow) { verifyDecompression(binData, {e1, e2}); } +TEST_F(BSONColumnTest, DoubleZerosSignDifference) { + BSONColumnBuilder cb("test"_sd); + + // 0.0 compares equal to -0.0 when compared as double. Make sure we can handle this case without + // data loss. + auto d1 = createElementDouble(0.0); + auto d2 = createElementDouble(-0.0); + cb.append(d1); + cb.append(d2); + + // These numbers are encoded as a large integer that does not fit in Simple8b so the result is + // two uncompressed literals. + ASSERT_EQ(deltaDoubleMemory(d2, d1), 0xFFFFFFFFFFFFFFFF); + + BufBuilder expected; + appendLiteral(expected, d1); + appendLiteral(expected, d2); + appendEOO(expected); + + auto binData = cb.finalize(); + verifyBinary(binData, expected); + verifyDecompression(binData, {d1, d2}); +} + TEST_F(BSONColumnTest, Decimal128Base) { BSONColumnBuilder cb("test"_sd); diff --git a/src/mongo/bson/util/simple8b_type_util.cpp b/src/mongo/bson/util/simple8b_type_util.cpp index b009c723f0b..1ec42cdf8bf 100644 --- a/src/mongo/bson/util/simple8b_type_util.cpp +++ b/src/mongo/bson/util/simple8b_type_util.cpp @@ -144,10 +144,14 @@ boost::optional<uint8_t> Simple8bTypeUtil::calculateDecimalShiftMultiplier(doubl } boost::optional<int64_t> Simple8bTypeUtil::encodeDouble(double val, uint8_t scaleIndex) { - if (scaleIndex == kMemoryAsInteger) { + auto bitCastToInt64 = [](double value) { int64_t ret; - memcpy(&ret, &val, sizeof(ret)); + memcpy(&ret, &value, sizeof(ret)); return ret; + }; + + if (scaleIndex == kMemoryAsInteger) { + return bitCastToInt64(val); } // Checks for both overflow and handles NaNs @@ -166,7 +170,10 @@ boost::optional<int64_t> Simple8bTypeUtil::encodeDouble(double val, uint8_t scal // We use encodeInt64 to handle negative floats by taking the signed bit and placing it at the // lsb position int64_t valueToBeEncoded = std::llround(valTimesMultiplier); - if (valueToBeEncoded / scaleMultiplier != val) { + + // We need to check that we can get the exact bit pattern back. 0.0 and -0.0 compares as equal + // when comparing as doubles but they have different bit patterns. + if (bitCastToInt64(valueToBeEncoded / scaleMultiplier) != bitCastToInt64(val)) { return boost::none; } // Delta encoding. Gap should never induce overflow |