ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/Storable.pm
(Generate patch)

Comparing Coro/Coro/Storable.pm (file contents):
Revision 1.5 by root, Thu Jun 21 12:10:57 2007 UTC vs.
Revision 1.6 by root, Sat Aug 18 17:32:07 2007 UTC

11This module implements a few functions from the Storable module in a way 11This module implements a few functions from the Storable module in a way
12so that it cede's more often. Some applications (such as the Crossfire 12so that it cede's more often. Some applications (such as the Crossfire
13game server) sometimes need to load large Storable objects without 13game server) sometimes need to load large Storable objects without
14blocking the server for a long time. 14blocking the server for a long time.
15 15
16This is being implemented by using a perlio layer that feeds only small
17amounts of data (512 bytes per call) into Storable, and C<Coro::cede>'ing
18regularly (at most 1000 times per second by default, though).
19
16As it seems that Storable is not reentrant, this module also serialises 20As it seems that Storable is not reentrant, this module also serialises
17calls to freeze and thaw between coroutines. 21calls to freeze and thaw between coroutines as necessary (for this to work
22reliably you always have to use this module, however).
18 23
19=head1 FUNCTIONS 24=head1 FUNCTIONS
20 25
21=over 4 26=over 4
22 27
29This works by calling C<Coro::cede> for every 4096 bytes read in. 34This works by calling C<Coro::cede> for every 4096 bytes read in.
30 35
31=item $pst = freeze $ref 36=item $pst = freeze $ref
32 37
33Freeze the given scalar into a Storable object. It uses the same format as 38Freeze the given scalar into a Storable object. It uses the same format as
34C<Storable::nstore_fd> (note the C<n>). 39C<Storable::store_fd>.
35 40
36This works by calling C<Coro::cede> for every write that Storable 41This works by calling C<Coro::cede> for every write that Storable
37issues. Unfortunately, Storable often makes many very small writes, so it 42issues. Unfortunately, Storable often makes many very small writes, so it
38is rather inefficient. But it does keep the latency low. 43is rather inefficient. But it does keep the latency low.
44
45=item $pst = nfreeze $ref
46
47Same as C<freeze> but is compatible to C<Storabel:.nstore_fd> (note the
48C<n>).
49
50=item $pst = blocking_freeze $ref
51
52Same as C<freeze> but is guaranteed to block. This is useful e.g. in
53C<Coro::Util::fork_eval> when you want to serialise a data structure
54for use with the C<thaw> function for this module. You cannot use
55C<Storable::freeze> for this as Storabel uses incompatible formats for
56memory and file images.
57
58=item $pst = blocking_nfreeze $ref
59
60Same as C<blocking_freeze> but uses C<nfreeze> internally.
39 61
40=back 62=back
41 63
42=cut 64=cut
43 65
49use Coro::Semaphore (); 71use Coro::Semaphore ();
50 72
51use Storable; 73use Storable;
52use base "Exporter"; 74use base "Exporter";
53 75
54our $VERSION = '0.1'; 76our $VERSION = '0.2';
55our @EXPORT = qw(freeze thaw); 77our @EXPORT = qw(thaw freeze nfreeze blocking_freeze blocking_nfreeze);
56 78
57my $lock = new Coro::Semaphore; 79my $lock = new Coro::Semaphore;
58
59sub freeze($) {
60 my $guard = $lock->guard;
61
62 open my $fh, ">:via(CoroCede)", \my $buf
63 or die "cannot open pst via CoroCede: $!";
64 Storable::nstore_fd $_[0], $fh;
65 $buf
66}
67 80
68sub thaw($) { 81sub thaw($) {
69 my $guard = $lock->guard; 82 my $guard = $lock->guard;
70 83
71 open my $fh, "<:via(CoroCede)", \$_[0] 84 open my $fh, "<:via(CoroCede)", \$_[0]
72 or die "cannot open pst via CoroCede: $!"; 85 or die "cannot open pst via CoroCede: $!";
73 Storable::fd_retrieve $fh 86 Storable::fd_retrieve $fh
74} 87}
75 88
89sub freeze($) {
90 my $guard = $lock->guard;
91
92 open my $fh, ">:via(CoroCede)", \my $buf
93 or die "cannot open pst via CoroCede: $!";
94 Storable::store_fd $_[0], $fh;
95 $buf
96}
97
98sub nfreeze($) {
99 my $guard = $lock->guard;
100
101 open my $fh, ">:via(CoroCede)", \my $buf
102 or die "cannot open pst via CoroCede: $!";
103 Storable::nstore_fd $_[0], $fh;
104 $buf
105}
106
107sub blocking_freeze {
108 open my $fh, ">", \my $buf
109 or die "cannot open pst: $!";
110 Storable::store_fd $_[0], $fh;
111 close $fh;
112
113 $buf
114}
115
116sub blocking_nfreeze {
117 open my $fh, ">", \my $buf
118 or die "cannot open pst: $!";
119 Storable::nstore_fd $_[0], $fh;
120 close $fh;
121
122 $buf
123}
124
76package PerlIO::via::CoroCede; 125package PerlIO::via::CoroCede;
77 126
78# generic cede-on-read/write filtering layer 127# generic cede-on-read/write filtering layer
128
129use Time::HiRes ("time");
130
131our $GRANULARITY = 0.001;
132
133my $next_cede;
79 134
80sub PUSHED { 135sub PUSHED {
81 __PACKAGE__ 136 __PACKAGE__
82} 137}
83 138
84sub FILL { 139sub FILL {
140 if ($next_cede <= time) {
141 $next_cede = time + $GRANULARITY; # calling time() twice usually is a net win
85 Coro::cede; 142 Coro::cede;
143 }
144
86 read $_[1], my $buf, 512 145 read $_[1], my $buf, 512
87 or return undef; 146 or return undef;
147
88 $buf 148 $buf
89} 149}
90 150
91sub WRITE { 151sub WRITE {
152 if ($next_cede <= (my $now = time)) {
92 Coro::cede; 153 Coro::cede;
154 $next_cede = $now + $GRANULARITY;
155 }
156
93 (print {$_[2]} $_[1]) ? length $_[1] : -1 157 (print {$_[2]} $_[1]) ? length $_[1] : -1
94} 158}
95 159
961; 1601;
97 161

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines