diff options
author | Eric Milkie <milkie@10gen.com> | 2015-04-09 08:02:20 -0400 |
---|---|---|
committer | Eric Milkie <milkie@10gen.com> | 2015-04-09 08:02:20 -0400 |
commit | 48f14493a3751483b67144897a44ed3297720f8c (patch) | |
tree | 596e6a9a7993de99622cd8d17cbc549a5a217704 /src/mongo/bson | |
parent | 04a120d6dc50d6bb1fd5073ea28a6c8ddc07fecd (diff) | |
download | mongo-48f14493a3751483b67144897a44ed3297720f8c.tar.gz |
Revert "SERVER-15047 Remove undefined behavior from Timestamp"
This reverts commit e87716a9286b6aa6f63a513012e55f6e42f634a2.
Diffstat (limited to 'src/mongo/bson')
-rw-r--r-- | src/mongo/bson/bsonelement.h | 5 | ||||
-rw-r--r-- | src/mongo/bson/bsonobjbuilder.h | 33 | ||||
-rw-r--r-- | src/mongo/bson/timestamp.cpp | 28 | ||||
-rw-r--r-- | src/mongo/bson/timestamp.h | 128 |
4 files changed, 86 insertions, 108 deletions
diff --git a/src/mongo/bson/bsonelement.h b/src/mongo/bson/bsonelement.h index a5919d7f6d7..cc5c687f8d7 100644 --- a/src/mongo/bson/bsonelement.h +++ b/src/mongo/bson/bsonelement.h @@ -454,10 +454,9 @@ namespace mongo { } Timestamp timestamp() const { - Timestamp result; if( type() == mongo::Date || type() == bsonTimestamp ) - result.readFrom(value()); - return result; + return Timestamp(ConstDataView(value()).readLE<unsigned long long>()); + return Timestamp(); } Date_t timestampTime() const { diff --git a/src/mongo/bson/bsonobjbuilder.h b/src/mongo/bson/bsonobjbuilder.h index 2e4bd5ccb10..2910e7da58a 100644 --- a/src/mongo/bson/bsonobjbuilder.h +++ b/src/mongo/bson/bsonobjbuilder.h @@ -458,23 +458,16 @@ namespace mongo { return *this; } + // Append a Timestamp field -- will be updated to next server Timestamp + BSONObjBuilder& appendTimestamp( StringData fieldName ); + + BSONObjBuilder& appendTimestamp( StringData fieldName , unsigned long long val ); + /** * To store a Timestamp in BSON, use this function. * This captures both the secs and inc fields. */ - inline BSONObjBuilder& append(StringData fieldName, Timestamp ts) { - ts.append(_b, fieldName); - return *this; - } - - // Append a Timestamp field -- will be updated to next server Timestamp - inline BSONObjBuilder& appendTimestamp(StringData fieldName) { - return append(fieldName, Timestamp()); - } - - inline BSONObjBuilder& appendTimestamp(StringData fieldName, unsigned long long val) { - return append(fieldName, Timestamp(val)); - } + BSONObjBuilder& append(StringData fieldName, Timestamp timestamp); /* Append an element of the deprecated DBRef type. @@ -956,4 +949,18 @@ namespace mongo { return *s_->_builder; } + inline BSONObjBuilder& BSONObjBuilder::append(StringData fieldName, Timestamp optime) { + optime.append(_b, fieldName); + return *this; + } + + inline BSONObjBuilder& BSONObjBuilder::appendTimestamp( StringData fieldName ) { + return append(fieldName, Timestamp()); + } + + inline BSONObjBuilder& BSONObjBuilder::appendTimestamp( StringData fieldName, + unsigned long long val ) { + return append(fieldName, Timestamp(val)); + } + } diff --git a/src/mongo/bson/timestamp.cpp b/src/mongo/bson/timestamp.cpp index 2aea7306e37..cfd43fe8fe2 100644 --- a/src/mongo/bson/timestamp.cpp +++ b/src/mongo/bson/timestamp.cpp @@ -25,15 +25,14 @@ * then also delete it in the license file. */ +#include "mongo/bson/bsontypes.h" #include "mongo/bson/timestamp.h" -#include <cstring> #include <ctime> #include <iostream> #include <limits> #include <sstream> -#include "mongo/bson/bsontypes.h" #include "mongo/platform/cstdint.h" #include "mongo/util/time_support.h" @@ -46,36 +45,29 @@ namespace mongo { } void Timestamp::append(BufBuilder& builder, const StringData& fieldName) const { - // No endian conversions needed, since we store in-memory representation - // in little endian format, regardless of target endian. - builder.appendNum( static_cast<char>(bsonTimestamp) ); - builder.appendStr( fieldName ); - builder.appendBuf(&_data, sizeof(_data)); - } - - const void* Timestamp::readFrom(const void* bytes) { - // No endian conversions needed, since we store in-memory representation - // in little endian format, regardless of target endian. - std::memcpy(&_data, bytes, sizeof(_data)); - return reinterpret_cast<const char*>(bytes) + sizeof(_data); + // No endian conversions needed, since we store in-memory representation + // in little endian format, regardless of target endian. + builder.appendNum( static_cast<char>(bsonTimestamp) ); + builder.appendStr( fieldName ); + builder.appendNum( asULL() ); } std::string Timestamp::toStringLong() const { std::stringstream ss; - ss << time_t_to_String_short(getSecs()) << ' '; - ss << std::hex << getSecs() << ':' << getInc(); + ss << time_t_to_String_short(secs) << ' '; + ss << std::hex << secs << ':' << i; return ss.str(); } std::string Timestamp::toStringPretty() const { std::stringstream ss; - ss << time_t_to_String_short(getSecs()) << ':' << std::hex << getInc(); + ss << time_t_to_String_short(secs) << ':' << std::hex << i; return ss.str(); } std::string Timestamp::toString() const { std::stringstream ss; - ss << std::hex << getSecs() << ':' << getInc(); + ss << std::hex << secs << ':' << i; return ss.str(); } diff --git a/src/mongo/bson/timestamp.h b/src/mongo/bson/timestamp.h index c18fb85bb07..b223b5deb50 100644 --- a/src/mongo/bson/timestamp.h +++ b/src/mongo/bson/timestamp.h @@ -27,74 +27,57 @@ #pragma once -#include <type_traits> - -#include "mongo/base/data_cursor.h" #include "mongo/base/data_view.h" -#include "mongo/platform/cstdint.h" #include "mongo/bson/util/builder.h" -#include "mongo/platform/endian.h" #include "mongo/util/assert_util.h" namespace mongo { - class StringData; - /** - * Timestamp: A combination of current second plus an ordinal value, held together in a - * single 64-bit integer, stored in memory as little endian, regardless of local endianness. + /* Timestamp: A combination of current second plus an ordinal value. */ +#pragma pack(4) class Timestamp { - public: - - Timestamp() = default; + unsigned i; // ordinal comes first so we can do a single 64 bit compare on little endian + unsigned secs; + public: + unsigned getSecs() const { + return secs; + } + unsigned getInc() const { + return i; + } - explicit Timestamp(Date_t date) { - _data = endian::nativeToLittle(date.millis); - dassert(static_cast<int>(getSecs()) >= 0); + Timestamp(Date_t date) { + reinterpret_cast<unsigned long long&>(*this) = date.millis; + dassert( (int)secs >= 0 ); } - Timestamp(unsigned secs, unsigned inc) { - DataCursor(reinterpret_cast<char*>(&_data)) - .writeLEAndAdvance<uint32_t>(inc) - .writeLE<uint32_t>(secs); + Timestamp(unsigned a, unsigned b) { + secs = a; + i = b; + dassert( (int)secs >= 0 ); + } + Timestamp( const Timestamp& other ) { + secs = other.secs; + i = other.i; + dassert( (int)secs >= 0 ); + } + Timestamp() { + secs = 0; + i = 0; } // Maximum Timestamp value. static Timestamp max(); - unsigned getSecs() const { - static_assert(sizeof(unsigned) == sizeof(uint32_t), "unsigned must be uint32"); - return ConstDataCursor(reinterpret_cast<const char*>(&_data)) - .skip<uint32_t>() - .readLE<uint32_t>(); - } - - unsigned getInc() const { - static_assert(sizeof(unsigned) == sizeof(uint32_t), "unsigned must be uint32"); - return ConstDataCursor(reinterpret_cast<const char*>(&_data)) - .readLE<uint32_t>(); - } - unsigned long long asULL() const { - return endian::littleToNative(_data); + return reinterpret_cast<const unsigned long long*>(&i)[0]; } - long long asLL() const { - const unsigned long long val = endian::littleToNative(_data); - return static_cast<long long>(val); + return reinterpret_cast<const long long*>(&i)[0]; } - bool isNull() const { - return getSecs() == 0; - } - - // Append the BSON representation of this Timestamp to the given BufBuilder with the given - // name. This lives here because Timestamp manages its own serialization format. - void append(BufBuilder& builder, const StringData& fieldName) const; - - // Set the value of this Timestamp to match that of the pointed to bytes. The - // return value points to the first byte not consumed by the read operation. - const void* readFrom(const void* bytes); + bool isNull() const { return secs == 0; } std::string toStringLong() const; @@ -102,35 +85,32 @@ namespace mongo { std::string toString() const; - private: - uint64_t _data = 0; - }; - - inline bool operator==(const Timestamp& lhs, const Timestamp& rhs) { - return (lhs.getInc() == rhs.getInc()) && (lhs.getSecs() == rhs.getSecs()); - } - - inline bool operator!=(const Timestamp& lhs, const Timestamp& rhs) { - return !(lhs == rhs); - } - - inline bool operator<(const Timestamp& lhs, const Timestamp& rhs) { - if ( lhs.getSecs() != rhs.getSecs() ) { - return lhs.getSecs() < rhs.getSecs(); + bool operator==(const Timestamp& r) const { + return i == r.i && secs == r.secs; + } + bool operator!=(const Timestamp& r) const { + return !(*this == r); + } + bool operator<(const Timestamp& r) const { + if ( secs != r.secs ) + return secs < r.secs; + return i < r.i; + } + bool operator<=(const Timestamp& r) const { + return *this < r || *this == r; + } + bool operator>(const Timestamp& r) const { + return !(*this <= r); + } + bool operator>=(const Timestamp& r) const { + return !(*this < r); } - return lhs.getInc() < rhs.getInc(); - } - - inline bool operator<=(const Timestamp& lhs, const Timestamp& rhs) { - return (lhs < rhs) || (lhs == rhs); - } - inline bool operator>(const Timestamp& lhs, const Timestamp& rhs) { - return !(lhs <= rhs); - } + // Append the BSON representation of this Timestamp to the given BufBuilder with the given + // name. This lives here because Timestamp manages its own serialization format. + void append(BufBuilder& builder, const StringData& fieldName) const; - inline bool operator>=(const Timestamp& lhs, const Timestamp& rhs) { - return !(lhs < rhs); - } + }; +#pragma pack() } // namespace mongo |