Source code for cup.services.generator
#!/usr/bin/env python
# -*- coding: utf-8 -*
# Copyright: [CUP] - See LICENSE for details.
# Authors: Guannan Ma (@mythmgn),
"""
class CGeneratorMan(object)
===========================
Generate unique integers, strings and auto incremental uint.
Notice CGeneratorMan is a singleton class, which means cup will keep
only 1 instance per process.
:init:
__init__(self, str_prefix=get_local_hostname())
local hostname will be used by default.
:methods:
**get_uniqname()**
get unique name.
Host-Level unique name (build upon str_prefix, pid, threadid)
**get_next_uniq_num()**
Process-level auto incremental uint. Thread-safe
**reset_uniqid_start(num=0)**
Reset next uniqid to which genman starts from
**get_random_str()**
Get random string by length
**get_uuid()**
Get uuid
"""
import os
import time
import uuid
import random
import string
import socket
import struct
import hashlib
import threading
try:
import Queue as queue
except ImportError:
import queue
import cup
from cup import log
from cup import decorators
__all__ = [
'CGeneratorMan',
'CycleIDGenerator',
'CachedUUID'
]
UUID1 = 0
UUID4 = 1
_UUID_LISTS_FUNCS = [
uuid.uuid1,
uuid.uuid4
]
@decorators.Singleton
class CGeneratorMan(object):
"""
refer to the docstring
"""
def __init__(self, str_prefix='localhost'):
"""
Generate unique integers, strings and auto incremental uint.
"""
if str_prefix == 'localhost':
prefix = cup.net.get_local_hostname()
else:
prefix = str(str_prefix)
self._prefix = prefix + str(os.getpid())
self._lock = threading.Lock()
self._ind = 0
self._nlock = threading.Lock()
self._nind = 0
def reset_uniqid_start(self, num=0):
"""
reset next uniqid to which genman starts from.
"""
self._lock.acquire()
self._nind = num
self._lock.release()
def get_uniqname(self):
"""
get a unique name
"""
self._lock.acquire()
strrev = self._prefix + str(self._ind) + '_thd_' + \
str(threading.current_thread().ident)
self._ind = self._ind + 1
self._lock.release()
return strrev
def get_next_uniq_num(self):
"""
get next uniq num. Thread-safe
"""
self._nlock.acquire()
temp = self._nind
self._nind += 1
self._nlock.release()
return temp
def get_next_uniqhex(self):
"""
return next uniqhex
"""
temp = self.get_next_uniq_num()
return str(hex(temp))
@classmethod
def get_random_str(cls, length):
"""get random str by length"""
return ''.join(random.choice(string.lowercase) for i in range(length))
@classmethod
def get_uuid(cls):
"""get random uuid"""
import uuid
uuid.uuid4()
[docs]class CycleIDGenerator(object):
"""
cycle id generator. 128bit ID will be produced.
128 bit contains: a. 64bit [ip, port, etc] b. 64bit[auto increment id]
"""
def __init__(self, ip, port):
"""
ip, port will be encoded into the ID
"""
self._ip = ip
self._port = port
self._lock = threading.Lock()
packed = socket.inet_aton(self._ip)
tmp = struct.unpack("!L", packed)[0] << 96
self._pre_num = tmp | (int(self._port) << 64)
self._max_id = 0X1 << 63
self._next_id = int(time.time())
[docs] def reset_nextid(self, nextid):
"""reset nextid that will return to you"""
self._lock.acquire()
if nextid > self._max_id:
self._lock.release()
return False
self._next_id = nextid
self._lock.release()
return True
[docs] def next_id(self):
"""get next id"""
self._lock.acquire()
num = self._pre_num | self._next_id
if self._next_id == self._max_id:
self._next_id = 0
else:
self._next_id += 1
self._lock.release()
return num
[docs] @classmethod
def id2_hexstring(cls, num):
"""return hex of the id"""
str_num = str(hex(num))
return str_num
@decorators.Singleton
class CachedUUID(object):
"""cached uuid object"""
def __init__(self, mode=UUID1, max_cachenum=100):
"""
ip, port will be encoded into the ID
"""
if mode > len(_UUID_LISTS_FUNCS):
raise ValueError('only support UUID1 UUID4')
self._uuidgen = _UUID_LISTS_FUNCS[mode]
self._fifoque = queue.Queue(max_cachenum)
self._max_cachenum = max_cachenum
def get_uuid(self, num=1):
"""
get serveral uuids by 'num'
:return:
a list of uuids (in hex string)
"""
ret = []
while num > 0:
try:
item = self._fifoque.get(block=False)
ret.append(item)
num -= 1
except queue.Empty:
self.gen_cached_uuid()
return ret
def gen_cached_uuid(self, num=50):
"""
generate num of uuid into cached queue
"""
while num > 0:
try:
md5obj = hashlib.md5()
hexstr = self._uuidgen().hex
if isinstance(hexstr, unicode):
md5obj.update(hexstr.encode('utf-8'))
else:
md5obj.update(hexstr)
self._fifoque.put(md5obj.hexdigest(), block=False)
num -= 1
except queue.Full:
break
size = self._fifoque.qsize()
log.info('after generate cached uuid queue size :{0}'.format(size))
# vi:set tw=0 ts=4 sw=4 nowrap fdm=indent