/** * Inqwell Unique Functions * * Generate Unique Ids. * * Private & Confidential Copyright © Inqwell Ltd 2004. * All rights reserved. */ package inq.util; /** * Generate a new Unique Id for the set given by Name. If the * specified set does not exist and onDemand * is true the set will be created with the * given initValue. * * @param Name The set of ids from which the new value * will be generated. * @param onDemand If truecreates a set if one * by the given Name * does not currently exist. Throws otherwise. * @param initValue Initial value for sequence if it does not * currently exist. Defaults to 1 * @param localTxn If true then new Id will be allocated within a * local transaction. If false then allocation happens in the caller's * transaction. localTxn=true is the default and is * preferred if the caller's transaction is long-lived. If the * caller's transaction is short-lived then using false * offers the benefit of the id not actually being allocated if the * transaction fails. * * @throws If the set does not exist and onDemand is false; * if Name is null. */ function getUniqueId(string Name, boolean onDemand = true, int initValue = 1, boolean localTxn = true) { if (length(Name) == 0 || isnull(Name)) throw("Unique ID Name cannot be null or zero length"); if (localTxn) { transaction { any ret = call allocateId(Name, onDemand, initValue); } } else any ret = call allocateId(Name, onDemand, initValue); ret; } local function allocateId(string Name, boolean onDemand, int initValue) { // Lock the code block. We do this because we don't want // one process to incur an exception because of unique key // violation if there is a collision creating a Name. lock("__unique" + Name); // Unless otherwise specified the read() function uses the unique key. // The key value is "." meaning the stack. The stack contains the Name // argument and therefore satisfies the field requirements for a // unique key value. if (read(Unique, .)) { // The return value ++Unique.Value; } else { if (!onDemand) throw("Unique Id requested for non-existent set " + Name); any Unique = new(Unique); Unique.Name = Name; // We must assign the value before we create the object in the // transaction, since subsequent mutations are ignored. // There is a (small) window in which two processes could create // the same new sequence. However, we have an explicit lock // protecting this transaction, so everything's OK! int ret = Unique.Value = initValue; create(Unique); // The return value Unique.Value; } }