Jochen Wiedmann wrote:
>
> b) deletions are performed by adding
> > a record's tell() into a hash and only physically performed when the
> > file is closed. This means that the unocking and the
> > truncating-rewriting only happens once for each file regardless of how
> > many operations are performed.
>
> That's *very* dangerous.
Can you explain the dangeres in your opinion?
> I would not do that, in particular
> because you have to care about the size of the deleted record.
No, one does not need to know the size of the record at all. I read a
record with fetch_row then get a tell(). I subtract the size of the
eol_char from the tell() and record that position in a hash table. From
then on, when fetch_row reads the file it checks the hash_table and only
sends back rows whose ending tell() is not in the hash table. On file
closure, I make a backup of the file, truncate the original, fetch all
the rows except the ones marked in the hash table from the backup and
write those fetched rows to the original file.
All inserts and updates are written to the end of the file as they
occur. If the computer crashes mid-script all the inserted and updated
information will still be in the file, the only thing that will be lost
is that the records that were deleted (or replaced by update) will still
be in the file, a situation which can be usually recovered from,
especially given the sequential nature of the file.
> > A side benefit of this approach will be that SQL::Statement will be able
> > to send updated rows as single rows, not as an entire array of all rows
> > which will be of great benefit to things like the AnyData::Format::SNMP
> > that Wes Hardaker is finalizing.
>
> I do not know about this module. IMO SQL::Statement (at least the
> classic module) puts no restrictions like that.
You must misunderstand me then because the classic SQL::Statement is
*very* restrictive in this regard. Here is your code for update with
comments where I would change it:
while ($array = $table->fetch_row($data)) {
if ($self->eval_where($eval)) {
...
$array->[$table->column_num($col->name())] = $val;
}
++$affected;
}
push(@rows, $array);
##
## here I would send the row to the subclassed push_row()
## and not add it to an array
##
}
##
## here I would not either truncate
## or send the entire array to the subclassed push_row()
##
$table->seek($data, 0, 0);
foreach $array (@rows) {
$table->push_row($data, $array);
}
$table->truncate($data);
What your version does is send every single row in the table to the
subclassed push_row() regardless of whether the row was updated or not.
There is no way for a subclassed push_row() to know which of that mass
was updated and which is simply being re-written. My method would send
only the updated rows to the subclassed push_row(), not the entire
table. The same for deletions. Nor would there be a need in my method
to put the entire table into an array as your method does since the call
to the subclassed push_row() would occur in the while loop, not in the
unnecessary foreach loop you have above.
--
Jeff