Permalink
Browse files

Use system time in microseconds as the timestamp format

  • Loading branch information...
1 parent fc1ea10 commit 4f6df2585df51a7b51fed59481c564c0aee74418 @vaterlaus committed Sep 13, 2012
Showing with 30 additions and 16 deletions.
  1. +8 −1 README.txt
  2. +22 −15 django_cassandra/db/utils.py
View
@@ -18,7 +18,7 @@ support) that are useful for the Django database backend, so I targeted that
instead of 0.6. Unfortunately, the Cassandra Thrift API changed between 0.6 and 0.7,
so the two version are incompatible.
-I currently use the 1.0.3 release. That's the only version I test against, so no
+I currently use the 1.0.10 release. That's the only version I test against, so no
promises if you try it with a different version. I have tested earlier versions
against the 0.7.x and 0.8.x versions of Cassandra with no problem, so I would expect
that it would still work.
@@ -199,6 +199,13 @@ Known Issues
daemon, etc. Currently you just get a somewhat uninformative exception in
these cases.
+Changes for 0.2.4
+=================
+- switch the timestamp format to use the system time in microseconds to be
+ consistent with the standard Cassandra timestamps used by other Cassandra
+ components (e.g. the Cassandra CLI) and to hopefully eliminate issues with
+ timestamp collisions across multiple Django processes.
+
Changes for 0.2.3
=================
- fixed a bug with the retry/reconnect logic where it would use a stale Cassandra
@@ -142,26 +142,33 @@ def combine_rows(rows1, rows2, op, primary_key_column):
return combined_rows
-_last_time = None
-_last_counter = None
+_last_timestamp = None
def get_next_timestamp():
# The timestamp is a 64-bit integer
- # We use the top 44 bits for the current time in milliseconds since the
- # epoch. The low 20 bits are a counter that is incremented if the current
- # time value from the top 44 bits is the same as the last
- # time value. This guarantees that a new timestamp is always
- # greater than the previous timestamp
- global _last_time, _last_counter
- current_time = int(time.time() * 1000)
+ # We now use the standard Cassandra timestamp format of the
+ # current system time in microseconds. We also keep track of the
+ # last timestamp we returned and if the current time is less than
+ # that, then we just advance the timestamp by 1 to make sure we
+ # return monotonically increasing timestamps. Note that this isn't
+ # guaranteed to handle the fairly common Django deployment model of
+ # having multiple Django processes that are dispatched to from a
+ # web server like Apache. In practice I don't think that case will be
+ # a problem though (at least with current hardware) because I don't
+ # think you could have two consecutive calls to Django from another
+ # process that would be dispatched to two different Django processes
+ # that would happen in the same microsecond.
+
+ global _last_timestamp
+
+ timestamp = int(time.time() * 1000000)
- if (_last_time == None) or (current_time > _last_time):
- _last_time = current_time
- _last_counter = 0
- else:
- _last_counter += 1
+ if (_last_timestamp != None) and (timestamp <= _last_timestamp):
+ timestamp = _last_timestamp + 1
+
+ _last_timestamp = timestamp
- return _last_time * 0x100000 + _last_counter
+ return timestamp
def convert_string_to_list(s):
# FIXME: Shouldn't use eval here, because of security considerations

0 comments on commit 4f6df25

Please sign in to comment.