summaryrefslogtreecommitdiff
path: root/src/mongo/bson
diff options
context:
space:
mode:
authorEric Milkie <milkie@10gen.com>2015-04-09 08:02:20 -0400
committerEric Milkie <milkie@10gen.com>2015-04-09 08:02:20 -0400
commit48f14493a3751483b67144897a44ed3297720f8c (patch)
tree596e6a9a7993de99622cd8d17cbc549a5a217704 /src/mongo/bson
parent04a120d6dc50d6bb1fd5073ea28a6c8ddc07fecd (diff)
downloadmongo-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.h5
-rw-r--r--src/mongo/bson/bsonobjbuilder.h33
-rw-r--r--src/mongo/bson/timestamp.cpp28
-rw-r--r--src/mongo/bson/timestamp.h128
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