Beispiel #1
0
        private GDIDBlock allocateBlockInSystem(string scopeName, string sequenceName, int blockSize, ulong?vicinity)
        {
            Instrumentation.AllocBlockRequestedEvent.Happened(scopeName, sequenceName);

            GDIDBlock result = null;
            var       batch  = Guid.NewGuid();
            var       list   = "";

            foreach (var node in this.AuthorityHosts.OrderBy(h => h.DistanceKm))//in the order of distances, closest first
            {
                list += (" Trying '{0}' at {1}km\n".Args(node.Name, node.DistanceKm));
                try
                {
                    using (var cl = AgniSystem.IsMetabase
                           ? ServiceClientHub.New <IGDIDAuthorityClient>(node.Name)
                           : new Clients.GDIDAuthority(node.Name)
                           )
                        result = cl.AllocateBlock(scopeName, sequenceName, blockSize, vicinity);

                    Instrumentation.AllocBlockSuccessEvent.Happened(scopeName, sequenceName, node.Name);
                }
                catch (Exception error)
                {
                    log(MessageType.Error, GetType().Name + ".allocateBlock()", "Error invoking GDIDAuthority.AllocateBlock('{0}')".Args(node), error, batch);

                    Instrumentation.AllocBlockFailureEvent.Happened(scopeName, sequenceName, blockSize, node.Name);
                }

                if (result != null)
                {
                    break;
                }
            }

            if (result == null)
            {
                if (list.IsNullOrWhiteSpace())
                {
                    list = "<none>";
                }
                log(MessageType.Emergency, GetType().Name + ".allocateBlock()", StringConsts.GDIDGEN_ALL_AUTHORITIES_FAILED_ERROR + list, batch: batch);
                Instrumentation.AllocBlockRequestFailureEvent.Happened(scopeName, sequenceName);
                throw new GDIDException(StringConsts.GDIDGEN_ALL_AUTHORITIES_FAILED_ERROR + list);
            }

            return(result);
        }
Beispiel #2
0
        private GDIDBlock allocate(byte authority, string scopeName, string sequenceName, int blockSize, ulong?vicinity)
        {
            var scopeKey = "{0}://{1}".Args(AuthorityPathSeg(authority), scopeName);

            var scope = m_Scopes.GetOrRegister(scopeKey, (key) => new scope {
                Name = key
            }, scopeKey);

            var sequence = scope.Sequences.GetOrRegister(sequenceName, (_) => new sequence {
                Name = sequenceName, New = true
            }, 0);                                                                                                       //with NEW=TRUE

            var result = new GDIDBlock()
            {
                ScopeName     = scopeName,
                SequenceName  = sequenceName,
                Authority     = authority,
                AuthorityHost = AgniSystem.HostName,
                BlockSize     = blockSize,
                ServerUTCTime = App.TimeSource.UTCNow
            };

            lock (scope)
            {
                //0. If just allocated then need to read from disk
                if (sequence.New)
                {
                    sequence.New = false;
                    var id = ReadFromLocations(authority, scopeName, sequenceName);
                    sequence.Era   = id.Era;
                    sequence.Value = id.Value;
                }

                //1. make a local copy of vars, that may mutate but dont get committed until written to disk
                var era   = sequence.Era;
                var value = sequence.Value;

                //1.1 make sure that GDID.Zero is never returned
                if (authority == 0 && era == 0 && value == 0)
                {
                    value = 1;                                          //Don't start value from Zero in ERA=0 and Autority=0
                }
                if (value >= GDID.COUNTER_MAX - (ulong)(blockSize + 1)) //its time to update ERA (+1 for safeguard/edge case)
                {
                    if (era == uint.MaxValue - 4)                       //ALERT, with some room
                    {
                        Log(MessageType.CriticalAlert, "allocate()", StringConsts.GDIDAUTH_ERA_EXHAUSTED_ALERT.Args(scopeName, sequenceName));
                    }
                    if (era == uint.MaxValue) //hard stop
                    {
                        var txt = StringConsts.GDIDAUTH_ERA_EXHAUSTED_ERROR.Args(scopeName, sequenceName);
                        Log(MessageType.CatastrophicError, "allocate()", txt);
                        throw new GDIDException(txt);
                    }

                    era++;
                    value = 0;
                    Instrumentation.AuthEraPromotedEvent.Happened(scopeName, sequenceName);
                    Log(MessageType.Warning, "allocate()", StringConsts.GDIDAUTH_ERA_PROMOTED_WARNING.Args(scopeName, sequenceName, era));
                }

                result.Era = era;
                result.StartCounterInclusive = value;

                value = value + (ulong)blockSize;

                //2. Try to write to disk, if it fails we could not allocate anything and will bail out with exception
                WriteToLocations(authority, scopeName, sequenceName, new _id(era, value));

                //3. only after write to disk succeeds do we commit the changes back into the sequence instance
                sequence.Era   = era;
                sequence.Value = value;
            }

            return(result);
        }