[Zope] GUID Equivalent in Zope?
Johan Carlsson
johanc at easypublisher.com
Fri Sep 12 15:24:05 EDT 2003
Philip Kilner wrote:
> Andy McKay wrote:
>> http://www.zope.org/Members/andym/GUID
>> "Ever had to generate unique ids? If you are running on Windows one
>> simple answer is the GUID generation system from Microsoft"
> You're a star!
There's also a none Windows GUID Python class at ActiveState
(that might be useful if you ever consider other plattforms):
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/163604
which I have made a Zope GUIDGenerator for:
#!/usr/bin/python
# A globally unique identifier made up of time and ip
# Copyright (C) 2002 Dr. Conan C. Albrecht <conan_albrecht at byu.edu>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import random
import socket
import time
from Persistence import Persistent
class GUID:
"""\
A globally-unique identifier made up of time and ip and the server
(client) port or 4 random digits:
36 characters wide
A globally unique identifier that combines ip, time, and random
bits. Since the
time is listed first, you can sort records by guid. You can
also extract the time
and ip if needed.
GUIDs make wonderful database keys. They require no access to the
database (to get the max index number), they are extremely
unique, and they sort
automatically by time. GUIDs prevent key clashes when merging
two databases together, combining data, or generating keys in
distributed
systems.
"""
rand = random.Random()
ip = ''
hexip = ''
lastguid = ''
def __init__(self, guid=None, port=None):
"""\
Constructor. Use no args if you want the guid generated (this
is the normal method)
or send a string-typed guid to generate it from the string
"""
if guid == None:
ip = ''
hexip = ''
try:
ip = socket.gethostbyname(socket.gethostname())
except (socket.gaierror): # if we don't have an ip, default
to someting in the 10.x.x.x private range
ip = '10'
for i in range(3):
ip += '.' + str(self.rand.randrange(1, 254))
hexip = ''.join(["%04x" % long(i) for i in ip.split('.')])
# leave space for ip v6 (65K in each sub)
ip_tuple=tuple(ip.split('.'))
if port is None or port>65535:
port=self.rand.randrange(1, 65535)
hexport=("%04x" % port)
guid = self.__class__.lastguid
while guid == self.__class__.lastguid:
timestamp = long(time.time() * 1000)
hextimestamp = "%016x" % timestamp
guid = hextimestamp + hexip + hexport
self.__class__.lastguid=self.__guid=guid
elif type(guid) == type(self):
self.update(guid)
else:
self.__guid=guid
def parse_guid(self, guid):
if type(guid)!=StringType or len(guid)!=36:
raise "InvalidGUID", "'%s' isn't a valid GUID." % str(guid)
hextimestamp=guid[0:16]
hexip=guid[16:32]
hexport=guid[32:36]
timestamp=long(guid[0:16], 16)
ip_tuple=()
for sub in (hexip[0:4], hexip[4:8], hexip[8:12], hexip[12:16]):
sub=eval('0x'+sub, {}, {})
ip_tuple=ip_tuple+(sub,)
ip='.'.join(ip_tuple)
port=eval('0x'+hexport, {}, {})
return timestamp, ip, ip_tuple, port,hextimestamp, hexip, hexport
def update(self, guid):
if type(guid) != type(self):
raise "InvalidGUID", "The value passed was not of the type
GUID."
self.__guid=self.getGUID()
def __str__(self):
"""Returns the string value of this guid"""
return self.__guid
def __repr__(self):
"""Returns the string value of this guid"""
return "<GUID %s />" % self.__guid
def getGUID(self):
return self.__guid
def getHexTimestamp(self):
return self.__guid[0:16]
def getHexIP(self):
return self.__guid[16:32]
def getHexPort(self):
return self.__guid[-4:]
def getTimestamp(self):
"""Extracts the time portion out of the guid and returns the
number of milliseconds since the epoch"""
return long(self.__guid[0:16], 16)
def getIP(self):
"""Extracts the ip portion out of the guid and returns it
as a string like 10.10.10.10"""
# there's probably a more elegant way to do this
ip = ''
index = 16
while index < 32:
if ip != '':
ip += "."
ip += str(int(self.__guid[index: index + 4], 16))
index += 4
return ip
def getIP_tuple(self):
ip_tuple=()
for sub in (self.__guid[16:20], self.__guid[20:24],
self.__guid[24:28], self.__guid[28:32]):
ip_tuple=ip_tuple+(int(sub, 16),)
return ip_tuple
def getPort(self):
"""Extracts the random bits from the guid. I have no idea
how this would be useful, but I've included it for
completeness"""
return int(self.__guid[-4:], 16)
class GUIDGenerator(Persistent):
"""\
This GUIDGenerator does provide a unique ID.
If two threads collide this the same GUID new none equal GUIDs will be
created and returned.
GUIDs are based on time and ip-adress and a random number.
The only time as GUID could be same is if the machines have the
same ip-address
and/or on machine has two server instances on different ports (this
needs to be fixed).
"""
_value=None
def createGUID(self):
self._value=GUID()
return self._value
def _p_resolveConflict(self, oldState, savedState, newState):
if savedState['_value'] == oldState['_value'] or
savedState['_value'] == newState['_value']:
oldState['_value'] = GUID()
return oldState
# XXX What if _p_resolveConflict _thinks_ it resolved the
# conflict, but did something wrong?
if __name__ == "__main__":
# just print out a for testing
guid = GUID()
print "GUID: " + str(guid)
millis = guid.time()
print "Time: " + str(millis) + " millis (" +
time.asctime(time.gmtime(millis / 1000)) + " UTC)"
print "IP: " + guid.ip()
print "Rand: " + str(guid.random())
--
Johan Carlsson Tel: + 46 8 31 24 94
Colliberty Mob: + 46 70 558 25 24
Torsgatan 72 Email: johanc at easypublisher.com
SE-113 37 STOCKHOLM
More information about the Zope
mailing list