/examples/testsimplecdb.pl

https://github.com/gitpan/SimpleCDB · Perl · 191 lines · 139 code · 26 blank · 26 comment · 29 complexity · 09b485a538e64cc3ba9f0c2764f6f521 MD5 · raw file

  1. #!/usr/local/bin/perl -w
  2. use strict;
  3. use SimpleCDB; # exports as per Fcntl
  4. # test the SimpleCDB
  5. # - create a DB, then fork off a number of readers
  6. # - every so often recreate the DB
  7. my $records = shift || 1_000;
  8. my $readers = shift || 0;
  9. my $cleanup = shift; $cleanup = 1 unless defined $cleanup;
  10. warn "$records records, $readers readers, ". ($cleanup ? '' : 'not ') .
  11. "cleaning up afterwards\n";
  12. my $columns = ($ENV{COLUMNS} || 80) - 8;
  13. $| = 1;
  14. $SimpleCDB::DEBUG = $ENV{SIMPLECDBDEBUG};
  15. # range of key,value chars
  16. #my @d = map {chr($_)} 0x20..0x7e;
  17. my @d = map {chr($_)} 0x00..0xff;
  18. my $magic = pop @d; # will be inserted in every value
  19. sub update
  20. {
  21. # create
  22. print "update: ";
  23. my %h;
  24. tie %h, 'SimpleCDB', 'db', O_WRONLY|O_TRUNC
  25. or die "tie failed: $SimpleCDB::ERROR\n";
  26. my $n = $records/$columns;
  27. my $m = 1;
  28. my $i;
  29. for ($i = 0; $i < $records; $i++)
  30. {
  31. my $j = $i % @d;
  32. my $k = $i;
  33. my $v = join '', (@d[$j..$#d], @d[0..($j-1)])[0..rand(@d)];
  34. substr($v, rand(length($v)), 1) = $magic;
  35. $h{$k} = $v;
  36. die "store: $SimpleCDB::ERROR" if $SimpleCDB::ERROR;
  37. $m += $n, print '.' if ($i == int $m);
  38. }
  39. untie %h; # release DB
  40. print "\n";
  41. }
  42. sub qgrep
  43. # check the number of records
  44. {
  45. my %h;
  46. print 'grep: ';
  47. tie %h, 'SimpleCDB', 'db', O_RDONLY, 0
  48. or die "tie failed: $SimpleCDB::ERROR\n";
  49. my $n = $records/$columns;
  50. my $m = 1;
  51. my $i = 0;
  52. while (my ($k, $v) = each %h)
  53. {
  54. die "invalid record\n" unless $v =~ /$magic/;
  55. $m += $n, print '+' if ($i++ == int $m);
  56. }
  57. die "invalid number of records: expected $records, got $i\n"
  58. if ($i != $records);
  59. print "\n";
  60. untie %h;
  61. }
  62. sub query
  63. {
  64. my %h;
  65. print 'o'; # "open"
  66. unless (tie %h, 'SimpleCDB', 'db', O_RDONLY)
  67. {
  68. if ($! == POSIX::EWOULDBLOCK)
  69. {
  70. print "!";
  71. }
  72. else
  73. {
  74. die "tie failed: $SimpleCDB::ERROR\n";
  75. }
  76. return undef;
  77. }
  78. #print "$$ query:\n";
  79. while (1)
  80. {
  81. my $i = int rand($records);
  82. my $v = $h{$i};
  83. die "fetch: $SimpleCDB::ERROR" if $SimpleCDB::ERROR;
  84. #print "$$\t$i = " . (defined $v ? 'ok' : '-') . "\n";
  85. print '+';
  86. die "there's just no magic between us anymore... [$v]\n"
  87. unless $v =~ /$magic/;
  88. last if rand() > 0.8;
  89. }
  90. print "\n";
  91. untie %h;
  92. }
  93. update();
  94. qgrep();
  95. my @kids;
  96. my $i;
  97. print "starting readers\n" if $readers;
  98. for ($i = 0; $i < $readers; $i++)
  99. {
  100. my $p = fork;
  101. srand();
  102. unless ($p) { @kids = (); last }
  103. push (@kids, $p);
  104. }
  105. if ($readers)
  106. {
  107. if (@kids) # parent
  108. {
  109. # an exercise in catching children
  110. # - perl 5.00x's signal handling is not reliable, and I quote from
  111. # perlipc "... doing nearly anything in your handler could in
  112. # theory trigger a memory fault". Nice, hey?
  113. # - hashes are probably not reliable, given that presumably memory
  114. # allocation can occur at any time. Hopefully a presized array is
  115. # ok...
  116. # - apparently 5.6 has signals handled via a separate thread, yippee
  117. my @zombies = map { 0 } @kids;
  118. my $z = 0;
  119. eval
  120. {
  121. local $SIG{INT} = sub { die "SIGINT\n" };
  122. local $SIG{TERM} = $SIG{INT};
  123. local $SIG{CHLD} = sub { $zombies[$z++] = wait; die "SIGCHLD\n" };
  124. while (1)
  125. {
  126. select(undef, undef, undef, 30);
  127. update();
  128. }
  129. };
  130. warn "\nchild exited unexpectedly\n" if $@ =~ /SIGCHLD/;
  131. print "\nstopping readers\n";
  132. # who's left?
  133. # - could just signal all @kids, but some may have exited already
  134. # and thus a race condition arises - don't want to signal another
  135. # unrelated process by accident (yes, yes, the probability of this
  136. # happening is approximately zero, but someday I might want to do
  137. # this for real so I can come back to this code and see how I did
  138. # it. Ok? :-)
  139. # find complement of @kids U @zombies
  140. my %k = map { $_, 1 } @kids;
  141. map { delete $k{$_} if $_ } @zombies;
  142. kill INT => keys %k;
  143. while (%k) { my $pid = wait; delete $k{$pid} }
  144. die "\n" if $@ =~ /SIGCHLD/;
  145. }
  146. else # child
  147. {
  148. eval
  149. {
  150. local $SIG{INT} = sub { die "SIGINT\n" };
  151. local $SIG{TERM} = $SIG{INT};
  152. while (1)
  153. {
  154. select(undef, undef, undef, 2 + rand(5));
  155. query();
  156. }
  157. };
  158. exit;
  159. }
  160. }
  161. if ($cleanup)
  162. {
  163. $ENV{PATH} = '/bin:/usr/bin';
  164. system(qw/rm -rf/, 'db') == 0 or die "erk: couldn't clean up\n";
  165. }