1CHI::Driver::DevelopmenUts(e3r)Contributed Perl DocumentCaHtIi:o:nDriver::Development(3)
2
3
4
6 CHI::Driver::Development - Manual for developing new CHI drivers
7
9 version 0.60
10
12 package CHI::Driver::MyDriver;
13 use Moo;
14 use strict;
15 use warnings;
16
17 extends 'CHI::Driver';
18
19 has ...;
20
21 sub fetch {
22 my ( $self, $key ) = @_;
23
24 }
25
26 sub store {
27 my ( $self, $key, $data[, $expires_in] ) = @_;
28
29 }
30
31 sub remove {
32 my ( $self, $key ) = @_;
33
34 }
35
36 sub clear {
37 my ($self) = @_;
38
39 }
40
41 sub get_keys {
42 my ($self) = @_;
43
44 }
45
46 sub get_namespaces {
47 my ($self) = @_;
48
49 }
50
52 This document describes how to implement a new CHI driver.
53
54 The easiest way to start is to look at existing drivers, such as
55 CHI::Driver::Memory and CHI::Driver::FastMmap.
56
58 If you are going to publicly release your driver, call it
59 'CHI::Driver::something' so that users can create it with
60
61 CHI->new(driver => 'I<something>');
62
63 If it's an internal driver, you can call it whatever you like and
64 create it like
65
66 CHI->new(driver => '+My::Internal::CHI::Driver');
67
69 CHI driver classes must be Moo or Moose based to be fully functional,
70 since we use Moose roles to implement various features. For backward
71 compatibility, non-Moo/Moose drivers will still work at a basic level,
72 but you will see an error if using any feature requiring a role.
73
74 All drivers must directly or indirectly extend CHI::Driver.
75
77 All cache handles have an assigned namespace that you can access with
78 "$self->namespace". You should use the namespace to partition your data
79 store. That is, two cache objects with different namespaces should be
80 able to access the same key without any collision.
81
82 Examples:
83
84 · The Memory driver uses a separate sub-hash inside its main memory
85 hash for each namespace.
86
87 · The File driver uses a separate top-level directory for each
88 namespace.
89
90 · The FastMmap driver uses a separate Cache::FastMmap file for each
91 namespace.
92
94 Required methods
95 The following methods have no default implementation, and MUST be
96 defined by your subclass:
97
98 store ( $self, $key, $data[, $expires_in] )
99 Associate $data with $key in the namespace, overwriting any
100 existing entry. Called by "set". $data will contain any necessary
101 metadata, including expiration options, so you can just store it as
102 a single block.
103
104 $expires_in is optionally the number of seconds from now when the
105 entry will expire. This will only be passed if "expires_on_backend"
106 in CHI is set. If your driver does not support expiration, or if
107 you'd rather just let CHI manage expiration, you can ignore this.
108
109 fetch ( $self, $key )
110 Returns the data associated with $key in the namespace. Called by
111 "get". The main CHI::Driver superclass will take care of
112 extracting out metadata like expiration options and determining if
113 the value has expired.
114
115 remove ( $self, $key )
116 Remove the data associated with the $key in the namespace.
117
118 clear ( $self )
119 Remove all data associated with the namespace. (Technically not
120 required, but the default implementation, which iterates over all
121 keys and calls "remove" for each, is very inefficient).
122
123 Overridable methods
124 The following methods have a default implementation, but MAY be
125 overridden by your subclass:
126
127 BUILD ( $self, $options )
128 Define the BUILD method if you want to process any options specific
129 to your driver. This is a standard Moo/Moose feature.
130
131 fetch_multi_hashref ( $keys )
132 Override this if you want to efficiently process multiple fetches.
133 Return a hash reference from keys to fetched data. If a key is not
134 available, it may be left out of the hash or paired with undef. The
135 default method will iterate over $keys and call fetch for each.
136
137 This method is called by get_multi_arrayref and get_multi_hashref.
138
139 store_multi ( $key_data, $options )
140 Override this if you want to efficiently process multiple stores.
141 $key_data is a hash of keys and data that should be stored. The
142 default will iterate over $key_data and call store for each pair.
143
144 This method is called by set_multi.
145
146 Optional methods
147 The following methods have no default implementation, and MAY be
148 defined by your subclass, but are not required for basic cache
149 operations.
150
151 get_keys ( $self )
152 Return all keys in the namespace. It is acceptable to either
153 include or omit expired keys.
154
155 get_namespaces ( $self )
156 Return namespaces associated with the cache. It is acceptable to
157 either include or omit namespaces with no valid keys.
158
160 You can create new discard policies for size aware caches, to choose
161 items to discard when the cache gets full. For example, the Memory
162 driver implements an LRU policy.
163
164 To implement a discard policy foo, define a subroutine
165 discard_policy_foo, which takes a driver object and returns a closure
166 that returns one key each time it is called. The closure should
167 maintain state so that each key is only returned once.
168
169 For example, here's the Memory driver's LRU implementation. It utilizes
170 a hash containing the last used time for each key.
171
172 sub discard_policy_lru {
173 my ($self) = @_;
174
175 my $last_used_time = $self->{metadata_for_namespace}->{last_used_time};
176 my @keys_in_lru_order =
177 sort { $last_used_time->{$a} <=> $last_used_time->{$b} } $self->get_keys;
178 return sub {
179 shift(@keys_in_lru_order);
180 };
181 }
182
183 You can set the default discard policy for your driver by overriding
184 default_discard_policy; otherwise the default is 'arbitrary'.
185
186 sub default_discard_policy { 'lru' }
187
189 CHI has a standard set of unit tests that should be used to ensure your
190 driver is fully implementing the CHI API.
191
192 To use CHI's tests (replacing MyDriver with the name of your driver):
193
194 · Install Test::Class and add it to the build dependencies for your
195 distribution.
196
197 · Add a module called CHI::Driver::MyDriver::t::CHIDriverTests to
198 your distribution containing:
199
200 package CHI::Driver::MyDriver::t::CHIDriverTests;
201 use strict;
202 use warnings;
203 use CHI::Test;
204 use base qw(CHI::t::Driver);
205
206 sub testing_driver_class { 'CHI::Driver::MyDriver' }
207
208 sub new_cache_options {
209 my $self = shift;
210
211 return (
212 $self->SUPER::new_cache_options(),
213
214 # Any necessary CHI->new parameters for your test driver
215 );
216 }
217
218 1;
219
220 · Add a test script called t/CHI-driver-tests.t to your distribution
221 containing:
222
223 #!perl -w
224 use strict;
225 use warnings;
226 use CHI::Driver::MyDriver::t::CHIDriverTests;
227 CHI::Driver::MyDriver::t::CHIDriverTests->runtests;
228
229 · You may need to override other methods in
230 CHI::Driver::MyDriver::t::CHIDriverTests, e.g. to skip tests that
231 do not apply to your driver. See CHI::t::Driver::Memory and
232 CHI::t::Driver::File in this distribution for examples.
233
234 Test cleanup
235 You are responsible for cleaning up your datastore after tests are
236 done. The easiest way to do this is to place your datastore wholly
237 inside a temporary directory, or use a guard to remove it at process
238 end.
239
240 For example, the File, FastMmap, and DBI tests place all data inside a
241 tempdir that is automatically cleaned up at process end.
242
244 CHI
245
247 Jonathan Swartz <swartz@pobox.com>
248
250 This software is copyright (c) 2012 by Jonathan Swartz.
251
252 This is free software; you can redistribute it and/or modify it under
253 the same terms as the Perl 5 programming language system itself.
254
255
256
257perl v5.32.0 2020-07-28 CHI::Driver::Development(3)