Browse Source

Add helpful functions for TimeUUID (#1338)

* Add helpful functions for TimeUUID
* Add tests for Min/MaxTimeUUID functions
Pavel Buchinchik 6 năm trước cách đây
mục cha
commit
df4b9cc330
3 tập tin đã thay đổi với 91 bổ sung4 xóa
  1. 1 0
      AUTHORS
  2. 47 4
      uuid.go
  3. 43 0
      uuid_test.go

+ 1 - 0
AUTHORS

@@ -111,3 +111,4 @@ Marco Cadetg <cadetg@gmail.com>
 Karl Matthias <karl@matthias.org>
 Thomas Meson <zllak@hycik.org>
 Martin Sucha <martin.sucha@kiwi.com>; <git@mm.ms47.eu>
+Pavel Buchinchik <p.buchinchik@gmail.com>

+ 47 - 4
uuid.go

@@ -112,21 +112,64 @@ func RandomUUID() (UUID, error) {
 
 var timeBase = time.Date(1582, time.October, 15, 0, 0, 0, 0, time.UTC).Unix()
 
+// getTimestamp converts time to UUID (version 1) timestamp.
+// It must be an interval of 100-nanoseconds since timeBase.
+func getTimestamp(t time.Time) int64 {
+	utcTime := t.In(time.UTC)
+	ts := int64(utcTime.Unix()-timeBase)*10000000 + int64(utcTime.Nanosecond()/100)
+
+	return ts
+}
+
 // TimeUUID generates a new time based UUID (version 1) using the current
 // time as the timestamp.
 func TimeUUID() UUID {
 	return UUIDFromTime(time.Now())
 }
 
+// The min and max clock values for a UUID.
+//
+// Cassandra's TimeUUIDType compares the lsb parts as signed byte arrays.
+// Thus, the min value for each byte is -128 and the max is +127.
+const (
+	minClock = 0x8080
+	maxClock = 0x7f7f
+)
+
+// The min and max node values for a UUID.
+//
+// See explanation about Cassandra's TimeUUIDType comparison logic above.
+var (
+	minNode = []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x80}
+	maxNode = []byte{0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f}
+)
+
+// MinTimeUUID generates a "fake" time based UUID (version 1) which will be
+// the smallest possible UUID generated for the provided timestamp.
+//
+// UUIDs generated by this function are not unique and are mostly suitable only
+// in queries to select a time range of a Cassandra's TimeUUID column.
+func MinTimeUUID(t time.Time) UUID {
+	return TimeUUIDWith(getTimestamp(t), minClock, minNode)
+}
+
+// MaxTimeUUID generates a "fake" time based UUID (version 1) which will be
+// the biggest possible UUID generated for the provided timestamp.
+//
+// UUIDs generated by this function are not unique and are mostly suitable only
+// in queries to select a time range of a Cassandra's TimeUUID column.
+func MaxTimeUUID(t time.Time) UUID {
+	return TimeUUIDWith(getTimestamp(t), maxClock, maxNode)
+}
+
 // UUIDFromTime generates a new time based UUID (version 1) as described in
 // RFC 4122. This UUID contains the MAC address of the node that generated
 // the UUID, the given timestamp and a sequence number.
-func UUIDFromTime(aTime time.Time) UUID {
-	utcTime := aTime.In(time.UTC)
-	t := int64(utcTime.Unix()-timeBase)*10000000 + int64(utcTime.Nanosecond()/100)
+func UUIDFromTime(t time.Time) UUID {
+	ts := getTimestamp(t)
 	clock := atomic.AddUint32(&clockSeq, 1)
 
-	return TimeUUIDWith(t, clock, hardwareAddr)
+	return TimeUUIDWith(ts, clock, hardwareAddr)
 }
 
 // TimeUUIDWith generates a new time based UUID (version 1) as described in

+ 43 - 0
uuid_test.go

@@ -240,3 +240,46 @@ func TestMarshalText(t *testing.T) {
 		t.Fatalf("uuids not equal after marshalling: before=%s after=%s", u, u2)
 	}
 }
+
+func TestMinTimeUUID(t *testing.T) {
+	aTime := time.Now()
+	minTimeUUID := MinTimeUUID(aTime)
+
+	ts := aTime.Unix()
+	tsFromUUID := minTimeUUID.Time().Unix()
+	if ts != tsFromUUID {
+		t.Errorf("timestamps are not equal: expected %d, got %d", ts, tsFromUUID)
+	}
+
+	clockFromUUID := minTimeUUID.Clock()
+	// clear two most significant bits, as they are used for IETF variant
+	if minClock&0x3FFF != clockFromUUID {
+		t.Errorf("clocks are not equal: expected %08b, got %08b", minClock&0x3FFF, clockFromUUID)
+	}
+
+	nodeFromUUID := minTimeUUID.Node()
+	if !bytes.Equal(minNode, nodeFromUUID) {
+		t.Errorf("nodes are not equal: expected %08b, got %08b", minNode, nodeFromUUID)
+	}
+}
+
+func TestMaxTimeUUID(t *testing.T) {
+	aTime := time.Now()
+	maxTimeUUID := MaxTimeUUID(aTime)
+
+	ts := aTime.Unix()
+	tsFromUUID := maxTimeUUID.Time().Unix()
+	if ts != tsFromUUID {
+		t.Errorf("timestamps are not equal: expected %d, got %d", ts, tsFromUUID)
+	}
+
+	clockFromUUID := maxTimeUUID.Clock()
+	if maxClock&0x3FFF != clockFromUUID {
+		t.Errorf("clocks are not equal: expected %08b, got %08b", maxClock&0x3FFF, clockFromUUID)
+	}
+
+	nodeFromUUID := maxTimeUUID.Node()
+	if !bytes.Equal(maxNode, nodeFromUUID) {
+		t.Errorf("nodes are not equal:  expected %08b, got %08b", maxNode, nodeFromUUID)
+	}
+}