ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/Storable.pm
Revision: 1.8
Committed: Mon Oct 8 00:47:19 2007 UTC (16 years, 8 months ago) by root
Branch: MAIN
CVS Tags: rel-4_11, rel-4_1
Changes since 1.7: +12 -0 lines
Log Message:
*** empty log message ***

File Contents

# Content
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 so that it cede's more often. Some applications (such as the Crossfire
13 game server) sometimes need to load large Storable objects without
14 blocking the server for a long time.
15
16 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 regularly (at most 1000 times per second by default, though).
19
20 As it seems that Storable is not reentrant, this module also serialises
21 calls to freeze and thaw between coroutines as necessary (for this to work
22 reliably you always have to use this module, however).
23
24 =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 This works by calling C<Coro::cede> for every 4096 bytes read in.
35
36 =item $pst = freeze $ref
37
38 Freeze the given scalar into a Storable object. It uses the same format as
39 C<Storable::store_fd>.
40
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 =item $pst = nfreeze $ref
46
47 Same as C<freeze> but is compatible to C<Storable::nstore_fd> (note the
48 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 C<Storable::freeze> for this as Storable uses incompatible formats for
56 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 =item $guard = guard;
63
64 Acquire the Storable lock, for when you want to call Storable yourself.
65
66 =back
67
68 =cut
69
70 package Coro::Storable;
71
72 use strict;
73
74 use Coro ();
75 use Coro::Semaphore ();
76
77 use Storable;
78 use base "Exporter";
79
80 our $VERSION = '0.2';
81 our @EXPORT = qw(thaw freeze nfreeze blocking_freeze blocking_nfreeze);
82
83 my $lock = new Coro::Semaphore;
84
85 sub guard {
86 $lock->guard
87 }
88
89 sub thaw($) {
90 my $guard = $lock->guard;
91
92 open my $fh, "<:via(CoroCede)", \$_[0]
93 or die "cannot open pst via CoroCede: $!";
94 Storable::fd_retrieve $fh
95 }
96
97 sub freeze($) {
98 my $guard = $lock->guard;
99
100 open my $fh, ">:via(CoroCede)", \my $buf
101 or die "cannot open pst via CoroCede: $!";
102 Storable::store_fd $_[0], $fh;
103 $buf
104 }
105
106 sub nfreeze($) {
107 my $guard = $lock->guard;
108
109 open my $fh, ">:via(CoroCede)", \my $buf
110 or die "cannot open pst via CoroCede: $!";
111 Storable::nstore_fd $_[0], $fh;
112 $buf
113 }
114
115 sub blocking_freeze {
116 my $guard = $lock->guard;
117
118 open my $fh, ">", \my $buf
119 or die "cannot open pst: $!";
120 Storable::store_fd $_[0], $fh;
121 close $fh;
122
123 $buf
124 }
125
126 sub blocking_nfreeze {
127 my $guard = $lock->guard;
128
129 open my $fh, ">", \my $buf
130 or die "cannot open pst: $!";
131 Storable::nstore_fd $_[0], $fh;
132 close $fh;
133
134 $buf
135 }
136
137 package PerlIO::via::CoroCede;
138
139 # generic cede-on-read/write filtering layer
140
141 use Time::HiRes ("time");
142
143 our $GRANULARITY = 0.001;
144
145 my $next_cede;
146
147 sub PUSHED {
148 __PACKAGE__
149 }
150
151 sub FILL {
152 if ($next_cede <= time) {
153 $next_cede = time + $GRANULARITY; # calling time() twice usually is a net win
154 Coro::cede;
155 }
156
157 read $_[1], my $buf, 512
158 or return undef;
159
160 $buf
161 }
162
163 sub WRITE {
164 if ($next_cede <= (my $now = time)) {
165 Coro::cede;
166 $next_cede = $now + $GRANULARITY;
167 }
168
169 (print {$_[2]} $_[1]) ? length $_[1] : -1
170 }
171
172 1;
173
174 =head1 AUTHOR
175
176 Marc Lehmann <schmorp@schmorp.de>
177 http://home.schmorp.de/
178
179 =cut
180
181