b594c68f1cc15b1a4a6275f978734cf22289245c
[multicloud/framework.git] / multivimbroker / multivimbroker / pub / utils / share_lock.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # Copyright (c) 2017 Wind River Systems, Inc.
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at:
8 #       http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
14 import time
15
16 import redis
17
18 from multivimbroker.pub.config.config import REDIS_HOST, REDIS_PORT, REDIS_PASSWD
19
20
21 class SharedLock:
22     def __init__(self, lock_key, host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWD, db=9, lock_timeout=5 * 60):
23         self.lock_key = lock_key
24         self.lock_timeout = lock_timeout
25         self.redis = redis.Redis(host=host, port=port, db=db, password=password)
26         self.acquire_time = -1
27
28     def acquire(self):
29         begin = now = int(time.time())
30         while (now - begin) < self.lock_timeout:
31
32             result = self.redis.setnx(self.lock_key, now + self.lock_timeout + 1)
33             if result == 1 or result is True:
34                 self.acquire_time = now
35                 return True
36
37             current_lock_timestamp = self.redis.get(self.lock_key)
38             if not current_lock_timestamp:
39                 time.sleep(1)
40                 continue
41
42             current_lock_timestamp = int(current_lock_timestamp)
43
44             if now > current_lock_timestamp:
45                 next_lock_timestamp = self.redis.getset(self.lock_key, now + self.lock_timeout + 1)
46                 if not next_lock_timestamp:
47                     time.sleep(1)
48                     continue
49                 next_lock_timestamp = int(next_lock_timestamp)
50
51                 if next_lock_timestamp == current_lock_timestamp:
52                     self.acquire_time = now
53                     return True
54             else:
55                 time.sleep(1)
56                 continue
57         return False
58
59     def release(self):
60         now = int(time.time())
61         if now > self.acquire_time + self.lock_timeout:
62             # key expired, do nothing and let other clients handle it
63             return
64         self.acquire_time = None
65         self.redis.delete(self.lock_key)
66
67
68 def do_biz_with_share_lock(lock_name, callback):
69     lock = SharedLock(lock_name)
70     try:
71         if not lock.acquire():
72             raise Exception(lock_name + " timeout")
73         callback()
74     except Exception as e:
75         raise e
76     finally:
77         lock.release()