[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