• Avalanche
  • Avalanche.Core
  • Lexical

    Show / Hide Table of Contents
    • Avalanche.Localization
      • Introduction
      • Localization
      • LocalizationFile
      • LocalizationFiles
      • LocalizationFileSystem
      • LocalizationFileFormat
      • LocalizationLine
      • LocalizationLines
      • TemplateFormat
      • CultureProvider
      • FallbackCultureProvider
      • ResourceManager
      • LocalizationError
      • Microsoft.Extensions
        • Introduction
        • DependencyInjection
        • FileProvider
        • Logging
        • ITextLocalizer
        • IFileLocalizer
        • Localization
        • AspNetCore
      • Pluralization
        • Introduction
        • Multiple plural parameters
        • Custom PluralRules
        • Invariant Culture
        • Unit Prefix
        • IPluralRule
        • IPluralNumber
        • IPluralRules
        • CLDRs
        • Unicode.CLDR41
        • Unicode.CLDR40
      • Articles
        • Alphabet localization
        • Benchmarks
        • Caching
        • Class Library
        • Demo
        • Diagnostics
        • Embedded resources
        • Emplacement
        • File localization
        • Text localization
    • Avalanche.Message
      • Introduction
      • IMessage
      • IMessageProvider
      • IMessageDescription
      • IMessageDescriptions
      • MessageLevel
      • Message printing
      • Messages and Exceptions
      • Logging
      • Validation
      • Localization
    • Avalanche.StatusCode
      • Introduction
      • HResult
        • Introduction
        • HResult.Facilities
        • BasicMessages
        • RpcMessages
        • DispatchMessages
        • ItfMessages
        • Win32Messages
        • ClrMessages
      • System
        • Introduction
        • AccessControlMessages
        • AggregateMessages
        • AppDomainMessages
        • ArgumentMessages
        • ArgumentNullMessages
        • ArgumentOutOfRangeMessages
        • ArithmeticMessages
        • ArrayMessages
        • AssemblyMessages
        • BadImageFormatMessages
        • CodeContractMessages
        • CodePageMessages
        • CollectionsMessages
        • CompilerServiceMessages
        • CryptographyMessages
        • CultureMessages
        • DiagnosticsMessages
        • EventSourceMessages
        • ExecutionEngineMessages
        • FormatMessages
        • HostProtectionMessages
        • IOMessages
        • IndexOutOfRangeMessages
        • InteropServiceMessages
        • InvalidCastMessages
        • InvalidOperationMessages
        • IsolatedStorageMessages
        • LazyMessages
        • MarshalerMessages
        • MemoryMessages
        • MiscellaneousMessages
        • NotImplementedMessages
        • NotSupportedMessages
        • ObjectDisposedMessages
        • OperationCanceledMessages
        • OverflowMessages
        • PlatformMessages
        • PolicyMessages
        • PrincipalMessages
        • ProgramMessages
        • ReferenceMessages
        • ReflectionMessages
        • RegionMessages
        • RemotingMessages
        • ResourcesMessages
        • SecurityMessages
        • SerializationMessages
        • StackMessages
        • TaskMessages
        • TextMessages
        • ThreadingMessages
        • TimeZoneMessages
        • TypeMessages
        • XmlMessages
    • Avalanche.Template
      • Introduction
      • TemplateFormats
      • ITemplatePrintable
      • ITemplateFormatPrintable
      • ITemplateText
      • ITemplateBreakdown
      • ITemplateFormat
      • ITemplateFormats
      • Extract Arguments
      • Emplacement
    • Avalanche.Tokenizer
      • Introduction
      • IToken
      • ITokenizer
      • Tokenizers
    • Avalanche.Service
      • Introduction
      • Service
        • IService
        • Construction
        • Query
        • CancellationToken
        • CachePolicy
        • Cast
        • Scope
        • Dispose
      • Handler
        • Introduction
        • IHandler
        • Cancel
        • Recursion
        • Cyclicity
        • Delegates
        • Casting
        • Invokable
        • Handlers
      • Request
        • Introduction
        • IRequest
        • [Request]
        • [ContextParameter]
        • Print Tree
      • Dependency Injection
        • Introduction
        • ServiceRequest<T>
        • Handler
        • CachePolicy
        • CancellationToken
        • QueryLogger
      • Examples
        • Expression Example
        • Mapper Example
      • ServiceMessages
    • Avalanche.Writer
      • Introduction
      • Writer
      • Referer
      • TypeCast
      • DefaultConstructor
      • DelegateWriter
      • WriterPipe
      • ConstantWriter
      • PassthroughWriter
      • Context
      • WriterMessages
    • Avalanche.Accessor
      • Introduction
      • AccessorServices
      • List
        • ListAccessor
        • ListConstructor
        • ListDeconstructor
        • ListDefaultConstructor
        • ListGet
        • ListSet
        • ListAdd
        • ListInsert
        • ListClear
        • ListCount
        • ListIndexOf
        • ListRemoveAt
        • ListReferer
      • Map
        • MapAccessor
        • MapConstructor
        • MapDeconstructor
        • MapDefaultConstructor
        • MapSet
        • MapGet
        • MapRemove
        • MapClear
        • MapCount
        • MapReferer
      • Record
        • RecordAccessor
        • RecordConstructor
        • RecordDeconstructor
        • RecordDefaultConstructor
      • Field
        • FieldAccessor
        • FieldReader
        • FieldWriter
        • FieldReferer
      • Dependency Injection
        • Introduction
      • AccessorMessages
    • Avalanche.Emit
      • Introduction
      • TypeBuilder
      • ConstructorBuilder
      • MethodBuilder
      • PropertyBuilder
      • FieldBuilder
      • Emit
      • Utilities
    • Avalanche.DataType
      • Introduction
      • IDataTypeBase
      • IDataType
      • IRecordType
      • IFieldType
      • IUnionType
      • IListType
      • IMapType
      • IValueType
      • IEnumerationType
      • IIntegerType
      • IRealType
      • IStringType
      • IAnyType
      • DataTypeRequest
      • PrintTree
      • DataTypeMessages
    • Avalanche.FileSystem
      • Introduction
      • Abstractions
        • IFileSystem
          • IFileSystemBrowse
          • IFileSystemCreateDirectory
          • IFileSystemDelete
          • IFileSystemFileAttribute
          • IFileSystemMount
          • IFileSystemMove
          • IFileSystemObserve
          • IFileSystemOpen
        • IEvent
        • IEntry
        • IOption
        • IToken
      • FileSystem
      • VirtualFileSystem
      • MemoryFileSystem
      • EmbeddedFileSystem
      • HttpFileSystem
      • Decoration
      • IFileProvider
      • Events
      • Utilities
        • Dispose
        • File Scanner
        • Visit Tree
        • File Operation
    • Avalanche.Identity
      • Introduction
      • Identity
      • IdentityParts
      • IdentityInterner
      • IdentityComparer
      • Print Tree
      • IdentityAccessors
        • Introduction
        • TypeName
    • Avalanche.Utilities
      • Introduction
      • Collections
        • Tuples
        • StructList
        • ArrayList
        • BijectionMap
        • LocakableDictionary
        • LockableList
        • MapList
        • Pipe
        • RingQueue
        • EnumerableExtensions
        • TupleUtilities
        • ArrayUtilities
      • Comparers
        • IGraphComparer
        • IGraphComparable
        • AlphaNumericComparer
        • EnumerableComparer
        • EnumerableGraphComparer
        • ReferenceComparer
        • KeyValuePairComparer
        • DefaultComparerProvider
        • RecordComparer
      • Cloners
        • ICloner
        • IGraphCloner
        • IGraphCloneable
        • EnumerableCloner
        • FieldCloner
        • PassthroughCloner
        • RecordCloner
        • ClonerProvider
      • Dispose
        • IDisposeAttachable
        • IDisposeBelatable
      • Provider
        • Introduction
        • ProviderBase
        • Delegate
        • Concatenation
        • Cache
        • ResultCapture
        • AsReadOnly
        • AsService
      • Record
        • IRecordDescription
        • IFieldDescription
        • IConstructorDescription
        • IConstructionDescription
        • IParameterDescription
        • IRecordProviders
        • RecordDelegates
          • RecordCreate
          • RecordClone
          • RecordCopy
          • IRecordDelegates
        • FieldDelegates
          • FieldRead
          • FieldWrite
          • RecreateWith
          • IFieldDelegates
      • String
        • IEscaper
        • UnicodeString
      • Miscellaneous
        • IIdGenerator
        • Permutation
        • IReadOnly
        • IUserDataContainer
        • Void
    • Avalanche.Core
      • License
      • Order

    Cyclicity

    One of the design requirements of Avalanche.Service library has been the capability to process cyclic requests and produce cyclic results. The requirement affected many aspects and needed to be addressed throughout the library. Cyclicity is a use case that is not used often, but when it is, it must be integral part of the design as it cannot be added afterwards.

    An object graph that has circular chain of references is cyclic.

    Cyclic query

    Handler implementation

    The library makes it easy to break down complicated cyclic requests into easily processable simple handlers.

    There are however a few special considerations that handler implementation must adhere to:

    1. Result objects must be reference objects
    2. Result objects must be constructed in two phases. Initial reference must be assigned after construction.
    3. Cache must be used for the request type.
    4. Other handlers must get reference with .GetInitialized()
    5. One handler must provide final reference with .SetValue to indicate result is completed.
    // Choose cache policy
    IRequestPolicy<CachePolicy> cachePolicy = CachePolicies.ToCache;
    // Create service
    IService<Node, int> countService = Services.Create<Node, int>(new NodeCounter(), cachePolicy);
    // Create nodes
    Node root = new(), node1 = new(), node2 = new(), node3 = new();
    // Cyclic graph
    root.Children = new Node[] { node1, node2, node3, root };
    // Count number of nodes
    int count = countService.GetRequired(root);
    
    public class Node
    {
        /// <summary>Forward reference edge</summary>
        public Node[]? Children;
    }
    
    public class NodeCounter : IHandler<Node, int>
    {
        public void Handle(IQuery<Node, int> query)
        {
            // Already handled
            if (query.Handled()) return;
            // Assign initial value (required)
            query.Response.SetValue(0);
            // Start counting, include self
            int count = 1;
            // Get node
            Node node = query.Request;
            // Count children
            if (node.Children != null)
            {
                foreach (Node child in node.Children)
                {
                    // Count nodes                    
                    query.Service.TryGetInitialized<Node, int>(child, out int childCount);
                    // Add up
                    count += childCount;
                }
            }
            // Assign new value
            query.Response.SetValue(count);
        }
    }
    

    Query handler cycle may occur if rules are not followed. The most common cause is that request is non-cached. To conserve CPU cycles and memory, the library does not detect perform detection of cyclicity of query handlers.

    Full Example

    Full example
    using System;
    using Avalanche.Service;
    
    public class handler_cyclic
    {
        public static void Run()
        {
            // <1>
            // Choose cache policy
            IRequestPolicy<CachePolicy> cachePolicy = CachePolicies.ToCache;
            // Create service
            IService<Node, int> countService = Services.Create<Node, int>(new NodeCounter(), cachePolicy);
            // Create nodes
            Node root = new(), node1 = new(), node2 = new(), node3 = new();
            // Cyclic graph
            root.Children = new Node[] { node1, node2, node3, root };
            // Count number of nodes
            int count = countService.GetRequired(root);
            // </1>
            Console.WriteLine(count);
        }
    
        // <2>
        public class Node
        {
            /// <summary>Forward reference edge</summary>
            public Node[]? Children;
        }
        // </2>
    
        // <3>
        public class NodeCounter : IHandler<Node, int>
        {
            public void Handle(IQuery<Node, int> query)
            {
                // Already handled
                if (query.Handled()) return;
                // Assign initial value (required)
                query.Response.SetValue(0);
                // Start counting, include self
                int count = 1;
                // Get node
                Node node = query.Request;
                // Count children
                if (node.Children != null)
                {
                    foreach (Node child in node.Children)
                    {
                        // Count nodes                    
                        query.Service.TryGetInitialized<Node, int>(child, out int childCount);
                        // Add up
                        count += childCount;
                    }
                }
                // Assign new value
                query.Response.SetValue(count);
            }
        }
        // </3>
    
    }
    
    Back to top Copyright © 2022 Toni Kalajainen, contact@avalanche.fi