summaryrefslogtreecommitdiff
path: root/TAO/orbsvcs/orbsvcs/ESF/ESF_Proxy_Collection.h
blob: 9f69b025d41fb43cca071dc4f9161bb1db7d1c9e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/* -*- C++ -*- */
// $Id$
//
// ============================================================================
//
// = LIBRARY
//   ORBSVCS Event Service Framework
//
// = FILENAME
//   ESF_Proxy_Collection
//
// = AUTHOR
//   Carlos O'Ryan (coryan@cs.wustl.edu)
//
// = CREDITS
//   http://www.cs.wustl.edu/~coryan/EC/index.html
//
// ============================================================================

#ifndef TAO_ESF_PROXY_COLLECTION_H
#define TAO_ESF_PROXY_COLLECTION_H

#include "tao/corba.h"

#if !defined (ACE_LACKS_PRAGMA_ONCE)
# pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */

template<class Target> class TAO_ESF_Worker;

template<class PROXY>
class TAO_ESF_Proxy_Collection
{
  // = TITLE
  //   ESF_Proxy_Collection
  //
  // = DESCRIPTION
  //   Many components in an Event Service need to keep a collection
  //   of proxies; these collections must be able to cope with several
  //   concurrency issues:
  //   + Some threads may need to iterate over the collection and
  //     invoke a method on each element.  Locking the collection
  //     while this is done is not feasible in all cases: under some
  //     configurations the same thread that is iterating over the
  //     collection may need to make changes to the set.
  //   + A recursive lock does not solve the concurrency problems
  //     because recursive changes to the collection still invalidate
  //     the iterators.
  //
  //   There are several solutions to this problem (see the VARIANTS)
  //   section, and there is no single one that works bests in all
  //   cases.  As usual, we wish the strategize the protocol used to
  //   serialize iterations and changes to the collection.  This class
  //   encapsulates that protocol.
  //
  //   The usual form of the Iterator pattern does not work well in
  //   this case: in several variants the synchronization protocol and
  //   the iteration loop must collaborate to work efficiently.
  //   Exposing an external iterator would require that every other
  //   component in the system can support all the synchronization
  //   protocols.   It is possible to hide some of that complexity
  //   using heavy weight iterators, but their use is ackward,
  //   specially since the Koening-style iterators have become more
  //   popular.
  //
  //   Regular member functions are used to insert, remove and update
  //   members of the collection and to shutdown (i.e. perform final
  //   cleanup operations).
  //
  //   The class must also collaborate with other components of the
  //   EC to efficiently and safely perform memory managment of the
  //   members in the collection.
  //
  // = REQUIREMENTS
  //   The PROXY object must be reference counted with the following
  //   operations:
  //
  //   _incr_refcnt() - increment the reference count.
  //   _decr_refcnt() - decrement the reference count.
  //
  // = VARIANTS
  //
  //   We identify several sources of variation:
  //
  //   + Immediate_Changes: in this variant the iteration in performed
  //   while holding some kind of synchronization primitive, such as a
  //   thread mutex, a recursive mutex, a RW lock, etc.
  //   This is only useful in configurations where a separate thread
  //   dispatches the events, and thus, can only be used with real
  //   locks.
  //
  //   + Copy_On_Read: before performing the iteration the collection
  //   is duplicated into a temporary array.  Thus no locks are held
  //   during the iteration.  This is a very expensive approach, but
  //   useful in many cases.
  //   The kind of lock is also strategized in this case.
  //
  //   + Copy_On_Write: this is very similar to the previous approach,
  //   but the collection is only duplicated when a change is required
  //   while some thread is performing an iteration.  The iteration
  //   continues over the original copy, while the changes are
  //   performed in the duplicate.  The new copy of the collection is
  //   used for any subsequent operations, the original is discarded
  //   when the last thread using it completes its work.
  //   This approach optimizes for the case where no changes are
  //   is duplicated into a temporary array.  Thus no locks are held
  //   during the iteration.  This is a very expensive approach, but
  //   useful in many cases.
  //   The kind of lock is also strategized in this case.
  //
  //   + Delayed_Changes: before starting the iteration a counter is
  //   incremented, this counter is used to keep track of the number
  //   of threads concurrently using the collection.
  //   If a thread wants to perform a change to the collection it must
  //   first verify that there are no threads iterating over it.  If
  //   there are any threads then the thread queues the modification
  //   for later execution, using the Command pattern.
  //   The kind of lock is strategized, as this approach is used in
  //   single threaded configurations.
  //   There are two main variations:
  //     - An upcall can result in new dispatches: in this case we
  //       have to keep track of a the list of current threads using
  //       a Set, to avoid dead-locks.
  //       IMPLEMENTATION: the design is not complete, probably
  //       similar to the next one.
  //     - Otherwise we just need to control the concurrency using the
  //       algorithm described below.
  //
  //
  // = MEMORY MANAGMENT
  //   It assumes ownership of the proxies added to the collection,
  //   it increases the reference count.
  //
  // = LOCKING
  //   Locking is provided by derived classes.
  //
  // = TODO
  //
public:
  virtual ~TAO_ESF_Proxy_Collection (void);
  // destructor

  virtual void for_each (TAO_ESF_Worker<PROXY> *worker,
                         CORBA::Environment &ACE_TRY_ENV) = 0;
  // Iterate over the collection and invoke worker->work() for each
  // member of the collection.
  // This encapsulates

  virtual void connected (PROXY *proxy,
                          CORBA::Environment &ACE_TRY_ENV) = 0;
  // Insert a new element into the collection.  The collection assumes
  // ownership of the element.

  virtual void reconnected (PROXY *proxy,
                            CORBA::Environment &ACE_TRY_ENV) = 0;
  // Insert an element into the collection.  No errors can be raised
  // if the element is already present.
  // The collection assumes ownership, i.e. must invoke
  // <proxy->_decr_refcnt()> if the element is already present in the
  // collection.

  virtual void disconnected (PROXY *proxy,
                             CORBA::Environment &ACE_TRY_ENV) = 0;
  // Remove an element from the collection.

  virtual void shutdown (CORBA::Environment &ACE_TRY_ENV) = 0;
  // The EC is shutting down, must release all the elements.
};

// ****************************************************************

#if defined (__ACE_INLINE__)
#include "ESF_Proxy_Collection.i"
#endif /* __ACE_INLINE__ */

#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
#include "ESF_Proxy_Collection.cpp"
#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */

#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
#pragma implementation ("ESF_Proxy_Collection.cpp")
#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */

#endif /* TAO_ESF_PROXY_COLLECTION_H */