00001 /******************************************************************************* 00002 00003 @file CacheInvalidator.d 00004 00005 Copyright (c) 2004 Kris Bell 00006 00007 This software is provided 'as-is', without any express or implied 00008 warranty. In no event will the authors be held liable for damages 00009 of any kind arising from the use of this software. 00010 00011 Permission is hereby granted to anyone to use this software for any 00012 purpose, including commercial applications, and to alter it and/or 00013 redistribute it freely, subject to the following restrictions: 00014 00015 1. The origin of this software must not be misrepresented; you must 00016 not claim that you wrote the original software. If you use this 00017 software in a product, an acknowledgment within documentation of 00018 said product would be appreciated but is not required. 00019 00020 2. Altered source versions must be plainly marked as such, and must 00021 not be misrepresented as being the original software. 00022 00023 3. This notice may not be removed or altered from any distribution 00024 of the source. 00025 00026 4. Derivative works are permitted, but they must carry this notice 00027 in full and credit the original source. 00028 00029 00030 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00031 00032 00033 @version Initial version, July 2004 00034 @author Kris 00035 00036 00037 *******************************************************************************/ 00038 00039 module mango.cluster.CacheInvalidator; 00040 00041 private import mango.cache.Payload; 00042 00043 public import mango.cluster.Client; 00044 00045 /******************************************************************************* 00046 00047 Utility class to invalidate specific cache entries across a 00048 network. Any active CacheInvalidatee objects listening upon 00049 the channel specified for this class will "wake up" whenever 00050 the invalidate() method is invoked. 00051 00052 *******************************************************************************/ 00053 00054 class CacheInvalidator : Client 00055 { 00056 private InvalidatorPayload filter; 00057 00058 /*********************************************************************** 00059 00060 Construct an invalidator on the specified channel. Only 00061 those CacheInvalidatee instances configured for the same 00062 channel will be listening to this invalidator. 00063 00064 ***********************************************************************/ 00065 00066 this (ICluster cluster, char[] channel) 00067 in { 00068 assert (channel.length); 00069 } 00070 body 00071 { 00072 super (cluster, channel); 00073 00074 // this is what we'll send as an invalidation notification ... 00075 this.filter = new InvalidatorPayload; 00076 } 00077 00078 /*********************************************************************** 00079 00080 Invalidate all network cache instances on this channel 00081 using the specified key. When 'timeLimit' is specified, 00082 only those cache entries with a time lesser or equal to 00083 that specified will be removed. This is often useful if 00084 you wish to avoid invalidating a cache (local or remote) 00085 that has just been updated; simply pass the time value 00086 of the 'old' IPayload as the argument. 00087 00088 Note that this is asynchronous! An invalidation is just 00089 a request to remove the item within a short time period. 00090 If you need the entry removed synchronously, you should 00091 use the NetworkCache extract() method instead. 00092 00093 ***********************************************************************/ 00094 00095 void invalidate (char[] key, ulong timeLimit = ulong.max) 00096 in { 00097 assert (key.length); 00098 } 00099 body 00100 { 00101 filter.setText (key); 00102 filter.setTimeout (timeLimit); 00103 00104 // broadcast a message across the cluster 00105 getCluster.broadcast (getChannel, filter); 00106 } 00107 } 00108 00109 00110 /******************************************************************************* 00111 00112 *******************************************************************************/ 00113 00114 private class InvalidatorPayload : Payload 00115 { 00116 private char[] text; 00117 private ulong timeout; 00118 00119 private InvalidatorPayload next; 00120 private static InvalidatorPayload freelist; 00121 00122 private import mango.io.PickleRegistry; 00123 00124 /*********************************************************************** 00125 00126 Register this class for pickling, so we can resurrect 00127 instances when they arrive on a network datagram. 00128 00129 ***********************************************************************/ 00130 00131 static this () 00132 { 00133 PickleRegistry.enroll (new InvalidatorPayload); 00134 } 00135 00136 /*********************************************************************** 00137 00138 Allocate a Payload from a list rather than creating a new one 00139 00140 ***********************************************************************/ 00141 00142 synchronized InvalidatorPayload create () 00143 { 00144 InvalidatorPayload s; 00145 00146 if (freelist) 00147 { 00148 s = freelist; 00149 freelist = s.next; 00150 } 00151 else 00152 s = new InvalidatorPayload; 00153 return s; 00154 } 00155 00156 /*********************************************************************** 00157 00158 ***********************************************************************/ 00159 00160 char[] getText () 00161 { 00162 return text; 00163 } 00164 00165 /*********************************************************************** 00166 00167 ***********************************************************************/ 00168 00169 void setText (char[] text) 00170 in { 00171 assert (text.length); 00172 } 00173 body 00174 { 00175 this.text = text; 00176 } 00177 00178 /*********************************************************************** 00179 00180 Set the identifier of the cache that should not be touched 00181 by an invalidation broadcast. This is typically a local 00182 cache on the machine originating the invalidation; without 00183 the ability to guard against local invalidation, the cache 00184 entry that was just added locally would be removed along 00185 with others across the cluster. The alternative would be 00186 to invalidate before addding, but that approach can quickly 00187 become complicated by timing issues. 00188 00189 ***********************************************************************/ 00190 00191 void setTimeout (ulong olderThan) 00192 { 00193 timeout = olderThan; 00194 } 00195 00196 /*********************************************************************** 00197 00198 ***********************************************************************/ 00199 00200 ulong getTimeout () 00201 { 00202 return timeout; 00203 } 00204 00205 /*********************************************************************** 00206 00207 Return this Payload to the free-list 00208 00209 ***********************************************************************/ 00210 00211 synchronized void destroy () 00212 { 00213 next = freelist; 00214 freelist = this; 00215 } 00216 00217 /*********************************************************************** 00218 00219 ***********************************************************************/ 00220 00221 void write (IWriter writer) 00222 { 00223 super.write (writer); 00224 writer.put (timeout).put(text); 00225 } 00226 00227 /*********************************************************************** 00228 00229 Read our attributes, after telling our superclass to do 00230 likewise. The order of this is important with respect to 00231 inheritance, such that a subclass and superclass may be 00232 populated in isolation where appropriate. 00233 00234 Note that we slice our text attribute, rather than copying 00235 it. Since this class is temporal we can forego allocation 00236 of memory, and just map it directly from the input buffer. 00237 00238 ***********************************************************************/ 00239 00240 void read (IReader reader) 00241 { 00242 super.read (reader); 00243 reader.get (timeout).get(text); 00244 } 00245 00246 /*********************************************************************** 00247 00248 ***********************************************************************/ 00249 00250 char[] getGuid () 00251 { 00252 return this.classinfo.name; 00253 } 00254 } 00255 00256