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