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.7 by root, Wed Oct 3 18:37:48 2007 UTC vs.
Revision 1.91 by root, Sat Jul 11 01:59:05 2015 UTC

7 use Coro::Storable; 7 use Coro::Storable;
8 8
9=head1 DESCRIPTION 9=head1 DESCRIPTION
10 10
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 Deliantra
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 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 17amounts of data (4096 bytes per call) into Storable, and C<Coro::cede>'ing
18regularly (at most 1000 times per second by default, though). 18regularly (at most 100 times per second by default, though).
19 19
20As it seems that Storable is not reentrant, this module also serialises 20As Storable is not reentrant, this module also wraps most functions of the
21calls to freeze and thaw between coroutines as necessary (for this to work 21Storable module so that only one freeze or thaw is done at any one moment
22reliably you always have to use this module, however). 22(and recursive invocations are not currently supported).
23 23
24=head1 FUNCTIONS 24=head1 FUNCTIONS
25 25
26=over 4 26=over 4
27 27
29 29
30Retrieve an object from the given $pst, which must have been created with 30Retrieve an object from the given $pst, which must have been created with
31C<Coro::Storable::freeze> or C<Storable::store_fd>/C<Storable::store> 31C<Coro::Storable::freeze> or C<Storable::store_fd>/C<Storable::store>
32(sorry, but Storable uses incompatible formats for disk/mem objects). 32(sorry, but Storable uses incompatible formats for disk/mem objects).
33 33
34This works by calling C<Coro::cede> for every 4096 bytes read in. 34This function will cede regularly.
35 35
36=item $pst = freeze $ref 36=item $pst = freeze $ref
37 37
38Freeze 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
39C<Storable::store_fd>. 39C<Storable::store_fd>.
40 40
41This works by calling C<Coro::cede> for every write that Storable 41This functino will cede regularly.
42issues. Unfortunately, Storable often makes many very small writes, so it
43is rather inefficient. But it does keep the latency low.
44 42
45=item $pst = nfreeze $ref 43=item $pst = nfreeze $ref
46 44
47Same as C<freeze> but is compatible to C<Storable::nstore_fd> (note the 45Same as C<freeze> but is compatible to C<Storable::nstore_fd> (note the
48C<n>). 46C<n>).
51 49
52Same as C<freeze> but is guaranteed to block. This is useful e.g. in 50Same 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 51C<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 52for use with the C<thaw> function for this module. You cannot use
55C<Storable::freeze> for this as Storable uses incompatible formats for 53C<Storable::freeze> for this as Storable uses incompatible formats for
56memory and file images. 54memory and file images, and this module uses file images.
57 55
58=item $pst = blocking_nfreeze $ref 56=item $pst = blocking_nfreeze $ref
59 57
60Same as C<blocking_freeze> but uses C<nfreeze> internally. 58Same as C<blocking_freeze> but uses C<nfreeze> internally.
59
60=item $guard = guard
61
62Acquire the Storable lock, for when you want to call Storable yourself.
63
64Note that this module already wraps all Storable functions, so there is
65rarely the need to do this yourself.
61 66
62=back 67=back
63 68
64=cut 69=cut
65 70
66package Coro::Storable; 71package Coro::Storable;
67 72
68use strict; 73use common::sense;
69 74
70use Coro (); 75use Coro ();
71use Coro::Semaphore (); 76use Coro::Semaphore ();
72 77
78BEGIN {
79 # suppress warnings
80 local $^W = 0;
81 require Storable;
82}
83
73use Storable; 84use Storable;
74use base "Exporter"; 85use base "Exporter";
75 86
76our $VERSION = '0.2'; 87our $VERSION = 6.47;
77our @EXPORT = qw(thaw freeze nfreeze blocking_freeze blocking_nfreeze); 88our @EXPORT = qw(thaw freeze nfreeze blocking_thaw blocking_freeze blocking_nfreeze);
89
90our $GRANULARITY = 0.01;
78 91
79my $lock = new Coro::Semaphore; 92my $lock = new Coro::Semaphore;
80 93
94sub guard {
95 $lock->guard
96}
97
98# wrap xs functions
99for (qw(net_pstore pstore net_mstore mstore pretrieve mretrieve dclone)) {
100 my $orig = \&{"Storable::$_"};
101 *{"Storable::$_"} = eval 'sub (' . (prototype $orig) . ') {
102 my $guard = $lock->guard;
103 &$orig
104 }';
105 die if $@;
106}
107
81sub thaw($) { 108sub thaw($) {
82 my $guard = $lock->guard; 109 open my $fh, "<:cede($GRANULARITY)", \$_[0]
83
84 open my $fh, "<:via(CoroCede)", \$_[0]
85 or die "cannot open pst via CoroCede: $!"; 110 or die "cannot open pst via PerlIO::cede: $!";
86 Storable::fd_retrieve $fh 111 Storable::fd_retrieve $fh
87} 112}
88 113
89sub freeze($) { 114sub freeze($) {
90 my $guard = $lock->guard; 115 open my $fh, ">:cede($GRANULARITY)", \my $buf
116 or die "cannot open pst via PerlIO::cede: $!";
117 Storable::store_fd $_[0], $fh;
118 close $fh;
91 119
92 open my $fh, ">:via(CoroCede)", \my $buf
93 or die "cannot open pst via CoroCede: $!";
94 Storable::store_fd $_[0], $fh;
95 $buf 120 $buf
96} 121}
97 122
98sub nfreeze($) { 123sub nfreeze($) {
99 my $guard = $lock->guard; 124 open my $fh, ">:cede($GRANULARITY)", \my $buf
125 or die "cannot open pst via PerlIO::cede: $!";
126 Storable::nstore_fd $_[0], $fh;
127 close $fh;
100 128
101 open my $fh, ">:via(CoroCede)", \my $buf
102 or die "cannot open pst via CoroCede: $!";
103 Storable::nstore_fd $_[0], $fh;
104 $buf 129 $buf
105} 130}
106 131
132sub blocking_thaw($) {
133 open my $fh, "<", \$_[0]
134 or die "cannot open pst: $!";
135 Storable::fd_retrieve $fh
136}
137
107sub blocking_freeze { 138sub blocking_freeze($) {
108 open my $fh, ">", \my $buf 139 open my $fh, ">", \my $buf
109 or die "cannot open pst: $!"; 140 or die "cannot open pst: $!";
110 Storable::store_fd $_[0], $fh; 141 Storable::store_fd $_[0], $fh;
111 close $fh; 142 close $fh;
112 143
113 $buf 144 $buf
114} 145}
115 146
116sub blocking_nfreeze { 147sub blocking_nfreeze($) {
117 open my $fh, ">", \my $buf 148 open my $fh, ">", \my $buf
118 or die "cannot open pst: $!"; 149 or die "cannot open pst: $!";
119 Storable::nstore_fd $_[0], $fh; 150 Storable::nstore_fd $_[0], $fh;
120 close $fh; 151 close $fh;
121 152
122 $buf 153 $buf
123} 154}
124 155
125package PerlIO::via::CoroCede;
126
127# generic cede-on-read/write filtering layer
128
129use Time::HiRes ("time");
130
131our $GRANULARITY = 0.001;
132
133my $next_cede;
134
135sub PUSHED {
136 __PACKAGE__
137}
138
139sub FILL {
140 if ($next_cede <= time) {
141 $next_cede = time + $GRANULARITY; # calling time() twice usually is a net win
142 Coro::cede;
143 }
144
145 read $_[1], my $buf, 512
146 or return undef;
147
148 $buf
149}
150
151sub WRITE {
152 if ($next_cede <= (my $now = time)) {
153 Coro::cede;
154 $next_cede = $now + $GRANULARITY;
155 }
156
157 (print {$_[2]} $_[1]) ? length $_[1] : -1
158}
159
1601; 1561;
161 157
162=head1 AUTHOR 158=head1 AUTHOR/SUPPORT/CONTACT
163 159
164 Marc Lehmann <schmorp@schmorp.de> 160 Marc A. Lehmann <schmorp@schmorp.de>
165 http://home.schmorp.de/ 161 http://software.schmorp.de/pkg/Coro.html
166 162
167=cut 163=cut
168 164
169 165

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines