Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Adding proper watch support and implements its dual, the unwatch command #33

Merged
merged 1 commit into from

2 participants

@dgvncsz0f

This commit enables users to use the following pattern:

WATCH
GET
MULTI
EXEC/DISCARD

The old behavior have been kept intact, i.e., the multi function
continues to accept a list of keys to watch prior issuing the watch
command, although I believe this use should be deprecated.

The watch command may also be used standalone. In this case, users
should make use of the watch command to clear the `inTransaction'
state.

Some examples (the following assumes inlineCallbacks):

# 1. Using watch/unwatch
tx = yield conn.watch(...)
...
yield tx.unwatch()

# 2. Using watch/multi
tx = yield conn.watch(...)
...
yield tx.multi()
...
yield tx.commit()

# 3. Using watch only
tx = yield conn.multi(...)
...
yield tx.commit()

# 4. All together:
tx = yield conn.watch(...)
...
yield tx.multi()
...
yield tx.unwatch() # this will not clear
# the inTransaction state
...
yield tx.commit()

@dgvncsz0f dgvncsz0f Adding proper watch support and implements its dual, the unwatch command
This commit enables users to use the following pattern:

   WATCH
   GET
   MULTI
   EXEC/DISCARD

The old behavior have been kept intact, i.e., the multi function
continues to accept a list of keys to watch prior issuing the watch
command, although I believe this use should be deprecated.

The watch command may also be used standalone. In this case, users
should make use of the watch command to clear the `inTransaction'
state.

Some examples (the following assumes inlineCallbacks):

  # 1. Using watch/unwatch
  tx = yield conn.watch(...)
  ...
  yield tx.unwatch()

  # 2. Using watch/multi
  tx = yield conn.watch(...)
  ...
  yield tx.multi()
  ...
  yield tx.commit()

  # 3. Using watch only
  tx = yield conn.multi(...)
  ...
  yield tx.commit()

  # 4. All together:
  tx = yield conn.watch(...)
  ...
  yield tx.multi()
  ...
  yield tx.unwatch() # this will not clear
                     # the `inTransaction` state
  ...
  yield tx.commit()
52cdc1a
@gleicon
Collaborator

looks good to me, I don't know why travis broke on this one, trial ran ok on my setup. It would be good to add tests for watch + pools and watch + shard if possible, but not required. Add your name as contributor to the README on the next patch :).

EDIT: it seems that travis broke either on timeout or build. Ran trial again on my setup and it passed.

@gleicon gleicon merged commit d150918 into fiorix:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 20, 2012
  1. @dgvncsz0f

    Adding proper watch support and implements its dual, the unwatch command

    dgvncsz0f authored
    This commit enables users to use the following pattern:
    
       WATCH
       GET
       MULTI
       EXEC/DISCARD
    
    The old behavior have been kept intact, i.e., the multi function
    continues to accept a list of keys to watch prior issuing the watch
    command, although I believe this use should be deprecated.
    
    The watch command may also be used standalone. In this case, users
    should make use of the watch command to clear the `inTransaction'
    state.
    
    Some examples (the following assumes inlineCallbacks):
    
      # 1. Using watch/unwatch
      tx = yield conn.watch(...)
      ...
      yield tx.unwatch()
    
      # 2. Using watch/multi
      tx = yield conn.watch(...)
      ...
      yield tx.multi()
      ...
      yield tx.commit()
    
      # 3. Using watch only
      tx = yield conn.multi(...)
      ...
      yield tx.commit()
    
      # 4. All together:
      tx = yield conn.watch(...)
      ...
      yield tx.multi()
      ...
      yield tx.unwatch() # this will not clear
                         # the `inTransaction` state
      ...
      yield tx.commit()
This page is out of date. Refresh to see the latest.
Showing with 56 additions and 18 deletions.
  1. +31 −2 tests/test_transactions.py
  2. +25 −16 txredisapi.py
View
33 tests/test_transactions.py
@@ -30,12 +30,41 @@ def testRedisConnection(self):
rapi = yield txredisapi.Connection(redis_host, redis_port)
# test set() operation
- transaction = yield rapi.multi()
- print "oi"
+ transaction = yield rapi.multi("txredisapi:test_transaction")
+ self.assertTrue(transaction.inTransaction)
for key, value in (("txredisapi:test_transaction", "foo"), ("txredisapi:test_transaction", "bar")):
yield transaction.set(key, value)
yield transaction.commit()
+ self.assertFalse(transaction.inTransaction)
result = yield rapi.get("txredisapi:test_transaction")
self.assertEqual(result, "bar")
yield rapi.disconnect()
+
+ @defer.inlineCallbacks
+ def testRedisWithOnlyWatchUnwatch(self):
+ rapi = yield txredisapi.Connection(redis_host, redis_port)
+
+ k = "txredisapi:testRedisWithOnlyWatchAndUnwatch"
+ tx = yield rapi.watch(k)
+ self.assertTrue(tx.inTransaction)
+ yield tx.set(k, "bar")
+ v = yield tx.get(k)
+ self.assertEqual("bar", v)
+ yield tx.unwatch()
+ self.assertFalse(tx.inTransaction)
+
+ yield rapi.disconnect()
+
+ @defer.inlineCallbacks
+ def testRedisWithWatchAndMulti(self):
+ rapi = yield txredisapi.Connection(redis_host, redis_port)
+
+ tx = yield rapi.watch("txredisapi:testRedisWithWatchAndMulti")
+ yield tx.multi()
+ yield tx.unwatch()
+ self.assertTrue(tx.inTransaction)
+ yield tx.commit()
+ self.assertFalse(tx.inTransaction)
+
+ yield rapi.disconnect()
View
41 txredisapi.py
@@ -197,6 +197,7 @@ def __init__(self, charset="utf-8", errors="strict"):
self.transactions = 0
self.inTransaction = False
+ self.unwatch_cc = lambda: ()
@defer.inlineCallbacks
def connectionMade(self):
@@ -1195,32 +1196,40 @@ def sort(self, key, start=None, end=None, by=None, get=None,
return self.execute_command("SORT", *pieces)
+ def _clear_txstate(self):
+ self.inTransaction = self.transactions != 0
+
+ def watch(self, keys):
+ self.inTransaction = True
+ self.unwatch_cc = self._clear_txstate
+ if isinstance(keys, (str, unicode)):
+ keys = [keys]
+ d = self.execute_command("WATCH", *keys).addCallback(self._tx_started)
+ return d
+
+ def unwatch(self):
+ self.unwatch_cc()
+ return self.execute_command("UNWATCH")
+
# Transactions
# multi() will return a deferred with a "connection" object
# That object must be used for further interactions within
# the transaction. At the end, either exec() or discard()
# must be executed.
def multi(self, keys=None):
- self.inTransaction = True
- if keys:
- if isinstance(keys, (str, unicode)):
- keys = [keys]
- d = defer.Deferred()
- self.execute_command("WATCH", *keys).addCallback(
- self._watch_added, d)
+ self.unwatch_cc = lambda: ()
+ if keys is not None:
+ d = self.watch(keys)
+ d.addCallback(lambda _: self.execute_command("MULTI"))
else:
- d = self.execute_command("MULTI").addCallback(self._multi_started)
+ self.inTransaction = True
+ d = self.execute_command("MULTI")
+ d.addCallback(self._tx_started)
return d
- def _watch_added(self, response, d):
- if response != 'OK':
- d.errback(RedisError('Invalid WATCH response: %s' % response))
- self.execute_command("MULTI").addCallback(
- self._multi_started).chainDeferred(d)
-
- def _multi_started(self, response):
+ def _tx_started(self, response):
if response != 'OK':
- raise RedisError('Invalid MULTI response: %s' % response)
+ raise RedisError('Invalid response: %s' % response)
return self
def _commit_check(self, response):
Something went wrong with that request. Please try again.