feisty meow concerns codebase  2.140
tentacle.cpp
Go to the documentation of this file.
1 /*****************************************************************************\
2 * *
3 * Name : tentacle *
4 * Author : Chris Koeritz *
5 * *
6 *******************************************************************************
7 * Copyright (c) 2002-$now By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
14 
15 #include "entity_data_bin.h"
16 #include "entity_defs.h"
17 #include "infoton.h"
18 #include "tentacle.h"
19 
20 #include <basis/astring.h>
21 #include <basis/mutex.h>
23 #include <processes/ethread.h>
24 #include <structures/amorph.h>
25 
26 using namespace basis;
27 using namespace loggers;
28 using namespace processes;
29 using namespace structures;
30 
31 namespace octopi {
32 
33 //#define DEBUG_TENTACLE
34  // uncomment for noisier version.
35 
36 #undef GRAB_CONSUMER_LOCK
37 #define GRAB_CONSUMER_LOCK auto_synchronizer l(*_input_guard)
38 
39 #undef LOG
40 #define LOG(t) CLASS_EMERGENCY_LOG(program_wide_logger::get(), t)
41 
43 
44 struct infoton_record {
45  infoton *_product;
46  octopus_request_id _id;
47 
48  infoton_record(infoton *product, octopus_request_id id)
49  : _product(product), _id(id) {}
50 
51  ~infoton_record() { WHACK(_product); }
52 };
53 
54 class queueton : public amorph<infoton_record> {};
55 
57 
58 class pod_motivator : public ethread
59 {
60 public:
61  pod_motivator(tentacle &parent, int motivational_rate)
62  : ethread(motivational_rate, ethread::SLACK_INTERVAL),
63  _parent(parent) {}
64 
65  void perform_activity(void *formal(ptr)) { _parent.propel_arm(); }
66 
67 private:
68  tentacle &_parent;
69 };
70 
72 
73 tentacle::tentacle(const string_array &group_name, bool backgrounded,
74  int motivational_rate)
75 : _group(new string_array(group_name)),
76  _pending(new queueton),
77  _input_guard(new mutex),
78  _action(NULL_POINTER),
79  _products(NULL_POINTER),
80  _backgrounded(backgrounded)
81 {
82  // we only start the thread if they've said they'll support backgrounding.
83  if (backgrounded)
84  _action = new pod_motivator(*this, motivational_rate);
85 }
86 
88 {
89  if (_action) _action->stop();
90  WHACK(_action);
91  WHACK(_group);
92  WHACK(_pending);
93  WHACK(_input_guard);
94 }
95 
96 const string_array &tentacle::group() const { return *_group; }
97 
98 const char *tentacle::outcome_name(const outcome &to_name)
99 { return common::outcome_name(to_name); }
100 
102 { if (_action) return _action->sleep_time(); else return 0; }
103 
104 entity_data_bin *tentacle::get_storage() { return _products; }
105 
107 {
108  _products = &storage;
109  if (_action) _action->start(NULL_POINTER);
110 }
111 
113 {
114  if (_action) _action->stop();
115  _products = NULL_POINTER;
116 }
117 
119  const octopus_request_id &original_id)
120 {
121  FUNCDEF("store_product");
122  if (!_products) {
123 //#ifdef DEBUG_TENTACLE
124  LOG("storage bunker has not been established!");
125 //#endif
126  return false;
127  }
128  return _products->add_item(product, original_id);
129 }
130 
132 {
134  int max_size = 0;
135  // this may be a bad assumption, but here goes: we assume that the limit
136  // on per entity storage in the bin is pretty much the same as a reasonable
137  // limit here on the queue of pending items. we need to limit it and would
138  // rather not add another numerical parameter to the constructor.
139  if (_products)
140  max_size = _products->max_bytes_per_entity();
141  int curr_size = 0;
142  if (max_size) {
143  // check that the pending queue is also constrained.
144  for (int i = 0; i < _pending->elements(); i++) {
145  curr_size += _pending->borrow(i)->_product->packed_size();
146  }
147  if (curr_size + to_chow->packed_size() > max_size) {
148  WHACK(to_chow);
149  return NO_SPACE;
150  }
151  }
152  *_pending += new infoton_record(to_chow, item_id);
153 //is there ever a failure outcome?
154 //yes, when space is tight!
155  return OKAY;
156 }
157 
159 {
161  if (!_pending->elements()) return NULL_POINTER; // nothing to return.
162  infoton *to_return = (*_pending)[0]->_product;
163  (*_pending)[0]->_product = NULL_POINTER;
164  // clean out so destructor doesn't delete the object.
165  item_id = (*_pending)[0]->_id;
166  _pending->zap(0, 0);
167  return to_return;
168 }
169 
171 {
172  FUNCDEF("propel_arm");
173  infoton *next_item = NULL_POINTER;
174  do {
176  next_item = next_request(id);
177  if (!next_item) break;
178  byte_array ignored;
179  outcome ret = consume(*next_item, id, ignored);
180  if (ret != OKAY) {
181 #ifdef DEBUG_TENTACLE
182  LOG(astring("failed to act on ") + next_item->classifier().text_form());
183 #endif
184  }
185  WHACK(next_item); // fulfill responsibility for cleanup.
186  } while (next_item);
187 }
188 
189 } //namespace.
190 
Provides a dynamically resizable ASCII character string.
Definition: astring.h:35
A very common template for a dynamic array of bytes.
Definition: byte_array.h:36
Outcomes describe the state of completion for an operation.
Definition: outcome.h:31
Stores a set of infotons grouped by the entity that owns them.
int max_bytes_per_entity() const
bool add_item(infoton *to_add, const octopus_request_id &id)
An infoton is an individual request parcel with accompanying information.
Definition: infoton.h:32
virtual int packed_size() const =0
reports how large the infoton will be when packed.
const structures::string_array & classifier() const
this array of strings is the "name" for this infoton.
Definition: infoton.cpp:85
Identifies requests made on an octopus by users.
Definition: entity_defs.h:114
bool store_product(infoton *product, const octopus_request_id &original_id)
used by tentacles to store the objects they produce from infotons.
Definition: tentacle.cpp:118
virtual ~tentacle()
Definition: tentacle.cpp:87
virtual basis::outcome consume(infoton &to_chow, const octopus_request_id &item_id, basis::byte_array &transformed)=0
this is the main function that processes infotons for this tentacle.
basis::outcome enqueue(infoton *to_chow, const octopus_request_id &item_id)
holds onto infotons coming from the octopus for backgrounding.
Definition: tentacle.cpp:131
const structures::string_array & group() const
returns the name of the group that this tentacle services.
Definition: tentacle.cpp:96
static const char * outcome_name(const basis::outcome &to_name)
returns the textual form of the outcome "to_name".
Definition: tentacle.cpp:98
void detach_storage()
unhooks the storage bin from this tentacle.
Definition: tentacle.cpp:112
int motivational_rate() const
returns the background processing rate this was constructed with.
Definition: tentacle.cpp:101
void attach_storage(entity_data_bin &storage)
used when a tentacle is being integrated with an octopus.
Definition: tentacle.cpp:106
infoton * next_request(octopus_request_id &item_id)
pops out the next queued request for processing.
Definition: tentacle.cpp:158
entity_data_bin * get_storage()
returns the current pointer, which might be nil.
Definition: tentacle.cpp:104
void propel_arm()
invoked by our thread to cause requests to be processed.
Definition: tentacle.cpp:170
Provides a platform-independent object for adding threads to a program.
Definition: ethread.h:36
An array of strings with some additional helpful methods.
Definition: string_array.h:32
basis::astring text_form() const
A synonym for the text_format() method.
Definition: string_array.h:71
#define formal(parameter)
This macro just eats what it's passed; it marks unused formal parameters.
Definition: definitions.h:48
#define NULL_POINTER
The value representing a pointer to nothing.
Definition: definitions.h:32
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition: enhance_cpp.h:57
The guards collection helps in testing preconditions and reporting errors.
Definition: array.h:30
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition: functions.h:121
A logger that sends to the console screen using the standard output device.
A dynamic container class that holds any kind of object via pointers.
Definition: amorph.h:55
#define GRAB_CONSUMER_LOCK
Definition: tentacle.cpp:37
#define LOG(t)
Definition: tentacle.cpp:40