// calculate fetches the information ID associated with the given information // sequence. In case the information sequence is not found within the underlying // storage, a new information ID is generated and used to store the given // information sequence. In any case the information ID is added to the given // context. func (c *clg) calculate(ctx spec.Context, informationSequence string) error { informationIDKey := key.NewNetworkKey("information-sequence:%s:information-id", informationSequence) informationID, err := c.Storage().General().Get(informationIDKey) if storage.IsNotFound(err) { // The given information sequence was never seen before. Thus we register it // now with its own very unique information ID. newID, err := c.Service().ID().New() if err != nil { return maskAny(err) } informationID = string(newID) err = c.Storage().General().Set(informationIDKey, informationID) if err != nil { return maskAny(err) } informationSequenceKey := key.NewNetworkKey("information-id:%s:information-sequence", informationID) err = c.Storage().General().Set(informationSequenceKey, informationSequence) if err != nil { return maskAny(err) } } else if err != nil { return maskAny(err) } ctx.SetInformationID(informationID) return nil }
func (c *clg) calculate(ctx spec.Context) (string, error) { behaviourID, ok := ctx.GetBehaviourID() if !ok { return "", maskAnyf(invalidBehaviourIDError, "must not be empty") } behaviourIDKey := key.NewNetworkKey("behaviour-id:%s:separator", behaviourID) separator, err := c.Storage().General().Get(behaviourIDKey) if storage.IsNotFound(err) { randomKey, err := c.Storage().Feature().GetRandom() if err != nil { return "", maskAny(err) } // Make sure the fetched feature is valid based on its key structure. The // key itself already contains the feature. Knowing the key structure makes // it possible to simply parse the feature from the key fetched from the // feature storage. These features are stored by the split-features CLG. // Changes in the key structure there must be aligned with implementation // details here. The current key structure looks as follows. // // feature:%s:positions // if len(randomKey) != 22 { return "", maskAnyf(invalidFeatureKeyError, "key '%s' must have length '22'", randomKey) } if !strings.HasPrefix(randomKey, "feature:") { return "", maskAnyf(invalidFeatureKeyError, "key '%s' prefix must be 'feature:'", randomKey) } if !strings.HasSuffix(randomKey, ":positions") { return "", maskAnyf(invalidFeatureKeyError, "key '%s' suffix must be ':positions'", randomKey) } // Create a new separator from the fetched random feature. Note that a // feature is considered 4 characters long and the random factory takes a // max parameter, which is exlusive. feature := randomKey[8:12] featureIndex, err := c.Service().Random().CreateMax(5) if err != nil { return "", maskAny(err) } separator = string(feature[featureIndex]) // Store the newly created separator using the CLGs own behaviour ID. In case // this CLG is asked again to return its separator, it will lookup its // separator in the general storage. err = c.Storage().General().Set(behaviourIDKey, separator) if err != nil { return "", maskAny(err) } } else if err != nil { return "", maskAny(err) } return separator, nil }
func (f *forwarder) GetNetworkPayloads(CLG systemspec.CLG, networkPayload objectspec.NetworkPayload) ([]objectspec.NetworkPayload, error) { ctx := networkPayload.GetContext() // Check if there are behaviour IDs known that we can use to forward the // current network payload to. behaviourID, ok := ctx.GetBehaviourID() if !ok { return nil, maskAnyf(invalidBehaviourIDError, "must not be empty") } behaviourIDsKey := key.NewNetworkKey("forward:configuration:behaviour-id:%s:behaviour-ids", behaviourID) newBehaviourIDs, err := f.Storage().General().GetAllFromSet(behaviourIDsKey) if storage.IsNotFound(err) { // No configuration of behaviour IDs is stored. Thus we return an error. // Eventually some other lookup is able to find sufficient network payloads. return nil, maskAny(networkPayloadsNotFoundError) } else if err != nil { return nil, maskAny(err) } // Create a list of new network payloads. var newNetworkPayloads []objectspec.NetworkPayload for _, behaviourID := range newBehaviourIDs { // Prepare a new context for the new network payload. newCtx := ctx.Clone() newCtx.SetBehaviourID(behaviourID) // Create a new network payload. newNetworkPayloadConfig := networkpayload.DefaultConfig() newNetworkPayloadConfig.Args = networkPayload.GetArgs() newNetworkPayloadConfig.Context = newCtx newNetworkPayloadConfig.Destination = string(behaviourID) newNetworkPayloadConfig.Sources = []string{networkPayload.GetDestination()} newNetworkPayload, err := networkpayload.New(newNetworkPayloadConfig) if err != nil { return nil, maskAny(err) } newNetworkPayloads = append(newNetworkPayloads, newNetworkPayload) } return newNetworkPayloads, nil }
// TODO there is nothing that reads pairs func (c *clg) calculate(ctx spec.Context) error { // The counter keeps track of the work already being done. We only increment // the counter in case we were not able to do our job. As soon as some // threshold is reached, we stop trying. var counter int for { // Fetch two random features from the feature storage. This is done by // fetching random keys. The keys itself already contain the features. Knowing // the key structure makes it possible to simply parse the features from the // keys fetched from the feature storage. These features are stored by the // split-features CLG. Changes in the key structure there must be aligned with // implementation details here. The current key structure looks as follows. // // feature:%s:positions // key1, err := c.Storage().Feature().GetRandom() if err != nil { return maskAny(err) } key2, err := c.Storage().Feature().GetRandom() if err != nil { return maskAny(err) } // Validate the fetched keys. for _, k := range []string{key1, key2} { if len(k) != 22 { return maskAnyf(invalidFeatureKeyError, "key '%s' must have length '22'", k) } if !strings.HasPrefix(key1, "feature:") { return maskAnyf(invalidFeatureKeyError, "key '%s' prefix must be 'feature:'", k) } if !strings.HasSuffix(key1, ":positions") { return maskAnyf(invalidFeatureKeyError, "key '%s' suffix must be ':positions'", k) } } // Combine the fetched keys to a new pair. pair := key1[8:12] + key2[8:12] // Write the new pair into the general storage. pairIDKey := key.NewNetworkKey("pair:syntactic:feature:%s:pair-id", pair) _, err = c.Storage().General().Get(pairIDKey) if storage.IsNotFound(err) { // The created pair was not found within the feature storage. That means // we created a new one which we can store. Once we stored the new pair, // we break the outer loop to be done. newID, err := c.Service().ID().New() if err != nil { return maskAny(err) } pairID := string(newID) err = c.Storage().General().Set(pairIDKey, pairID) if err != nil { return maskAny(err) } break } if counter >= 3 { // We tried to create a new pair 3 times, but it looks like there is not // enough data. That is why the created pair was found all the time. It // looks like we cannot create any new pair and stop doing anything here. break } counter++ } return nil }
func (a *activator) GetNetworkPayload(CLG systemspec.CLG, queue []objectspec.NetworkPayload) (objectspec.NetworkPayload, error) { // Fetch the combination of successful behaviour IDs which are known to be // useful for the activation of the requested CLG. The network payloads sent // by the CLGs being fetched here are known to be useful because they have // already been helpful for the execution of the current CLG tree. behaviourID, ok := queue[0].GetContext().GetBehaviourID() if !ok { return nil, maskAnyf(invalidBehaviourIDError, "must not be empty") } behaviourIDsKey := key.NewNetworkKey("activate:configuration:behaviour-id:%s:behaviour-ids", behaviourID) s, err := a.Storage().General().Get(behaviourIDsKey) if storage.IsNotFound(err) { // No successful combination of behaviour IDs is stored. Thus we return an // error. Eventually some other lookup is able to find a sufficient network // payload. return nil, maskAny(networkPayloadNotFoundError) } else if err != nil { return nil, maskAny(err) } behaviourIDs := strings.Split(s, ",") if len(behaviourIDs) == 0 { // No activation configuration of the requested CLG is stored. Thus we // return an error. Eventually some other lookup is able to find a // sufficient network payload. return nil, maskAny(networkPayloadNotFoundError) } // Check if there is a queued network payload for each behaviour ID we found in the // storage. Here it is important to obtain the order of the behaviour IDs // stored as connections. They represent the input interface of the requested // CLG. Thus there must not be any variation applied to the lookup here, // because we need the lookup to be reproducible. var matches []objectspec.NetworkPayload for _, behaviourID := range behaviourIDs { for _, np := range queue { // At this point there is only one source given. That is the CLG that // forwarded the current network payload to here. If this is not the case, // we return an error. sources := np.GetSources() if len(sources) != 1 { return nil, maskAnyf(invalidSourcesError, "there must be one source") } if behaviourID == string(sources[0]) { // The current behaviour ID belongs to the current network payload. We // add the matching network payload to our list and go on to find the // network payload belonging to the next behabiour ID. matches = append(matches, np) break } } } if len(behaviourIDs) != len(matches) { // No match using the stored configuration associated with the requested CLG // can be found. Thus we return an error. Eventually some other lookup is // able to find a sufficient network payload. return nil, maskAny(networkPayloadNotFoundError) } // The received network payloads are able to satisfy the interface of the // requested CLG. We merge the matching network payloads together and return // the result. newNetworkPayload, err := mergeNetworkPayloads(matches) if err != nil { return nil, maskAny(err) } return newNetworkPayload, nil }