8 |
## |
## |
9 |
## ------------------------------------------------------------------------- |
## ------------------------------------------------------------------------- |
10 |
## $Log$ |
## $Log$ |
11 |
|
## Revision 1.13 2004/06/19 16:53:38 joko |
12 |
|
## fix: handle local checksum only if database is configured with "hasLocalChecksum" |
13 |
|
## |
14 |
|
## Revision 1.12 2004/06/19 01:45:08 joko |
15 |
|
## introduced "local checksum"-mechanism |
16 |
|
## moved _dumpCompact to ::Compare::Checksum |
17 |
|
## |
18 |
|
## Revision 1.11 2004/05/11 20:03:48 jonen |
19 |
|
## bugfix[joko] related to Attribute Map |
20 |
|
## |
21 |
|
## Revision 1.10 2003/06/25 23:03:57 joko |
22 |
|
## no debugging |
23 |
|
## |
24 |
## Revision 1.9 2003/05/13 08:17:52 joko |
## Revision 1.9 2003/05/13 08:17:52 joko |
25 |
## buildAttributeMap now propagates error |
## buildAttributeMap now propagates error |
26 |
## |
## |
114 |
#use misc::HashExt; |
#use misc::HashExt; |
115 |
use Hash::Serializer; |
use Hash::Serializer; |
116 |
use Data::Mungle::Compare::Struct qw( getDifference isEmpty ); |
use Data::Mungle::Compare::Struct qw( getDifference isEmpty ); |
117 |
|
use Data::Mungle::Transform::Deep qw( deep_copy expand ); |
118 |
use Data::Storage::Container; |
use Data::Storage::Container; |
119 |
use DesignPattern::Object; |
use DesignPattern::Object; |
120 |
use shortcuts::database qw( quotesql ); |
use shortcuts::database qw( quotesql ); |
202 |
return; |
return; |
203 |
} |
} |
204 |
|
|
205 |
|
#print Dumper(@$results); |
206 |
|
#exit; |
207 |
|
|
208 |
# check if we actually *have* a synchronization method |
# check if we actually *have* a synchronization method |
209 |
if (!$self->{options}->{metadata}->{syncMethod}) { |
if (!$self->{options}->{metadata}->{syncMethod}) { |
214 |
|
|
215 |
# dereference |
# dereference |
216 |
my @results = @{$results}; |
my @results = @{$results}; |
217 |
|
#print Dumper(@results); |
218 |
|
|
219 |
# iterate through set |
# iterate through set |
220 |
foreach my $source_node_real (@results) { |
foreach my $source_node_real (@results) { |
221 |
|
|
222 |
print ":" if $self->{verbose}; |
print ":" if $self->{verbose}; |
223 |
|
|
224 |
|
#print Dumper($source_node_real); |
225 |
|
|
226 |
$tc->{total}++; |
$tc->{total}++; |
227 |
|
|
228 |
#print "======================== iter", "\n"; |
#print "=" x 80, "\n"; |
229 |
|
|
230 |
# clone object (in case we have to modify it here) |
# clone object (in case we have to modify it here) |
231 |
# TODO: |
# TODO: |
234 |
# - after all, just take care for now that this object doesn't get updated! |
# - after all, just take care for now that this object doesn't get updated! |
235 |
# - so, just use its reference for now - if some cloning is needed in future, do this here! |
# - so, just use its reference for now - if some cloning is needed in future, do this here! |
236 |
my $source_node = $source_node_real; |
my $source_node = $source_node_real; |
237 |
|
#my $source_node = expand($source_node_real); |
238 |
|
|
239 |
# modify entry - handle new style callbacks (the readers) |
# modify entry - handle new style callbacks (the readers) |
240 |
|
|
241 |
# trace |
# trace |
242 |
#print Dumper($source_node); |
#print Dumper($source_node); |
243 |
#exit; |
#exit; |
244 |
|
|
245 |
my $descent = 'source'; |
my $descent = 'source'; |
246 |
|
|
256 |
|
|
257 |
foreach my $node (keys %{$callbacks->{read}}) { |
foreach my $node (keys %{$callbacks->{read}}) { |
258 |
|
|
259 |
|
#print "cb_node: $node", "\n"; |
260 |
|
|
261 |
my $object = $source_node; |
my $object = $source_node; |
262 |
my $value; # = $source_node->{$node}; |
my $value; # = $source_node->{$node}; |
263 |
|
|
315 |
print "n" if $self->{verbose}; |
print "n" if $self->{verbose}; |
316 |
} |
} |
317 |
|
|
|
#print "checksum", "\n"; |
|
|
|
|
|
#print Dumper($self); |
|
|
|
|
318 |
# determine status of entry by synchronization method |
# determine status of entry by synchronization method |
319 |
if ( lc $self->{options}->{metadata}->{syncMethod} eq 'checksum' ) { |
if ( lc $self->{options}->{metadata}->{syncMethod} eq 'checksum' ) { |
320 |
#if ( $statOK && (lc $self->{args}->{method} eq 'checksum') ) { |
#if ( $statOK && (lc $self->{args}->{method} eq 'checksum') ) { |
321 |
#if ( !$self->{node}->{status}->{new} && (lc $self->{args}->{method} eq 'checksum') ) { |
#if ( !$self->{node}->{status}->{new} && (lc $self->{args}->{method} eq 'checksum') ) { |
322 |
|
|
323 |
|
# new 2004-06-17: calculate local checksum of source node |
324 |
|
# new 2004-06-19: ... only if requested |
325 |
|
if ($self->{options}->{source}->{storage}->{handle}->{locator}->{hasLocalChecksum}) { |
326 |
|
$self->handleLocalChecksum('source'); |
327 |
|
} |
328 |
|
|
329 |
# calculate checksum of source node |
# calculate checksum of source node |
330 |
#$self->_calcChecksum('source'); |
#$self->_calcChecksum('source'); |
331 |
if (!$self->_readChecksum('source')) { |
if (!$self->readChecksum('source')) { |
332 |
$logger->warning( __PACKAGE__ . "->_run: Could not find \"source\" entry with ident=\"$self->{node}->{source}->{ident}\"" ); |
$logger->warning( __PACKAGE__ . "->_run: Could not find \"source\" entry with ident=\"$self->{node}->{source}->{ident}\"" ); |
333 |
$tc->{skip}++; |
$tc->{skip}++; |
334 |
print "s" if $self->{verbose}; |
print "s" if $self->{verbose}; |
336 |
} |
} |
337 |
|
|
338 |
# get checksum from synchronization target |
# get checksum from synchronization target |
339 |
$self->_readChecksum('target'); |
$self->readChecksum('target'); |
340 |
#if (!$self->_readChecksum('target')) { |
#if (!$self->readChecksum('target')) { |
341 |
# $logger->critical( __PACKAGE__ . "->_readChecksum: Could not find \"target\" entry with ident=\"$self->{node}->{source}->{ident}\"" ); |
# $logger->critical( __PACKAGE__ . "->readChecksum: Could not find \"target\" entry with ident=\"$self->{node}->{source}->{ident}\"" ); |
342 |
# next; |
# next; |
343 |
#} |
#} |
344 |
|
|
355 |
# trace |
# trace |
356 |
#print Dumper($self->{node}); |
#print Dumper($self->{node}); |
357 |
#exit; |
#exit; |
358 |
|
#print "LOCAL: ", $self->{node}->{source}->{checksum_local_storage}, " <-> ", $self->{node}->{source}->{checksum_local_calculated}, "\n"; |
359 |
|
#print "REMOTE: ", $self->{node}->{source}->{checksum}, " <-> ", $self->{node}->{target}->{checksum}, "\n"; |
360 |
|
|
361 |
|
# calculate new/dirty status |
362 |
$self->{node}->{status}->{new} = !$self->{node}->{target}->{checksum}; |
$self->{node}->{status}->{new} = !$self->{node}->{target}->{checksum}; |
363 |
if (!$self->{node}->{status}->{new}) { |
if (!$self->{node}->{status}->{new}) { |
364 |
$self->{node}->{status}->{dirty} = |
$self->{node}->{status}->{dirty} = |
368 |
$self->{args}->{force}; |
$self->{args}->{force}; |
369 |
} |
} |
370 |
|
|
371 |
|
# new 2004-06-17: also check if local checksum is inconsistent |
372 |
|
# new 2004-06-19: ... only if requested |
373 |
|
if ($self->{options}->{source}->{storage}->{handle}->{locator}->{hasLocalChecksum} and |
374 |
|
($self->{node}->{source}->{checksum_local_storage} ne $self->{node}->{source}->{checksum_local_calculated}) ) { |
375 |
|
$self->{node}->{status}->{dirty_local} = 1; |
376 |
|
$self->{node}->{status}->{dirty} = 1; |
377 |
|
} |
378 |
|
|
379 |
} else { |
} else { |
380 |
$logger->warning( __PACKAGE__ . "->_run: Synchronization method '$self->{options}->{metadata}->{syncMethod}' is not implemented" ); |
$logger->warning( __PACKAGE__ . "->_run: Synchronization method '$self->{options}->{metadata}->{syncMethod}' is not implemented" ); |
381 |
$tc->{skip}++; |
$tc->{skip}++; |
383 |
next; |
next; |
384 |
} |
} |
385 |
|
|
386 |
|
# new 2004-06-17: also update local checksum |
387 |
|
if ($self->{node}->{status}->{dirty_local}) { |
388 |
|
$tc->{locally_modified}++; |
389 |
|
print "[lm]" if $self->{verbose}; |
390 |
|
$self->_doModify_LocalChecksum('source'); |
391 |
|
} |
392 |
|
|
393 |
# first reaction on entry-status: continue with next entry if the current is already "in sync" |
# first reaction on entry-status: continue with next entry if the current is already "in sync" |
394 |
if (!$self->{node}->{status}->{new} && !$self->{node}->{status}->{dirty}) { |
if (!$self->{node}->{status}->{new} && !$self->{node}->{status}->{dirty}) { |
395 |
$tc->{in_sync}++; |
$tc->{in_sync}++; |
396 |
next; |
next; |
397 |
} |
} |
398 |
|
|
399 |
|
#print Dumper($self->{node}->{source}); |
400 |
|
|
401 |
# build map to actually transfer the data from source to target |
# build map to actually transfer the data from source to target |
402 |
if (!$self->buildAttributeMap()) { |
if (!$self->buildAttributeMap()) { |
403 |
#$logger->warning( __PACKAGE__ . "->_run: Attribute Map could not be created. Will not insert or modify node."); |
#$logger->warning( __PACKAGE__ . "->_run: Attribute Map could not be created. Will not insert or modify node."); |
404 |
$tc->{skip}++; |
push( @{$tc->{error_per_row}}, "Attribute Map could not be created. Will not insert or modify node $self->{node}->{source}->{ident}."); |
405 |
|
#push( @{$tc->{error_per_row}}, "Attribute Map could not be created. Will not insert or modify node " . Dumper($self->{node}->{source}) . "."); |
406 |
|
$tc->{error}++; |
407 |
print "e" if $self->{verbose}; |
print "e" if $self->{verbose}; |
408 |
next; |
next; |
409 |
} |
} |
434 |
# asymmetry: refetch node from target to re-calculate new ident and checksum (TODO: is IdentAuthority of relevance here?) |
# asymmetry: refetch node from target to re-calculate new ident and checksum (TODO: is IdentAuthority of relevance here?) |
435 |
#print Dumper($self->{node}); |
#print Dumper($self->{node}); |
436 |
$self->_statloadNode('target', $self->{node}->{target}->{ident}, 1); |
$self->_statloadNode('target', $self->{node}->{target}->{ident}, 1); |
437 |
$self->_readChecksum('target'); |
$self->readChecksum('target'); |
438 |
|
|
439 |
} elsif ($self->{node}->{status}->{dirty}) { |
} elsif ($self->{node}->{status}->{dirty}) { |
440 |
$tc->{attempt_modify}++; |
$tc->{attempt_modify}++; |
441 |
# asymmetry: get ident before updating (TODO: is IdentAuthority of relevance here?) |
# asymmetry: get ident before updating (TODO: is IdentAuthority of relevance here?) |
442 |
$self->{node}->{target}->{ident} = $self->{node}->{map}->{$self->{meta}->{target}->{IdentProvider}->{arg}}; |
$self->{node}->{target}->{ident} = $self->{node}->{map}->{$self->{meta}->{target}->{IdentProvider}->{arg}}; |
443 |
$self->_doTransferToTarget('update'); |
$self->_doTransferToTarget('update'); |
444 |
$self->_readChecksum('target'); |
$self->readChecksum('target'); |
445 |
} |
} |
446 |
|
|
447 |
if ($self->{node}->{status}->{ok}) { |
if ($self->{node}->{status}->{ok}) { |
469 |
#exit; |
#exit; |
470 |
$self->_doModifySource_IdentChecksum($self->{node}->{target}->{ident}); |
$self->_doModifySource_IdentChecksum($self->{node}->{target}->{ident}); |
471 |
} |
} |
472 |
|
|
473 |
|
#print "UNLOAD", "\n"; |
474 |
|
#$self->{meta}->{source}->{storage}->unload( $self->{node}->{source}->{payload} ); |
475 |
|
|
476 |
} |
} |
477 |
|
|
496 |
} |
} |
497 |
|
|
498 |
|
|
|
# refactor this as some core-function to do a generic dump resolving data-encapsulations of e.g. Set::Object |
|
|
sub _dumpCompact { |
|
|
my $self = shift; |
|
|
|
|
|
#my $vars = \@_; |
|
|
my @data = (); |
|
|
|
|
|
my $count = 0; |
|
|
foreach (@_) { |
|
|
my $item = {}; |
|
|
foreach my $key (keys %$_) { |
|
|
my $val = $_->{$key}; |
|
|
|
|
|
#print Dumper($val); |
|
|
|
|
|
if (ref $val eq 'Set::Object') { |
|
|
#print "========================= SET", "\n"; |
|
|
#print Dumper($val); |
|
|
#print Dumper($val->members()); |
|
|
#$val = $val->members(); |
|
|
#$vars->[$count]->{$key} = $val->members() if $val->can("members"); |
|
|
#$item->{$key} = $val->members() if $val->can("members"); |
|
|
$item->{$key} = $val->members(); |
|
|
#print Dumper($vars->[$count]->{$key}); |
|
|
|
|
|
} else { |
|
|
$item->{$key} = $val; |
|
|
} |
|
|
|
|
|
} |
|
|
push @data, $item; |
|
|
$count++; |
|
|
} |
|
|
|
|
|
#print "Dump:", Dumper(@data), "\n"; |
|
|
|
|
|
$Data::Dumper::Indent = 0; |
|
|
my $result = Dumper(@data); |
|
|
$Data::Dumper::Indent = 2; |
|
|
return $result; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
499 |
sub _doTransferToTarget { |
sub _doTransferToTarget { |
500 |
my $self = shift; |
my $self = shift; |
501 |
my $action = shift; |
my $action = shift; |
528 |
$self->_modifyNode('source', 'update', $map); |
$self->_modifyNode('source', 'update', $map); |
529 |
} |
} |
530 |
|
|
531 |
|
sub _doModify_LocalChecksum { |
532 |
|
my $self = shift; |
533 |
|
my $descent = shift; |
534 |
|
my $map = { |
535 |
|
cs_local => $self->{node}->{$descent}->{checksum_local_calculated}, |
536 |
|
}; |
537 |
|
$self->_modifyNode($descent, 'update', $map); |
538 |
|
} |
539 |
|
|
540 |
sub _prepareNode_MetaProperties { |
sub _prepareNode_MetaProperties { |
541 |
my $self = shift; |
my $self = shift; |
571 |
|
|
572 |
} |
} |
573 |
|
|
574 |
|
# TODO: load column-metadata from reversed mapping-metadata |
575 |
sub _prepareNode_DummyIdent { |
sub _prepareNode_DummyIdent { |
576 |
my $self = shift; |
my $self = shift; |
577 |
my $descent = shift; |
my $descent = shift; |
578 |
|
|
579 |
|
#print Dumper($self->{options}); |
580 |
$logger->info( __PACKAGE__ . "->_prepareNode_DummyIdent( descent $descent )" ); |
$logger->info( __PACKAGE__ . "->_prepareNode_DummyIdent( descent $descent )" ); |
581 |
|
|
582 |
my $list = $self->_getNodeList($descent); |
my $list = $self->_getNodeList($descent); |
590 |
my $map = { |
my $map = { |
591 |
$self->{meta}->{$descent}->{IdentProvider}->{arg} => $ident_dummy, |
$self->{meta}->{$descent}->{IdentProvider}->{arg} => $ident_dummy, |
592 |
cs => undef, |
cs => undef, |
593 |
|
cs_local => undef, |
594 |
}; |
}; |
595 |
|
|
596 |
# diff lists and ... |
# diff lists and ... |
615 |
$i++; |
$i++; |
616 |
} |
} |
617 |
|
|
618 |
#print "\n" if $self->{verbose}; |
print "\n" if $self->{verbose}; |
619 |
|
|
620 |
if (!$i) { |
if (!$i) { |
621 |
$logger->warning( __PACKAGE__ . "->_prepareNode_DummyIdent: no nodes touched" ); |
$logger->warning( __PACKAGE__ . "->_prepareNode_DummyIdent: no nodes touched" ); |