first check-in of feisty meow codebase. many things broken still due to recent
[feisty_meow.git] / octopi / library / octopus / octopus.h
1 #ifndef OCTOPUS_CLASS
2 #define OCTOPUS_CLASS
3
4 /*****************************************************************************\
5 *                                                                             *
6 *  Name   : octopus                                                           *
7 *  Author : Chris Koeritz                                                     *
8 *                                                                             *
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 \*****************************************************************************/
17
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>
23
24 namespace octopi {
25
26 // forward.
27 class entity_data_bin;
28 class filter_list;
29 class infoton;
30 class modula_oblongata;
31 class octopus_entity;
32 class octopus_request_id;
33 class tentacle;
34
35 //! Octopus is a design pattern for generalized request processing systems.
36 /*!
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
43   outcomes.
44 */
45
46 class octopus : public virtual basis::root_object
47 {
48 public:
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. */
56
57   virtual ~octopus();
58
59   DEFINE_CLASS_NAME("octopus");
60
61   const basis::astring &name() const;
62     //!< returns the name that the octopus was constructed with.
63
64   // tentacle management functions...
65
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. */
77
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). */
84
85   basis::outcome zap_tentacle(const structures::string_array &group_name);
86     //!< similar to remove_tentacle(), but destroys the tentacle.
87
88   // entity management methods...
89
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. */
95
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. */
100
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. */
104
105   // main functionality: restoring infotons, evaluating requests and
106   // locating responses.
107
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. */
114
115   basis::outcome evaluate(infoton *request, const octopus_request_id &item_id,
116           bool now = false);
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. */
131
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-NIL. */
140
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 NIL. */
145
146   //////////////
147
148   // tentacle accessors: careful with these--you must always unlock after
149   // you have locked.
150
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
154     invoked. */
155
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. */
160
161   void lock_tentacles();
162     //!< locks the tentacle list for use with locked_get_tentacle.
163
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.
168
169   //////////////
170
171   // used internally; don't mess with externally.
172
173   void periodic_cleaning();
174     //!< flushes any abandoned data from the response bin.
175
176 private:
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.
190
191   // not accessible.
192   octopus(const octopus &);
193   octopus &operator =(const octopus &);
194 };
195
196 } //namespace.
197
198 #endif
199