4 /*****************************************************************************\
7 * Author : Chris Koeritz *
9 *******************************************************************************
10 * Copyright (c) 2001-$now By Author. This program is free software; you can *
11 * redistribute it and/or modify it under the terms of the GNU General Public *
12 * License as published by the Free Software Foundation; either version 2 of *
13 * the License or (at your option) any later version. This is online at: *
14 * http://www.fsf.org/copyleft/gpl.html *
15 * Please send any updates to: fred@gruntose.com *
16 \*****************************************************************************/
18 #include <basis/contracts.h>
19 #include <mathematics/chaos.h>
20 #include <processes/safe_roller.h>
21 #include <structures/set.h>
22 #include <timely/time_stamp.h>
27 class entity_data_bin;
30 class modula_oblongata;
32 class octopus_request_id;
35 //! Octopus is a design pattern for generalized request processing systems.
37 Octopus is a plug-in module manager that can serve as the base for highly
38 extensible program architectures. Each module is called a tentacle,
39 following the conceit of the naming conventions, and it services one type
40 of request. The requests come in the form of infoton objects, where the
41 tentacle that handles each class of infotons is uniquely identifiable.
42 Note that the outcomes returned here are from the tentacle's set of
46 class octopus : public virtual basis::root_object
49 octopus(const basis::astring &name, int max_size_per_entity);
50 //!< constructs an octopus named "name".
51 /*!< the "name" string identifies the arena where this octopus is running.
52 this could be a network host or other identification string. the
53 "max_size_per_entity" is the largest that we allow one entity's bin of
54 pending data to be. this should be quite large if massive transactions
55 need to be processed. */
59 DEFINE_CLASS_NAME("octopus");
61 const basis::astring &name() const;
62 //!< returns the name that the octopus was constructed with.
64 // tentacle management functions...
66 basis::outcome add_tentacle(tentacle *to_add, bool filter = false);
67 //!< hooks a tentacle in to provide processing of one type of infoton.
68 /*!< lists the tentacle "to_add" as being responsible for handling requests
69 for the tentacle's group(). note that the octopus takes over control of
70 the "to_add" pointer; do not destroy that pointer independently, and do
71 not use the tentacle after adding it to the octopus unless the tentacle is
72 thread-safe. the add will replace an existing tentacle if it was already
73 registered under the same group name. if the "filter" flag is enabled,
74 then this tentacle is considered a filter; it will be consulted on all
75 infotons before they are processed. filters will be invoked in the order
76 that they are added. */
78 basis::outcome remove_tentacle(const structures::string_array &group_name, tentacle * &free_me);
79 //!< removes the tentacle listed for the "group_name", if any.
80 /*!< "free_me" provides the means for getting back what was originally
81 registered. NOTE: remember to destroy "free_me" if that's appropriate
82 (i.e. it was dynamically allocated, has no other users and no other entity
83 has responsibility for it). */
85 basis::outcome zap_tentacle(const structures::string_array &group_name);
86 //!< similar to remove_tentacle(), but destroys the tentacle.
88 // entity management methods...
90 octopus_entity issue_identity();
91 //!< creates an entity identifier that is unique for this octopus.
92 /*!< this provides a unique identity using the "name" specified in the
93 constructor and the current process id. the sequence number and random
94 add_in are generated by this class also. */
96 void expunge(const octopus_entity &to_remove);
97 //!< invokes every tentacle's expunge() method on the id "to_remove".
98 /*!< this indicates that the entity is no longer extant and resources
99 held for it can be destroyed. */
101 entity_data_bin &responses();
102 //!< allows external access to our set of results.
103 /*!< this should not be used unless you know what you're doing. */
105 // main functionality: restoring infotons, evaluating requests and
106 // locating responses.
108 basis::outcome restore(const structures::string_array &classifier, basis::byte_array &packed_form,
109 infoton * &reformed);
110 //!< regenerates a packed infoton given its classifier.
111 /*!< locates the appropriate type of infoton with the "classifier" and
112 consumes the bytes in "packed_form" to return a new version of the original
113 data in "reformed", if possible. */
115 basis::outcome evaluate(infoton *request, const octopus_request_id &item_id,
117 //!< tries to process the "request" using the current set of tentacles.
118 /*!< if there is no group handler for the "request", then NO_HANDLER will
119 be returned. the classifier for "request" specifies the group name for
120 processing. NOTE: the octopus assumes all responsibility for the
121 "request", even if the outcome denotes failure; do not touch the "request"
122 after this call. if the "request" will be processed further by lower
123 level octopi, then the classifier can be patched as appropriate. the
124 "item_id" must be maintained with the request in order to identify the
125 entity making the request and the sequence number of this particular
126 request. the "now" parameter specifies whether the processing must occur
127 immediately; if false, the processing will occur later when the tentacle
128 get around to it. if "now" is true, there is more load on the octopus
129 itself. note that "now" is ignored if the tentacle does not support
130 backgrounding; true is always assumed for that case. */
132 infoton *acquire_result(const octopus_entity &requester,
133 octopus_request_id &original_id);
134 //!< acquires responses to previous requests if there are any waiting.
135 /*!< it returns an infoton for the "requester", if any are available.
136 call this function repeatedly to ensure that all responses have been
137 provided. the "original_id" is a copy of the "item_id" that was
138 originally passed to evaluate_request(). the returned object must
139 eventually be destroyed if non-null. */
141 infoton *acquire_specific_result(const octopus_request_id &original_id);
142 //!< supports seeking the result for a specific request.
143 /*!< either the infoton that is a response to "original_id" will be
144 returned or NULL_POINTER. */
148 // tentacle accessors: careful with these--you must always unlock after
151 tentacle *lock_tentacle(const structures::string_array &tentacle_name);
152 //!< locates the tentacle with the "tentacle_name" and returns it.
153 /*!< the octopus will stay locked until the unlock_tentacle() method is
156 void unlock_tentacle(tentacle *to_unlock);
157 //!< unlocks the octopus when given a previously locked tentacle.
158 /*!< this must be the same object that was obtained via the
159 lock_tentacle() method. */
161 void lock_tentacles();
162 //!< locks the tentacle list for use with locked_get_tentacle.
164 // the following are only valid if the tentacle list is locked.
165 int locked_tentacle_count(); //!< number of tentacles.
166 tentacle *locked_get_tentacle(int indy); //!< access indy'th tentacle.
167 void unlock_tentacles(); //!< unlocks the list.
171 // used internally; don't mess with externally.
173 void periodic_cleaning();
174 //!< flushes any abandoned data from the response bin.
177 basis::astring *_name; //!< our name as passed to the constructor.
178 modula_oblongata *_tentacles; //!< the list of tentacles.
179 basis::mutex *_molock; //!< the synchronizer for our tentacle list.
180 entity_data_bin *_responses; //!< data awaiting pickup by requester.
181 int _disallow_removals;
182 //!< simplifies locking behavior for immediate requests.
183 /*!< we set this flag and don't need to lock the whole octopus. if it's
184 non-zero, then no tentacles can be removed yet. */
185 timely::time_stamp *_next_cleaning; //!< when we'll next flush old items.
186 basis::mutex *_clean_lock; //!< used only to protect the time stamp above.
187 filter_list *_filters; //!< the filters that must vet infotons.
188 processes::safe_roller *_sequencer; //!< identity issue; this is the next entity id.
189 mathematics::chaos *_rando; //!< randomizer for providing extra uniquification.
192 octopus(const octopus &);
193 octopus &operator =(const octopus &);