Feature dcDb - Gadreel/divconq GitHub Wiki

Intro to dcDB

TODO add intro

Data Types & Codes

1 byte codes

  • 0x00 = Alpha, marks boundaries between keys

  • 0xff = Omega, marks end of database and database version

  • These have a sortable order, the rest not in any meaningful way

    • 0x01 = Null/Empty
    • 0x02 = Boolean
      • 0x02 0x00 False
      • 0x02 0x01 True
    • 0x06 = Number (DB_TYPE_NUMBER)
      • 1 byte is pos/neg flag
        • 0x06 0x00 0xNN 0xNN etc neg number
        • 0x06 0x01 0xNN 0xNN etc pos number
      • 16 value bytes - 12 bytes before decimal and 4 bytes after
        • official MAX/MIN before is 10,000,000,000,000,000,000,000,000,000 aka 10,000Y (where Y = yotta = septillion)
        • official MAX/MIN after is 0.000,000,001 aka 1n (where n = nano = billionth)
      • positive numbers are Little-endian
      • negative numbers are Little-endian and XORed with all 0xFFs
      • see examples below
    • 0x09 = DateTime (YYYYMMDDTHHMMSSsssZ)
      • 0x09 0xNN 0xNN etc UTF 8 codes
    • 0x0C = BigDateTime (tYYYYYYYYYYYMMDDhhmmss)
      • 0x0C 0xNN 0xNN etc UTF 8 codes
    • 0x0F = Time (HHMMSSsss)
      • 0x0F 0xNN 0xNN etc UTF 8 codes
    • 0x12 = Date (YYYYMMDD)
      • 0x12 0xNN 0xNN etc UTF 8 codes
    • 0x15 = Binary, indexes as Number (size in bytes)
      • 0x15 0xNN 0xNN etc binary codes
    • 0x18 = String encoded as UTF8 (codes not allowed 0x00 - 0x08, 0x0E - 0x1F, 0x7F), indexes as first 1024 bytes
      • 0x18 0xNN 0xNN etc UTF 8 codes
      • full text index option also
  • Value only, not sortable per say

    • 0x1B = Special Number, indexes as Number (conversion)
      • 0x1B 0xNN 0xNN etc bytes in BigDecimal
    • 0x1E = Composite (JSON) - (special case of String), indexes as Number (size in bytes)
      • 0x1E 0xNN 0xNN etc compact version of JSON, which can be directly output as response
    • 0x1F = XML - (special case of String), indexes as Number (size in bytes)
      • 0x1F 0xNN 0xNN etc bytes UTF 8 codes

DB_TYPE_NUMBER Examples

Note how the resulting numbers will sort correctly...

ByteUtil.longToDBNumber output

        Long.MIN_VALUE: 00 ffffffff7fffffffffffffff ffffffff
           -9999999999: 00 fffffffffffffffdabf41c00 ffffffff
                 -1000: 00 fffffffffffffffffffffc17 ffffffff
                    -1: 00 fffffffffffffffffffffffe ffffffff
                     1: 01 000000000000000000000001 00000000
                  1000: 01 0000000000000000000003e8 00000000
            9999999999: 01 0000000000000002540be3ff 00000000
        Long.MIN_VALUE: 01 000000007fffffffffffffff 00000000   		

ByteUtil.decimalToDBNumber output

         DB_NUMBER_MIN: 00 dfb031a1c1dafd9eefffffff ffffffff
        Long.MIN_VALUE: 00 ffffffff7fffffffffffffff ffffffff
 -9999999999.999999999: 00 fffffffffffffffdabf41c00 c4653600
           -9999999999: 00 fffffffffffffffdabf41c00 ffffffff
            -1000.0001: 00 fffffffffffffffffffffc17 fffe795f
                 -1000: 00 fffffffffffffffffffffc17 ffffffff
          -1.000000001: 00 fffffffffffffffffffffffe fffffffe
                    -1: 00 fffffffffffffffffffffffe ffffffff
                  -0.1: 00 ffffffffffffffffffffffff fa0a1eff
         -0.0000000017: 00 ffffffffffffffffffffffff fffffffd
          0.0000000017: 01 000000000000000000000000 00000002
                   0.1: 01 000000000000000000000000 05f5e100
                     1: 01 000000000000000000000001 00000000
           1.000000001: 01 000000000000000000000001 00000001
                  1000: 01 0000000000000000000003e8 00000000
             1000.0001: 01 0000000000000000000003e8 000186a0
            9999999999: 01 0000000000000002540be3ff 00000000
  9999999999.999999999: 01 0000000000000002540be3ff 3b9ac9ff
        Long.MAX_VALUE: 01 000000007fffffffffffffff 00000000
         DB_NUMBER_MAX: 01 204fce5e3e25026110000000 00000000

ByteUtil.dbNumberToNumber tests

         DB_NUMBER_MIN: -10000000000000000000000000000
              near MIN: -9999999999999999999999999999.999999999
 -9999999999.999999999: -9999999999.999999999
          -999999.9999: -999999.9999
              -1000.01: -1000.01
                  -1.1: -1.1
                   1.1: 1.1
               1000.01: 1000.01
           999999.9999: 999999.9999
  9999999999.999999999: 9999999999.999999999
              near MAX: 9999999999999999999999999999.999999999
         DB_NUMBER_MAX: 10000000000000000000000000000

Also

        Long.MAX_VALUE: -9223372036854775808
           -9999999999: -9999999999
                 -1000: -1000
                    -1: -1
                     1: 1
                  1000: 1000
            9999999999: 9999999999
        Long.MAX_VALUE: 9223372036854775807

Common Record Meta

DB_GLOBAL_RECORD_META, table, "Id" = last id seq

Domain Record Meta

DB_GLOBAL_RECORD_META, domain, table, "Count" = count

StaticScalar

DB_GLOBAL_RECORD, domain, table, id, field, stamp, "Data" = value - any db scalar type DB_GLOBAL_RECORD, domain, table, id, field, stamp, "Tags" = | delim string w/ leading/trailing |
DB_GLOBAL_RECORD, domain, table, id, field, stamp, "Retired" = t/f

DB_GLOBAL_INDEX_1, domain, table, field, value = index count (approx number)

DB_GLOBAL_INDEX_1, domain, table, field, value, id, stamp = to stamp, null means always will be

StaticList

DB_GLOBAL_RECORD, domain, table, id, field, sid, stamp, "Data" = value - any db scalar type DB_GLOBAL_RECORD, domain, table, id, field, sid, stamp, "Tags" = | delim string w/ leading/trailing |
DB_GLOBAL_RECORD, domain, table, id, field, sid, stamp, "Retired" = t/f

DB_GLOBAL_INDEX_2, domain, table, field, value = index count (approx number)

DB_GLOBAL_INDEX_2, domain, table, field, value, id, sid, stamp = to stamp, null means always will be

DynamicScalar

DB_GLOBAL_RECORD, domain, table, id, field, sid, stamp, "Data" = value - any db scalar type DB_GLOBAL_RECORD, domain, table, id, field, sid, stamp, "From" = date time, null means always was DB_GLOBAL_RECORD, domain, table, id, field, sid, stamp, "Tags" = | delim string w/ leading/trailing |
DB_GLOBAL_RECORD, domain, table, id, field, sid, stamp, "Retired" = t/f

DB_GLOBAL_INDEX_2, domain, table, field, value = index count (approx number)

DB_GLOBAL_INDEX_2, domain, table, field, value, id, sid, stamp = to stamp, null means always will be

DynamicList

DB_GLOBAL_RECORD, domain, table, id, field, sid, stamp, "Data" = value - any db scalar type DB_GLOBAL_RECORD, domain, table, id, field, sid, stamp, "From" = date time, null means always was DB_GLOBAL_RECORD, domain, table, id, field, sid, stamp, "To" = date time, null means always will be DB_GLOBAL_RECORD, domain, table, id, field, sid, stamp, "Tags" = | delim string w/ leading/trailing |
DB_GLOBAL_RECORD, domain, table, id, field, sid, stamp, "Retired" = t/f

DB_GLOBAL_INDEX_2, domain, table, field, value = index count (approx number)

DB_GLOBAL_INDEX_2, domain, table, field, value, id, sid, stamp = to stamp, null means always will be

Index Example

keep in mind that stamp92 is newer (later date) than stamp98 or stamp107

Example Data

DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp92, "Data" = "Jed"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Data" = "Ned"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Data" = "Ted" DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 9, "Name", stamp46, "Data" = "Brian"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 9, "Name", stamp212, "Data" = "Ned"

DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Brian", 9, stamp46 = null (future) DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Jed", 5, stamp92 = null (future) DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 5, stamp98 = stamp92 DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 9, stamp212 = stamp46 DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ted", 5, stamp107 = stamp98

Example Search I

If searching for "Ned" on stamp96 we find the Neds:

DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 5, stamp98 = stamp92 DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 9, stamp212 = stamp46

For each we must verify that the entry is current for the stamp:

Person 5 has a stamp98 and stamp92 and so stamp98 >= stamp96 > stamp92 - TRUE: therefore, for stamp96, "Ned" is correct Person 9 has a stamp212 and stamp46 and so stamp212 >= stamp96 > stamp46 - TRUE: therefore, for stamp96, "Ned" is correct

Example Search II

However, if searching for "Ned" on stamp86 we find the Neds:

DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 5, stamp98 = stamp92 DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 9, stamp212 = stamp46

For each we must verify that the entry is current for the stamp:

Person 5 has a stamp98 and stamp92 and so stamp98 >= stamp86 > stamp92 - FALSE: therefore, for stamp86, "Ned" NOT is correct Person 9 has a stamp212 and stamp46 and so stamp212 >= stamp86 > stamp46 - TRUE: therefore, for stamp86, "Ned" is correct

Retired Field

The same results happen with retired fields. What if we retired instead of changed the name of Person 5 at stamp92? Here is what the record would look like for 5:

DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp92, "Retired" = true
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Data" = "Ned"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Data" = "Ted"

And here is what the index would look like for 5:

DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 5, stamp98 = stamp92 DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ted", 5, stamp107 = stamp98

Again we can see that searching the index for stamp96 and "Ned" still provides Person 5 as a result and searching with stamp86 does not.

Indexing Operation

Typical Future Set

Here is what we have for Person 5:

DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Data" = "Ned"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Data" = "Ted"

DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 5, stamp98 = NULL (future) DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ted", 5, stamp107 = stamp98

And we are setting name to "Jed" for stamp92 (future, after stamp98 in time but before in collation).

  • SET on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp92, "Data" = "Jed"
  • find the next, older, stamp after current
  • NEXT PEER on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp92 results in stamp98
  • take stamp98 and check for old value
  • IS SET on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Data" results in TRUE [NODE]
  • take stamp98 and look up the old value
  • GET on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Data" results in "Ned"
  • now read the stamp from the old index
  • GET on DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 5, stamp98 results in NULL
  • now set the new index with the value returned above
  • SET on DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Jed", 5, stamp92 = NULL (future)
  • finally update the old index with current stamp
  • SET on DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 5, stamp98 = stamp92

And now we have:

DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp92, "Data" = "Jed"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Data" = "Ned"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Data" = "Ted"

DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Jed", 5, stamp92 = NULL (future) DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 5, stamp98 = stamp92 DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ted", 5, stamp107 = stamp98

Typical Future Retire

Here is what we have for Person 5:

DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Data" = "Ned"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Data" = "Ted"

DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 5, stamp98 = NULL (future) DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ted", 5, stamp107 = stamp98

And we are retiring name for stamp92 (future, after stamp98 in time but before in collation).

  • SET on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp92, "Retired" = TRUE
  • find the next, older, stamp after current
  • NEXT PEER on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp92 results in stamp98
  • take stamp98 and check for old value
  • IS SET on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Data" results in TRUE [NODE]
  • take stamp98 and look up the old value
  • GET on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Data" results in "Ned"
  • now read the stamp from the old index
  • GET on DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 5, stamp98 results in NULL
  • finally update the old index with current stamp
  • SET on DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 5, stamp98 = stamp92

And now we have:

DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp92, "Retired" = true
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Data" = "Ned"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Data" = "Ted"

DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 5, stamp98 = stamp92 DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ted", 5, stamp107 = stamp98

Replicate Between Set

Here is what we have for Person 5 - on Hub A:

DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp92, "Data" = "Jed"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Data" = "Ted"

DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Jed", 5, stamp92 = NULL (future) DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ted", 5, stamp107 = stamp92

And replicating (slowly) - is a stamp between stamp92 and stamp107 - this is from Hub B:

DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Data" = "Ned"

We are setting name to "Ned" for stamp98.

  • SET on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Data" = "Ned"
  • find the next, older, stamp after current
  • NEXT PEER on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98 results in stamp107
  • take stamp107 and check for old value
  • IS SET on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Data" results in TRUE [NODE]
  • take stamp107 and look up the old value
  • GET on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Data" results in "Ted"
  • now read the stamp from the old index
  • GET on DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ted", 5, stamp107 results in stamp92
  • now set the new index with the value returned above
  • SET on DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 5, stamp98 = stamp92
  • finally update the old index with current stamp
  • SET on DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ted", 5, stamp107 = stamp98

And now we have:

DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp92, "Data" = "Jed"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Data" = "Ned"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Data" = "Ted"

DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Jed", 5, stamp92 = NULL (future) DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 5, stamp98 = stamp92 DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ted", 5, stamp107 = stamp98

Replicate End Set

Here is what we have for Person 5 - on Hub A:

DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp92, "Data" = "Jed"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Data" = "Ned"

DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Jed", 5, stamp92 = NULL (future) DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 5, stamp98 = stamp92

And replicating (slowly) - is a stamp before stamp92 and stamp98 - this is from Hub B:

DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Data" = "Ted"

We are setting name to "Ted" for stamp107.

  • SET on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Data" = "Ted"
  • find the next, older, stamp after current
  • NEXT PEER on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107 results in NULL
  • the NULL is not conclusive, look forward in time
  • PREV PEER on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107 results in stamp98
  • now set the new index with the value returned above
  • SET on DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ted", 5, stamp107 = stamp98

And now we have:

DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp92, "Data" = "Jed"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Data" = "Ned"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Data" = "Ted"

DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Jed", 5, stamp92 = NULL (future) DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 5, stamp98 = stamp92 DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ted", 5, stamp107 = stamp98

Replicate Between Retire

Here is what we have for Person 5 - on Hub A:

DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp92, "Data" = "Jed"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Data" = "Ted"

DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Jed", 5, stamp92 = NULL (future) DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ted", 5, stamp107 = stamp92

And replicating (slowly) - is a stamp between stamp92 and stamp107 - this is from Hub B:

DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Retired" = TRUE

We are setting name to retired for stamp98.

  • SET on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Retired" = true
  • find the next, older, stamp after current
  • NEXT PEER on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98 results in stamp107
  • take stamp107 and check for old value
  • IS SET on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Data" results in TRUE [NODE]
  • take stamp107 and look up the old value
  • GET on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Data" results in "Ted"
  • finally update the old index with current stamp
  • SET on DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ted", 5, stamp107 = stamp98

And now we have:

DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp92, "Data" = "Jed"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Retired" = TRUE
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Data" = "Ted"

DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Jed", 5, stamp92 = NULL (future) DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ted", 5, stamp107 = stamp98

Replicate End Retire

Here is what we have for Person 5 - on Hub A:

DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp92, "Data" = "Jed"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Data" = "Ned"

DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Jed", 5, stamp92 = NULL (future) DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 5, stamp98 = stamp92

And replicating (slowly) - is a stamp before (in time, not collation) stamp92 and stamp98 - this is from Hub B:

DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Retired" = TRUE

We are setting name to retired for stamp107.

  • SET on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Retired" = TRUE
  • find the next, older, stamp after current
  • NEXT PEER on DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107 results in NULL
  • the NULL is enough, nothing more to do

And now we have:

DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp92, "Data" = "Jed"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp98, "Data" = "Ned"
DB_GLOBAL_RECORD, ROOT_DOMAIN, "Person", 5, "Name", stamp107, "Retired" = TRUE

DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Jed", 5, stamp92 = NULL (future) DB_GLOBAL_INDEX_1, ROOT_DOMAIN, "Person", "Name", "Ned", 5, stamp98 = stamp92