feisty meow concerns codebase  2.140
t_bin_threaded.cpp
Go to the documentation of this file.
1 /*****************************************************************************\
2 * *
3 * Name : test_entity_data_bin_threaded *
4 * Author : Chris Koeritz *
5 * *
6 *******************************************************************************
7 * Copyright (c) 2010-$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 
16 #include <basis/byte_array.h>
17 #include <mathematics/chaos.h>
18 #include <basis/functions.h>
19 #include <basis/guards.h>
20 #include <basis/astring.h>
21 #include <basis/mutex.h>
22 #include <structures/amorph.h>
24 #include <loggers/console_logger.h>
25 #include <processes/ethread.h>
26 #include <processes/safe_roller.h>
27 #include <timely/time_control.h>
28 #include <timely/time_stamp.h>
30 #include <octopus/entity_defs.h>
35 
36 #include <stdio.h>
37 
38 #ifdef __WIN32__
39  #include <process.h>
40 #endif
41 
42 using namespace application;
43 using namespace loggers;
44 using namespace octopi;
45 using namespace processes;
46 using namespace timely;
47 
48 // global constants...
49 
50 // how much data is the entity data bin allowed to hold at one time.
52 //tiny limit to test having too much data.
53 
54 // controls the timing of the thread that adds items.
55 const int MIN_ADDER_THREAD_PAUSE = 3;
56 const int MAX_ADDER_THREAD_PAUSE = 20;
57 
58 // controls the timing of the item deleting thread.
60 const int MAX_WHACKER_THREAD_PAUSE = 70;
61 
62 // bound the randomly chosen pause time for the cleanup thread.
63 const int MIN_TIDIER_THREAD_PAUSE = 60;
64 const int MAX_TIDIER_THREAD_PAUSE = 500;
65 
66 // monk is kept asleep most of the time or he'd be trashing
67 // all our data too frequently.
70 
71 // the range of new items added whenever the creator thread is hit.
72 const int MINIMUM_ITEMS_ADDED = 1;
73 const int MAXIMUM_ITEMS_ADDED = 20;
74 
75 const int DEFAULT_THREADS = 90;
76  // the number of threads we create by default.
77 
78 const int DEFAULT_RUN_TIME = 80 * MINUTE_ms;
79 //2 * MINUTE_ms;
80  // the length of time to run the program.
81 
82 const int DATA_DECAY_TIME = 1 * MINUTE_ms;
83  // how long we retain unclaimed data.
84 
85 const int MONKS_CLEANING_TIME = 10 * SECOND_ms;
86  // a very short duration for data to live.
87 
88 #define LOG(to_print) printf("%s\n", (char *)astring(to_print).s());
89 //CLASS_EMERGENCY_LOG(program_wide_logger().get(), to_print)
90  // our macro for logging with a timestamp.
91 
92 // global objects...
93 
94 chaos _rando; // our randomizer.
95 
96 // replace app_shell version with local randomizer, so all the static
97 // functions can employ it also.
98 #define randomizer() _rando
99 
101 
103 {
104  // test the basic filling of the values in an entity.
105  octopus_request_id req_id;
106  if (randomizer().inclusive(1, 100) < 25) {
107  // some of the time we make a totally random entity id.
108  int sequencer = randomizer().inclusive(1, MAXINT - 10);
109  int add_in = randomizer().inclusive(0, MAXINT - 10);
110  int process_id = randomizer().inclusive(0, MAXINT - 10);
111  req_id._entity = octopus_entity(string_manipulation::make_random_name(),
112  process_id, sequencer, add_in);
113  } else {
114  // sometimes we use a less random identity.
115  int sequencer = randomizer().inclusive(1, 3);
116  int add_in = 12;
117  int process_id = randomizer().inclusive(1, 4);
118  req_id._entity = octopus_entity("boringentity",
119  process_id, sequencer, add_in);
120  }
121  req_id._request_num = randomizer().inclusive(1, MAXINT - 10);
122  return req_id;
123 }
124 
125 // this thread creates new items for the entity data bin.
126 class ballot_box_stuffer : public ethread
127 {
128 public:
129  ballot_box_stuffer() : ethread(0) {
130  FUNCDEF("constructor");
131  LOG("+creator");
132  }
133 
134  virtual ~ballot_box_stuffer() {
135  FUNCDEF("destructor");
136  LOG("~creator");
137  }
138 
139  DEFINE_CLASS_NAME("ballot_box_stuffer");
140 
141  void perform_activity(void *formal(data)) {
142  FUNCDEF("perform_activity");
143  while (!should_stop()) {
144  // add a new item to the cache.
145  int how_many = randomizer().inclusive(MINIMUM_ITEMS_ADDED,
147  for (int i = 0; i < how_many; i++) {
148  string_array random_strings;
149  int string_count = randomizer().inclusive(1, 10);
150  // we create a random classifier, just to use up some space.
151  for (int q = 0; q < string_count; q++) {
152  random_strings += string_manipulation::make_random_name();
153  }
155  random_strings);
156  binger.add_item(newbert, create_request_id());
157  }
158  // snooze.
159  int sleepy_time = randomizer().inclusive(MIN_ADDER_THREAD_PAUSE,
161  time_control::sleep_ms(sleepy_time);
162  }
163  }
164 
165 };
166 
167 // this thread eliminates entries in the ballot box.
168 class vote_destroyer : public ethread
169 {
170 public:
171  vote_destroyer() : ethread(0) {
172  FUNCDEF("constructor");
173  LOG("+destroyer");
174  }
175 
176  virtual ~vote_destroyer() {
177  FUNCDEF("destructor");
178  LOG("~destroyer");
179  }
180 
181  DEFINE_CLASS_NAME("vote_destroyer");
182 
183  void perform_activity(void *formal(data)) {
184  FUNCDEF("perform_activity");
185  while (!should_stop()) {
186  // snag any old item and drop it on the floor.
188  infoton *found = binger.acquire_for_any(id);
189  WHACK(found);
190  // snooze.
191  int sleepy_time = randomizer().inclusive(MIN_WHACKER_THREAD_PAUSE,
193  time_control::sleep_ms(sleepy_time);
194  }
195  }
196 };
197 
198 // this class makes sure the deadwood is cleaned out of the entity bin.
199 class obsessive_compulsive : public ethread
200 {
201 public:
202  obsessive_compulsive() : ethread(0) {
203  FUNCDEF("constructor");
204  LOG("+cleaner");
205  }
206 
207  virtual ~obsessive_compulsive() {
208  FUNCDEF("destructor");
209  LOG("~cleaner");
210  }
211 
212  DEFINE_CLASS_NAME("obsessive_compulsive");
213 
214  void perform_activity(void *formal(data)) {
215  FUNCDEF("perform_activity");
216  while (!should_stop()) {
217  // make sure there's nothing rotting too long.
219  // snooze.
220  int sleepy_time = randomizer().inclusive(MIN_TIDIER_THREAD_PAUSE,
222  time_control::sleep_ms(sleepy_time);
223  }
224  }
225 };
226 
227 // this thread will destroy all data in the bins while cleaning furiously.
228 class monk_the_detective : public ethread
229 {
230 public:
231  monk_the_detective() : ethread(0) {
232  FUNCDEF("constructor");
233  LOG("+monk");
234  }
235 
236  virtual ~monk_the_detective() {
237  FUNCDEF("destructor");
238  LOG("~monk");
239  }
240 
241  DEFINE_CLASS_NAME("monk_the_detective");
242 
243  void perform_activity(void *formal(data)) {
244  FUNCDEF("perform_activity");
245  while (!should_stop()) {
246  // one activation of monk has devastating consequences. we empty out
247  // the data one item at a time until we see no data at all. after
248  // cleaning each item, we ensure that the deadwood is cleaned out.
249  binger._ent_lock->lock();
250 LOG(a_sprintf("monk sees %d items.", binger.items_held()));
251  while (binger.items_held()) {
252  // grab one instance of any item in the bin.
254  infoton *found = binger.acquire_for_any(id);
255  WHACK(found);
256  // also clean out things a lot faster than normal.
258  }
259  binger._ent_lock->unlock();
260 LOG(a_sprintf("after a little cleaning, monk sees %d items.", binger.items_held()));
261  // snooze.
262  int sleepy_time = randomizer().inclusive(MIN_MONK_THREAD_PAUSE,
264  time_control::sleep_ms(sleepy_time);
265  }
266  }
267 };
268 
270 
271 class test_entity_data_bin_threaded : public application_shell
272 {
273 public:
274  test_entity_data_bin_threaded() : application_shell(class_name()) {}
275 
276  DEFINE_CLASS_NAME("test_entity_data_bin_threaded");
277 
278  int execute();
279 };
280 
281 int test_entity_data_bin_threaded::execute()
282 {
283  FUNCDEF("execute");
284 
285  amorph<ethread> thread_list;
286 
287  for (int i = 0; i < DEFAULT_THREADS; i++) {
288  ethread *t = NULL_POINTER;
289  if (i == DEFAULT_THREADS - 1) {
290  // last item gets special treatment; we reserve this space for monk.
291  t = new monk_the_detective;
292  } else if (i % 3 == 0) {
293  t = new ballot_box_stuffer;
294  } else if (i % 3 == 1) {
295  t = new vote_destroyer;
296  } else { // i % 3 must = 2.
297  t = new obsessive_compulsive;
298  }
299  thread_list.append(t);
300  ethread *q = thread_list[thread_list.elements() - 1];
301  if (q != t)
302  deadly_error(class_name(), func, "amorph has incorrect pointer!");
303  // start the thread we added.
304  thread_list[thread_list.elements() - 1]->start(NULL_POINTER);
305  }
306 
307  time_stamp when_to_leave(DEFAULT_RUN_TIME);
308  while (when_to_leave > time_stamp()) {
309  time_control::sleep_ms(100);
310  }
311 
312 // LOG("now cancelling all threads....");
313 
314 // for (int j = 0; j < thread_list.elements(); j++) thread_list[j]->cancel();
315 
316 // LOG("now stopping all threads....");
317 
318 // for (int k = 0; k < thread_list.elements(); k++) thread_list[k]->stop();
319 
320 // LOG("resetting thread list....");
321 
322  thread_list.reset(); // should whack all threads.
323 
324  LOG("done exiting from all threads....");
325 
326 //report the results:
327 // how many objects created.
328 // how many got destroyed.
329 // how many evaporated due to timeout.
330 
331 
332  guards::alert_message("t_bin_threaded:: works for all functions tested.");
333  return 0;
334 }
335 
336 HOOPLE_MAIN(test_entity_data_bin_threaded, )
337 
The application_shell is a base object for console programs.
void lock()
Clamps down on the mutex, if possible.
Definition: mutex.cpp:95
void unlock()
Gives up the possession of the mutex.
Definition: mutex.cpp:107
Stores a set of infotons grouped by the entity that owns them.
bool add_item(infoton *to_add, const octopus_request_id &id)
infoton * acquire_for_any(octopus_request_id &id)
void clean_out_deadwood(int decay_interval=4 *basis::MINUTE_ms)
An infoton is an individual request parcel with accompanying information.
Definition: infoton.h:32
Provides a way of identifying users of an octopus object.
Definition: entity_defs.h:35
Identifies requests made on an octopus by users.
Definition: entity_defs.h:114
int _request_num
the item number from the entity.
Definition: entity_defs.h:117
octopus_entity _entity
the entity.
Definition: entity_defs.h:116
Informs the caller that a request type was unknown to the server octopus.
Provides a platform-independent object for adding threads to a program.
Definition: ethread.h:36
Represents a point in time relative to the operating system startup time.
Definition: time_stamp.h:38
#define deadly_error(c, f, i)
#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 DEFINE_CLASS_NAME(objname)
Defines the name of a class by providing a couple standard methods.
Definition: enhance_cpp.h:45
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition: enhance_cpp.h:57
Provides macros that implement the 'main' program of an application.
#define HOOPLE_MAIN(obj_name, obj_args)
options that should work for most unix and linux apps.
Definition: hoople_main.h:61
Implements an application lock to ensure only one is running at once.
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition: functions.h:121
const int SECOND_ms
Number of milliseconds in a second.
Definition: definitions.h:120
const int MINUTE_ms
Number of milliseconds in a minute.
Definition: definitions.h:121
const int KILOBYTE
Number of bytes in a kilobyte.
Definition: definitions.h:134
A logger that sends to the console screen using the standard output device.
#include <time.h>
Definition: earth_time.cpp:37
const int MINIMUM_ITEMS_ADDED
octopus_request_id create_request_id()
const int MIN_ADDER_THREAD_PAUSE
entity_data_bin binger(MAXIMUM_DATA_PER_ENTITY)
const int MAX_MONK_THREAD_PAUSE
const int MAX_TIDIER_THREAD_PAUSE
const int DATA_DECAY_TIME
const int DEFAULT_RUN_TIME
const int MIN_WHACKER_THREAD_PAUSE
const int DEFAULT_THREADS
#define randomizer()
const int MAX_WHACKER_THREAD_PAUSE
const int MIN_MONK_THREAD_PAUSE
const int MAXIMUM_ITEMS_ADDED
const int MAX_ADDER_THREAD_PAUSE
#define LOG(to_print)
const int MIN_TIDIER_THREAD_PAUSE
const int MONKS_CLEANING_TIME
chaos _rando
const int MAXIMUM_DATA_PER_ENTITY
string_array(1, math_list))) const char *addr_list[]