AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein TGUID - einzigartige ID auf andere Computer Systeme ?
Thema durchsuchen
Ansicht
Themen-Optionen

TGUID - einzigartige ID auf andere Computer Systeme ?

Ein Thema von paule32.jk · begonnen am 20. Okt 2023 · letzter Beitrag vom 2. Nov 2023
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.358 Beiträge
 
Delphi 11 Alexandria
 
#1

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 27. Okt 2023, 12:17
Ich habe mir für den Zweck eine eigene Guid aufgebaut.
Wichtig ist mir, dass diese global persistent eindeutig sind und dass die Reihenfolge (jedenfalls auf einem Rechner) aufsteigend nachvollziehbar ist.

Sie besteht aus zwei Zeitstempeln und einem fortlaufenden Zähler.
Der erste Zeitstempel enthält den Moment des Projektstarts (ist also so eine Art Session-ID), der zweite den Moment der ID-Erzeugung.
Der Zähler läuft bei jeder ID-Erzeugung weiter zwischen 0 bis 65535. So ist die Reihenfolge gut nachvollziehbar und es gibt noch eine Differenzierung falls doch mal beide Zeitstempel auf zwei Geräten gleich sein sollten.

Ich bin nicht auf die Standard-Guid angewiesen und so ist das für mich sinnvoller und nachvollziehbarer.
Sie braucht mit 18 Byte zwei Byte mehr als die Standard-Guid.

Delphi-Quellcode:
unit myGuid;

interface

  uses

    System.Classes;

  const

    MaxWord = 65535;

  type

    PmyGuid = ^TmyGuid;

    TmyGuid = record //: 18 Byte / 144 Bit
      C : Word; //: 2 Byte / 16 Bit
      TS1: TDateTime; //: 8 Byte / 64 Bit
      Ts2: TDateTime; //: 8 Byte / 64 Bit
      class function Create(const aGuid: PmyGuid): TmyGuid; overload; static;
      class function Create(const aGuid: String): TmyGuid; overload; static;
      class function Create(const aGuid: TmyGuid): TmyGuid; overload; static;
      class function CreateEmpty: TmyGuid; static;
      class function CreateNew: TmyGuid; static;
      class function StringIsValidGuid(const aGuid: String): Boolean; static;
      class operator Equal(const Left, Right: TmyGuid): Boolean;
      class operator NotEqual(const Left, Right: TmyGuid): Boolean; inline;
      function GetHashCode: Integer;
      function IsEmpty: Boolean;
      function ToString: String;
      procedure DoEmpty;
      procedure DoNew;
      procedure FromString(const aGuid: String);
      procedure ReadFromStream(const aStream: TMemoryStream);
      procedure WriteToStream(const aStream: TMemoryStream);
    end;

implementation

  uses

    System.SysUtils, System.DateUtils, System.Hash;

  var

    customTS1: TDateTime = 0;
    customTS2: TDateTime = 0;
    customC : Word = 0;

  {: *********************************** TmyGuid ********************************** :}

  {: ----------------------------------- default ---------------------------------- :}

  //: 2023-10-27
  class function TmyGuid.Create(const aGuid: String): TmyGuid;
  begin
    Result := TmyGuid.CreateEmpty;
    Result.FromString(aGuid);
  end;

  //: 2023-10-27
  class function TmyGuid.Create(const aGuid: TmyGuid): TmyGuid;
  begin
    Result := aGuid;
  end;

  //: 2023-10-27
  class function TmyGuid.Create(const aGuid: PmyGuid): TmyGuid;
  begin
    Result := aGuid^;
  end;

  //: 2023-10-27
  class function TmyGuid.CreateEmpty: TmyGuid;
  begin
    Result.TS1 := 0;
    Result.TS2 := 0;
    Result.C := 0;
  end;

  //: 2023-10-27
  class function TmyGuid.CreateNew: TmyGuid;
  begin
    customTS2 := Now;
    if (customC = MaxWord) then
      customC := 0
    else
      Inc(customC);
    Result.TS1 := customTS1;
    Result.TS2 := customTS2;
    Result.C := customC;
  end;

  //: 2023-10-27
  class function TmyGuid.StringIsValidGuid(const aGuid: String): Boolean;
  var
    I: Integer;
    C: Char;
  begin
    if (Length(aGuid) = 42) then
      begin
        Result := True;
        for I := 1 to Length(aGuid) do
          begin
            C := aGuid[I];
            case I of
              1:
                if C <> '#then
                  begin
                    Result := False;
                    Break;
                  end;
              19, 37:
                if C <> '-then
                  begin
                    Result := False;
                    Break;
                  end;
            else
              if not CharInSet(C, ['0'..'9']) then
                begin
                  Result := False;
                  Break;
                end;
            end;
          end;
      end
    else
      Result := False;
  end;

  //: 2023-10-27
  class operator TmyGuid.Equal(const Left, Right: TmyGuid): Boolean;
  begin
    Result := ((Left.TS1 = Right.TS1) and (Left.TS2 = Right.TS2) and (Left.C = Right.C));
  end;

  //: 2023-10-27
  class operator TmyGuid.NotEqual(const Left, Right: TmyGuid): Boolean;
  begin
    Result := ((Left.TS1 <> Right.TS1) or (Left.TS2 <> Right.TS2) or (Left.C <> Right.C));
  end;

  //: 2023-10-27
  function TmyGuid.GetHashCode: Integer;
  begin
    Result := 17;
    Result := Result * 397 + Integer(C);
    Result := Result * 397 + THashBobJenkins.GetHashValue(TS1, sizeOf(TDateTime), 5);
    Result := Result * 397 + THashBobJenkins.GetHashValue(TS2, sizeOf(TDateTime), 7);
  end;

  //: 2023-10-27
  function TmyGuid.IsEmpty: Boolean;
  begin
    Result := ((TS1 = 0) and (Ts2 = 0) and (C = 0));
  end;

  function TmyGuid.ToString: String;
  var
    S1, S2, S3: String;
  begin
    //: #yyyymmddhhnnsszzz-yyyymmddhhnnsszzz-xxxxx
    //: #12345678901234567890123456789012345678901 - > Length = 42
    if (TS1 = 0) then
      S1 := '00000000000000000'
    else
      S1 := FormatDateTime('yyyymmddhhnnsszzz', TS1);
    if (Ts2 = 0) then
      S2 := '00000000000000000'
    else
      S2 := FormatDateTime('yyyymmddhhnnsszzz', Ts2);
    if (C = 0) then
      S3 := '00000'
    else
      S3 := Format('%0.5d', [C]);
    Result := '#' + S1 + '-' + S2 + '-' + S3;
  end;

  //: 2023-10-27
  procedure TmyGuid.DoEmpty;
  begin
    TS1 := 0;
    TS2 := 0;
    C := 0;
  end;

  //: 2023-10-27
  procedure TmyGuid.DoNew;
  var
    lGuid: TmyGuid;
  begin
    lGuid := CreateNew;
    TS1 := lGuid.TS1;
    TS2 := lGuid.TS2;
    C := lGuid.C;
  end;

  //: 2023-10-27
  procedure TmyGuid.FromString(const aGuid: String);

    function EncodeTS(aGuid: String): TDateTime;
    var
      AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word;
    begin
      AYear := StrToInt(Copy(aGuid, 1, 4));
      AMonth := StrToInt(Copy(aGuid, 5, 2));
      ADay := StrToInt(Copy(aGuid, 7, 2));
      AHour := StrToInt(Copy(aGuid, 9, 2));
      AMinute := StrToInt(Copy(aGuid, 11, 2));
      ASecond := StrToInt(Copy(aGuid, 13, 2));
      AMilliSecond := StrToInt(Copy(aGuid, 15, 3));
      Result := EncodeDateTime(AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond);
    end;

  begin
    if (StringIsValidGuid(aGuid)) then
      begin
        TS1 := EncodeTS(Copy(aGuid, 2, 17));
        Ts2 := EncodeTS(Copy(aGuid, 20, 17));
        C := StrToInt(Copy(aGuid, 38, 5));
      end
    else
      begin
        TS1 := 0;
        Ts2 := 0;
        C := 0;
      end;
  end;

  //: 2023-10-27
  procedure TmyGuid.ReadFromStream(const aStream: TMemoryStream);
  begin
    aStream.ReadData(C);
    aStream.ReadData(TS1);
    aStream.ReadData(Ts2);
  end;

  //: 2023-10-27
  procedure TmyGuid.WriteToStream(const aStream: TMemoryStream);
  begin
    aStream.WriteData(C);
    aStream.WriteData(TS1);
    aStream.WriteData(Ts2);
  end;

initialization

  customTS1 := Now;
  customTS2 := Now;
  customC := MaxWord;

end.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.550 Beiträge
 
Delphi 12 Athens
 
#2

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 27. Okt 2023, 12:34
ich bin mir fast sicher, dass die //: 18 Byte / 144 Bit so nicht stimmen
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.358 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 27. Okt 2023, 13:41
Oh, das stimmt.

SizeOf gibt 24 Byte an, bei TGuid nur 16.

Die einzelnen Werte sind ja aber korrekt:
Delphi-Quellcode:
  TmyGUID = record
      C : Word; //: 2 Byte
      TS1: TDateTime; //: 8 Byte
      TS2: TDateTime; //: 8 Byte
Summe=18
Delphi-Quellcode:
  TGUID = record
    D1: Cardinal; //: 4 Byte
    D2: Word; //: 2 Byte
    D3: Word; //: 2 Byte
    D4: array[0..7] of Byte; //: 8 Byte
Summe=16
Wo ist da mein Denkfehler bzw. Wissenslücke?
TGuid ist ja auch kein gepackter Record oder so?

Mir kam es bei meinen Überlegungen darauf an, ob es "verhältnismäßig" ist, eine eigene Guid zu verwenden.
Entsprechend hatte ich die einzelnen Variablen angesehen, die verwendet werden und bin auf die kaum höhere Größe gekommen.

Die reale Größe hatte ich dann gar nicht untersucht.


EDIT: Ok, mit "packed record" komme ich auf das erwartete Ergebnis.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)

Geändert von stahli (27. Okt 2023 um 14:35 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.733 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#4

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 27. Okt 2023, 15:35
Oh, das stimmt.

SizeOf gibt 24 Byte an, bei TGuid nur 16.

Die einzelnen Werte sind ja aber korrekt:
Delphi-Quellcode:
  TmyGUID = record
      C : Word; //: 2 Byte
      TS1: TDateTime; //: 8 Byte
      TS2: TDateTime; //: 8 Byte
Summe=18
Delphi-Quellcode:
  TGUID = record
    D1: Cardinal; //: 4 Byte
    D2: Word; //: 2 Byte
    D3: Word; //: 2 Byte
    D4: array[0..7] of Byte; //: 8 Byte
Summe=16
Wo ist da mein Denkfehler bzw. Wissenslücke?
TGuid ist ja auch kein gepackter Record oder so?

EDIT: Ok, mit "packed record" komme ich auf das erwartete Ergebnis.
Das Problem ist, dass das erste Feld in Deinem Record nur 2 Bytes groß ist. Das zweite Feld wird aber ohne Packed auf eine 8-Byte Grenze verschoben. Dadurch gibt es zwischen dem ersten und dem zweiten Feld eine Lücke von 6 Bytes. Mit Packed Record wird diese dann entfernt.
Thomas Mueller

Geändert von dummzeuch (27. Okt 2023 um 15:37 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sinspin
Sinspin

Registriert seit: 15. Sep 2008
Ort: Dubai
749 Beiträge
 
Delphi 10.3 Rio
 
#5

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 27. Okt 2023, 16:15
Ich würde auch auf TDateTime verzichten, das ist ein Gleitkommawert bei dem es zu unabsichtlicher Veränderung im Millisekundenbereich kommen kann.
Mikrosekunden als Int64 ab einem bestimmten Datum halte ich für deutlich einfacher zu handeln. Auch weil es ein Wert ist den Du so wie er ist vom System abfragen kannst.

UInt64 basiert, µs Qualität TimeCode via QueryPerformanCecounter oder 2*DWord, µs Qualität, FileTime format, UTC TimeStamp via GetSystemTimePreciseAsFileTime
Stefan
Nur die Besten sterben jung
A constant is a constant until it change.
  Mit Zitat antworten Zitat
mytbo

Registriert seit: 8. Jan 2007
483 Beiträge
 
#6

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 27. Okt 2023, 16:45
Als Ergänzung zum Post von Thomas (dummzeuch) hier der Link zur Hilfe (Record-Typen). Zur Veranschaulichung:
Delphi-Quellcode:
type
  TTestGuid = {packed} record
    c: Word;
    ts1: TDateTime;
    ts2: TDateTime;
  end;

const
  REC_SIZE = SizeOf(TTestGuid);
var
  guid: TTestGuid;
  p: array[0..REC_SIZE - 1] of Byte absolute guid;
begin
  FillChar(guid, REC_SIZE, 0);
  FillChar(guid.ts1, SizeOf(TDateTime), MaxByte);
  guid.c := MAXWORD;
  var s: String;
  for var i: Integer := Low(p) to High(p) do
    s := s + IfThen((p[i] <> 0), '#', '*');

  ShowMessage(Format('Size: %d: %s', [REC_SIZE, s])); // Size: 24: ##******########********
Bis bald...
Thomas
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.550 Beiträge
 
Delphi 12 Athens
 
#7

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 27. Okt 2023, 17:54
Die Speicherausrichtung.
Nach den ersten 2 Byte, wird der nächste Typ an den nächsten geraden 8 Byte ausgerichtet, da er so groß ist.
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.358 Beiträge
 
Delphi 11 Alexandria
 
#8

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 27. Okt 2023, 18:42
Danke Euch.

@Sinspin
Eine Änderung des Zeitstempels (des Realwertes) sollte m.E. nur möglich sein, wenn man mit den Werten rechnet.

Ich
- ermittle jedoch den Wert nur einmalig,
- speichere ihn in die Variablen,
- übergebe ich an Methoden,
- schreibe in in einen Stream,
- wandle ihn in einen String um und zurück,
- und vergleiche die Werte auf Gleichheit.

Besteht auch in diesen Fällen die Gefahr einer Verfälschung?
Wenn nicht, würde ich lieber bei den Timestamps bleiben, da diese dann beim Debugging auch besser einzuordnen sind(gestern erzeugt oder letzten Monat).

Die Systemlaufzeit wäre gleich sicher aber weniger sprechend. Wenn in meinem Anwendungsfall tatsächlich die Gefahr einer Timestampverfälschung bestehen kann, dann würde ich aber tatsächlich lieber umstellen.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
mytbo

Registriert seit: 8. Jan 2007
483 Beiträge
 
#9

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 27. Okt 2023, 22:48
Für alle, die es schon vermisst haben, mORMot hat dieses Angebot:
Zitat:
TSynUniqueIdentifierGenerator: thread-safe 64-bit integer unique identifier computation
- contain generation time
- they are increasing over time (so are much easier to store/shard/balance than UUID/GUID)
- each identifier would contain a 16-bit process identifier, which is supplied by the application
- identifiers may be obfuscated as hexadecimal text, using both encryption and digital signature
Hier etwas Quelltext:
Delphi-Quellcode:
uses
  mormot.core.base,
  mormot.core.unicode,
  mormot.crypt.secure;

var
  guid: Int64;
  guidStr: String;
  guidGen: TSynUniqueIdentifierGenerator;
begin
  guidGen := TSynUniqueIdentifierGenerator.Create({Identifier:}12345, {SharedObfuscationKey:}'TopSecret', 10); // create once in application
  try
    guid := guidGen.ComputeNew;
    ShowMessage(Format('Guid: %s', [guid.ToString]));

    guidStr := Utf8ToString(guidGen.ToObfuscated(guid));
    ShowMessage(Format('Guid obfuscated: %s', [guidStr]));

    var fromObfuscatedGuid: TSynUniqueIdentifier; // Int64
    if guidGen.FromObfuscated(StringToUtf8(guidStr), fromObfuscatedGuid) then
      ShowMessage(Format('Guid: %d, From obfuscated: %d', [guid, Int64(fromObfuscatedGuid)]));

    var guidBits: TSynUniqueIdentifierBits;
    guidBits.From(guid);
    ShowMessage(Format('DateTime created: %s', [DateTimeToStr(guidBits.CreateDateTime)]));

    ShowMessage(Format('JSON: %s', [Utf8ToString(guidBits.AsVariant._JSON)]));
  finally
    guidGen.Free;
  end;
Im Beispiel ist der Identifikator "12345". Es stehen 16-Bit zur Verfügung. Eine Möglichkeit wäre, jedem Kunden/Installation eine eigene zuzuweisen.

Die Ausgabe für das Beispiel ist:
Code:
Guid: 3647375681599078401
Guid obfuscated: 7dc1647a8d032aaeebe65dff209d32ff
Guid: 3647375681599078401, From obfuscated: 3647375681599078401
DateTime created: 27.10.2023 21:20:55
JSON: {"Created":"2023-10-27T21:20:55","Identifier":12345,"Counter":1,"Value":3647375681599078401,"Hex":"329E14DB981C8001"}
Bis bald...
Thomas
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.052 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#10

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 28. Okt 2023, 19:37
Dieser Thread erinnert mich stark an https://xkcd.com/927/
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:23 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz