line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
=head1 TITLE: Cache::RamDisk::Functions |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
Script-like things for installing and monitoring a Cache::RamDisk |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 SYNOPSIS |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
cache_install( { 'Base' => '/tmp/rd', |
8
|
|
|
|
|
|
|
'Size' => 16, |
9
|
|
|
|
|
|
|
'INodes' => 1024, |
10
|
|
|
|
|
|
|
'SIndex' => { 'fie' => 8, |
11
|
|
|
|
|
|
|
'foe' => 64, |
12
|
|
|
|
|
|
|
'fum' => 512 }, |
13
|
|
|
|
|
|
|
'ShMem' => 'RdLk', |
14
|
|
|
|
|
|
|
'Keys' => { 'fie' => 50, |
15
|
|
|
|
|
|
|
'foe' => 200, |
16
|
|
|
|
|
|
|
'fum' => 4000 }, |
17
|
|
|
|
|
|
|
'User' => 'apache', |
18
|
|
|
|
|
|
|
'Group' => 'apache' } ); |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
cache_status ('/tmp/rd'); |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
cache_remove ('/tmp/rd'); |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=head1 VERSION |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
0.1.6 |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=head1 EXPORTS |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
cache_install |
33
|
|
|
|
|
|
|
cache_status |
34
|
|
|
|
|
|
|
cache_remove |
35
|
|
|
|
|
|
|
cache_objects |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head1 REQUIRES |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
Perl B<5.6.1> on a Linux/ Unix System containing the following binaries: |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
chown, mkdir, mke2fs, mount, umount |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
The package uses these Perl modules available from CPAN: |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
IPC::Shareable |
47
|
|
|
|
|
|
|
IPC::SysV |
48
|
|
|
|
|
|
|
Filesys::Df |
49
|
|
|
|
|
|
|
Filesys::Statvfs |
50
|
|
|
|
|
|
|
File::stat |
51
|
|
|
|
|
|
|
Fcntl |
52
|
|
|
|
|
|
|
Symbol |
53
|
|
|
|
|
|
|
Class::Struct |
54
|
|
|
|
|
|
|
POSIX |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=head1 DESCRIPTION |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
The package provides programmers with functions for creating, monitoring and removing a cache based on a |
60
|
|
|
|
|
|
|
bundle of ramdisks. |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=head2 cache_install ( $href ) |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
Initialize the rd bundle. What will actually happen when you call this method depends on how the system |
65
|
|
|
|
|
|
|
kernel had been compiled. Please refer to the manpages about lilo.conf, lsmod etc. for some |
66
|
|
|
|
|
|
|
further details about manipulating the standard rd size on your box. All rds will be formatted with |
67
|
|
|
|
|
|
|
standard e2fs and under the default blocksize parameter. |
68
|
|
|
|
|
|
|
Of course the calling process has to have root privileges. |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
C does not terminate the calling process after an error has occurred, but emits a warning and |
71
|
|
|
|
|
|
|
returns a somehow valuable result! After successful execution the function calls C on the freshly |
72
|
|
|
|
|
|
|
installed cache and passes the return value to the caller. |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
From version 0.1.5 on C tries to find out whether there an C has been installed. The most effective - but |
75
|
|
|
|
|
|
|
nevertheless hack-like - way to me was to grep in C. If an entry named 'initrd' can be found, the first rd it tries to install |
76
|
|
|
|
|
|
|
will be on /dev/ram1, assuming that /dev/ram0 is occupied in some way... |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=head3 Arguments |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
Of course all argument names are case sensitive. |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=head4 Base |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
'Base' is an optional argument defaulting to '/tmp/rd'. Please note that the argument will not be treated |
86
|
|
|
|
|
|
|
as a pathname, but as the beginning of it. With the default value the rds will be called '/tmp/rd0', '/tmp/rd1', ... |
87
|
|
|
|
|
|
|
From version 0.1.5 on can be stated that an initrd being found on '/tmp/rd0' will be respected. |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=head4 Size |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
The B user space in B to be installed. "Minimum" results from the root space that ext2 reserves on |
92
|
|
|
|
|
|
|
each disk. The creating loop stops when there are more blocks available than necessary for the requested |
93
|
|
|
|
|
|
|
value. This will in effect lead to an available space of ca. 19 MB when you want just 16 - but there aren't |
94
|
|
|
|
|
|
|
many of such opportunities in life, so don't complain.. 'Size' is an optional argument that defaults to 16. |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=head4 SIndex |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
Each key's index will be stored on a shared memory segment of the key's 'SIndex' Size in B. |
99
|
|
|
|
|
|
|
This is an optional value with a default of 128 for each key. An index element will have the length |
100
|
|
|
|
|
|
|
of the item's id plus 4 bytes (or 5 if there are more than 10 rds keeping the data). In order to speed |
101
|
|
|
|
|
|
|
up performance the indexes are stored as strings and parsed by regexes, which I expect to act somewhat |
102
|
|
|
|
|
|
|
faster than painful C loops over arrays. |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
Although the installation doesn't care about how the cache will be used, setting the 'SIndex' values |
105
|
|
|
|
|
|
|
predefines its policies: when you know that you will always treat a key under LRU aspects with a rather |
106
|
|
|
|
|
|
|
low amount of items to be stored (e.g. C<{'fie' => 50}>), the index will probably be no longer than 2 kB. |
107
|
|
|
|
|
|
|
On the other hand storing sessions with keys of 32 bytes of size each and lifetimes of one hour may lead to |
108
|
|
|
|
|
|
|
an index that doesn't fit into 128 kB. |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=head4 ShMem |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
All data the install function has gathered so far are static data for a running cache. They consist of |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=over4 |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=item * |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
the total rds allocated, |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=item * |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
their common blocksize, |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=item * |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
the cache keys and their limiting values and keys under which the indexes can be accessed on the shared |
128
|
|
|
|
|
|
|
memory. |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=back |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
They all have to be stored somewhere, hence another shmem segment came out to be the appropriate place. |
133
|
|
|
|
|
|
|
The value 'ShMem' awaits is the key, under which this segment will be reachable. Please see L |
134
|
|
|
|
|
|
|
for details on what this value is allowed to be. |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
The existence of this argument may look weird to some people, as the shmem key could easily be calculated |
137
|
|
|
|
|
|
|
through C from one of the freshly created directories as well. |
138
|
|
|
|
|
|
|
But implementing it enables your cache to serve more than just one |
139
|
|
|
|
|
|
|
application at the same time - as long as they all stick to the same cache control segment. |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
'ShMem' is an optional argument with a default of 'RdLk'. You will always be advised well when you leave |
142
|
|
|
|
|
|
|
it untouched - unless there is another application running on your server which you can't persuade of |
143
|
|
|
|
|
|
|
using another key. Because if another key than the default is used, it has to passed to every |
144
|
|
|
|
|
|
|
C constructor. ;) |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=head4 INodes |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
The number of inodes to be reserved for the filesystem on each disk, see L. This optional |
149
|
|
|
|
|
|
|
parameter defaults to 1024. Both the number of inodes and that of the available blocks determine how the |
150
|
|
|
|
|
|
|
disks' capacities will be used by the cache: when you know that most of the objects to be stored will have |
151
|
|
|
|
|
|
|
a rather small size (around 1k) it can make sense to double the value, as else only about 50% of the |
152
|
|
|
|
|
|
|
disk spaces may be occupied. But mostly the default should suffice. Please note that as for the current |
153
|
|
|
|
|
|
|
version it is not intended to let programmers alter the blocksize on the rds. But this may change, and |
154
|
|
|
|
|
|
|
any comments being able to change my mind about this item will be appreciated. |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=head4 Keys |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
'Keys' is the only mandatory argument, as a cache without a cache key wouldn't make a sense. 'Keys' awaits |
159
|
|
|
|
|
|
|
a hashref, where the keys are the cache's keys, and the values limitate each individual Cache::RamDisk |
160
|
|
|
|
|
|
|
instance's behaviour: for a TIMED instance a value means an item's maximum lifetime in seconds, a LRU |
161
|
|
|
|
|
|
|
instance treats a cache key's value as maximum number of items allowed. Per DEFAULT the cache is ignorant. |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=head4 User/ Group |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
The system user and group allowed to access the cache. Values have to be real names and not numeric ids. |
166
|
|
|
|
|
|
|
Both arguments are optional and default to 'root'. |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=head3 What happened? |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
cd /tmp/rd0 && ls -la |
172
|
|
|
|
|
|
|
ipcs |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=head2 cache_status ( $basename [, $shmemkey] ) |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
my $s = cache_status('/tmp/rd'); |
178
|
|
|
|
|
|
|
print $s->key_stat('fie'); |
179
|
|
|
|
|
|
|
print $s->rd_stat(0)->{bavail}; |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
The monitoring tool for a running cache. Requires the cache's base pathname (-fragment, see cache_install), and |
182
|
|
|
|
|
|
|
the 'ShMem' key for this cache, if another than the default value 'RdLk' had been chosen. |
183
|
|
|
|
|
|
|
Always (!) returns a Class::Struct reference with the following accessible members: |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
$s->error # contains the error message in case something went wrong |
186
|
|
|
|
|
|
|
$s->start_disk # the index of the first rd allocated |
187
|
|
|
|
|
|
|
$s->disks # the total of allocated disks |
188
|
|
|
|
|
|
|
$s->blocksize # guess what |
189
|
|
|
|
|
|
|
$s->keys # a key's limit, as set in 'Keys' |
190
|
|
|
|
|
|
|
$s->key_stat # the number of items currently being stored for a key |
191
|
|
|
|
|
|
|
$s->rd_stat # the resulting hashref from a df() call on a rd |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=head2 cache_objects ( $basename [, $shmemkey] ) |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
Monitoring tool #2: get lists of all cached objects. (new in 0.1.6) Returns a hashref keyed to object types. For each object |
197
|
|
|
|
|
|
|
type the value is another hashref, keyed to the rds' numbers and containing arrayrefs with the object ids as values. E.g.: |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
{ 'User' => { '1' => [ 2, 5, 67, 8999 ], |
200
|
|
|
|
|
|
|
'2' => [ 1, 3, 4, 66 ] |
201
|
|
|
|
|
|
|
}, |
202
|
|
|
|
|
|
|
'Foo' => { '1' => [ 'fie', 'fee', 'fum' ], |
203
|
|
|
|
|
|
|
'2' => [ 'blah', 'bar', 'baz' ] |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=head2 cache_remove ( $basename [, $shmemkey] ) |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
Completely clears all devices (by unmounting them) and removes all relevant shared memory segments. |
210
|
|
|
|
|
|
|
Awaits the same arguments as cache_status. Returns 1 on success, else emits a warning and returns 0. |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=head1 NOTES |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
As both key and internal information are stored on the 'ShMem' segment, they have to be distinguishable |
216
|
|
|
|
|
|
|
from another: internal keys all begin and end with each a double underscore. From this follows that input |
217
|
|
|
|
|
|
|
keys matching the pattern C^__.*__$/> are ignored by C. |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
The same applies to key names containing any Perl non-word chars (C\W/>). |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=head1 SEE ALSO |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
L, L, L, L, L, L |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=head1 AUTHOR |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
Martin Haase-Thomas Ethcsoft@snafu.deE |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=head1 HISTORY |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
B<0.1.6> (08/04/03) Fixed some samll bugs, added C method. |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
B<0.1.5> Some smaller changes due to my newly achieved respect for initrd's. |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
B<0.1.4> Nothing serious. Just beautified the docs a little. |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
B<0.1.3> Implemented 'SIndex' as hashref for assigning shmem sizes to the keys directly. |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
B<0.1.2> dropped the idea of keeping any internal data on the rds and added 'SIndex' arg, rewrote locking |
241
|
|
|
|
|
|
|
again. Added cache_remove. |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
B<0.1.1> rewrote locking concept and cache_install, wrote cache_status. Stress tests showed an |
244
|
|
|
|
|
|
|
extremely lame performance. |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
B<0.1> Jul. 02, cache_install ok, but cache unuseable: locking unclear |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
=head1 TODO |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
What about that funny blocksize story? |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
=cut |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
############################################################################## |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
package Cache::RamDisk::Functions; |
260
|
|
|
|
|
|
|
|
261
|
1
|
|
|
1
|
|
848
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
103
|
|
262
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
41
|
|
263
|
1
|
|
|
1
|
|
5
|
no warnings 'untie'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
42
|
|
264
|
1
|
|
|
1
|
|
5
|
use vars qw($VERSION @ISA @EXPORT); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
103
|
|
265
|
|
|
|
|
|
|
$VERSION = 0.1.6; |
266
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
267
|
|
|
|
|
|
|
@EXPORT = qw(cache_install cache_status cache_objects cache_remove); |
268
|
|
|
|
|
|
|
|
269
|
1
|
|
|
1
|
|
10
|
use IPC::SysV 'ftok'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
80
|
|
270
|
1
|
|
|
1
|
|
6
|
use IPC::Shareable qw(:lock); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
169
|
|
271
|
1
|
|
|
1
|
|
6
|
use Filesys::Df; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
72
|
|
272
|
1
|
|
|
1
|
|
6
|
use Filesys::Statvfs; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
65
|
|
273
|
1
|
|
|
1
|
|
6
|
use File::stat; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
10
|
|
274
|
1
|
|
|
1
|
|
67
|
use Symbol 'gensym'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
59
|
|
275
|
1
|
|
|
1
|
|
6
|
use Class::Struct; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
8
|
|
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
sub cache_install { |
278
|
1
|
50
|
|
1
|
1
|
74
|
if ($<) { |
279
|
0
|
|
|
|
|
0
|
warn "You must be root to install a cache"; |
280
|
0
|
|
|
|
|
0
|
return {}; # a somehow useable value... |
281
|
|
|
|
|
|
|
} |
282
|
1
|
|
50
|
|
|
5
|
my $args = shift || return 0; |
283
|
1
|
|
|
|
|
2
|
my ($i, $rdpath, $hdl, $ret, @stat); |
284
|
1
|
50
|
|
|
|
4
|
$args->{'Base'} = '/tmp/rd' unless $args->{'Base'}; |
285
|
1
|
50
|
|
|
|
5
|
$args->{'Size'} = 16 unless $args->{'Size'}; |
286
|
1
|
50
|
|
|
|
4
|
$args->{'INodes'}= 1024 unless $args->{'INodes'}; |
287
|
1
|
50
|
|
|
|
5
|
$args->{'ShMem'} = 'RdLk' unless $args->{'ShMem'}; |
288
|
1
|
50
|
|
|
|
4
|
$args->{'User'} = 'root' unless $args->{'User'}; |
289
|
1
|
50
|
|
|
|
6
|
$args->{'Group'} = 'root' unless $args->{'Group'}; |
290
|
1
|
50
|
|
|
|
4
|
unless ($args->{'Keys'}) { |
291
|
0
|
|
|
|
|
0
|
warn "A cache like me needs a key"; |
292
|
0
|
|
|
|
|
0
|
return {}; |
293
|
|
|
|
|
|
|
} |
294
|
1
|
50
|
|
|
|
4
|
$args->{'SIndex'} = {} unless $args->{'SIndex'}; |
295
|
|
|
|
|
|
|
|
296
|
1
|
|
|
|
|
2
|
my @keys; |
297
|
1
|
|
|
|
|
1
|
foreach (keys %{$args->{'Keys'}}) { |
|
1
|
|
|
|
|
5
|
|
298
|
3
|
50
|
33
|
|
|
16
|
unless(/\W/ or /^__.*__$/) { |
299
|
3
|
|
|
|
|
3
|
push @keys, $_; |
300
|
3
|
50
|
|
|
|
11
|
$args->{'SIndex'}->{$_} = 128 unless $args->{'SIndex'}->{$_}; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
} |
304
|
1
|
|
|
|
|
5
|
$ret = { 'Disks' => 0, 'DStart' => 0, 'Blocks' => 0, 'BSize' => 1024 }; |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
# new in 0.1.5: respect an eventual initrd. |
307
|
|
|
|
|
|
|
# to me this looks like an ugly hack... |
308
|
1
|
|
|
|
|
7
|
$hdl = gensym; |
309
|
1
|
|
|
|
|
101
|
open $hdl, '/proc/mounts' || do { warn "Oops! Is this a linux box? Can't open /proc/mounts: $!"; |
310
|
|
|
|
|
|
|
return $ret; |
311
|
|
|
|
|
|
|
}; |
312
|
1
|
|
|
|
|
97
|
@stat = (<$hdl>); |
313
|
1
|
|
|
|
|
12
|
close $hdl; |
314
|
1
|
50
|
|
|
|
9
|
$ret->{'DStart'} = 1 if (grep 'initrd', @stat); |
315
|
|
|
|
|
|
|
|
316
|
1
|
|
|
|
|
8
|
print STDERR "\n"; # some scripts don't make a nice display... ;) |
317
|
1
|
|
|
|
|
3
|
for ($i=$ret->{'DStart'};;$i++) { |
318
|
|
|
|
|
|
|
|
319
|
1
|
|
|
|
|
4
|
$rdpath = $args->{'Base'}.$i; |
320
|
1
|
|
|
|
|
4
|
$hdl = gensym; |
321
|
1
|
|
|
|
|
60
|
open $hdl, '/etc/mtab' || do { warn "Can't open /etc/mtab: $!"; |
322
|
|
|
|
|
|
|
return $ret; |
323
|
|
|
|
|
|
|
}; |
324
|
1
|
|
|
|
|
58
|
my @mount = (<$hdl>); |
325
|
1
|
|
|
|
|
9
|
close $hdl; |
326
|
1
|
50
|
33
|
|
|
28
|
if (grep(/$rdpath/, @mount) && system("umount ".$rdpath) < 0) { |
327
|
0
|
|
|
|
|
0
|
warn "Can't unmount $rdpath: $!"; |
328
|
0
|
|
|
|
|
0
|
return $ret; |
329
|
|
|
|
|
|
|
} |
330
|
1
|
50
|
|
|
|
25
|
if (-e "/dev/ram$i") { |
331
|
0
|
0
|
0
|
|
|
0
|
if (system("mke2fs -q -N".$args->{'INodes'}." /dev/ram$i") < 0 || |
|
|
|
0
|
|
|
|
|
332
|
|
|
|
|
|
|
system("mkdir -p $rdpath") < 0 || |
333
|
|
|
|
|
|
|
system("mount /dev/ram$i $rdpath")) { |
334
|
0
|
|
|
|
|
0
|
warn "Error while creating /dev/ram$i on $rdpath: $!"; |
335
|
0
|
|
|
|
|
0
|
return $ret; |
336
|
|
|
|
|
|
|
} |
337
|
0
|
0
|
|
|
|
0
|
$ret->{'BSize'} = (statvfs $rdpath)[0] unless $i; |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
# chowning must not affect a 'lost+found' directory, that's why it's not done recursively |
340
|
|
|
|
|
|
|
# for the whole of each disk, but lets the '.' directory belong to root |
341
|
0
|
|
|
|
|
0
|
foreach (@keys) { |
342
|
0
|
0
|
|
|
|
0
|
unless (mkdir "$rdpath/$_") { |
343
|
0
|
|
|
|
|
0
|
warn "Error while creating directories on $rdpath: $!"; |
344
|
0
|
|
|
|
|
0
|
return $ret; |
345
|
|
|
|
|
|
|
} |
346
|
0
|
0
|
|
|
|
0
|
if (system("chown -R ".$args->{'User'}.".".$args->{'Group'}." $rdpath/$_") < 0) { |
347
|
0
|
|
|
|
|
0
|
warn "Unable to change ownership of $rdpath/$_: $!"; |
348
|
0
|
|
|
|
|
0
|
return $ret; |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
} |
351
|
0
|
|
|
|
|
0
|
@stat = statvfs($rdpath); # df doesn't return the blocksize ?! |
352
|
0
|
|
|
|
|
0
|
$ret->{'Blocks'} += $stat[4]; |
353
|
0
|
|
|
|
|
0
|
$ret->{$i} = $stat[0]; |
354
|
0
|
|
|
|
|
0
|
$ret->{'Disks'} = $i; |
355
|
0
|
0
|
|
|
|
0
|
last if $ret->{'Blocks'} > $args->{'Size'}*$ret->{'BSize'}; |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
else { |
359
|
1
|
|
|
|
|
11
|
warn "Not enough devices for ".$args->{'Size'}."MB - run 'man MAKEDEV'"; |
360
|
1
|
|
|
|
|
10
|
return $ret; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
# write static data to the control segment: |
365
|
|
|
|
|
|
|
# 1. get the shmem keys |
366
|
0
|
|
|
|
|
0
|
my @ftoks; |
367
|
0
|
|
|
|
|
0
|
for ($i = 0; $i < @keys; $i++) { |
368
|
0
|
|
|
|
|
0
|
$ftoks[$i] = ftok($args->{'Base'}.$ret->{'DStart'}."/$keys[$i]", 0); |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
|
371
|
0
|
|
|
|
|
0
|
my (%cache, $stie); |
372
|
0
|
0
|
|
|
|
0
|
unless (eval { $stie = tie %cache, 'IPC::Shareable', $args->{'ShMem'}, { create => 1, mode => 0666, |
|
0
|
|
|
|
|
0
|
|
373
|
|
|
|
|
|
|
size => 65536, exclusive => 0, |
374
|
|
|
|
|
|
|
destroy => 0 } } ) { |
375
|
0
|
|
|
|
|
0
|
warn $@; |
376
|
0
|
|
|
|
|
0
|
return $ret; |
377
|
|
|
|
|
|
|
} |
378
|
0
|
|
|
|
|
0
|
$stie->shlock; |
379
|
0
|
|
|
|
|
0
|
$cache{__Disks__} = $ret->{'Disks'}; |
380
|
0
|
|
|
|
|
0
|
$cache{__BSize__} = $ret->{'BSize'}; |
381
|
0
|
|
|
|
|
0
|
$cache{__DStart__} = $ret->{'DStart'}; |
382
|
|
|
|
|
|
|
|
383
|
0
|
|
|
|
|
0
|
for ($i = 0; $i < @keys; $i++) { |
384
|
0
|
|
|
|
|
0
|
$cache{$keys[$i]} = $args->{'Keys'}->{$keys[$i]}.":0:$ftoks[$i]:".$args->{'SIndex'}->{$keys[$i]}; |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
# foreach (keys %cache) { print STDERR "$_=".$cache{$_}."\n";} |
387
|
0
|
|
|
|
|
0
|
$stie->shunlock; |
388
|
0
|
|
|
|
|
0
|
undef $stie; |
389
|
0
|
|
|
|
|
0
|
untie %cache; |
390
|
|
|
|
|
|
|
# finally create the shmem segments and prefill them |
391
|
0
|
|
|
|
|
0
|
for ($i = 0; $i < @keys; $i++) { |
392
|
0
|
|
|
|
|
0
|
my $baz = ""; |
393
|
0
|
0
|
|
|
|
0
|
unless (eval { $stie = tie $baz, 'IPC::Shareable', $ftoks[$i], { create => 1, mode => 0666, |
|
0
|
|
|
|
|
0
|
|
394
|
|
|
|
|
|
|
size => $args->{'SIndex'}->{$keys[$i]}*1024, |
395
|
|
|
|
|
|
|
exclusive => 0, destroy => 0 } } ) { |
396
|
0
|
|
|
|
|
0
|
warn $@; |
397
|
0
|
|
|
|
|
0
|
return $ret; |
398
|
|
|
|
|
|
|
} |
399
|
0
|
|
|
|
|
0
|
$stie->shlock; |
400
|
0
|
|
|
|
|
0
|
$baz = ""; |
401
|
0
|
|
|
|
|
0
|
$stie->shunlock; |
402
|
0
|
|
|
|
|
0
|
undef $stie; |
403
|
0
|
|
|
|
|
0
|
untie $baz; |
404
|
|
|
|
|
|
|
} |
405
|
|
|
|
|
|
|
|
406
|
0
|
|
|
|
|
0
|
cache_status ($args->{'Base'}, $args->{'ShMem'}); |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
# monitoring tool |
410
|
|
|
|
|
|
|
sub cache_status { |
411
|
1
|
50
|
|
1
|
1
|
20
|
struct ( c_status => { disks => '$', |
412
|
|
|
|
|
|
|
blocksize => '$', |
413
|
|
|
|
|
|
|
keys => '*%', |
414
|
|
|
|
|
|
|
rd_stat => '*%', |
415
|
|
|
|
|
|
|
key_stat => '*%', |
416
|
|
|
|
|
|
|
error => '$', |
417
|
|
|
|
|
|
|
start_disk => '$' |
418
|
|
|
|
|
|
|
} ) unless defined &c_status::new; |
419
|
1
|
|
|
|
|
1498
|
my $stat = new c_status (disks => 0, blocksize => 1024, error => 0); |
420
|
1
|
|
33
|
|
|
64
|
my $rdpath = shift || do { |
421
|
|
|
|
|
|
|
$stat->error("Argument missing"); |
422
|
|
|
|
|
|
|
return $stat; |
423
|
|
|
|
|
|
|
}; |
424
|
1
|
|
|
|
|
2
|
my (%cache, $tie); |
425
|
1
|
|
50
|
|
|
7
|
my $shkey = shift || 'RdLk'; |
426
|
1
|
50
|
|
|
|
2
|
unless (eval { $tie = tie %cache, 'IPC::Shareable', $shkey, { create => 0, destroy => 0, |
|
1
|
|
|
|
|
8
|
|
427
|
|
|
|
|
|
|
exclusive => 0, mode => 0666, |
428
|
|
|
|
|
|
|
size => 65536 } } ) { |
429
|
1
|
|
|
|
|
411
|
$stat->error($@); |
430
|
1
|
|
|
|
|
9
|
return $stat; |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
|
433
|
0
|
|
|
|
|
0
|
$tie->shlock(LOCK_SH); |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
# 1. general: |
436
|
0
|
|
|
|
|
0
|
$stat->disks($cache{__Disks__}); |
437
|
0
|
|
|
|
|
0
|
$stat->blocksize($cache{__BSize__}); |
438
|
0
|
|
|
|
|
0
|
$stat->start_disk($cache{__DStart__}); # new in 0.1.5 |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
# 2. key infos: |
441
|
0
|
|
|
|
|
0
|
my @key; |
442
|
0
|
|
|
|
|
0
|
foreach (keys %cache) { |
443
|
0
|
0
|
|
|
|
0
|
unless (/^__.*__/) { |
444
|
0
|
|
|
|
|
0
|
@key = split /:/, $cache{$_}; |
445
|
0
|
|
|
|
|
0
|
$stat->keys($_, $key[0]); |
446
|
0
|
|
|
|
|
0
|
$stat->key_stat($_, $key[1]); |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
} |
449
|
0
|
|
|
|
|
0
|
$tie->shunlock; |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
# 3. disk infos: |
452
|
0
|
|
|
|
|
0
|
for (my $i = $stat->start_disk; $i < $stat->disks+$stat->start_disk; $i++) { |
453
|
0
|
|
|
|
|
0
|
$stat->rd_stat($i, df($rdpath.$i)); |
454
|
|
|
|
|
|
|
} |
455
|
|
|
|
|
|
|
|
456
|
0
|
|
|
|
|
0
|
undef $tie; |
457
|
0
|
|
|
|
|
0
|
untie %cache; |
458
|
|
|
|
|
|
|
|
459
|
0
|
|
|
|
|
0
|
$stat; |
460
|
|
|
|
|
|
|
} |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
# new in 0.1.6: monitoring tool, pt.2: |
463
|
|
|
|
|
|
|
sub cache_objects { |
464
|
0
|
|
0
|
0
|
1
|
0
|
my $rdpath = shift || die "Argument missing!"; |
465
|
0
|
|
|
|
|
0
|
my (%cache, $tie); |
466
|
0
|
|
0
|
|
|
0
|
my $shkey = shift || 'RdLk'; |
467
|
0
|
0
|
|
|
|
0
|
die $@ unless (eval { $tie = tie %cache, 'IPC::Shareable', $shkey, { create => 0, destroy => 0, |
|
0
|
|
|
|
|
0
|
|
468
|
|
|
|
|
|
|
exclusive => 0, mode => 0666, |
469
|
|
|
|
|
|
|
size => 65536 } } ); |
470
|
0
|
|
|
|
|
0
|
my $res = {}; |
471
|
0
|
|
|
|
|
0
|
my (@key, $idx, $xtie, $obj, @tidx, $ikey, $rd, $id); |
472
|
0
|
|
|
|
|
0
|
foreach $ikey (keys %cache) { |
473
|
0
|
|
|
|
|
0
|
@key = split /:/, $cache{$ikey}; # [0] = cache value, [1] = items on cache, [2] = ftok, [3] = shmemsize |
474
|
0
|
0
|
|
|
|
0
|
unless (eval { $xtie = tie $idx, 'IPC::Shareable', $key[2], { create => 0, destroy => 0, |
|
0
|
|
|
|
|
0
|
|
475
|
|
|
|
|
|
|
exclusive => 0, mode => 0666, |
476
|
|
|
|
|
|
|
size => $key[3]*1024 } } ) { |
477
|
0
|
|
|
|
|
0
|
undef $tie; |
478
|
0
|
|
|
|
|
0
|
untie %cache; |
479
|
0
|
|
|
|
|
0
|
die $@; |
480
|
|
|
|
|
|
|
} |
481
|
0
|
0
|
|
|
|
0
|
unless ($ikey =~ /^__\w+__$/) { |
482
|
0
|
|
|
|
|
0
|
$obj = {}; |
483
|
0
|
|
|
|
|
0
|
@tidx = split /\n/, $idx; |
484
|
0
|
|
|
|
|
0
|
foreach (@tidx) { |
485
|
0
|
|
|
|
|
0
|
($rd, $id) = split /\/\//; |
486
|
0
|
0
|
|
|
|
0
|
$obj->{$rd} = [] unless defined $obj->{$rd}; |
487
|
0
|
|
|
|
|
0
|
push @{$obj->{$rd}}, $id; |
|
0
|
|
|
|
|
0
|
|
488
|
|
|
|
|
|
|
} |
489
|
0
|
|
|
|
|
0
|
$res->{$ikey} = $obj; |
490
|
|
|
|
|
|
|
} |
491
|
0
|
|
|
|
|
0
|
undef $xtie; |
492
|
0
|
|
|
|
|
0
|
untie $idx; |
493
|
|
|
|
|
|
|
} |
494
|
|
|
|
|
|
|
|
495
|
0
|
|
|
|
|
0
|
undef $tie; |
496
|
0
|
|
|
|
|
0
|
untie %cache; |
497
|
0
|
|
|
|
|
0
|
$res; |
498
|
|
|
|
|
|
|
} |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
# remove all system resources related to a cache. |
501
|
|
|
|
|
|
|
sub cache_remove { |
502
|
1
|
50
|
|
1
|
1
|
17
|
if ($<) { |
503
|
0
|
|
|
|
|
0
|
warn "You must be root to remove a cache"; |
504
|
0
|
|
|
|
|
0
|
return 0; |
505
|
|
|
|
|
|
|
} |
506
|
|
|
|
|
|
|
|
507
|
1
|
|
33
|
|
|
4
|
my $rdpath = shift || do { |
508
|
|
|
|
|
|
|
warn "Argument missing"; |
509
|
|
|
|
|
|
|
return 0; |
510
|
|
|
|
|
|
|
}; |
511
|
1
|
|
|
|
|
2
|
my (%cache, $tie); |
512
|
1
|
|
50
|
|
|
5
|
my $shkey = shift || 'RdLk'; |
513
|
1
|
50
|
|
|
|
2
|
unless (eval { $tie = tie %cache, 'IPC::Shareable', $shkey, { create => 0, destroy => 0, |
|
1
|
|
|
|
|
7
|
|
514
|
|
|
|
|
|
|
exclusive => 0, mode => 0666, |
515
|
|
|
|
|
|
|
size => 65536 } } ) { |
516
|
1
|
|
|
|
|
348
|
warn $@; |
517
|
1
|
|
|
|
|
5
|
return 0; |
518
|
|
|
|
|
|
|
} |
519
|
0
|
|
|
|
|
|
$tie->shlock(LOCK_EX); |
520
|
|
|
|
|
|
|
|
521
|
0
|
|
|
|
|
|
for (my $rd = $cache{__DStart__}; $rd < $cache{__Disks__}+$cache{__DStart__}; $rd++) { |
522
|
0
|
|
|
|
|
|
system "umount $rdpath".$rd; |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
|
525
|
0
|
|
|
|
|
|
foreach (keys %cache) { |
526
|
0
|
0
|
|
|
|
|
next if /^__.*__$/; |
527
|
0
|
|
|
|
|
|
my (@key, $ttie, $idx); |
528
|
0
|
|
|
|
|
|
@key = split /:/, $cache{$_}; |
529
|
0
|
0
|
|
|
|
|
unless (eval { $ttie = tie $idx, 'IPC::Shareable', $key[2], { create => 0, destroy => 0, |
|
0
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
exclusive => 0, mode => 0666, |
531
|
|
|
|
|
|
|
size => $key[3]*1024 } } ) { |
532
|
0
|
|
|
|
|
|
warn $@; |
533
|
0
|
|
|
|
|
|
return 0; |
534
|
|
|
|
|
|
|
} |
535
|
0
|
|
|
|
|
|
$ttie->remove; |
536
|
|
|
|
|
|
|
} |
537
|
0
|
|
|
|
|
|
$tie->remove; |
538
|
0
|
|
|
|
|
|
1; |
539
|
|
|
|
|
|
|
} |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
1; |