ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/Storable.pm
Revision: 1.23
Committed: Sun Sep 21 01:23:26 2008 UTC (15 years, 8 months ago) by root
Branch: MAIN
CVS Tags: rel-4_746
Changes since 1.22: +1 -1 lines
Log Message:
4.746

File Contents

# User Rev Content
1 root 1.1 =head1 NAME
2    
3     Coro::Storable - offer a more fine-grained Storable interface
4    
5     =head1 SYNOPSIS
6    
7     use Coro::Storable;
8    
9     =head1 DESCRIPTION
10    
11     This module implements a few functions from the Storable module in a way
12 root 1.22 so that it cede's more often. Some applications (such as the Deliantra
13 root 1.1 game server) sometimes need to load large Storable objects without
14     blocking the server for a long time.
15    
16 root 1.6 This is being implemented by using a perlio layer that feeds only small
17     amounts of data (512 bytes per call) into Storable, and C<Coro::cede>'ing
18 root 1.21 regularly (at most 100 times per second by default, though).
19 root 1.6
20 root 1.22 As it seems that Storable is not reentrant, this module also wraps most
21     functions of the Storable module so that only one freeze or thaw is done
22     at any one moment (recursive invocations are not currently supported).
23 root 1.2
24 root 1.1 =head1 FUNCTIONS
25    
26     =over 4
27    
28     =item $ref = thaw $pst
29    
30     Retrieve an object from the given $pst, which must have been created with
31     C<Coro::Storable::freeze> or C<Storable::store_fd>/C<Storable::store>
32     (sorry, but Storable uses incompatible formats for disk/mem objects).
33    
34 root 1.4 This works by calling C<Coro::cede> for every 4096 bytes read in.
35 root 1.1
36     =item $pst = freeze $ref
37    
38     Freeze the given scalar into a Storable object. It uses the same format as
39 root 1.6 C<Storable::store_fd>.
40 root 1.1
41     This works by calling C<Coro::cede> for every write that Storable
42     issues. Unfortunately, Storable often makes many very small writes, so it
43     is rather inefficient. But it does keep the latency low.
44    
45 root 1.6 =item $pst = nfreeze $ref
46    
47 root 1.7 Same as C<freeze> but is compatible to C<Storable::nstore_fd> (note the
48 root 1.6 C<n>).
49    
50     =item $pst = blocking_freeze $ref
51    
52     Same as C<freeze> but is guaranteed to block. This is useful e.g. in
53     C<Coro::Util::fork_eval> when you want to serialise a data structure
54     for use with the C<thaw> function for this module. You cannot use
55 root 1.7 C<Storable::freeze> for this as Storable uses incompatible formats for
56 root 1.6 memory and file images.
57    
58     =item $pst = blocking_nfreeze $ref
59    
60     Same as C<blocking_freeze> but uses C<nfreeze> internally.
61    
62 root 1.22 =item $guard = guard
63 root 1.8
64     Acquire the Storable lock, for when you want to call Storable yourself.
65    
66 root 1.22 Note that this module already wraps the Storable functions, so there is
67     rarely the need to do this yourself.
68    
69 root 1.1 =back
70    
71     =cut
72    
73     package Coro::Storable;
74    
75 root 1.22 use strict qw(subs vars);
76 root 1.13 no warnings;
77 root 1.1
78     use Coro ();
79 root 1.2 use Coro::Semaphore ();
80 root 1.1
81 root 1.13 BEGIN {
82     # suppress warnings
83     local $^W = 0;
84     require Storable;
85     }
86    
87 root 1.1 use Storable;
88     use base "Exporter";
89    
90 root 1.23 our $VERSION = 4.746;
91 root 1.9 our @EXPORT = qw(thaw freeze nfreeze blocking_thaw blocking_freeze blocking_nfreeze);
92 root 1.1
93 root 1.2 my $lock = new Coro::Semaphore;
94    
95 root 1.8 sub guard {
96     $lock->guard
97     }
98    
99 root 1.22 # wrap xs functions
100     for (qw(net_pstore mstore net_mstore pretrieve mretrieve dclone)) {
101     my $orig = \&{"Storable::$_"};
102     *{"Storable::$_"} = sub {
103     my $guard = $lock->guard;
104     &$orig
105     };
106     die if $@;
107     }
108    
109 root 1.6 sub thaw($) {
110     open my $fh, "<:via(CoroCede)", \$_[0]
111     or die "cannot open pst via CoroCede: $!";
112     Storable::fd_retrieve $fh
113     }
114    
115 root 1.1 sub freeze($) {
116     open my $fh, ">:via(CoroCede)", \my $buf
117     or die "cannot open pst via CoroCede: $!";
118 root 1.6 Storable::store_fd $_[0], $fh;
119 root 1.1 $buf
120     }
121    
122 root 1.6 sub nfreeze($) {
123     open my $fh, ">:via(CoroCede)", \my $buf
124 root 1.1 or die "cannot open pst via CoroCede: $!";
125 root 1.6 Storable::nstore_fd $_[0], $fh;
126     $buf
127     }
128    
129 root 1.10 sub blocking_thaw($) {
130 root 1.9 open my $fh, "<", \$_[0]
131     or die "cannot open pst: $!";
132     Storable::fd_retrieve $fh
133     }
134    
135 root 1.10 sub blocking_freeze($) {
136 root 1.6 open my $fh, ">", \my $buf
137     or die "cannot open pst: $!";
138     Storable::store_fd $_[0], $fh;
139     close $fh;
140    
141     $buf
142     }
143    
144 root 1.10 sub blocking_nfreeze($) {
145 root 1.6 open my $fh, ">", \my $buf
146     or die "cannot open pst: $!";
147     Storable::nstore_fd $_[0], $fh;
148     close $fh;
149    
150     $buf
151 root 1.1 }
152    
153     package PerlIO::via::CoroCede;
154    
155     # generic cede-on-read/write filtering layer
156    
157 root 1.6 use Time::HiRes ("time");
158    
159 root 1.21 our $GRANULARITY = 0.01;
160 root 1.6
161     my $next_cede;
162    
163 root 1.1 sub PUSHED {
164     __PACKAGE__
165     }
166    
167     sub FILL {
168 root 1.6 if ($next_cede <= time) {
169     $next_cede = time + $GRANULARITY; # calling time() twice usually is a net win
170 root 1.16 Coro::cede ();
171 root 1.6 }
172    
173 root 1.5 read $_[1], my $buf, 512
174 root 1.3 or return undef;
175 root 1.6
176 root 1.1 $buf
177     }
178    
179     sub WRITE {
180 root 1.21 if ($next_cede <= time) {
181     $next_cede = time + $GRANULARITY;
182 root 1.20 Coro::cede ();
183 root 1.6 }
184    
185 root 1.1 (print {$_[2]} $_[1]) ? length $_[1] : -1
186     }
187    
188     1;
189    
190     =head1 AUTHOR
191    
192     Marc Lehmann <schmorp@schmorp.de>
193     http://home.schmorp.de/
194    
195     =cut
196    
197