Exemplo n.º 1
0
    def test_user_abort(self):

        t = ZKTransaction(zkhost)
        txid = None

        try:
            with ZKTransaction(zkhost) as t1:

                txid = t1.txid
                t1.set_mem_state('bar')

                self.assertIsNone(t.zkstorage.state.get(txid)[0])

                val = t1.mem_state
                self.assertEqual(
                    {
                        'got_keys': [],
                        'data': 'bar',
                        "start_ts": t1.start_ts
                    }, val)

                val = t1.get_mem_state()
                self.assertEqual('bar', val)

                t1.abort()
        except UserAborted:
            pass

        self.assertIsNone(t.zkstorage.state.get(txid)[0])
Exemplo n.º 2
0
    def test_lock_get_timeout(self):
        def _tx(tx):
            tx.begin()
            tx.lock_get('foo')
            time.sleep(4)

        th = threadutil.start_daemon(_tx,
                                     args=(ZKTransaction(zkhost, txid=0), ))

        with ZKTransaction(zkhost, lock_timeout=0.5) as t1:

            try:
                t1.lock_get('foo')
                self.fail('TXTimeout expected')
            except TXTimeout as e:
                dd(repr(e))

        with ZKTransaction(zkhost) as t2:

            try:
                t2.lock_get('foo', timeout=0.5)
                self.fail('TXTimeout expected')
            except TXTimeout as e:
                dd(repr(e))

        th.join()
Exemplo n.º 3
0
    def test_journal_purge(self):

        n_tx = 10
        k = 'foo'

        for ii in range(n_tx):

            with ZKTransaction(zkhost) as t1:
                t1.zkstorage.max_journal_history = 5
                foo = t1.lock_get(k)
                foo.v = foo.v or 0
                foo.v += 1
                t1.set(foo)
                t1.commit()

        t = ZKTransaction(zkhost)
        journal_id_set, ver = t.zkstorage.journal_id_set.get()
        self.assertEqual({
            PURGED: [[0, 5]],
            COMMITTED: [[0, 10]]
        }, journal_id_set)

        for i in range(5):
            self.assertRaises(NoNodeError, t.zkstorage.journal.get,
                              '%010d' % i)
Exemplo n.º 4
0
    def test_committed(self):

        t = ZKTransaction(zkhost)
        txid = None

        with ZKTransaction(zkhost) as t1:

            txid = t1.txid

            # not set yet
            self.assertIsNone(t.zkstorage.state.get(txid)[0])

            foo = t1.lock_get('foo')
            foo.v = 100
            t1.set(foo)
            t1.set_state('bar')

            val, ver = t.zkstorage.state.get(txid)
            self.assertEqual(
                {
                    'got_keys': ['foo'],
                    'data': 'bar',
                    "start_ts": t1.start_ts
                }, val)

            t1.commit()

        self.assertIsNone(t.zkstorage.state.get(txid)[0])
Exemplo n.º 5
0
    def test_exception_with_state(self):

        t = ZKTransaction(zkhost)
        txid = None

        try:
            with ZKTransaction(zkhost) as t1:
                t1.lock_get('foo')
                raise ValueError('foo')
        except ValueError:
            pass

        nodes = t.zke.get_children('/lock')
        self.assertEqual([], nodes)

        try:
            with ZKTransaction(zkhost) as t2:
                txid = t2.txid
                t2.lock_get('foo')
                t2.set_state('bar')
                raise ValueError('foo')
        except ValueError:
            pass

        val, ver = t.zkstorage.state.get(txid)
        self.assertEqual({'got_keys': ['foo'], 'data': 'bar'}, val)

        nodes = t.zke.get_children('/lock')
        self.assertEqual(['foo'], nodes)
Exemplo n.º 6
0
    def test_exception(self):

        # tx raised by other exception is recoverable

        t = ZKTransaction(zkhost)
        txid = None

        try:
            with ZKTransaction(zkhost) as t1:

                txid = t1.txid
                t1.set_state('bar')
                start_ts = t1.start_ts

                val, ver = t.zkstorage.state.get(txid)
                self.assertEqual(
                    {
                        'got_keys': [],
                        'data': 'bar',
                        "start_ts": t1.start_ts
                    }, val)

                raise ValueError('foo')

        except ValueError:
            pass

        val, ver = t.zkstorage.state.get(txid)
        self.assertEqual({
            'got_keys': [],
            'data': 'bar',
            "start_ts": start_ts
        }, val)
Exemplo n.º 7
0
    def test_recover(self):

        txid = None
        with ZKTransaction(zkhost, timeout=0.5) as t1:

            txid = t1.txid
            f1 = t1.lock_get('foo')
            f2 = t1.lock_get('foo2')

            f1.v = "foo_val"
            f2.v = "foo2_val"

            t1.set(f1)
            t1.set(f2)

            t1.set_mem_state('bar')

        with ZKTransaction(zkhost, txid=txid, timeout=0.5) as t2:
            st = t2.get_state()
            self.assertEqual(None, st)

            f1 = t2.lock_get('foo')
            f2 = t2.lock_get('foo2')

            self.assertEqual(f1.v, None)
            self.assertEqual(f2.v, None)

            try:
                with ZKTransaction(zkhost, txid=txid, timeout=0.5) as t3:
                    dd(t3)
                self.fail("expected TXTimeout")
            except TXTimeout:
                pass
Exemplo n.º 8
0
    def test_sequential(self):

        n_tx = 10
        k = 'foo'

        for ii in range(n_tx):

            with ZKTransaction(zkhost) as t1:

                foo = t1.lock_get(k)
                foo.v = foo.v or 0
                foo.v += 1

                t1.set(foo)

                t1.commit()

        t = ZKTransaction(zkhost)

        rst, ver = t.zkstorage.record.get(k)
        dd(rst)
        self.assertEqual(n_tx, rst[-1])

        rst, ver = t.zkstorage.journal_id_set.get()
        dd(rst)
        self.assertEqual(n_tx, rst[COMMITTED].length())
Exemplo n.º 9
0
    def test_journal_purge(self):

        n_tx = 10
        k = 'foo'

        # ACACACACACACACACACAC
        # 01234567890123456789

        for ii in range(n_tx):

            with ZKTransaction(zkhost) as t1:
                t1.zkstorage.max_journal_history = 5
                foo = t1.lock_get(k)
                foo.v = 1
                t1.set(foo)
                t1.abort()

            t = ZKTransaction(zkhost)
            txidset, ver = t.zkstorage.txidset.get()
            self.assertLessEqual(txidset[COMMITTED].length(), 5)

            with ZKTransaction(zkhost) as t1:
                t1.zkstorage.max_journal_history = 5
                foo = t1.lock_get(k)
                foo.v = 1
                t1.set(foo)
                t1.commit()

            t = ZKTransaction(zkhost)
            txidset, ver = t.zkstorage.txidset.get()
            self.assertLessEqual(txidset[COMMITTED].length(), 5)
Exemplo n.º 10
0
    def test_redo_dead_tx_without_journal(self):

        t1 = ZKTransaction(zkhost)
        t1.begin()
        t1.lock_get('foo')

        t1.zke.stop()

        with ZKTransaction(zkhost) as t2:

            foo = t2.lock_get('foo')
            foo.v = foo.v or 0
            foo.v += 1

            t2.set(foo)
            t2.commit()

        t = ZKTransaction(zkhost)

        rst, ver = t.zkstorage.record.get('foo')
        dd(rst)
        self.assertEqual(1, rst[-1])

        journal_id_set, ver = t.zkstorage.journal_id_set.get()
        self.assertEqual({COMMITTED: [[0, 1]], PURGED: []}, journal_id_set)
Exemplo n.º 11
0
    def test_deepcopy_value(self):

        with ZKTransaction(zkhost) as t1:

            foo = t1.lock_get('foo')
            foo.v = {'foo': 'foo'}
            t1.set(foo)
            t1.commit()

        with ZKTransaction(zkhost) as t1:

            # When retrieving a dict, it should be deep-copied.
            # All zktx always though modified == original
            foo = t1.lock_get('foo')
            foo.v['foo'] = 'bar'
            t1.set(foo)
            t1.commit()

        rst, ver = self.zk.get('record/foo')
        self.assertEqual([{
            'foo': 'foo'
        }, {
            'foo': 'bar'
        }],
                         utfjson.load(rst)[-2:])
Exemplo n.º 12
0
    def test_exception_and_recover(self):

        # tx raised by other exception is recoverable

        t = ZKTransaction(zkhost)
        txid = None

        try:
            with ZKTransaction(zkhost) as t1:
                start_ts = t1.start_ts

                txid = t1.txid

                f1 = t1.lock_get('foox')
                f1.v = "foox_val"
                t1.set(f1)

                t1.set_state('bar')
                start_ts = t1.start_ts

                val, ver = t.zkstorage.state.get(txid)
                self.assertEqual(
                    {
                        'got_keys': ["foox"],
                        'data': 'bar',
                        "start_ts": start_ts
                    }, val)

                raise ValueError('foo')

        except ValueError:
            pass

        val, ver = t.zkstorage.state.get(txid)
        self.assertEqual(
            {
                'got_keys': ['foox'],
                'data': 'bar',
                "start_ts": start_ts
            }, val)

        ident = zkutil.make_identifier(txid, None)
        keylock = zkutil.ZKLock('foox',
                                zkclient=t.zke,
                                zkconf=t.zke._zkconf,
                                ephemeral=False,
                                identifier=ident)

        val, ver = keylock.get_lock_val()
        self.assertEqual(val['v'], "foox_val")

        with ZKTransaction(zkhost, txid=txid, timeout=1) as t1:
            self.assertEqual(t1.start_ts, start_ts)

            f1 = t1.lock_get('foox')
            self.assertEqual(f1.v, "foox_val")

            val = t1.get_state()
            self.assertEqual(val, 'bar')
Exemplo n.º 13
0
    def test_redo_all(self):

        # txid=1 committed
        # txid=2 nothing
        # txid=3 has journal
        # txid=4 no tx but has state
        # txid=5 committed

        # txid=1
        with ZKTransaction(zkhost) as t1:
            foo = t1.lock_get('foo')
            foo.v = 1
            t1.set(foo)
            t1.commit()

        t = ZKTransaction(zkhost)

        # make txid=2, leave it a hole
        t.zke.set(t.zke._zkconf.txid_maker(), 'x')

        # make txid=3
        t.zke.set(t.zke._zkconf.txid_maker(), 'x')
        txid = 3
        # fake a journal
        t.zkstorage.journal.create(txid, {'bar': 3})

        # txid=4, has state
        t.zke.set(t.zke._zkconf.txid_maker(), 'x')
        t.zkstorage.state.create(4, {'xx': 'yy'})

        # txid=5, committed
        with ZKTransaction(zkhost) as t5:
            foo = t5.lock_get('foo')
            foo.v = 5
            t5.set(foo)
            t5.commit()

        sets, ver = t.zkstorage.txidset.get()
        dd('init txidset:', sets)
        self.assertEqual({'PURGED': [], 'COMMITTED': [[1, 2], [5, 6]]}, sets)

        t.redo_all_dead_tx()  # redo txid=2, abort
        sets, ver = t.zkstorage.txidset.get()
        dd('after redo 2:', sets)
        self.assertEqual({'PURGED': [[2, 3]], 'COMMITTED': [[1, 2], [5, 6]]}, sets)

        t.redo_all_dead_tx()  # redo txid=3, committed
        sets, ver = t.zkstorage.txidset.get()
        dd('after redo 3:', sets)
        self.assertEqual({'PURGED': [[2, 3]], 'COMMITTED': [[1, 2], [3, 4], [5, 6]]}, sets)

        t.redo_all_dead_tx()  # redo txid=4, can not redo a tx with state
        sets, ver = t.zkstorage.txidset.get()
        dd('after redo 4, ignored 4:', sets)
        self.assertEqual({'PURGED': [[2, 3]], 'COMMITTED': [[1, 2], [3, 4], [5, 6]]}, sets)
Exemplo n.º 14
0
    def test_deadlock(self):

        # deadlock is not recoverable

        t = ZKTransaction(zkhost)
        # t.txid is lower
        t.begin()
        t.lock_get('foo')

        def _commit():
            t.commit()

        txid = None

        try:
            with ZKTransaction(zkhost, timeout=0.5) as t1:

                txid = t1.txid

                # lock another key first to produce deadlock
                t1.lock_get('woo')

                t1.set_state('bar')
                threadutil.start_daemon(_commit, after=0.2)
                t1.lock_get('foo')  # should deadlock waiting for higher txid

        except Deadlock:
            pass

        t = ZKTransaction(zkhost)
        self.assertIsNone(t.zkstorage.state.get(txid)[0])
Exemplo n.º 15
0
    def test_recover_and_timeout(self):

        # tx raised by other exception is recoverable

        t = ZKTransaction(zkhost)
        txid = None

        try:
            with ZKTransaction(zkhost) as t1:

                txid = t1.txid

                f1 = t1.lock_get('foox')
                f1.v = "foox_val"
                t1.set(f1)

                t1.set_state('bar')
                start_ts = t1.start_ts

                val, ver = t.zkstorage.state.get(txid)
                self.assertEqual(
                    {
                        'got_keys': ["foox"],
                        'data': 'bar',
                        "start_ts": t1.start_ts
                    }, val)

                raise ValueError('foo')

        except ValueError:
            pass

        val, ver = t.zkstorage.state.get(txid)
        self.assertEqual(
            {
                'got_keys': ["foox"],
                'data': 'bar',
                "start_ts": start_ts
            }, val)

        time.sleep(2)

        try:
            with ZKTransaction(zkhost, txid=txid, timeout=3) as t1:
                self.assertEqual(t1.start_ts, start_ts)

                f1 = t1.lock_get('foox')
                self.assertEqual(f1.v, "foox_val")

                val = t1.get_state()
                self.assertEqual(val, 'bar')
        except TXTimeout:
            pass
Exemplo n.º 16
0
    def test_list_recoverable(self):

        with ZKTransaction(zkhost, timeout=0.5) as t1:

            t1.lock_get('foo')
            t1.set_mem_state('bar')

            with ZKTransaction(zkhost, timeout=0.5) as t2:
                t2.lock_get('foo2')
                t2.set_mem_state('bar2')

            self.assertEqual([], [x for x in zktx.list_recoverable(zkhost)])
Exemplo n.º 17
0
    def test_unlock_with_state(self):

        # NotLocked is retrieable

        txid = None

        try:
            with ZKTransaction(zkhost, timeout=0.5) as t1:

                txid = t1.txid
                t1.set_state('bar')
                start_ts = t1.start_ts

                foo = t1.lock_get('foo')
                t1.unlock(foo)
                t1.unlock(foo)

        except NotLocked:
            pass

        t = ZKTransaction(zkhost)
        val, ver = t.zkstorage.state.get(txid)
        self.assertEqual({
            'got_keys': [],
            'data': 'bar',
            "start_ts": start_ts
        }, val)

        # UnlockNotAllowed is retrieable

        txid = None

        try:
            with ZKTransaction(zkhost, timeout=0.5) as t1:

                txid = t1.txid
                t1.set_state('bar')
                start_ts = t1.start_ts

                foo = t1.lock_get('foo')
                t1.set(foo)
                t1.unlock(foo)

        except UnlockNotAllowed:
            pass

        t = ZKTransaction(zkhost)
        val, ver = t.zkstorage.state.get(txid)
        self.assertEqual({
            'got_keys': [],
            'data': 'bar',
            "start_ts": start_ts
        }, val)
Exemplo n.º 18
0
    def test_noblocking_lock_get(self):

        with ZKTransaction(zkhost) as t1:

            t1.lock_get('foo')
            f2 = t1.lock_get('foo', blocking=False)
            self.assertIsNotNone(f2)

            with ZKTransaction(zkhost) as t2:

                f4 = t2.lock_get('foo', blocking=False)
                self.assertIsNone(f4)
Exemplo n.º 19
0
    def test_redo_dead_tx_without_journal(self):

        t1 = ZKTransaction(zkhost)
        t1.begin()
        t1.lock_get('foo')

        t1.zke.stop()

        with ZKTransaction(zkhost) as t2:

            foo = t2.lock_get('foo')
            foo.v = foo.v or 0
            foo.v += 1

            t2.set(foo)
            t2.commit()

        t = ZKTransaction(zkhost)

        rst, ver = t.zkstorage.record.get('foo')
        dd(rst)
        self.assertEqual(1, rst[-1][1])

        rst, ver = t.zkstorage.txidset.get()
        dd(rst)
        self.assertEqual([1, 2], rst[PURGED][0])
        self.assertEqual([2, 3], rst[COMMITTED][0])
Exemplo n.º 20
0
    def test_redo_dead_tx_without_journal(self):

        t1 = ZKTransaction(zkhost)
        t1.begin()
        t1.lock_get('foo')

        t1.zke.stop()

        with ZKTransaction(zkhost) as t2:

            foo = t2.lock_get('foo')
            foo.v = foo.v or 0
            foo.v += 1

            t2.set(foo)
            t2.commit()

        t = ZKTransaction(zkhost)

        rst, ver = t.zkstorage.record.get('foo')
        dd(rst)
        self.assertEqual(1, rst[-1])

        journal_id_set, ver = t.zkstorage.journal_id_set.get()
        self.assertEqual({COMMITTED: [[0, 1]], PURGED: []}, journal_id_set)
Exemplo n.º 21
0
    def test_uncommitted(self):

        # uncommitted is recoverable

        t = ZKTransaction(zkhost)
        txid = None

        with ZKTransaction(zkhost, timeout=0.5) as t1:

            txid = t1.txid
            t1.lock_get('foo')
            t1.set_state('bar')

        val, ver = t.zkstorage.state.get(txid)
        self.assertEqual({'got_keys': ['foo'], 'data': 'bar'}, val)
Exemplo n.º 22
0
    def test_list_recoverable(self):

        txid = None
        with ZKTransaction(zkhost, timeout=0.5) as t1:

            txid = t1.txid
            t1.lock_get('foo')
            t1.set_state('bar')

            with ZKTransaction(zkhost, timeout=0.5) as t2:
                txid = t2.txid
                t2.lock_get('foo2')
                t2.set_state('bar2')

            self.assertEqual([(txid, 'bar2')],
                             [x for x in zktx.list_recoverable(zkhost)])
Exemplo n.º 23
0
        def _tx(i):
            while True:
                try:
                    with ZKTransaction(zkhost) as t1:

                        for ii in range(len(ks)):
                            k = ks[(ii+i) % len(ks)]

                            foo = t1.lock_get(k)
                            foo.v = foo.v or 0
                            foo.v += 1

                            t1.set(foo)

                        t1.commit()
                        dd(str(t1) + ' committed')
                        return

                except (Deadlock,
                        HigherTXApplied) as e:
                    dd(str(t1) + ': ' + repr(e))
                    continue
                except TXTimeout as e:
                    dd(str(t1) + ': ' + repr(e))
                    raise
Exemplo n.º 24
0
    def test_abort(self):

        try:
            with ZKTransaction(zkhost) as t1:
                foo = t1.lock_get('foo')
                foo.v = 100
                t1.set(foo)
                t1.abort()
        except UserAborted:
            pass

        t = ZKTransaction(zkhost)

        rst, ver = t.zkstorage.record.get('foo')
        dd(rst)
        self.assertEqual(None, rst[-1])
Exemplo n.º 25
0
    def test_concurrent_single_record(self):

        n_tx = 10

        def _tx():
            while True:
                try:
                    with ZKTransaction(zkhost) as t1:

                        foo = t1.lock_get('foo')
                        foo.v = foo.v or 0
                        foo.v += 1

                        t1.set(foo)
                        t1.commit()
                        return

                except Deadlock as e:
                    dd(repr(e))
                    continue

        for th in [threadutil.start_daemon(_tx) for i in range(n_tx)]:

            th.join()

        t = ZKTransaction(zkhost)

        rst, ver = t.zkstorage.record.get('foo')
        dd(rst)
        self.assertEqual(n_tx, rst[-1])

        rst, ver = t.zkstorage.journal_id_set.get()
        dd(rst)
        self.assertEqual(n_tx, rst[COMMITTED].length())
Exemplo n.º 26
0
    def test_user_abort(self):

        t = ZKTransaction(zkhost)
        txid = None

        with ZKTransaction(zkhost) as t1:

            txid = t1.txid
            t1.set_state('bar')

            val, ver = t.zkstorage.state.get(txid)
            self.assertEqual({'got_keys': [], 'data': 'bar'}, val)

            t1.abort()

        self.assertIsNone(t.zkstorage.state.get(txid)[0])
Exemplo n.º 27
0
    def test_run_tx_unretriable_error(self):

        sess = dict(n=0)
        errs = [UserAborted, TXTimeout, ConnectionLoss, None]

        def _tx(tx, err):

            sess['n'] += 1

            foo = tx.lock_get('foo')
            foo.v = 100
            tx.set(foo)

            if err is not None:
                raise err()
            else:
                tx.commit()

        for err in errs:
            try:
                zktx.run_tx(zkhost, _tx, args=(err, ))
            except TXError as e:
                dd(repr(e))

        self.assertEqual(len(errs), sess['n'])

        tx = ZKTransaction(zkhost)
        rst, ver = tx.zkstorage.record.get('foo')
        self.assertEqual(100, rst[-1])
Exemplo n.º 28
0
    def test_unlock_changed_record(self):

        with ZKTransaction(zkhost) as t1:

            foo = t1.lock_get('foo')
            t1.set(foo)
            self.assertRaises(UnlockNotAllowed, t1.unlock, foo)
Exemplo n.º 29
0
    def test_unlock_nonlocked(self):

        with ZKTransaction(zkhost) as t1:

            foo = t1.lock_get('foo')
            t1.unlock(foo)
            self.assertRaises(NotLocked, t1.unlock, foo)
Exemplo n.º 30
0
    def test_unlock(self):

        with ZKTransaction(zkhost) as t1:

            foo = t1.lock_get('foo')
            t1.unlock(foo)

            self.assertEqual({}, t1.got_keys)

            # re-get is ok
            foo = t1.lock_get('foo')
            t1.unlock(foo)

            with ZKTransaction(zkhost) as t2:
                # t2 can lock a unlocked key
                t2.lock_get('foo')
Exemplo n.º 31
0
    def test_abort(self):

        with ZKTransaction(zkhost) as t1:
            foo = t1.lock_get('foo')
            foo.v = 100
            t1.set(foo)
            t1.abort()

        t = ZKTransaction(zkhost)

        rst, ver = t.zkstorage.record.get('foo')
        dd(rst)
        self.assertEqual(None, rst[-1][1])

        rst, ver = t.zkstorage.txidset.get()
        dd(rst)
        self.assertEqual([1, 2], rst[PURGED][0])
Exemplo n.º 32
0
    def test_deadlock(self):

        # deadlock is not recoverable

        t = ZKTransaction(zkhost)
        # t.txid is lower
        t.begin()
        t.lock_get('foo')

        def _commit():
            t.commit()

        txid = None

        try:
            with ZKTransaction(zkhost, timeout=0.5) as t1:

                txid = t1.txid

                # lock another key first to produce deadlock
                t1.lock_get('woo')

                t1.set_state('bar')
                threadutil.start_daemon(_commit, after=0.2)
                t1.lock_get('foo')  # should deadlock waiting for higher txid

        except Deadlock:
            pass

        t = ZKTransaction(zkhost)
        self.assertIsNone(t.zkstorage.state.get(txid)[0])
Exemplo n.º 33
0
    def test_timeout(self):

        # timeout on waiting is recoverable

        t = ZKTransaction(zkhost)
        txid = None

        try:
            with ZKTransaction(zkhost, timeout=0.5) as t1:

                txid = t1.txid

                # t.txid is higher
                t.begin()
                t.lock_get('foo')

                t1.set_state('bar')
                t1.lock_get('foo')  # should timeout waiting for higher txid

        except TXTimeout:
            pass

        val, ver = t.zkstorage.state.get(txid)
        self.assertEqual({'got_keys': [], 'data': 'bar'}, val)
Exemplo n.º 34
0
    def test_single_record(self):

        tx = ZKTransaction(zkhost)
        tx.begin()

        foo = tx.lock_get('foo')
        self.assertEqual('foo', foo.k)
        self.assertIsNone(foo.v)
        foo.v = 1

        tx.set(foo)

        tx.commit()

        rst, ver = self.zk.get('record/foo')
        self.assertEqual([None, 1], utfjson.load(rst))

        rst, ver = self.zk.get('tx/journal_id_set')
        self.assertEqual({COMMITTED: [[0, 1]],
                          PURGED: [],
                          }, utfjson.load(rst))
Exemplo n.º 35
0
    def test_noblocking_lock_get(self):

        with ZKTransaction(zkhost) as t1:

            t1.lock_get('foo')
            f2 = t1.lock_get('foo', blocking=False)
            self.assertIsNotNone(f2)

            with ZKTransaction(zkhost) as t2:

                f4 = t2.lock_get('foo', blocking=False)
                self.assertIsNone(f4)

        t = ZKTransaction(zkhost)
        t.begin()
        t.lock_get('foo')
        t.zke.stop()

        dd(self.zk.get('lock/foo'))
        # can lock the key which is hold by a dead tx without state
        with ZKTransaction(zkhost) as t1:
            self.assertIsNotNone(t1.lock_get('foo', blocking=False))

        t = ZKTransaction(zkhost)
        t.begin()
        t.lock_get('foo')
        t.set_state('s')
        t.zke.stop()

        dd(self.zk.get('lock/foo'))
        # can not lock the key which is hold by a dead tx with state
        with ZKTransaction(zkhost) as t1:
            self.assertIsNone(t1.lock_get('foo', blocking=False))