Branch data Line data Source code
1 : : // $Id: StateAccess.cc 6888 2009-08-20 18:23:11Z vern $
2 : :
3 : : #include "Val.h"
4 : : #include "StateAccess.h"
5 : : #include "Serializer.h"
6 : : #include "Event.h"
7 : : #include "NetVar.h"
8 : : #include "DebugLogger.h"
9 : : #include "RemoteSerializer.h"
10 : : #include "PersistenceSerializer.h"
11 : :
12 : : int StateAccess::replaying = 0;
13 : :
14 : : StateAccess::StateAccess(Opcode arg_opcode,
15 : : const MutableVal* arg_target, const Val* arg_op1,
16 : 0 : const Val* arg_op2, const Val* arg_op3)
17 : : {
18 : 0 : opcode = arg_opcode;
19 : 0 : target.val = const_cast<MutableVal*>(arg_target);
20 : 0 : target_type = TYPE_MVAL;
21 : 0 : op1.val = const_cast<Val*>(arg_op1);
22 : 0 : op1_type = TYPE_VAL;
23 : 0 : op2 = const_cast<Val*>(arg_op2);
24 : 0 : op3 = const_cast<Val*>(arg_op3);
25 : 0 : delete_op1_key = false;
26 : :
27 : 0 : RefThem();
28 : 0 : }
29 : :
30 : : StateAccess::StateAccess(Opcode arg_opcode,
31 : : const ID* arg_target, const Val* arg_op1,
32 : 16 : const Val* arg_op2, const Val* arg_op3)
33 : : {
34 : 16 : opcode = arg_opcode;
35 : 16 : target.id = const_cast<ID*>(arg_target);
36 : 16 : target_type = TYPE_ID;
37 : 16 : op1.val = const_cast<Val*>(arg_op1);
38 : 16 : op1_type = TYPE_VAL;
39 : 16 : op2 = const_cast<Val*>(arg_op2);
40 : 16 : op3 = const_cast<Val*>(arg_op3);
41 : 16 : delete_op1_key = false;
42 : :
43 : 16 : RefThem();
44 : 16 : }
45 : :
46 : : StateAccess::StateAccess(Opcode arg_opcode,
47 : : const ID* arg_target, const HashKey* arg_op1,
48 : 0 : const Val* arg_op2, const Val* arg_op3)
49 : : {
50 : 0 : opcode = arg_opcode;
51 : 0 : target.id = const_cast<ID*>(arg_target);
52 : 0 : target_type = TYPE_ID;
53 : 0 : op1.key = new HashKey(arg_op1->Key(), arg_op1->Size(), arg_op1->Hash());
54 : 0 : op1_type = TYPE_KEY;
55 : 0 : op2 = const_cast<Val*>(arg_op2);
56 : 0 : op3 = const_cast<Val*>(arg_op3);
57 : 0 : delete_op1_key = true;
58 : :
59 : 0 : RefThem();
60 : 0 : }
61 : :
62 : : StateAccess::StateAccess(Opcode arg_opcode,
63 : : const MutableVal* arg_target, const HashKey* arg_op1,
64 : 0 : const Val* arg_op2, const Val* arg_op3)
65 : : {
66 : 0 : opcode = arg_opcode;
67 : 0 : target.val = const_cast<MutableVal*>(arg_target);
68 : 0 : target_type = TYPE_MVAL;
69 : 0 : op1.key = new HashKey(arg_op1->Key(), arg_op1->Size(), arg_op1->Hash());
70 : 0 : op1_type = TYPE_KEY;
71 : 0 : op2 = const_cast<Val*>(arg_op2);
72 : 0 : op3 = const_cast<Val*>(arg_op3);
73 : 0 : delete_op1_key = true;
74 : :
75 : 0 : RefThem();
76 : 0 : }
77 : :
78 : 0 : StateAccess::StateAccess(const StateAccess& sa)
79 : 0 : : SerialObj()
80 : : {
81 : 0 : opcode = sa.opcode;
82 : 0 : target_type = sa.target_type;
83 : 0 : op1_type = sa.op1_type;
84 : 0 : delete_op1_key = false;
85 : :
86 [ # # # # ]: 0 : if ( target_type == TYPE_ID )
87 : 0 : target.id = sa.target.id;
88 : : else
89 : 0 : target.val = sa.target.val;
90 : :
91 [ # # ][ # # ]: 0 : if ( op1_type == TYPE_VAL )
92 : 0 : op1.val = sa.op1.val;
93 : : else
94 : : {
95 : : // We need to copy the key as the pointer may not be
96 : : // valid anymore later.
97 : : op1.key = new HashKey(sa.op1.key->Key(), sa.op1.key->Size(),
98 : 0 : sa.op1.key->Hash());
99 : 0 : delete_op1_key = true;
100 : : }
101 : :
102 : 0 : op2 = sa.op2;
103 : 0 : op3 = sa.op3;
104 : :
105 : 0 : RefThem();
106 : 0 : }
107 : :
108 : 16 : StateAccess::~StateAccess()
109 : : {
110 [ + - ][ # # ]: 16 : if ( target_type == TYPE_ID )
[ # # ]
111 : 16 : Unref(target.id);
112 : : else
113 : 0 : Unref(target.val);
114 : :
115 [ + - ][ # # ]: 16 : if ( op1_type == TYPE_VAL )
[ # # ]
116 : 16 : Unref(op1.val);
117 [ # # ][ # # ]: 0 : else if ( delete_op1_key )
[ # # ]
118 [ # # ][ # # ]: 0 : delete op1.key;
[ # # ]
119 : :
120 : 16 : Unref(op2);
121 : 16 : Unref(op3);
122 [ + - ][ # # ]: 16 : }
[ # # ]
123 : :
124 : 16 : void StateAccess::RefThem()
125 : : {
126 [ + - ]: 16 : if ( target_type == TYPE_ID )
127 : 16 : Ref(target.id);
128 : : else
129 : 0 : Ref(target.val);
130 : :
131 [ + - ][ + - ]: 16 : if ( op1_type == TYPE_VAL && op1.val )
132 : 16 : Ref(op1.val);
133 : :
134 [ - + ]: 16 : if ( op2 )
135 : 0 : Ref(op2);
136 [ - + ]: 16 : if ( op3 )
137 : 0 : Ref(op3);
138 : 16 : }
139 : :
140 : : bool StateAccess::CheckOld(const char* op, ID* id, Val* index,
141 : 0 : Val* should, Val* is)
142 : : {
143 [ # # ]: 0 : if ( ! remote_check_sync_consistency )
144 : 0 : return true;
145 : :
146 [ # # ][ # # ]: 0 : if ( ! should && ! is )
147 : 0 : return true;
148 : :
149 : : // 'should == index' means that 'is' should be non-nil.
150 [ # # ][ # # ]: 0 : if ( should == index && is )
151 : 0 : return true;
152 : :
153 [ # # ][ # # ]: 0 : if ( should && is )
154 : : {
155 : : // There's no general comparision for non-atomic vals currently.
156 [ # # ][ # # ]: 0 : if ( ! (is_atomic_val(is) && is_atomic_val(should)) )
[ # # ]
157 : 0 : return true;
158 : :
159 [ # # ]: 0 : if ( same_atomic_val(should, is) )
160 : 0 : return true;
161 : : }
162 : :
163 : : Val* arg1;
164 : : Val* arg2;
165 : : Val* arg3;
166 : :
167 [ # # ]: 0 : if ( index )
168 : : {
169 : 0 : ODesc d;
170 : 0 : d.SetShort();
171 : 0 : index->Describe(&d);
172 : 0 : arg1 = new StringVal(fmt("%s[%s]", id->Name(), d.Description()));
173 : : }
174 : : else
175 : 0 : arg1 = new StringVal(id->Name());
176 : :
177 [ # # ]: 0 : if ( should )
178 : : {
179 : 0 : ODesc d;
180 : 0 : d.SetShort();
181 : 0 : should->Describe(&d);
182 : 0 : arg2 = new StringVal(d.Description());
183 : : }
184 : : else
185 : 0 : arg2 = new StringVal("<none>");
186 : :
187 [ # # ]: 0 : if ( is )
188 : : {
189 : 0 : ODesc d;
190 : 0 : d.SetShort();
191 : 0 : is->Describe(&d);
192 : 0 : arg3 = new StringVal(d.Description());
193 : : }
194 : : else
195 : 0 : arg3 = new StringVal("<none>");
196 : :
197 : 0 : val_list* args = new val_list;
198 : 0 : args->append(new StringVal(op));
199 : 0 : args->append(arg1);
200 : 0 : args->append(arg2);
201 : 0 : args->append(arg3);
202 : 0 : mgr.QueueEvent(remote_state_inconsistency, args);
203 : :
204 : 0 : return false;
205 : : }
206 : :
207 : : bool StateAccess::CheckOldSet(const char* op, ID* id, Val* index,
208 : 0 : bool should, bool is)
209 : : {
210 [ # # ]: 0 : if ( ! remote_check_sync_consistency )
211 : 0 : return true;
212 : :
213 [ # # ]: 0 : if ( should == is )
214 : 0 : return true;
215 : :
216 : 0 : ODesc d;
217 : 0 : d.SetShort();
218 : 0 : index->Describe(&d);
219 : :
220 : 0 : Val* arg1 = new StringVal(fmt("%s[%s]", id->Name(), d.Description()));
221 [ # # ]: 0 : Val* arg2 = new StringVal(should ? "set" : "not set");
222 [ # # ]: 0 : Val* arg3 = new StringVal(is ? "set" : "not set");
223 : :
224 : 0 : val_list* args = new val_list;
225 : 0 : args->append(new StringVal(op));
226 : 0 : args->append(arg1);
227 : 0 : args->append(arg2);
228 : 0 : args->append(arg3);
229 : 0 : mgr.QueueEvent(remote_state_inconsistency, args);
230 : :
231 : 0 : return false;
232 : : }
233 : :
234 : 0 : bool StateAccess::MergeTables(TableVal* dst, Val* src)
235 : : {
236 [ # # ]: 0 : if ( ! src->Type()->Tag() == TYPE_TABLE )
237 : : {
238 : 0 : run_time("type mismatch while merging tables");
239 : 0 : return false;
240 : : }
241 : :
242 [ # # ]: 0 : if ( ! src->AsTableVal()->FindAttr(ATTR_MERGEABLE) )
243 : 0 : return false;
244 : :
245 : 0 : DBG_LOG(DBG_STATE, "merging tables %s += %s", dst->UniqueID()->Name(),
246 : : src->AsTableVal()->UniqueID()->Name());
247 : :
248 : 0 : src->AsTableVal()->AddTo(dst, 0);
249 : :
250 : : // We need to make sure that the resulting table is accessible by
251 : : // the new name (while keeping the old as an alias).
252 : 0 : dst->TransferUniqueID(src->AsMutableVal());
253 : :
254 : 0 : return true;
255 : : }
256 : :
257 : 0 : void StateAccess::Replay()
258 : : {
259 : : // For simplicity we assume that we only replay unserialized accesses.
260 [ # # ][ # # ]: 0 : assert(target_type == TYPE_ID && op1_type == TYPE_VAL);
[ # # ]
261 : :
262 [ # # ]: 0 : if ( ! target.id )
263 : 0 : return;
264 : :
265 : 0 : Val* v = target.id->ID_Val();
266 [ # # ]: 0 : TypeTag t = v ? v->Type()->Tag() : TYPE_VOID;
267 : :
268 [ # # ][ # # ]: 0 : if ( opcode != OP_ASSIGN && ! v )
269 : : {
270 : : // FIXME: I think this warrants an internal error,
271 : : // but let's check that first ...
272 : : // internal_error("replay id lacking a value");
273 : 0 : run_time("replay id lacks a value");
274 : 0 : return;
275 : : }
276 : :
277 : 0 : ++replaying;
278 : :
279 [ # # # # # : 0 : switch ( opcode ) {
# # # # # ]
280 : : case OP_ASSIGN:
281 [ # # ]: 0 : assert(op1.val);
282 : : // There mustn't be a direct assignment to a unique ID.
283 [ # # ]: 0 : assert(target.id->Name()[0] != '#');
284 : 0 : CheckOld("assign", target.id, 0, op2, v);
285 : :
286 [ # # # # ]: 0 : if ( t == TYPE_TABLE && v &&
[ # # ][ # # ]
287 : : v->AsTableVal()->FindAttr(ATTR_MERGEABLE) )
288 [ # # ]: 0 : if ( MergeTables(v->AsTableVal(), op1.val) )
289 : 0 : break;
290 : :
291 : 0 : target.id->SetVal(op1.val->Ref());
292 : 0 : break;
293 : :
294 : : case OP_INCR:
295 [ # # ][ # # ]: 0 : if ( IsIntegral(t) )
[ # # ]
296 : : {
297 [ # # ][ # # ]: 0 : assert(op1.val && op2);
[ # # ]
298 : : // We derive the amount as difference between old
299 : : // and new value.
300 : : bro_int_t amount =
301 : 0 : op1.val->CoerceToInt() - op2->CoerceToInt();
302 : :
303 : : target.id->SetVal(new Val(v->CoerceToInt() + amount, t),
304 : 0 : OP_INCR);
305 : : }
306 : 0 : break;
307 : :
308 : : case OP_ASSIGN_IDX:
309 [ # # ]: 0 : assert(op1.val);
310 : :
311 [ # # ]: 0 : if ( t == TYPE_TABLE )
312 : : {
313 [ # # ]: 0 : assert(op2);
314 : :
315 : 0 : BroType* yt = v->Type()->AsTableType()->YieldType();
316 : :
317 [ # # # # ]: 0 : if ( yt && yt->Tag() == TYPE_TABLE )
[ # # ]
318 : : {
319 : 0 : TableVal* tv = v->AsTableVal();
320 : 0 : Val* w = tv->Lookup(op1.val);
321 [ # # # # ]: 0 : if ( w && w->AsTableVal()->FindAttr(ATTR_MERGEABLE) )
[ # # ]
322 [ # # ]: 0 : if ( MergeTables(w->AsTableVal(), op2) )
323 : 0 : break;
324 : : }
325 : :
326 : : CheckOld("index assign", target.id, op1.val, op3,
327 : 0 : v->AsTableVal()->Lookup(op1.val));
328 : :
329 [ # # ]: 0 : v->AsTableVal()->Assign(op1.val, op2 ? op2->Ref() : 0);
330 : : }
331 : :
332 [ # # ]: 0 : else if ( t == TYPE_RECORD )
333 : : {
334 : 0 : const char* field = op1.val->AsString()->CheckString();
335 : 0 : int idx = v->Type()->AsRecordType()->FieldOffset(field);
336 : :
337 [ # # ]: 0 : if ( idx >= 0 )
338 : : {
339 : 0 : BroType* ft = v->Type()->AsRecordType()->FieldType(field);
340 : :
341 [ # # # # ]: 0 : if ( ft && ft->Tag() == TYPE_TABLE )
[ # # ]
342 : : {
343 : 0 : RecordVal* rv = v->AsRecordVal();
344 : 0 : Val* w = rv->Lookup(idx);
345 [ # # # # ]: 0 : if ( w && w->AsTableVal()->FindAttr(ATTR_MERGEABLE) )
[ # # ]
346 [ # # ]: 0 : if ( MergeTables(w->AsTableVal(), op2) )
347 : 0 : break;
348 : : }
349 : :
350 : : CheckOld("index assign", target.id, op1.val, op3,
351 : 0 : v->AsRecordVal()->Lookup(idx));
352 [ # # ]: 0 : v->AsRecordVal()->Assign(idx, op2 ? op2->Ref() : 0);
353 : : }
354 : : else
355 : 0 : run_time(fmt("access replay: unknown record field %s for assign", field));
356 : : }
357 : :
358 [ # # ]: 0 : else if ( t == TYPE_VECTOR )
359 : : {
360 [ # # ]: 0 : assert(op2);
361 : 0 : bro_uint_t index = op1.val->AsCount();
362 : :
363 : 0 : BroType* yt = v->Type()->AsVectorType()->YieldType();
364 : :
365 [ # # # # ]: 0 : if ( yt && yt->Tag() == TYPE_TABLE )
[ # # ]
366 : : {
367 : 0 : VectorVal* vv = v->AsVectorVal();
368 : 0 : Val* w = vv->Lookup(index);
369 [ # # # # ]: 0 : if ( w && w->AsTableVal()->FindAttr(ATTR_MERGEABLE) )
[ # # ]
370 [ # # ]: 0 : if ( MergeTables(w->AsTableVal(), op2) )
371 : 0 : break;
372 : : }
373 : :
374 : : CheckOld("index assign", target.id, op1.val, op3,
375 : 0 : v->AsVectorVal()->Lookup(index));
376 [ # # ]: 0 : v->AsVectorVal()->Assign(index, op2 ? op2->Ref() : 0, 0);
377 : : }
378 : :
379 : : else
380 : 0 : internal_error("unknown type in replaying index assign");
381 : :
382 : 0 : break;
383 : :
384 : : case OP_INCR_IDX:
385 : : {
386 [ # # ][ # # ]: 0 : assert(op1.val && op2 && op3);
[ # # ][ # # ]
387 : :
388 : : // We derive the amount as the difference between old
389 : : // and new value.
390 : 0 : bro_int_t amount = op2->CoerceToInt() - op3->CoerceToInt();
391 : :
392 [ # # ]: 0 : if ( t == TYPE_TABLE )
393 : : {
394 : 0 : t = v->Type()->AsTableType()->YieldType()->Tag();
395 : 0 : Val* lookup_op1 = v->AsTableVal()->Lookup(op1.val);
396 : 0 : int delta = lookup_op1->CoerceToInt() + amount;
397 : 0 : Val* new_val = new Val(delta, t);
398 : 0 : v->AsTableVal()->Assign(op1.val, new_val, OP_INCR );
399 : : }
400 : :
401 [ # # ]: 0 : else if ( t == TYPE_RECORD )
402 : : {
403 : 0 : const char* field = op1.val->AsString()->CheckString();
404 : 0 : int idx = v->Type()->AsRecordType()->FieldOffset(field);
405 [ # # ]: 0 : if ( idx >= 0 )
406 : : {
407 : 0 : t = v->Type()->AsRecordType()->FieldType(idx)->Tag();
408 : : Val* lookup_field =
409 : 0 : v->AsRecordVal()->Lookup(idx);
410 : : bro_int_t delta =
411 : 0 : lookup_field->CoerceToInt() + amount;
412 : 0 : Val* new_val = new Val(delta, t);
413 : 0 : v->AsRecordVal()->Assign(idx, new_val, OP_INCR);
414 : : }
415 : : else
416 : 0 : run_time(fmt("access replay: unknown record field %s for assign", field));
417 : : }
418 : :
419 [ # # ]: 0 : else if ( t == TYPE_VECTOR )
420 : : {
421 : 0 : bro_uint_t index = op1.val->AsCount();
422 : 0 : t = v->Type()->AsVectorType()->YieldType()->Tag();
423 : 0 : Val* lookup_op1 = v->AsVectorVal()->Lookup(index);
424 : 0 : int delta = lookup_op1->CoerceToInt() + amount;
425 : 0 : Val* new_val = new Val(delta, t);
426 : 0 : v->AsVectorVal()->Assign(index, new_val, 0);
427 : : }
428 : :
429 : : else
430 : 0 : internal_error("unknown type in replaying index increment");
431 : :
432 : 0 : break;
433 : : }
434 : :
435 : : case OP_ADD:
436 [ # # ]: 0 : assert(op1.val);
437 [ # # ]: 0 : if ( t == TYPE_TABLE )
438 : : {
439 : : CheckOldSet("add", target.id, op1.val, op2 != 0,
440 : 0 : v->AsTableVal()->Lookup(op1.val) != 0);
441 : 0 : v->AsTableVal()->Assign(op1.val, 0);
442 : : }
443 : 0 : break;
444 : :
445 : : case OP_DEL:
446 [ # # ]: 0 : assert(op1.val);
447 [ # # ]: 0 : if ( t == TYPE_TABLE )
448 : : {
449 [ # # ]: 0 : if ( v->Type()->AsTableType()->IsSet() )
450 : : CheckOldSet("delete", target.id, op1.val, op2 != 0,
451 : 0 : v->AsTableVal()->Lookup(op1.val) != 0);
452 : : else
453 : : CheckOld("delete", target.id, op1.val, op2,
454 : 0 : v->AsTableVal()->Lookup(op1.val));
455 : :
456 : 0 : Unref(v->AsTableVal()->Delete(op1.val));
457 : : }
458 : 0 : break;
459 : :
460 : : case OP_EXPIRE:
461 [ # # ]: 0 : assert(op1.val);
462 [ # # ]: 0 : if ( t == TYPE_TABLE )
463 : : {
464 : : // No old check for expire. It may have already
465 : : // been deleted by ourselves. Furthermore, we
466 : : // ignore the expire_func's return value.
467 : 0 : TableVal* tv = v->AsTableVal();
468 [ # # ]: 0 : if ( tv->Lookup(op1.val, false) )
469 : : {
470 : : // We want to propagate state updates which
471 : : // are performed in the expire_func.
472 : 0 : StateAccess::ResumeReplay();
473 : :
474 [ # # ]: 0 : if ( remote_serializer )
475 : 0 : remote_serializer->ResumeStateUpdates();
476 : :
477 : 0 : tv->CallExpireFunc(op1.val->Ref());
478 : :
479 [ # # ]: 0 : if ( remote_serializer )
480 : 0 : remote_serializer->SuspendStateUpdates();
481 : :
482 : 0 : StateAccess::SuspendReplay();
483 : :
484 : 0 : Unref(tv->AsTableVal()->Delete(op1.val));
485 : : }
486 : : }
487 : :
488 : 0 : break;
489 : :
490 : : case OP_PRINT:
491 [ # # ]: 0 : assert(op1.val);
492 : 0 : internal_error("access replay for print not implemented");
493 : : break;
494 : :
495 : : case OP_READ_IDX:
496 [ # # ]: 0 : if ( t == TYPE_TABLE )
497 : : {
498 [ # # ]: 0 : assert(op1.val);
499 : 0 : TableVal* tv = v->AsTableVal();
500 : :
501 : : // Update the timestamp if we have a read_expire.
502 [ # # ]: 0 : if ( tv->FindAttr(ATTR_EXPIRE_READ) )
503 : : {
504 [ # # ][ # # ]: 0 : if ( ! tv->UpdateTimestamp(op1.val) &&
[ # # ]
505 : : remote_check_sync_consistency )
506 : : {
507 : 0 : ODesc d;
508 : 0 : d.SetShort();
509 : 0 : op1.val->Describe(&d);
510 : :
511 : 0 : val_list* args = new val_list;
512 : 0 : args->append(new StringVal("read"));
513 : 0 : args->append(new StringVal(fmt("%s[%s]", target.id->Name(), d.Description())));
514 : 0 : args->append(new StringVal("existent"));
515 : 0 : args->append(new StringVal("not existent"));
516 : 0 : mgr.QueueEvent(remote_state_inconsistency, args);
517 : : }
518 : : }
519 : : }
520 : : else
521 : 0 : run_time("read for non-table");
522 : 0 : break;
523 : :
524 : : default:
525 : 0 : internal_error("access replay: unknown opcode for StateAccess");
526 : : break;
527 : : }
528 : :
529 : 0 : --replaying;
530 : :
531 [ # # ]: 0 : if ( remote_state_access_performed )
532 : : {
533 : 0 : val_list* vl = new val_list;
534 : 0 : vl->append(new StringVal(target.id->Name()));
535 : 0 : vl->append(target.id->ID_Val()->Ref());
536 : 0 : mgr.QueueEvent(remote_state_access_performed, vl);
537 : : }
538 : : }
539 : :
540 : 0 : ID* StateAccess::Target() const
541 : : {
542 [ # # ]: 0 : return target_type == TYPE_ID ? target.id : target.val->UniqueID();
543 : : }
544 : :
545 : 0 : bool StateAccess::Serialize(SerialInfo* info) const
546 : : {
547 : 0 : return SerialObj::Serialize(info);
548 : : }
549 : :
550 : 0 : StateAccess* StateAccess::Unserialize(UnserialInfo* info)
551 : : {
552 : : StateAccess* sa =
553 : 0 : (StateAccess*) SerialObj::Unserialize(info, SER_STATE_ACCESS);
554 : 0 : return sa;
555 : : }
556 : :
557 : 3 : IMPLEMENT_SERIAL(StateAccess, SER_STATE_ACCESS);
558 : :
559 : 0 : bool StateAccess::DoSerialize(SerialInfo* info) const
560 : : {
561 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_STATE_ACCESS, SerialObj);
562 : :
563 [ # # ]: 0 : if ( ! SERIALIZE(char(opcode)) )
564 : 0 : return false;
565 : :
566 : : const ID* id =
567 [ # # ]: 0 : target_type == TYPE_ID ? target.id : target.val->UniqueID();
568 : :
569 [ # # ]: 0 : if ( ! SERIALIZE(id->Name()) )
570 : 0 : return false;
571 : :
572 [ # # ]: 0 : if ( op1_type == TYPE_KEY )
573 : : {
574 : : Val* index =
575 : 0 : id->ID_Val()->AsTableVal()->RecoverIndex(this->op1.key);
576 : :
577 [ # # ]: 0 : if ( ! index )
578 : 0 : return false;
579 [ # # ]: 0 : if ( ! index->Serialize(info) )
580 : 0 : return false;
581 : :
582 : 0 : Unref(index);
583 : : }
584 : :
585 [ # # ]: 0 : else if ( ! op1.val->Serialize(info) )
586 : 0 : return false;
587 : :
588 : : // Don't send the "old" operand if we don't want consistency checks.
589 : : // Unfortunately, it depends on the opcode which operand that actually
590 : : // is.
591 : :
592 : 0 : const Val* null = 0;
593 : :
594 [ # # ]: 0 : if ( remote_check_sync_consistency )
595 : : {
596 [ # # ][ # # ]: 0 : SERIALIZE_OPTIONAL(op2);
[ # # ][ # # ]
[ # # ][ # # ]
597 [ # # ][ # # ]: 0 : SERIALIZE_OPTIONAL(op3);
[ # # ][ # # ]
[ # # ][ # # ]
598 : : }
599 : :
600 : : else
601 : : {
602 [ # # # # : 0 : switch ( opcode ) {
# ]
603 : : case OP_PRINT:
604 : : case OP_EXPIRE:
605 : : case OP_READ_IDX:
606 : : // No old.
607 [ # # ][ # # ]: 0 : SERIALIZE_OPTIONAL(null);
[ # # ][ # # ]
[ # # ][ # # ]
608 [ # # ][ # # ]: 0 : SERIALIZE_OPTIONAL(null);
[ # # ][ # # ]
[ # # ][ # # ]
609 : 0 : break;
610 : :
611 : : case OP_INCR:
612 : : case OP_INCR_IDX:
613 : : // Always need old.
614 [ # # ][ # # ]: 0 : SERIALIZE_OPTIONAL(op2);
[ # # ][ # # ]
[ # # ][ # # ]
615 [ # # ][ # # ]: 0 : SERIALIZE_OPTIONAL(op3);
[ # # ][ # # ]
[ # # ][ # # ]
616 : 0 : break;
617 : :
618 : : case OP_ASSIGN:
619 : : case OP_ADD:
620 : : case OP_DEL:
621 : : // Op2 is old.
622 [ # # ][ # # ]: 0 : SERIALIZE_OPTIONAL(null);
[ # # ][ # # ]
[ # # ][ # # ]
623 [ # # ][ # # ]: 0 : SERIALIZE_OPTIONAL(null);
[ # # ][ # # ]
[ # # ][ # # ]
624 : 0 : break;
625 : :
626 : : case OP_ASSIGN_IDX:
627 : : // Op3 is old.
628 [ # # ][ # # ]: 0 : SERIALIZE_OPTIONAL(op2);
[ # # ][ # # ]
[ # # ][ # # ]
629 [ # # ][ # # ]: 0 : SERIALIZE_OPTIONAL(null);
[ # # ][ # # ]
[ # # ][ # # ]
630 : 0 : break;
631 : :
632 : : default:
633 : 0 : internal_error("StateAccess::DoSerialize: unknown opcode");
634 : : }
635 : : }
636 : :
637 : 0 : return true;
638 : : }
639 : :
640 : 0 : bool StateAccess::DoUnserialize(UnserialInfo* info)
641 : : {
642 [ # # ]: 0 : DO_UNSERIALIZE(SerialObj);
643 : :
644 : : char c;
645 [ # # ]: 0 : if ( ! UNSERIALIZE(&c) )
646 : 0 : return false;
647 : :
648 : 0 : opcode = Opcode(c);
649 : :
650 : : const char* name;
651 [ # # ]: 0 : if ( ! UNSERIALIZE_STR(&name, 0) )
652 : 0 : return false;
653 : :
654 : 0 : target_type = TYPE_ID;
655 : 0 : target.id = global_scope()->Lookup(name);
656 : :
657 [ # # ]: 0 : if ( target.id )
658 : : // Otherwise, we'll delete it below.
659 [ # # ]: 0 : delete [] name;
660 : :
661 : 0 : op1_type = TYPE_VAL;
662 : 0 : op1.val = Val::Unserialize(info);
663 [ # # ]: 0 : if ( ! op1.val )
664 : 0 : return false;
665 : :
666 [ # # ][ # # ]: 0 : UNSERIALIZE_OPTIONAL(op2, Val::Unserialize(info));
[ # # ]
667 [ # # ][ # # ]: 0 : UNSERIALIZE_OPTIONAL(op3, Val::Unserialize(info));
[ # # ]
668 : :
669 [ # # ]: 0 : if ( target.id )
670 : 0 : Ref(target.id);
671 : : else
672 : : {
673 : : // This may happen as long as we haven't agreed on the
674 : : // unique name for an ID during initial synchronization, or if
675 : : // the local peer has already deleted the ID.
676 : 0 : DBG_LOG(DBG_STATE, "state access referenced unknown id %s", name);
677 : :
678 [ # # ]: 0 : if ( info->install_uniques )
679 : : {
680 : 0 : target.id = new ID(name, SCOPE_GLOBAL, true);
681 : 0 : Ref(target.id);
682 : 0 : global_scope()->Insert(name, target.id);
683 : : #ifdef USE_PERFTOOLS
684 : : heap_checker->IgnoreObject(target.id);
685 : : #endif
686 : : }
687 : :
688 [ # # ]: 0 : delete [] name;
689 : : }
690 : :
691 : 0 : return true;
692 : : }
693 : :
694 : 16 : void StateAccess::Describe(ODesc* d) const
695 : : {
696 : : const ID* id;
697 : 16 : const char* id_str = "";
698 : 16 : const char* unique_str = "";
699 : :
700 : 16 : d->SetShort();
701 : :
702 [ + - ]: 16 : if ( target_type == TYPE_ID )
703 : : {
704 : 16 : id = target.id;
705 : :
706 [ - + ]: 16 : if ( ! id )
707 : : {
708 : 0 : d->Add("(unknown id)");
709 : 0 : return;
710 : : }
711 : :
712 : 16 : id_str = id->Name();
713 : :
714 [ - + # # ]: 16 : if ( id->ID_Val() && id->ID_Val()->IsMutableVal() &&
[ # # ][ - + ]
715 : : id->Name()[0] != '#' )
716 : 16 : unique_str = fmt(" [id] (%s)", id->ID_Val()->AsMutableVal()->UniqueID()->Name());
717 : : }
718 : : else
719 : : {
720 : 0 : id = target.val->UniqueID();
721 : :
722 : : #ifdef DEBUG
723 [ # # ]: 0 : if ( target.val->GetID() )
724 : : {
725 : 0 : id_str = target.val->GetID()->Name();
726 : 0 : unique_str = fmt(" [val] (%s)", id->Name());
727 : : }
728 : : else
729 : : #endif
730 : 0 : id_str = id->Name();
731 : : }
732 : :
733 : : const Val* op1 = op1_type == TYPE_VAL ?
734 : : this->op1.val :
735 [ + - ]: 16 : id->ID_Val()->AsTableVal()->RecoverIndex(this->op1.key);
736 : :
737 [ + - - - - : 16 : switch ( opcode ) {
- - - - - ]
738 : : case OP_ASSIGN:
739 [ - + ]: 16 : assert(op1);
740 : 16 : d->Add(id_str);
741 : 16 : d->Add(" = ");
742 : 16 : op1->Describe(d);
743 [ - + ]: 16 : if ( op2 )
744 : : {
745 : 0 : d->Add(" (");
746 : 0 : op2->Describe(d);
747 : 0 : d->Add(")");
748 : : }
749 : 16 : d->Add(unique_str);
750 : 16 : break;
751 : :
752 : : case OP_INCR:
753 [ # # ][ # # ]: 0 : assert(op1 && op2);
[ # # ]
754 : 0 : d->Add(id_str);
755 : 0 : d->Add(" += ");
756 : 0 : d->Add(op1->CoerceToInt() - op2->CoerceToInt());
757 : 0 : d->Add(unique_str);
758 : 0 : break;
759 : :
760 : : case OP_ASSIGN_IDX:
761 [ # # ]: 0 : assert(op1);
762 : 0 : d->Add(id_str);
763 : 0 : d->Add("[");
764 : 0 : op1->Describe(d);
765 : 0 : d->Add("]");
766 : 0 : d->Add(" = ");
767 [ # # ]: 0 : if ( op2 )
768 : 0 : op2->Describe(d);
769 : : else
770 : 0 : d->Add("(null)");
771 [ # # ]: 0 : if ( op3 )
772 : : {
773 : 0 : d->Add(" (");
774 : 0 : op3->Describe(d);
775 : 0 : d->Add(")");
776 : : }
777 : 0 : d->Add(unique_str);
778 : 0 : break;
779 : :
780 : : case OP_INCR_IDX:
781 [ # # ][ # # ]: 0 : assert(op1 && op2 && op3);
[ # # ][ # # ]
782 : 0 : d->Add(id_str);
783 : 0 : d->Add("[");
784 : 0 : op1->Describe(d);
785 : 0 : d->Add("]");
786 : 0 : d->Add(" += ");
787 : 0 : d->Add(op2->CoerceToInt() - op3->CoerceToInt());
788 : 0 : d->Add(unique_str);
789 : 0 : break;
790 : :
791 : : case OP_ADD:
792 [ # # ]: 0 : assert(op1);
793 : 0 : d->Add("add ");
794 : 0 : d->Add(id_str);
795 : 0 : d->Add("[");
796 : 0 : op1->Describe(d);
797 : 0 : d->Add("]");
798 [ # # ]: 0 : if ( op2 )
799 : : {
800 : 0 : d->Add(" (");
801 : 0 : op2->Describe(d);
802 : 0 : d->Add(")");
803 : : }
804 : 0 : d->Add(unique_str);
805 : 0 : break;
806 : :
807 : : case OP_DEL:
808 [ # # ]: 0 : assert(op1);
809 : 0 : d->Add("del ");
810 : 0 : d->Add(id_str);
811 : 0 : d->Add("[");
812 : 0 : op1->Describe(d);
813 : 0 : d->Add("]");
814 [ # # ]: 0 : if ( op2 )
815 : : {
816 : 0 : d->Add(" (");
817 : 0 : op2->Describe(d);
818 : 0 : d->Add(")");
819 : : }
820 : 0 : d->Add(unique_str);
821 : 0 : break;
822 : :
823 : : case OP_EXPIRE:
824 [ # # ]: 0 : assert(op1);
825 : 0 : d->Add("expire ");
826 : 0 : d->Add(id_str);
827 : 0 : d->Add("[");
828 : 0 : op1->Describe(d);
829 : 0 : d->Add("]");
830 [ # # ]: 0 : if ( op2 )
831 : : {
832 : 0 : d->Add(" (");
833 : 0 : op2->Describe(d);
834 : 0 : d->Add(")");
835 : : }
836 : 0 : d->Add(unique_str);
837 : 0 : break;
838 : :
839 : : case OP_PRINT:
840 [ # # ]: 0 : assert(op1);
841 : 0 : d->Add("print ");
842 : 0 : d->Add(id_str);
843 : 0 : op1->Describe(d);
844 : 0 : d->Add(unique_str);
845 : 0 : break;
846 : :
847 : : case OP_READ_IDX:
848 [ # # ]: 0 : assert(op1);
849 : 0 : d->Add("read ");
850 : 0 : d->Add(id_str);
851 : 0 : d->Add("[");
852 : 0 : op1->Describe(d);
853 : 0 : d->Add("]");
854 : 0 : break;
855 : :
856 : : default:
857 : 0 : internal_error("unknown opcode for StateAccess");
858 : : break;
859 : : }
860 : :
861 [ - + ]: 16 : if ( op1_type != TYPE_VAL )
862 : 16 : Unref(const_cast<Val*>(op1));
863 : : }
864 : :
865 : 16 : void StateAccess::Log(StateAccess* access)
866 : : {
867 : 16 : bool synchronized = false;
868 : 16 : bool persistent = false;
869 : 16 : bool tracked = false;
870 : :
871 [ + - ]: 16 : if ( access->target_type == TYPE_ID )
872 : : {
873 [ + + ]: 16 : if ( access->target.id->FindAttr(ATTR_SYNCHRONIZED) )
874 : 2 : synchronized = true;
875 : :
876 [ + + ]: 16 : if ( access->target.id->FindAttr(ATTR_PERSISTENT) )
877 : 14 : persistent = true;
878 : :
879 [ - + ]: 16 : if ( access->target.id->FindAttr(ATTR_TRACKED) )
880 : 16 : tracked = true;
881 : : }
882 : : else
883 : : {
884 [ # # ]: 0 : if ( access->target.val->GetProperties() & MutableVal::SYNCHRONIZED )
885 : 0 : synchronized = true;
886 : :
887 [ # # ]: 0 : if ( access->target.val->GetProperties() & MutableVal::PERSISTENT )
888 : 0 : persistent = true;
889 : :
890 [ # # ]: 0 : if ( access->target.val->GetProperties() & MutableVal::TRACKED )
891 : 0 : tracked = true;
892 : : }
893 : :
894 [ + + ]: 16 : if ( synchronized )
895 : : {
896 [ - + ]: 2 : if ( state_serializer )
897 : : {
898 : 0 : SerialInfo info(state_serializer);
899 : 0 : state_serializer->Serialize(&info, *access);
900 : : }
901 : :
902 : 2 : SerialInfo info(remote_serializer);
903 : 2 : remote_serializer->SendAccess(&info, *access);
904 : : }
905 : :
906 [ + + ][ - + ]: 16 : if ( persistent && persistence_serializer->IsSerializationRunning() )
[ - + ]
907 : 0 : persistence_serializer->LogAccess(*access);
908 : :
909 [ - + ]: 16 : if ( tracked )
910 : 0 : notifiers.AccessPerformed(*access);
911 : :
912 : : #ifdef DEBUG
913 : 16 : ODesc desc;
914 : 16 : access->Describe(&desc);
915 [ + + ][ + + ]: 16 : DBG_LOG(DBG_STATE, "operation: %s%s [%s%s]",
[ - + ]
916 : : desc.Description(), replaying > 0 ? " (replay)" : "",
917 : : persistent ? "P" : "", synchronized ? "S" : "");
918 : : #endif
919 : :
920 [ + - ]: 16 : delete access;
921 : :
922 : 16 : }
923 : :
924 : 6 : NotifierRegistry notifiers;
925 : :
926 : 0 : void NotifierRegistry::Register(ID* id, NotifierRegistry::Notifier* notifier)
927 : : {
928 : 0 : DBG_LOG(DBG_NOTIFIERS, "registering ID %s for notifier %s",
929 : : id->Name(), notifier->Name());
930 : :
931 [ # # ]: 0 : if ( id->Attrs() )
932 : 0 : id->Attrs()->AddAttr(new Attr(ATTR_TRACKED));
933 : : else
934 : : {
935 : 0 : attr_list* a = new attr_list;
936 : 0 : Attr* attr = new Attr(ATTR_TRACKED);
937 : 0 : a->append(attr);
938 : 0 : id->SetAttrs(new Attributes(a, id->Type()));
939 : 0 : Unref(attr);
940 : : }
941 : :
942 : 0 : NotifierMap::iterator i = ids.find(id->Name());
943 : :
944 [ # # ]: 0 : if ( i != ids.end() )
945 : 0 : i->second->insert(notifier);
946 : : else
947 : : {
948 : 0 : NotifierSet* s = new NotifierSet;
949 : 0 : s->insert(notifier);
950 : 0 : ids.insert(NotifierMap::value_type(id->Name(), s));
951 : : }
952 : :
953 : 0 : Ref(id);
954 : 0 : }
955 : :
956 : 0 : void NotifierRegistry::Register(Val* val, NotifierRegistry::Notifier* notifier)
957 : : {
958 [ # # ]: 0 : if ( val->IsMutableVal() )
959 : 0 : Register(val->AsMutableVal()->UniqueID(), notifier);
960 : 0 : }
961 : :
962 : 0 : void NotifierRegistry::Unregister(ID* id, NotifierRegistry::Notifier* notifier)
963 : : {
964 : 0 : DBG_LOG(DBG_NOTIFIERS, "unregistering ID %s for notifier %s",
965 : : id->Name(), notifier->Name());
966 : :
967 : 0 : NotifierMap::iterator i = ids.find(id->Name());
968 : :
969 [ # # ]: 0 : if ( i == ids.end() )
970 : 0 : return;
971 : :
972 : 0 : id->Attrs()->RemoveAttr(ATTR_TRACKED);
973 : :
974 : 0 : NotifierSet* s = i->second;
975 : 0 : s->erase(notifier);
976 : :
977 [ # # ]: 0 : if ( s->size() == 0 )
978 : : {
979 [ # # ]: 0 : delete s;
980 : 0 : ids.erase(i);
981 : : }
982 : :
983 : 0 : Unref(id);
984 : : }
985 : :
986 : 0 : void NotifierRegistry::Unregister(Val* val, NotifierRegistry::Notifier* notifier)
987 : : {
988 [ # # ]: 0 : if ( val->IsMutableVal() )
989 : 0 : Unregister(val->AsMutableVal()->UniqueID(), notifier);
990 : 0 : }
991 : :
992 : 0 : void NotifierRegistry::AccessPerformed(const StateAccess& sa)
993 : : {
994 : 0 : ID* id = sa.Target();
995 : :
996 : 0 : NotifierMap::iterator i = ids.find(id->Name());
997 : :
998 [ # # ]: 0 : if ( i == ids.end() )
999 : 0 : return;
1000 : :
1001 : 0 : DBG_LOG(DBG_NOTIFIERS, "modification to tracked ID %s", id->Name());
1002 : :
1003 : 0 : NotifierSet* s = i->second;
1004 : :
1005 [ # # ]: 0 : if ( id->IsInternalGlobal() )
1006 [ # # ]: 0 : for ( NotifierSet::iterator j = s->begin(); j != s->end(); j++ )
1007 : 0 : (*j)->Access(id->ID_Val(), sa);
1008 : : else
1009 [ # # ]: 0 : for ( NotifierSet::iterator j = s->begin(); j != s->end(); j++ )
1010 : 0 : (*j)->Access(id, sa);
1011 : : }
1012 : :
1013 : 0 : const char* NotifierRegistry::Notifier::Name() const
1014 : : {
1015 : 0 : return fmt("%p", this);
1016 [ + - ][ + - ]: 6 : }
1017 : 3 :
|