Comunidad Gambas-es
Identificador único universal - Versión para impresión

+- Comunidad Gambas-es (https://gambas-es.org)
+-- Foro: Gambas (https://gambas-es.org/forum-3.html)
+--- Foro: Aplicaciones/Fragmentos de Código (https://gambas-es.org/forum-8.html)
+--- Tema: Identificador único universal (/thread-1355.html)

Páginas: 1 2 3


RE: Identificador único universal - tercoide - 11-05-2023

La palabra "universal" implica otros planetas lejanos?

Yo diria que solo es necesario chequear en el entorno donde se usara la informacion puesto que es imposible saber si es unico habiando multiples dispositivos generandolos. En todo caso, suponiendo que estamos desarrollando software multi-PC o multi-Servidor y que cada servidor tiene asignado un nombre o numero se podrian generar codigos del tipo:

123e4567-e89b-12d3-a456-426655440000 

donde cada parte es, por ejemplo 

timestamp - maquina - usuario - sub proceso - incremental 

entonces cada PC/servidor podria generar un numero que seria unico en todo el sistema que aloja o usa el software porque cada maquina es unica, y la velocidad no importa porque el INCREMENTAL se va agrandando a medida que se generan items en la lista, en un ejemplo practico:

La MAQUINA 1 genera a las 12:00 del 01/01/2024 una operacion X, siendo la primera del dia:

0101241200-0001-0000-000000000001

La MAQUINA 2 genera a las 12:00 del 01/01/2024 una operacion X, siendo la primera del dia:

0101241200-0002-0000-000000000001

y ambos son unicos en el todo sistema


RE: Identificador único universal - Shordi - 11-05-2023

Cita:timestamp - maquina - usuario - sub proceso - incremental 

entonces cada PC/servidor podria generar un numero que seria unico en todo el sistema que aloja o usa el software porque cada maquina es unica, y la velocidad no importa porque el INCREMENTAL se va agrandando a medida que se generan items en la lista, en un ejemplo practico:

La MAQUINA 1 genera a las 12:00 del 01/01/2024 una operacion X, siendo la primera del dia:

0101241200-0001-0000-000000000001

La MAQUINA 2 genera a las 12:00 del 01/01/2024 una operacion X, siendo la primera del dia:

0101241200-0002-0000-000000000001

y ambos son unicos en el todo sistema
Eso es lo mismo, más o menos, que sugería yo más arriba, pero lo veo excesivamente complejo.
Usando el timestamp sin más ya tienes hecho la mitad del camino. Añade símplemente el nombre de la máquina o el ID del disco duro y ya está.
Lo del incremental no lo tengo claro porque ¿Cómo sabe el sistema emisor qué día es si el 1 o el 2?
Para ello el sistema receptor es quien debiera signar el código único... y en tal caso con el TimeStamp es suficiente porque no hay posibilidad de duplicidad.

En el caso que plantea Tincho, que el código sea irrepetible "per se", creo que el problema es irresoluble de por sí habiendo distintas máquinas generando los códigos. Hay que basarse en algo más.

Saludos


RE: Identificador único universal - tincho - 11-05-2023

Si tienen un momento estudien este código que les paso, donde en un bucle le pido 1 millón de claves irrepetibles y solo cumple el el método que usa el archivo del sistema "/proc/sys/kernel/random/uuid"

Algo mas de información sobre lo que es un UUID
https://digitalbunker.dev/understanding-how-uuids-are-generated/


RE: Identificador único universal - Shordi - 12-05-2023

Se acerca a lo que intentas... pero aunque la ratio de claves únicas conseguidas fuese del 100%, eso sólo indica que en una máquina se puede hacer única... pero no dice nada de que las claves generadas en las demás máquinas que generen los ID no vayan a ser iguales nunca.

Te adjunto una propuesta con TimeStamp que sí genera claves únicas sin recurrir a nada externo a Gambas. Le he puesto dos tests, por tiempo o por número de veces. T2 te daba siempre 0 porque no le dabas tiempo suficiente dado que se generan, más o menos 20.000 claves por segundo.

Saludos


RE: Identificador único universal - tercoide - 12-05-2023

(11-05-2023, 18:20)Shordi escribió: Lo del incremental no lo tengo claro porque

Eso es para resolver el problema de la velocidad de generacion. Si solo se logran 20k/seg de claves sera insuficiente. AutoDesk en los archivos CAD usa un indice incremental que empieza en 0 y se incremente en cada generacion de un nuevo objeto: 
Código:
Public lIndex as Long = 0


Public Function NewID() as String
   Inc lIndex
   Return Hex(lIndex)
End Function



RE: Identificador único universal - Shordi - 12-05-2023

Cita:Eso es para resolver el problema de la velocidad de generacion. Si solo se logran 20k/seg de claves sera insuficiente.
¿Insuficiente para qué? Creo que no he entendido el problema aún...


RE: Identificador único universal - tercoide - 12-05-2023

Claro, Tincho necesita un UUID de algun tipo para asociarlo a algun dato, que puede ser cualquier cosa. Pero para poder responder a su inquietud es necesario saber para que lo necesita. Mi aproximacion a la solucion del problema esta pensada para un programa CAD donde puede ser necesario duplicar las entidades de un plano (textos, lineas, circulos, etc) y puede haber 20.000.000 de esas entidades. Por lo tanto es inaceptable esperar 1.000 segundos para generar UUID para cada una de ellas, entonces ¿que tan unicas tienen que ser las claves UUID? ¿en que contexto tienen que ser unicas? ¿para el documento grafico en cuestion? ¿para la PC en cuestion? ¿para el entorno de trabajo, PCs, Users, etc? 
En el ejemplo que planteo solo es necesario que sean unicas en el grafico. Suponiendo que copio parte de un grafico y lo pego en otro grafico, entonces puede haber conflicto de UUID, pero en el proceso de copiado el software debe generar nuevas UUID para los datos copiados en el otro contexto (el segundo grafico). 

Por ejemplo, Voutt se cansa de Italia y se va a vivir a China. Su numero de pasaporte ITALIANO puede ser igual al de un chino, pero es otro contexto entonces no importa. Cuando VOUTT pida nacionalidad CHINA le asignaran otro numero de pasaporte, y sera unico.


RE: Identificador único universal - vuott - 12-05-2023

tincho,
en Mailing List preguntaste si alguien sabe como usar Extern con libuuid.

He encontrado un ejemplo en lenguaje C que funciona, pero cuando lo traduzco a Gambas:
Código:
Library "libuuid:1.3.0"

Private Const UUID_STR_LEN As Integer = 37

' void uuid_generate(uuid_t out)
Private Extern uuid_generate(out As Integer)

' void uuid_unparse_lower(const uuid_t uu, char *out)
Private Extern uuid_unparse_lower(uu As Integer, out As Byte[]) As Integer


Public Sub Main()

  Dim uuid As New Byte[UUID_STR_LEN]
  Dim i As Integer
  
  uuid_generate(i)
  
  uuid_unparse_lower(i, uuid)
  
  Print uuid.ToString(0, 36)

End
me da un Sad error en la primera función externa de la librería 'libuuid'.
Lamentablemente también encuentro este problema Sad con otros códigos similares con la librería 'libuuid'.

 
Para resolver el problema y presentarte un código que siga utilizando las funciones externas de la librería 'libuuid', escribí una librería .so compartida externa especial, que implementa precisamente dos funciones externas de la librería 'libuuid'.
Dejo aquí el código de trabajo adecuado para el uso de mi librería externa, que he llamado "libcreauuid.so".

Código:
' char * creauuid()
Private Extern creauuid() As Pointer In "/tmp/libcreauuid"

Public Sub Main()

  Dim p As Pointer
  
  Creaso()
  
  p = creauuid()
  
  Print String@(p)

End


Private Procedure Creaso()
  
  File.Save("/tmp/libcreauuid.c", "#include <stdlib.h>\n#include <stdio.h>\n#include <uuid/uuid.h>\n\n" &
            "char out[UUID_STR_LEN]={0};\n\n"
            "char * creauuid() {\n\n" &
            "uuid_t i;\n\n" &
            "   uuid_generate(i);\n\n" &
            "   uuid_unparse_lower(i, out);\n\n" &
            "   return out;\n\n}")
  
  Shell "gcc -o /tmp/libcreauuid.so /tmp/libcreauuid.c -luuid -shared -fPIC" Wait
  
End



RE: Identificador único universal - tincho - 12-05-2023

(12-05-2023, 14:16)vuott escribió: He encontrado un ejemplo en lenguaje C que funciona, pero cuando lo traduzco a Gambas:

Si, vi ese código también pero no supe convertirlo a gambas, te felicito por hacerlo.
(12-05-2023, 14:16)vuott escribió: me da un Sad error en la primera función externa de la librería 'libuuid'.

Estoy probando tu código y también me da error.
(12-05-2023, 13:32)Shordi escribió: ¿Insuficiente para qué? Creo que no he entendido el problema aún...

El objetivo es lograr un UUID (como el definido en el estándar RFC 4122) en gambas si recurrir a uuidgen (el programa de la terminal de Linux) ni tomarlo del archivo "/proc/sys/kernel/random/uuid"

Para mas información sobre que las características técnicas de un UUID vean el siguiente articulo de wikipedia:
https://es.wikipedia.org/wiki/Identificador_%C3%BAnico_universal
Cita:Una muestra de 3,26*10¹⁶ UUID tiene un 99,99% de posibilidades de no tener duplicados. Generar tantos UUID, a razón de uno por segundo, llevaría mil millones de años. Así que, aunque los UUID no son realmente únicos, sí lo son lo suficiente a efectos prácticos, teniendo en cuenta las limitaciones naturales de la vida humana y la separación de los sistemas.

(12-05-2023, 13:58)tercoide escribió: Claro, Tincho necesita un UUID de algun tipo para asociarlo a algun dato, que puede ser cualquier cosa. Pero para poder responder a su inquietud es necesario saber para que lo necesita.

Para que lo necesito en este caso es para asignar una clave única a cada ítem de una lista de una colección. Para lo que valdría la ultima versión del código de Shordi, que ademas tiene la ventaja de permitir ordenar la lista por dichas claves. Pero este post apunta a otro sitio.

Mi pregunta es mas general y no esta sujeta a un entorno en concreto, sino que (si leen la definición del UUID de wikipedia) se trata de obtener el identificador con recursos de gambas o tal vez con Extern y la librería libuuid, que cumpla con el estándar RFC 4122.

(11-05-2023, 18:01)tercoide escribió: La palabra "universal" implica otros planetas lejanos?

La respuesta a esto, aunque parezca un chiste, es si. Smile


RE: Identificador único universal - tincho - 12-05-2023

Bueno lo que compartió Vuott funciono perfectamente, les dejo aquí el código adaptado a trabajar como una función (uuid.class):
Código:
' Gambas class file

Export

Library "libuuid"

Private Const UUID_STR_LEN As Integer = 37

' void uuid_generate(uuid_t out)
Private Extern uuid_generate(out As Integer)

' void uuid_unparse_lower(const uuid_t uu, char *out)
Private Extern uuid_unparse_lower(uu As Integer, out As Byte[]) As Integer

Private Extern creauuid() As Pointer In "/tmp/libcreauuid"

Static Public Function Gen() As String

  Dim p As Pointer

  If Not Exist("/tmp/libcreauuid.so") Then
    File.Save("/tmp/libcreauuid.c", "#include <stdlib.h>\n#include <stdio.h>\n#include <uuid/uuid.h>\n\n" &
      "char out[UUID_STR_LEN]={0};\n\n"
    "char * creauuid() {\n\n" &
      "uuid_t i;\n\n" &
      "   uuid_generate(i);\n\n" &
      "   uuid_unparse_lower(i, out);\n\n" &
      "   return out;\n\n}")

    Shell "gcc -o /tmp/libcreauuid.so /tmp/libcreauuid.c -luuid -shared -fPIC" Wait
  Endif

  p = creauuid()

  Return String@(p)

End

El código de Shordi es el mas rápido de todos y si bien no genera un uuid estándar, funcionaria muy bien entornos locales incluso puede incorporarse algún prefijo para diferenciar una computadora de otra. Pero no en el infinito y mas allá !! Big Grin
Lo usare para generar las claves del control de listas.
Dejo el código toqueteado:
Código:
Public Function UIDBro() As String

  Static nkey As Integer
  Static sLastKey As String
  Dim sOffset As String
  Static sCurrKeytKey As String
  Dim sMark As String
  ' Utilizo la forma ISO 2023-05-12 22:48:01.235
  sCurrKeytKey = Format(Now(), "yyyymmddhhnnssuu")
  If sCurrKeytKey <> sLastKey Then
    sLastKey = sCurrKeytKey
    nkey = 0
    ' Pongo una marca para saber donde se resetea el contador, luego en produccion hay que comentar est alinea
    sMark = "---"
  Endif

  sOffset = Right("00000" & Str(nkey), 5) & sMark
  sMark = ""
  Inc nkey
  Return sCurrKeytKey & sOffset

End

La velocidad de cada método es la siguiente:
 
Cita:Algorithm Kernel works, for 100000 attempts it took 0.743848797999817 milliseconds.
Algorithm Timestamp works, for 100000 attempts it took 0.14394091000031 milliseconds.
The algorithm Randomize is risky as out of a rate of 100000 attempts only 99999 were unique.
Algorithm C-Library works, for 100000 attempts it took 0.985727743000098 milliseconds.

Las conclusiones que saco son las siguientes:
  • Si hay que registrar los datos, utilizo el UUID del Kernel(Tincho) como ID del registro y el Timestamp(Shordi) es decir como te llamas y cuando viniste, son dos conceptos distintos, dos campos distintos.
  • Si NO hay que registrar los datos, o por lo menos no hay que usar el UUID para ello con un simple numero vale, en el caso de las colecciones con un String HEX valdría.
TercoIDE tiene que enviar la función de como lo hacia en GambasCAD para las entidades. Big Grin

[Imagen: 0n8qctn.png]