Import original source of IndexData-Utils 0.01
authorMike Taylor <mike@indexdata.com>
Tue, 9 Dec 2014 12:47:44 +0000 (12:47 +0000)
committerMike Taylor <mike@indexdata.com>
Tue, 9 Dec 2014 12:47:44 +0000 (12:47 +0000)
.gitignore [new file with mode: 0644]
Changes [new file with mode: 0644]
MANIFEST [new file with mode: 0644]
Makefile.PL [new file with mode: 0644]
README [new file with mode: 0644]
lib/IndexData/Utils.pm [new file with mode: 0644]
lib/IndexData/Utils/PersistentCounter.pm [new file with mode: 0644]
t/01-IndexData-Utils.t [new file with mode: 0644]
t/02-IndexData-Utils-PersistentCounter.t [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..9ed8c12
--- /dev/null
@@ -0,0 +1,5 @@
+MYMETA.json
+MYMETA.yml
+Makefile
+blib
+pm_to_blib
diff --git a/Changes b/Changes
new file mode 100644 (file)
index 0000000..933ee96
--- /dev/null
+++ b/Changes
@@ -0,0 +1,6 @@
+Revision history for Perl extension IndexData::Utils.
+
+0.01  Mon Dec  8 12:18:26 2014
+       - original version; created by h2xs 1.23 with options
+               -X IndexData::Utils
+
diff --git a/MANIFEST b/MANIFEST
new file mode 100644 (file)
index 0000000..3ae38c6
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,8 @@
+Changes
+MANIFEST
+Makefile.PL
+README
+lib/IndexData/Utils.pm
+lib/IndexData/Utils/PersistentCounter.pm
+t/01-IndexData-Utils.t
+t/02-IndexData-Utils-PersistentCounter.t
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100644 (file)
index 0000000..5a1db51
--- /dev/null
@@ -0,0 +1,12 @@
+use 5.018002;
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+    NAME              => 'IndexData::Utils',
+    VERSION_FROM      => 'lib/IndexData/Utils.pm', # finds $VERSION
+    PREREQ_PM         => {}, # e.g., Module::Name => 1.1
+    ($] >= 5.005 ?     ## Add these new keywords supported since 5.005
+      (ABSTRACT_FROM  => 'lib/IndexData/Utils.pm', # retrieve abstract from module
+       AUTHOR         => 'Mike Taylor <mike@indexdata.com>') : ()),
+);
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..f449964
--- /dev/null
+++ b/README
@@ -0,0 +1,26 @@
+IndexData-Utils
+===============
+
+This library contains utility functions that we at Index Data want to
+share between multiple applications -- for example, the persistent
+counter used by both IRSpy (see issue IR-350) and MKHome (IR-351).
+
+
+INSTALLATION
+
+To install this module type the following:
+
+   perl Makefile.PL
+   make
+   make test
+   make install
+
+COPYRIGHT AND LICENCE
+
+Copyright (C) 2014 by Index Data.
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.8.4 or,
+at your option, any later version of Perl 5 you may have available.
+
+
diff --git a/lib/IndexData/Utils.pm b/lib/IndexData/Utils.pm
new file mode 100644 (file)
index 0000000..4e61396
--- /dev/null
@@ -0,0 +1,47 @@
+package IndexData::Utils;
+
+use 5.018002;
+use strict;
+use warnings;
+
+our $VERSION = '0.01';
+
+use IndexData::Utils::PersistentCounter;
+
+1;
+__END__
+
+
+=head1 NAME
+
+IndexData::Utils - Utility Perl extension for Index Data applications
+
+=head1 SYNOPSIS
+
+  use IndexData::Utils;
+  # Use functions from the various submodules.
+
+=head1 DESCRIPTION
+
+This library contains utility functions that we at Index Data want to
+share between multiple applications -- for example, the persistent
+counter used by both IRSpy (see issue IR-350) and MKHome (IR-351).
+
+=head1 SEE ALSO
+
+IndexData::Utils::PersistentCounter
+
+=head1 AUTHOR
+
+Mike Taylor, E<lt>mike@indexdata.comE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2014 by Index Data.
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.8.4 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
diff --git a/lib/IndexData/Utils/PersistentCounter.pm b/lib/IndexData/Utils/PersistentCounter.pm
new file mode 100644 (file)
index 0000000..e8223f9
--- /dev/null
@@ -0,0 +1,137 @@
+package IndexData::Utils::PersistentCounter;
+
+use 5.018002;
+use strict;
+use warnings;
+
+use IO::File;
+
+
+=head1 NAME
+
+IndexData::Utils::PersistentCounter - Perl extension imnlementing persistent counters
+
+=head1 SYNOPSIS
+
+  use IndexData::Utils::PersistentCounter;
+  $counter = new IndexData::Utils::PersistentCounter($file, 1);
+  $n = $counter->next();
+  $n = $counter->next();
+  # ...
+  $n = $counter->delete();
+
+=head1 DESCRIPTION
+
+This library provides a simple persistent counter class for
+maintaining a counter on disk across multiple runs of a program. It is
+safe against multiple concurrent accesses (i.e. will not issue the
+same value twice to different processes). It can be used for
+applications such as generating unique record IDs.
+
+=head1 METHODS
+
+=head2 new()
+
+  $old = new IndexData::Utils::PersistentCounter($file1);
+  $new = new IndexData::Utils::PersistentCounter($file2, 1);
+
+Creates a new counter object associated with a file which contains the
+persistent state of the counter. The purpose of the counter is to
+return consecutive integers on consecutive calls, even if those calls
+are made from multiple concurrent processes. The file stores the state
+across invocations.
+
+In the usual case (no second argument), the file must already exist;
+if it does not, it is not created, but an undefined value is returned.
+
+If a second argument is provided and its value is true, then a new
+counter file is created with initial value 1. Note that B<this will
+overwrite any existing file>, so use with caution.
+
+=cut
+
+sub new {
+    my $class = shift();
+    my($file, $create) = @_;
+
+    if (! -f $file) {
+       return undef if !$create;
+       #   ### There is a bit of a race condition here, but it's not
+       #       something that's going to crop up in real life.
+       my $fh = new IO::File(">$file") || return undef;
+       $fh->print("1\n");
+       $fh->close() or return undef;
+    }
+
+    my $this = bless {
+       file => $file,
+    }, $class;
+
+    return $this;
+}
+
+
+=head2 next()
+
+  $n = $counter->next();
+
+Returns the next available integer from the specified counter, and
+increments the counter ready for the next invocation (whether that
+invocation is in this process or a different one).
+
+The first call of C<next()> on a newly created counter returns 1, not
+0. Each subsequent call returns a value one higher than the previous
+call.
+
+=cut
+
+sub next {
+    my $this = shift();
+
+    my $fh = new IO::File('+<' . $this->{file}) || return undef;
+    flock($fh, 2) || die "can't lock file";
+    my $n = <$fh>;
+    $fh->seek(0, 0);
+    $fh->print($n+1, "\n");
+    $fh->close() or return undef;
+    return $n+0;
+}
+
+
+=head2 delete()
+
+  $ok = $counter->delete();
+
+Permanently deletes a counter file. Returns true if the deletion was
+successful, false otherwise.
+
+=cut
+
+sub delete {
+    my $this = shift();
+
+    unlink $this->{file} or return 0;
+    return 1;
+}
+
+
+=head1 SEE ALSO
+
+IndexData::Utils
+
+=head1 AUTHOR
+
+Mike Taylor, E<lt>mike@indexdata.comE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2014 by Index Data.
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.8.4 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
+
+1;
diff --git a/t/01-IndexData-Utils.t b/t/01-IndexData-Utils.t
new file mode 100644 (file)
index 0000000..a3496a9
--- /dev/null
@@ -0,0 +1,8 @@
+use strict;
+use warnings;
+
+use Test::More tests => 1;
+BEGIN { use_ok('IndexData::Utils') };
+
+# Nothing more to test for this, unless perhaps that the submodules
+# have been loaded.
diff --git a/t/02-IndexData-Utils-PersistentCounter.t b/t/02-IndexData-Utils-PersistentCounter.t
new file mode 100644 (file)
index 0000000..8b57c30
--- /dev/null
@@ -0,0 +1,49 @@
+use strict;
+use warnings;
+
+use Test::More tests => 17;
+BEGIN { use_ok('IndexData::Utils::PersistentCounter') };
+
+my $file = "/tmp/id-u-pc-$$";
+my $counter = new IndexData::Utils::PersistentCounter($file);
+ok(!defined $counter, "can't open non-existent counter");
+
+$counter = new IndexData::Utils::PersistentCounter("/x/$file", 1);
+ok(!defined $counter, "can't create counter in silly place");
+
+$counter = new IndexData::Utils::PersistentCounter($file, 1);
+my $detail = defined $counter ? '' : ": $!@";
+ok(defined $counter, "created new counter$detail");
+
+foreach my $i (1..5) {
+    my $n = $counter->next();
+    ok(defined $n, "n is defined");
+    ok($n == $i, "n has correct value $i");
+}
+
+# Three processes making five accesses each
+for (my $i = 0; $i < 3; $i ++) {
+    my $pid = fork();
+    if ($pid == 0) {
+       # child
+       foreach my $j (1..5) {
+           my $n = $counter->next();
+           print "# child ", $i+1, ", access ", $j+1, ": value is $n\n";
+       }
+       exit 0;
+    } else {
+       print "# process $pid started\n";
+    }
+}
+
+while ((my $pid = wait()) > 0) {
+    print "# process $pid completed\n";
+}
+
+my $n = $counter->next();
+ok($n == 21, "n == 21 on 21 total access (n=$n)");
+
+my $ok = $counter->delete();
+ok($ok, "deleted counter file");
+$counter = new IndexData::Utils::PersistentCounter($file);
+ok(!defined $counter, "can't open deleted counter");