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.3 by root, Wed Apr 18 13:46:32 2007 UTC vs.
Revision 1.71 by root, Fri Nov 11 20:22:09 2011 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
16As it seems that Storable is not reentrant, this module also serialises 16This is being implemented by using a perlio layer that feeds only small
17calls to freeze and thaw between coroutines. 17amounts of data (4096 bytes per call) into Storable, and C<Coro::cede>'ing
18regularly (at most 100 times per second by default, though).
19
20As Storable is not reentrant, this module also wraps most functions of the
21Storable module so that only one freeze or thaw is done at any one moment
22(and recursive invocations are not currently supported).
18 23
19=head1 FUNCTIONS 24=head1 FUNCTIONS
20 25
21=over 4 26=over 4
22 27
24 29
25Retrieve 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
26C<Coro::Storable::freeze> or C<Storable::store_fd>/C<Storable::store> 31C<Coro::Storable::freeze> or C<Storable::store_fd>/C<Storable::store>
27(sorry, but Storable uses incompatible formats for disk/mem objects). 32(sorry, but Storable uses incompatible formats for disk/mem objects).
28 33
29This works by calling C<Coro::cede> for every 512 bytes read in. 34This function will cede regularly.
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 functino will cede regularly.
37issues. Unfortunately, Storable often makes many very small writes, so it 42
38is rather inefficient. But it does keep the latency low. 43=item $pst = nfreeze $ref
44
45Same as C<freeze> but is compatible to C<Storable::nstore_fd> (note the
46C<n>).
47
48=item $pst = blocking_freeze $ref
49
50Same as C<freeze> but is guaranteed to block. This is useful e.g. in
51C<Coro::Util::fork_eval> when you want to serialise a data structure
52for use with the C<thaw> function for this module. You cannot use
53C<Storable::freeze> for this as Storable uses incompatible formats for
54memory and file images, and this module uses file images.
55
56=item $pst = blocking_nfreeze $ref
57
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.
39 66
40=back 67=back
41 68
42=cut 69=cut
43 70
44package Coro::Storable; 71package Coro::Storable;
45 72
46use strict; 73use common::sense;
47 74
48use Coro (); 75use Coro ();
49use Coro::Semaphore (); 76use Coro::Semaphore ();
50 77
78BEGIN {
79 # suppress warnings
80 local $^W = 0;
81 require Storable;
82}
83
51use Storable; 84use Storable;
52use base "Exporter"; 85use base "Exporter";
53 86
54our $VERSION = '0.1'; 87our $VERSION = 6.07;
55our @EXPORT = qw(freeze thaw); 88our @EXPORT = qw(thaw freeze nfreeze blocking_thaw blocking_freeze blocking_nfreeze);
89
90our $GRANULARITY = 0.01;
56 91
57my $lock = new Coro::Semaphore; 92my $lock = new Coro::Semaphore;
58 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
108sub thaw($) {
109 open my $fh, "<:cede($GRANULARITY)", \$_[0]
110 or die "cannot open pst via PerlIO::cede: $!";
111 Storable::fd_retrieve $fh
112}
113
59sub freeze($) { 114sub freeze($) {
60 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;
61 119
62 open my $fh, ">:via(CoroCede)", \my $buf
63 or die "cannot open pst via CoroCede: $!";
64 Storable::nstore_fd $_[0], $fh;
65 $buf 120 $buf
66} 121}
67 122
68sub thaw($) { 123sub nfreeze($) {
69 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;
70 128
129 $buf
130}
131
132sub blocking_thaw($) {
71 open my $fh, "<:via(CoroCede)", \$_[0] 133 open my $fh, "<", \$_[0]
72 or die "cannot open pst via CoroCede: $!"; 134 or die "cannot open pst: $!";
73 Storable::fd_retrieve $fh 135 Storable::fd_retrieve $fh
74} 136}
75 137
76package PerlIO::via::CoroCede; 138sub blocking_freeze($) {
139 open my $fh, ">", \my $buf
140 or die "cannot open pst: $!";
141 Storable::store_fd $_[0], $fh;
142 close $fh;
77 143
78# generic cede-on-read/write filtering layer
79
80sub PUSHED {
81 __PACKAGE__
82}
83
84sub FILL {
85 Coro::cede;
86 read $_[1], my $buf, 512
87 or return undef;
88 $buf 144 $buf
89} 145}
90 146
91sub WRITE { 147sub blocking_nfreeze($) {
92 Coro::cede; 148 open my $fh, ">", \my $buf
93 (print {$_[2]} $_[1]) ? length $_[1] : -1 149 or die "cannot open pst: $!";
150 Storable::nstore_fd $_[0], $fh;
151 close $fh;
152
153 $buf
94} 154}
95 155
961; 1561;
97 157
98=head1 AUTHOR 158=head1 AUTHOR

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines