Revision a4b8c277
Von Bernd Bleßmann vor 3 Monaten hinzugefügt
SL/Controller/CsvImport/Base.pm | ||
---|---|---|
534 | 534 |
return unless $data->[0]; |
535 | 535 |
return unless $data->[0]{object}; |
536 | 536 |
|
537 |
# If we store into tables which get numbers from the TransNumberGenerator |
|
538 |
# we have to lock all tables referenced by the storage table (or by |
|
539 |
# tables stored alongside with the storage table) that are handled by |
|
540 |
# the TransNumberGenerator, too. |
|
541 |
# Otherwise we can run into a deadlock if someone saves a document via |
|
542 |
# the user interface. The exact behavoir depends on timing. |
|
543 |
# E.g. we are importing orders and a user want to |
|
544 |
# book an invoice: |
|
545 |
# web: locks ar (via before-save hook and TNG (or SL::TransNumber)) |
|
546 |
# importer: locks oe (via before-save hook and TNG) (*) |
|
547 |
# importer: locks defaults (via before-save hook and TNG) |
|
548 |
# web: wants to lock defaults (via before-save hook and TNG (or SL::TransNumber)) -> is waiting |
|
549 |
# importer: wants to save oe and wants to lock referenced tables (here ar) -> is waiting |
|
550 |
# --> deadlock |
|
551 |
# |
|
552 |
# (*) if the importer locks ar here, too, everything is fine, because it will wait here |
|
553 |
# before locking the defaults table. |
|
554 |
# |
|
555 |
# List of referenced tables: |
|
556 |
# (Locking is done in the transaction below) |
|
557 |
my %referenced_tables_by_type = ( |
|
558 |
orders => [qw(ar customer vendor)], |
|
559 |
delivery_orders => [qw(customer vendor) ], |
|
560 |
ar_transactions => [qw(customer) ], |
|
561 |
ap_transactions => [qw(vendor) ], |
|
562 |
); |
|
563 |
|
|
537 | 564 |
$self->controller->track_progress(phase => 'saving data', progress => 0); # scale from 45..95%; |
538 | 565 |
|
539 | 566 |
my $last_index = $#$data; |
... | ... | |
542 | 569 |
for my $chunk (0 .. $last_index / $chunk_size) { |
543 | 570 |
$self->controller->track_progress(progress => ($chunk_size * $chunk)/scalar(@$data) * 100); # scale from 45..95%; |
544 | 571 |
SL::DB->client->with_transaction(sub { |
572 |
|
|
573 |
foreach my $refs (@{ $referenced_tables_by_type{$self->controller->{type}} || [] }) { |
|
574 |
SL::DB->client->dbh->do("LOCK " . $refs) || die SL::DB->client->dbh->errstr; |
|
575 |
} |
|
576 |
|
|
545 | 577 |
foreach my $entry_index ($chunk_size * $chunk .. min( $last_index, $chunk_size * ($chunk + 1) - 1 )) { |
546 | 578 |
my $entry = $data->[$entry_index]; |
547 | 579 |
|
Auch abrufbar als: Unified diff
Csv-Import: Referenzierte Tabellen locken, wenn TransNumberGenarator …
… verwendet wird.
Wenn der Importer in Tabellen speichert, die Nummern über den
TransNumberGenerator erhalten können, dann müssen auch von diesen
Tabellen referenzierte Tabellen, die Nummern über den TransNumberGenerator
erhalten können, gelockt werden.
Andernfalls kann es zu einer Verklemmung kommen, wenn jemand an der Oerfläche
einen Beleg speichern möchte.
WEB: sperrt Zieltabelle (z.B. ar für Rechnungen)
Importer: sperrt oe (für Aufträge) (*)
Importer: sperrt defaults
WEB: will defaults sperren
> warten
> deadlockImporter: will oe speichern, muss dazu aber auch die referenzierten Tabellen
locken (hier z.B. ar). ar ist gelockt -> warten
(*) wenn hier auch referenzierte Tabellen (ar im Beispiel) gesperrt werden,
dann ist alles ok, da der Importer dann wartet, bevor er die defaults sperrt.