Monday, 10 March 2008
Bug: Cycling of cluster synchronisation log files
When the cluster synchronisation log file was cycled after receipt of
a {\tt HUP} signal, the cycling was erroneously performed both in the
signal processing code and in the main loop code which responds to
the signal. I removed the file cycling from the signal handler,
where it is vulnerable to race conditions within Perl and the underlying
C library.
Feature: Line buffering of cluster synchronisation log file
Added code to set automatic buffer flush for the ClusterSync log file
when it is initially opened and cycled after receipt of the {\tt HUP}
signal. This allows those who monitor the log file with, for example,
{\tt tail~-f} to see the complete log item for a transaction without
waiting for the buffer to be flushed.
Modified the cluster synchronisation log file generation to skip
the ``Results:'' line if the command produced no output.
Feature: Recovery from transient cluster synchronisation failures
Implemented recovery from transient and permanent cluster synchronisation
transaction failures. Previously, if any error occurred reading, verifying, or
executing a cluster synchronisation transaction, the {\tt ClusterSync.pl}
program would crash, suspending cluster synchronisation until it was
restarted. Unfortunately, there were a number of circumstances in which
such errors could occur, the most common being cases where a race condition
between queueing the transaction and {\tt ClusterSync}'s processing of it
caused an incomplete file to be read (transient), and those where a crash
of the process queueing the transaction caused an incomplete file to be
written to the transaction directory (persistent).
When a cluster sync transaction fails, for whatever reason, it is placed
into a failed transaction hash whose key is the transaction file name
and whose value is an array containing the number of times the
transaction has been tried and the next time the transaction
should be retried. On subsequent passes through the transaction
directory, failed transactions are skipped unless their retry time
has arrived, whereupon they are retried and, if they fail, their
try count is incremented and the next attempt count updated.
If the transaction eventually succeeds, it is closed out normally
and removed from the failed transaction hash. If the transaction
fails again, its try count is increment and if it has reached
the limit, the transaction is deleted from the transaction
directory and the failed transaction hash. Failre to delete
the transaction from the transaction directory remains fatal to the
{\tt ClusterSync} program.
The intervals between retries of a failed transaction and the number of
failures which cause a transaction to be abandoned are set by configuration
parameters.
Saturday, 12 January 2008
Feature: Paper log form generation
Completed the implementation of a facility for generating and printing
paper log forms for people who wish to log offline and then transcribe
the data to the application later. A new ``Print paper log forms''
item on the Utilities menu displays a form which allows the user to
select the first and last month and year (the form is preset to the
default of all months in the current year). The current, previous, and
next years may be selected. (If the user sets the end date before the
start date, they are silently swapped.) When the ``Generate'' button
is pressed, a new window opens with the log document in it, and after
a one second delay to allow the page to render, a print command is
queued (these features require JavaScript to function; if it is absent,
the log document opens in the same window as the request form and the
user must print it manually and return to the application with the
``Back'' button). A paged media style sheet is used to insert page breaks
so that each monthly log prints on its own page.
Saturday, 17 November 2007
Bug: Caption in historical charts with multiple days per pixel changes with chart size
Historical chart generation with multiple days per pixel could report
different values for the trend analysis and flag fraction in the caption
depending upon the chart size (and hence the number of days aggregated
into each horizontal pixel). This was because {\tt getDays} is not
guaranteed to examine every day in the interval, particularly in the case
of long intervals and small charts. I added code to {\tt drawChart} in
{\tt history.pm} to call {\tt analyseTrend} for the entire interval to
perform the analysis and use the values it computes for the caption,
instead of those computed on the fly by {\tt getDays} which may depend
upon the chart scale. (Reported by Jim Hollcraft.)
Bug: Excel format CSV import with space before exercise rung
If an Excel-format CSV record contained a space before a single-digit
exercise rung field, the record would be skipped as not parsable.
I modified the test pattern to allow leading (but not trailing)
spaces. Records of this type are created by the Palm HDread program when a day has an exercise rung between 1 and 9 and the -o option is used to generate Excel-format CSV. (Reported by Ömer Ay.)
Wednesday, 14 November 2007
Admin: Global statistics thwarted by weightless monthly log
If a user created one or more non-void monthly logs with no weight
entries (for example, containing only exercise rung and/or comment fields),
the administrator global statistics report would fail with a
division by zero when it attempted to compute the ``coverage'' of
the time period by weight log entries. I modified
\verb+receive_aggregated_statistics_records+ to ignore returned
records with undefined weight fields, as only such records are relevant
to the global statistics.
Monday, 17 September 2007
Bug: Cluster synchronisation of already-deleted session files
Cluster synchronisation could loop with a failed copy transaction
when, while processing a backlog of synchronisation transactions,
a copy transaction for a session ({\tt .hds}), active session
({\tt .hda}), or remember me ({\tt .hdr}) file was executed
after the file in question had been deleted at the close of the
session. I added code, similar to the September 5 fix for deletion
transactions, which considers copy transactions which fail due to
nonexistence of the source file as having completed normally.
Bug: Cluster synchronisation of files containing ISO-8859 unescaped characters
Cluster synchronisation transaction files were written in UTF-8, but
{\tt ClusterSync.pl} failed to open them in this mode. This caused
file names which contained ISO-8859 characters above the 7 bit ASCII
range which we do not escape to be misinterpreted when the transaction
was read, resulting in a signature verification failure for the
transaction. I added a ``{\tt :utf8}'' specification to the open of
the transaction file so it will be read correctly. I also set
{\tt STDOUT} to UTF-8 mode so that error messages are printed in
that mode. The log file remains in ISO-8859 mode, as that will
handle all characters which we do not escape.
Wednesday, 5 September 2007
Bug/admin: Global statistics for recently-created accounts
Global statistics computation became confused when presented with
a user account which had a database entry for the first month in
the statistics computation interval (currently 30 days), but in
which the first weight entry was after the start of the interval.
The code which computes the user's trend slope would pass undefined
trend items to the fitter, generating a snowdrift of (otherwise
harmless) warning messages. I added a test for undefined trend
values returned by the aggregator, which causes the coverage of
such users' logs to be deemed incomplete and thus excluded from the
summary trend analysis.
Bug: Trend propagation from an empty initial log
Propagation from an initial month in the database with no weight
entries to subsequent months would reference an undefined trend value
for the month. I added code to set the trend carry-forward to zero in
this case, as a trend of zero is our indication that no trend
carry-forward exists. Since the undefined trend value would be
treated as zero, this caused no problems but produced a warning
message in the error log.
Feature/admin: Report number of accounts using Web badges in global statistics
Added a line to the Open Accounts summary in the Global Statistics
page which shows the number of accounts which have Web badge
generation enabled.
Documentation: Global statistics section in style sheet
Corrected the description of the global statistics table section in
the {\tt hdiet.css} style sheet and removed a reference to a
nonexistent macro for synthetic data generation style definitions.
Bug: Cluster synchronisation loop attempting to delete file
The {\tt ClusterSync.pl} program could go into an infinite loop
if given a transaction which requested the deletion of a file
which was not present on the destination cluster host. This
situation could occur due to race conditions in which a RememberMe
file was created and replaced almost instantaneously. I added
code which detects this case and considers the deletion
transaction as having been completed successfully if the file
is found not to exist on the destination host. The error handling
has been restructured to allow other such special cases to be handled
should they arise.
Bug: Trend propagation to monthly logs in the future
If a user makes log entries in a month in the future (for example,
to add ``to do'' items in the comment field), the future month
would be assigned a trend carry-forward at the time it was created,
but the carry-forward would not be updated when weight entries
were made in the current month because trend propagation was
triggered only for entries in months prior to the ``current month''
in the user's time zone. This was an example of the sinfulness
of premature optimisation---compared to the cost of updating the
chart for an entry in a monthly log, checking the user directory
for subsequent months, even if in the future, to which the trend
should be propagated is negligible. I removed the unwarranted
``optimisation'' from ``Write updated log item back to database'',
causing a check for trend propagation to be performed for all
weight changes in monthly logs. (Reported by Anna E. Sage.)
Tuesday, 21 August 2007
Installation: File copy race condition for executable Perl programs
Modified the {\tt publish} and {\tt production} targets in
the {\tt Makefile} to install the executable Perl components
({\tt HackDiet}, {\tt HackDietBadge}, and {\tt ClusterSync})
by copying them to the destination directories with an
extension of {\tt .NEW} and then renaming them to the
destination name. This avoids the possible race condition
when a request arrives while the file is being copied to the
server and the CGI process attempts to read the Perl program
before it has been entirely copied. Note that we still have
a potential race condition for the modules in {\tt HDiet}, but
as these files are much smaller, the odds of encountering it
are much less than with the large main program. I will eventually
change these to install with a copy and move strategy as well,
but that will require more work since they are installed with
a recursive copy rather than a simple file copy.
Documentation: New CPAN module requirements
Added newly-referenced CPAN modules to the list of library
modules we require in the documentation. Each is linked
to its documentation on the CPAN site.
Clean-up: Badge configuration
Eliminated a redundant ampersand in the URL submitted when the
``Configure Web page badge image'' item is clicked in the
Utilities menu.
Deleted a redundant definition of the array of labels for trend
analysis durations in the \verb+update_badge+ transaction
handler.
Bug: Incorrect weight in badge when log and display unit set differently
Badge generation mis-handled the case where the log unit and
display unit were set differently---fixed.
Feature: Status “badges” for Web pages
Completed implementation of ``Web badges'', which allow users to display
their most recent weight log entry and the energy balance and rate of
gain/loss for a specified trend interval. A new badge configuration page,
accessible from the main utility menu, allows enabling the badge and
selecting the trend interval, which is kept in a new \verb+badge_trend+
field in the {\tt user} object. When this field is nonzero, any operation
which modifies a log entry calls {\tt history::drawBadgeImage} to update
the {\tt BadgeImage.png} file in the user's directory. (This file is
swapped into place with a {\tt mv} command to avoid race conditions if
it is being retrieved at the time an update is in progress.)
The badge configuration page takes the user to a confirmation
page which, if badge generation is enabled, shows XHTML code the
user can copy and paste into a Web page to display the badge. This
code invokes a new stand-alone lightweight CGI program named
{\tt HackDietBadge}, which is called with an opaque argument which
is the user file name of the owner of the badge salted and encrypted
with the application's master key using AES in CBC mode. The
{\tt HackDietBadge} program is separate so as to avoid having to
load the full application and all of the modules it requires just
to display a badge image on a Web page which may be hit far more
frequently than full-fledged application transactions. The
{\tt HackDietBadge} program decrypts and validates the
argument and, if all is well, copies the badge image for
the specified user to standard output hacing specified a
{\tt Content-type} of {\tt image/png}. If the argument is
in error, or the specified user has disabled badge generation,
a canned ``Invalid request'' image is returned instead.
Subscribe to:
Posts (Atom)