Branch data Line data Source code
1 : : /*
2 : : *
3 : : * Copyright 2006,2007 Savarese Software Research Corporation
4 : : *
5 : : * Licensed under the Apache License, Version 2.0 (the "License");
6 : : * you may not use this file except in compliance with the License.
7 : : * You may obtain a copy of the License at
8 : : *
9 : : * http://www.savarese.com/software/ApacheLicense-2.0
10 : : *
11 : : * Unless required by applicable law or agreed to in writing, software
12 : : * distributed under the License is distributed on an "AS IS" BASIS,
13 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : : * See the License for the specific language governing permissions and
15 : : * limitations under the License.
16 : : */
17 : :
18 : : /**
19 : : * @file
20 : : * This header defines the ScatterMessage class.
21 : : */
22 : :
23 : : #ifndef __SSRC_SPREAD_SCATTER_MESSAGE_H
24 : : #define __SSRC_SPREAD_SCATTER_MESSAGE_H
25 : :
26 : : #include <ssrc/spread/Message.h>
27 : :
28 : : #include <utility>
29 : : #include <vector>
30 : :
31 : : __BEGIN_NS_SSRC_SPREAD
32 : :
33 : : /**
34 : : * ScatterMessage is a reusable container of multiple in-place data
35 : : * buffers. It can be populated with Message instances or straight
36 : : * data pointers. However, the auto-resizing feature of
37 : : * Mailbox::receive will be exercised only if the ScatterMessage
38 : : * contains at least one Message instance. You will want to use a
39 : : * ScatterMessage primarily when you want to avoid multiple buffer
40 : : * copies. For example, if you know the format of an incoming message
41 : : * you can add data pointers for each message part instead of parsing
42 : : * the message and copying the data. Also, instead of allocating a
43 : : * message buffer and copying multiple data items to it for a send,
44 : : * you can populate a ScatterMessage with pointers to the data items
45 : : * and avoid an extra copy.
46 : : *
47 : : * We do not document ScatterMessage protected members because they
48 : : * are intended only for internal library use.
49 : : */
50 [ + - ][ - + ]: 20 : class ScatterMessage : public BaseMessage {
51 : : public:
52 : :
53 : : enum {
54 : : /**
55 : : * The maximum number of elements that can be added to a scatter
56 : : * message.
57 : : */
58 : : MaxScatterElements = MAX_CLIENT_SCATTER_ELEMENTS
59 : : };
60 : :
61 : : private:
62 : : friend class Mailbox;
63 : :
64 : : typedef std::pair<Message *, int> value_type;
65 : :
66 : : Spread::scatter _scatter;
67 : : std::vector<value_type> _messages;
68 : : unsigned int _size;
69 : :
70 : 9 : const Spread::scatter *scatter() const {
71 : 9 : return &_scatter;
72 : : }
73 : :
74 : 9 : Spread::scatter *scatter() {
75 : 9 : return &_scatter;
76 : : }
77 : :
78 : : void init_pre_receive();
79 : :
80 : : void init_post_receive(int bytes_received);
81 : :
82 : 1 : Message * message(const unsigned int index) {
83 : 1 : return _messages[index].first;
84 : : }
85 : :
86 : 1 : void resize_message(const unsigned int message_index,
87 : : const unsigned int size)
88 : : {
89 : 1 : value_type & v = _messages[message_index];
90 : 1 : Message *m = v.first;
91 : :
92 : 1 : _size-=m->size();
93 : 1 : m->resize(size);
94 : 1 : _size+=m->size();
95 : 1 : _scatter.elements[v.second].buf = &((*m)[0]);
96 : 1 : _scatter.elements[v.second].len = m->size();
97 : 1 : }
98 : :
99 : : protected:
100 : :
101 : : #ifdef LIBSSRCSPREAD_ENABLE_MEMBERSHIP_INFO
102 : :
103 : 0 : virtual int sp_get_membership_info(Spread::membership_info *info) const {
104 : 0 : return Spread::SP_scat_get_memb_info(&_scatter, service(), info);
105 : : }
106 : :
107 : 0 : virtual int sp_get_vs_set_members(const Spread::vs_set_info *vs_set,
108 : : Spread::group_type member_names[],
109 : : unsigned int member_names_count)
110 : : const
111 : : {
112 : : return
113 : : Spread::SP_scat_get_vs_set_members(&_scatter, vs_set, member_names,
114 : 0 : member_names_count);
115 : : }
116 : :
117 : 0 : virtual int sp_get_vs_sets_info(Spread::vs_set_info *vs_sets,
118 : : unsigned int num_vs_sets,
119 : : unsigned int *index)
120 : : const
121 : : {
122 : : return
123 : 0 : Spread::SP_scat_get_vs_sets_info(&_scatter, vs_sets, num_vs_sets, index);
124 : : }
125 : :
126 : : #endif
127 : :
128 : : public:
129 : :
130 : : /**
131 : : * Creates a ScatterMessage with a size of zero and no message parts.
132 : : * See BaseMessage() for the default values of various properties,
133 : : * including service type.
134 : : */
135 : : // The initial vector capacity of 8 is an arbitrary choice. We don't expect
136 : : // a typical ScatterMessage to have too many parts.
137 [ + - ][ + - ]: 20 : ScatterMessage() : _messages(8), _size(0) {
138 : 20 : _scatter.num_elements = 0;
139 : 20 : }
140 : :
141 : : /**
142 : : * Returns the total size of the message (comprising all of its
143 : : * parts) in bytes.
144 : : * @returns The total size of the message in bytes.
145 : : */
146 : 1 : virtual unsigned int size() const {
147 : 1 : return _size;
148 : : }
149 : :
150 : : /**
151 : : * Clears the message for reuse, resetting both its size and number
152 : : * of message parts to zero.
153 : : */
154 : 15 : virtual void clear() {
155 : 15 : _scatter.num_elements = 0;
156 : 15 : _size = 0;
157 : 15 : _messages.clear();
158 : 15 : }
159 : :
160 : : /**
161 : : * Returns the number of parts that have been added to the message.
162 : : * @return The number of parts that have been added to the message.
163 : : */
164 : : unsigned int count_message_parts() const {
165 : : return _scatter.num_elements;
166 : : }
167 : :
168 : : /**
169 : : * Returns the number of Message instances that have been added to
170 : : * the message. This number will be different from that returned by
171 : : * count_message_parts() if any straight pointers have ben added.
172 : : *
173 : : * @return The number of Message instances that have been added to the
174 : : * message.
175 : : */
176 : 2 : unsigned int count_message_objects() const {
177 : 2 : return _messages.size();
178 : : }
179 : :
180 : : bool add(const void *data, const unsigned int size);
181 : :
182 : : /**
183 : : * Adds a Message as a message part. ScatterMessage will store a
184 : : * pointer to the original Message; therefore you should not alter
185 : : * the Message between the time it is added and when the send or
186 : : * receive is performed. Note that for receives, each Message added
187 : : * will be filled up to its capacity, not its size. The size will
188 : : * be ajdusted to reflect the amount of data written to the Message.
189 : : * The capacity will not be increased to accommodate more data
190 : : * except for the last Message added to the ScatterMessage. If you
191 : : * don't want this behavior, use add(const void *, const unsigned int)
192 : : * instead, with <code>&message[0]</code> as the data argument.
193 : : * When using fixed-length message parts, it is often useful to tack
194 : : * on a Message as the last message part to store any unexpected
195 : : * overflow.
196 : : *
197 : : * @param message The Message to add.
198 : : * @return true if the message part was added, false if no more parts
199 : : * can be added.
200 : : */
201 : 18 : bool add(const Message & message) {
202 [ + - ]: 18 : if(add(&message[0], message.size())) {
203 : : // We cheat and cast away constness!
204 : : _messages.push_back(value_type(const_cast<Message*>(&message),
205 : 18 : _scatter.num_elements - 1));
206 : 18 : return true;
207 : : } else
208 : 18 : return false;
209 : : }
210 : : };
211 : :
212 : :
213 : : __END_NS_SSRC_SPREAD
214 : :
215 : : #endif
|