Script Library: 1238 scripts
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
View scriptLicenseDownload documentation as: HTML or editable
Download scriptHistoryOther scripts by: sunanda

Documentation for: tsn.r

     script: tsn.r
      title: Tranched Serial Numbers
    purpose: Quick, safe way of allocating categorized unique serial numbers
     author: Sunanda
       date: 30-apr-2007
    Version: 0.0.1

1. purpose

tsn.r is a tool for allocating two-level unique serial numbers.

The numbers are unique as each time you call tsn.r (for the same tsn set) you will receive a new number that has not been issued before (for that tsn set).

They are two level as on each call to tsn.r you supply a category id. The serial number issued also includes a unique category serial number.

That may make more sense if you read the quick example (below) and the section what could I possibly want with a script like this? (much later on).

2. quick example

  [1] do %tsn.r                      ;; install the utility
  [2] my-set: tsn-api/make-new-set   ;; create a new number set

  [3] my-cats: copy ["green" "red" "blue"]
  [4] my-tsns: make block! 50000
  [5] loop 50000 [
  [6]   append my-tsns third tsn-api/get-tsn my-set random/only my-cats
  • [1] -- install tsn.r
  • [2] -- create a tsn set called my-set
  • [3] -- create some "categories" against which you wish to issue unique serial numbers
  • [4] -- create a block to hold the unique serial numbers we are about to allocate
  • [5] -- run a loop to create 50,000 unique serial numbers
  • [6] -- allocate 50,000 unique numbers....
    • append my-tsns third ... the unique serial number comes back in the third item of the block
    • tsn-api/get-tsn ... the function to allocate the unique serial number
    • my-set ... your tsn set from which the numbers will be allocated
    • random/only my-cats ... the category for which we want a unique serial number

my-tsns now contains 50,000 unique serial numbers. You can use these as short, efficient, keys in database. You can also use them to get back to the category id and unique category serial number. See following example:

   [1] length? my-tsns
   [2] length? unique my-tsns
   [3]  for nn 1 10 1 [
   [4]   print mold tsn-api/get-cat-id my-set my-tsns/:nn
  • [1] [2] -- just to prove tsn.r issued 50,000 unique numbers
  • [3] -- a loop to check some of them
  • [4] -- a print of some results:
    • my-tsns/:nn ... the unique serial number we are checking
    • tsn-api/get-cat-id ... the request to be returned the cat id and cat serial number
    • my-set ... the tsn set we are using
    • my-tsns/:nn ...the unique serial number who's cat we want
    A typical result looks like: ["blue" 5 103]: unique serial number 103 maps to blue 5: the fifth number issued for category "blue"

The whole data structure to map 50,000 numbers back to the their categories is highly compact:

   >> length?  mold my-set
   == 476

(Your precise number will vary as the example uses randomised data).

3. installing

do %tsn.r 

tsn.r also requires rse-ids.r (also in the Library) to be in the same folder.

4. api functions

The Application Programmer Interface has these functions:

  • make-new-set -- create a new tsn set
  • get-tsn -- return the next unique serial number and unique category serial number
  • get-all-categories -- returns all category ids
  • get-cat-id -- given a unique serial number return its category id and its unique category serial number
  • get-all-tsns-for-cat -- given a category id, return all defined unique serial numbers for it
  • remove-category -- remove a category

All the API functions (except make-new-set require the tsn set as a parameter. You can have multiple tsn sets; the serial numbers created will be unique only within that tsn set

4.1. make-new-set

Returns you an object that defines the tsn set

     my-set: tsn-api/make-new-set


You are responsible for:

  • saving this object if you need persistence across sessions -- see below
  • providing it to all future API calls


   tsn-set-1: tsn-api/make-new-set
   tsn-set-2: tsn-api/make-new-set

You now have two separate tsn sets. Each will return its own series of unique serial numbers. But note that the numbers are not unique across the two tsn sets: both may (for example) have a serial number 101.

4.1.1. saving and reloading a tsn set

If you wish to access or create unique serial numbers across multiple sessions, you need to save the tsn set object at the end of one session and reload it at the start of the next:

    write %saved-tsn-set.txt mold tsn-set-1
    tsn-set-1: first reduce load/all %saved-tsn-set.txt

To reduce the risk of users editing or corrupting the saved file, consider saving it as binary or encloaking it:

    write/binary %saved-tsn-set.txt encloak compress mold tsn-set-1 "secret key"
    first reduce load/all decompress decloak read/binary %saved-tsn-set.txt  "secret key"

4.2. get-tsn

Given a category id, returns a unique serial number and a unique category serial number.

     tsn-api/get-tsn tsn-set cat-id

      tsn-set -- the tsn-set in use (Type: object)
      cat-id -- the category id (Type: string integer)

The function returns a block! with four entries:

  • cat-id -- as supplied in the input
  • unique category serial number -- the unique number allocated within this category
  • unique serial number -- the unique number allocated within this tsn-set
  • stats info --a not very useful code that tells you a bit about the numbers just allocated:
    • nc -- new category: first number issued for this category
    • ot -- old tranche: number issued within a reserved range
    • et -- extended tranche: number issued in a tranche that has been extended
    • nt -- new tranche: first number issued in a new tranche


    print new-usn: third tsn-api/get-tsn my-set "red"
    == 4776

4.3. get-all-categories

Returns a block of all the defined categories

     tsn-api/get-all-categories tsn-set

      tsn-set -- the tsn-set in use (Type: object)


    probe tsn-api/get-all-categories my-set
    == ["blue" "green" "red"]

4.4. get-cat-id

Given a unique serial number, it returns the category id and unique category serial number.

     tsn-api/get-cat-id tsn-set usn

      tsn-set -- the tsn-set in use (Type: object)
      usn -- unique serial number (Type: integer)

The function returns either:

  • none -- the unique serial number is unknown / not allocated
  • a block -- of three items:
    • category-id (string or integer)
    • unique category serial number (integer)
    • unique serial number (integer) (same as input supplied)


    probe tsn-api/get-cat-id my-set 1888
    == ["red" 629 1888]

4.5. get-all-tsns-for-cat

Given a category, returns all unique serial numbers allocated to that category:

     tsn-api/get-all-tsns-for-cat tsn-set cat-id

      tsn-set -- the tsn-set in use (Type: object)
      cat-id  -- category-id (Type string integer)

The function returns either:

  • none -- the category is unknown
  • block -- containing the unique serial numbers allocated to the category


    probe tsn-api/get-all-tsns-for-cat my-set "red"
    == [1 2 3 4 ... 600 601 602 .... 1009 1010 .... ]

4.6. remove-category

Removes a category and all unique serial numbers allocated to it.

This does not mean the serial numbers will be reissued later. The publicly released version of tsn.r does not reuse numbers, ever. It does mean:

  • any future call to get-cat-id for numbers that were allocated to that category will return none.
  • any future call to get-tsn for that category will start a new sequence of unique category serial numbers.
     tsn-api/remove-category tsn-set cat-id

      tsn-set -- the tsn-set in use (Type: object)
      cat-id  -- category-id (Type string integer)


    probe tsn-api/remove-category my-set "green"
    == true

5. what could I possibly want with a script like this?

Good question! It is either something you need very badly, or it seems completely pointless.

5.1. historical

The original usage was for an experiment database-type application. The database supported various entities (let's call some of the entities users, files, programs, memos, to make a concrete example).

Each entity type had unique entity numbers: eg users were numbered 1,2,3,4; Files were numbered 1,2,3,4,5 etc.

That meant we could have made unique serial numbers like this: U1, U2, U3 (for users), F1, F2, F3, F4 for files.

But (reasoning omitted for simplicity) we needed (wanted!) all identifiers to be integers.

tsn.r was an easy way to make that possible. It also enabled a simple (almost flat) database structure with records like this:

20 [5775 377 4477 388] 

meaning entity 20 is associated with entities 5775, 377, 4477 and 388 without us having to know what types of entity [5775 377 4477 388] are.

That was a sort of advance on the many-to-many relationship that many databases support....More of an any-to-any relationship. And that came in very handy for some data manipulations.

5.2. present day

tsn.r is a component in the (soon to be released) Altme World Indexer.

It allow us a simple way of flattening [Group-id Post-id] into a single, relatively low, integer for indexing purposes.

6. configuring

There are two magic numbers you can change in a tsn set. Changing them may affect performance. They adjust how unique serial number ranges are reserved for categories.

You can change the settings globally (the changes will affect all tsn-sets allocated after the change); or locally (the changes affect only the specific tsn-set.

6.1. global change

    tsn-api/tsn-template/smallest-tranche: 25
    tsn-api/tsn-template/growth-factor: 1.1

6.2. local change

   my-set: tsn-api/make-new-set
   my-set/smallest-tranche: 25
   my-set/growth-factor: 1.1

6.3. smallest-tranche

Defines the smallest range reserved for a category.

6.4. growth-factor

Defines the size of the second and subsequent ranges reserved for a category. If a category exhausts a range, then tsn.r reserves a range equal to the current size of the category times the growth factor.

Example: category red has a highest unique category serial number of 950 and we need to allocate another range to it. If the growth-factor is 1.4, then tsn.r allocates a range that is 1330 wide (950 * 1.4).