App-Diskd

 view release on metacpan or  search on metacpan

lib/App/Diskd.pm  view on Meta::CPAN

=item 3. using POE to achieve both of the above

=item 4. using POE to periodically run an external program without blocking

=item 5. encapsulating a data structure that can be accessed and updated by the above

=back

The information shared between peers in this example is the list of
disks that are currently attached to each system. The "blkid" program
is used to gather this information. It reports on all disks attached,
regardless of whether the disk (or partition) is currently mounted or
not.

A copy of diskd should be run on each of the peer machines. The first
thing that it does is join a pre-defined multicast channel. The daemon
then collects the list of disks attached to the system and schedules
the collection to trigger again periodically. It also sets up a
periodic event that will send the details of the disks attached to the
machine to other peers that have joined the multicast channel. It also
listens to the channel for incoming multicast messages from another
peer and uses them to update its list of which disks are attached to
that peer. As a result of this, each daemon will be able to build up a
full list of which disks are available in the peer network and to
which machine they are attached. Thus the primary function of the
program is to be able to locate disks, no matter which machine they
are currently attached to.

The diskd program can also be run in client mode on any machine that
has a running diskd daemon. The client conencts via a local unix
domain socket and, providing the connection succeeds, it will then be
able to pass commands to the daemon. Currently the only useful command
that is implemented is 'list', which prints a list of all the disks
that the daemon knows about. More commands could be added quite
easily.

=head1 MOTIVATION/GENESIS

The reason for writing this program was to explore three key areas:

=over

=item 1. Multicast (and peer-to-peer) networking

=item 2. Daemons and method of communicating with them

=item 3. Using POE to develop a non-trivial program with a focus on asynchronous, event-based operation

=back

As I write this, the size of the program is significantly less than
1,000 lines (not including this documentation), while still managing
to implement a reasonably complex network daemon. In all, it took
about an evening's work to code and eliminate most of the major
bugs. The reason for both the small size and quick development time
can be attributed to the combination of Perl and POE. Despite this
being my first time writing any program using POE, the speed of
development was not down to amazing programming skill on my
part. Rather, it boiled down to just one factor: almost all of the POE
code I have here was based, in one way or another, on example code
hosted on the L<POE Cookbook site|http://poe.perl.org/?POE_Cookbook>.

Since I had already read up sufficiently on POE (and the examples in
the cookbook) and knew in general how I wanted my daemon to work,
selecting the relevant recipes and reworking them was a pretty
straightforward process. Based on this experience, I would definitely
recommend other Perl programmers to consider POE for programs of this
sort (network daemons) as well as for any other task where the an
event-based approach is suitable.


=head1 POINTS OF INTEREST

From the outset, I had decided that I would modularise the code and
use different objects (classes) for each functional part of the
overall program. Besides being a reasonable approach in general, it
also turned out that this was a good practical fit with the POE way of
doing things since I could use a separate POE session for each
class. Using separate classes meant that, for example, I could have
the same event name across several different sessions/classes without
needing to worry about whether they would interfere with each
other. This was a boon considering that most of my POE code started as
cut and paste from other examples.

For the remainder of this section, I would like to simply go through
each of the classes used in the program and give some brief notes. I
have attempted to comment the code to make it easier to read and
understand, but the notes here give some extra context and extra
levels of detail.

=head2 Info class

This class simply encapsulates the data structures that are collected
locally and shared among nodes. A distinction is made between the two
so that calling classes have a convenient interface for updating only
local data (eg, DiskWatcher), or querying globally-shared data (eg, a
client running a 'list' command).

The Info class does not have an associated POE session, though a
reference to the Info object is passed to every class/POE session that
needs to access/update it. So even though it doesn't use POE itself,
it is basically the glue that holds all the POE sessions together and
gives them meaning.

The current implementation simply keeps all the data in memory, though
it would be simple enough to either:

=over

=item * provide a routine to be called at program startup to read in saved data from a file or other backing storage (along with a complementary routine to save the data when the program is shutting down); or

=item * interface with a database to act as a permanent storage medium (POE provides mechanisms for doing this asynchronously, which might be appropriate here)

=back

Internally, this class also uses YAML to pack and unpack (serialise
and deserialise) the stored data. This is used by the MulticastServer
class to safely transmit and receive data within the UDP packets. It
could also be used to load/save the data to local storage between
program runs (ie, provide persistence of data).



( run in 1.178 second using v1.01-cache-2.11-cpan-39bf76dae61 )