Recent Posts

    Authors

    Published

    Tag Cloud

    301 302 404 accessibility accounts ACLs advertising aggregation Agile Analytics android APP Article attachments awards backup BCM beta browser business continuity Calendar case-study categories Chrome citigroup cms codes coding standards Complaints contact management software control panel crm CSS customer management software customer relationship system customize database DataModel DDoS demo design designer device compatibility difference distribute a published article via email DND DNS documents drag & drop Editor email EOL erp event Excel featured feeds file manager file sharing file volume Firefox Firewall HA hack Handlebar how-to HTML HTML5 HTTP HTTPS iCal IE Instructions intranet iOS iPad Java JavaScript JDBC JDK Jenkins Job Track Journal JSON JVM landing-page launcher layered database layout logging login mac marketing menu meta Microsoft Outlook mobile module modules mustache navigation NTLM offline page painter password passwords PCI policy poll pricing privacy PROXY publish publisher publsher PWA redirect Redundancy release release-notes Report Tool Reports Responsive ReST RESTFul Rich text RSS Safari sandbox sanity schedule scrum search security SEO sessions setup shipping site builder source spell SQL Injection SSL SSO standards store stSoftware support survey Swagger Task template testimonial Threads timezone tinyMCE Transaction Search trigger twitter twitter bootstrap Ubuntu unit tests unsubscribe URL validation WC3 AAA web folders web services webdav windows 8 wizard workflow WYSIWYG XLS XLST XML XPath XSS

    Multi-Threads: secondary cache design

    Handling race conditions in secondary cache.

     

    1 /*
    2 * Copyright (c) 2013 ASP Converters pty ltd 3 * 4 * www.aspconverters.com.au. 5 * 6 * All Rights Reserved. 7 * 8 * This software is the proprietary information of 9 * ASP Converters Pty Ltd. 10 * Use is subject to license terms. 11 */ 12 import com.aspc.DBObj.*; 13 import com.aspc.DBObj.Listeners.*; 14 15 /** 16 * Use a secondary cache to fetch a "Thing". We are in a multi-machine / multi-processor / 17 * multi-user / multi-threaded environment. Records can and do change at any time from one 18 * line to the next. A few points to look out for:- 19 * 20 * 1) All work must be done with local variables so that we don"t get Null 21 * Pointer Exceptions when the cache is cleared while we are in this method. 22 * 23 * 2) Threads can take their copies of object variables which are only flushed/sync"d when 24 * synchronized is called on the object. 25 * 26 * 3) Database queries etc. can take a while to run (specially if the query returns multiple rows) 27 * a record in the result set maybe changed and a message sent/clear cache called before the 28 * result is returned. This case must be handled ( it happens a lot with bulk records) 29 * 30 * 4) Synchronizing the method synchronizes the whole Object. So for complex objects like Company 31 * or DBClass which may have many secondary caches we would be blocking a fetch of something 32 * that is in memory due to a fetch of something else that is not. 34 * 5) Having complex logic within the synchronized block which calls other objects with 35 * synchronized blocks it is easy to cause Java deadlocks. A deadlock within Java will NEVER 36 * return unlike a normal database deadlock. 37 */ 38 public class Bits extends DBObject implements DependanceListener, ReloadEventListener 39 { 40 /** 41 * Std. DBObject constructor. 42 * 43 * @param def The class of this object 44 * @param dataSource The datasource for this object 45 * @throws Exception A serious problem occurred 46 */ 47 public Bits(DBClass def, DataSource dataSource) throws Exception 48 { 49 super( def, dataSource); 50 } 51 52 /** 53 * Sample secondary cache. 54 * 55 * Step 1. 56 * Enter a synchronized block so that we see a clean version of cache of "Thing" and the cache 57 * of thing is prevented while we are within this block. 58 * 59 * Step 2. 60 * If the cache handle is null then create a new handle and set the local copy. If any 61 * clear cache events are now called it"ll clear the handle and the next call will reload the 62 * cache but this call will continue with the local handle. 63 * 64 * Step 3. 65 * If what the handle points to is null then do the Slow search and set the local handle. 66 * There is some question on whether we should sync the setting of the local handle, I 67 * believe not as another thread not getting the new value (which is flushed fairly frequently) 68 * would just result in another search. If the object"s version of the handle hasn't been 69 * cleared i.e. same as the local version it is now set. 70 * 71 * Step 4. 72 * Return the value of the local handle which will never be null. 73 */ 74 public Thing getCacheThing() throws Exception 75 { 76 Thing holder[] = null; 77 78 // OPTIONAL A: Safer if sync block is here 79 synchronized( this)// Step 1. 80 { 81 holder = cacheThing; 82 83 if( holder == null) 84 { 85 // OPTIONAL B: Faster if the sync block is here. ( must have A or B) 86 holder = new Thing[1]; 87 88 cacheThing=holder; // Step 2 89 } 90 } 91 92 if( holder[0] == null) // Step 3. 93 { 94 DBQuery q = new DBQuery( Thing.DBCLASS_NAME, getDS()); 95 96 q.addClause( /* A complex/slow search criteria */); 97 98 DBObject obj = q.findOne(); 99 // Enter a new synchronized block to prevent reordering of instructions 100 synchronized( this) 101 { 102 holder[0] = obj; 103 } 104 } 105 106 return holder[0]; // Step 4. 107 } 108 109 /** 110 * A dependent of Bits has been added. This may effect the secondary cache so we should clear it. 111 * 112 * @param addedKey The dependent added 113 * @param sourceFieldKey The field that points to this object 114 */ 115 public void eventDependantAdded( GlobalKey addedKey, GlobalKey sourceFieldKey) 116 { 117 clearCache( addedKey); 118 } 119 120 /** 121 * A that we are watching has been changed 122 * 123 * @param obj The DBObject that was reload. 124 */ 125 public void eventReload( DBObject obj ) 126 { 127 clearCache( obj.getGlobalKey()); 128 } 129 130 /** 131 * A dependent of Bits has been removed. This may effect the secondary cache. 132 * 133 * @param removedKey The DBObject was removed. 134 * @param sourceFieldKey The linked field 135 */ 136 public void eventDependantRemoved( GlobalKey removedKey, GlobalKey sourceFieldKey) 137 { 138 clearCache( removedKey); 139 } 140 141 /** 142 * We should only clear the cache if the record changed could have possibly effected the cache. 143 * This method we be called MANY times. So it is cheaper just to clear the cache if in any doubt. 144 * Eg. If you are holding the primary security for this Company and the class of the changed 145 * object is "security" don"t go selecting it here to work out if you should clear it or not. 146 * 147 * This is automatically called by eventDataLoaded() in DBObject which does a programmer check 148 * that you have call the super.clearCache( changedKey); 149 */ 150 protected void clearCache( GlobalKey changedKey) 151 { 152 super.clearCache( changedKey); 153 154 if( /* only clear if the changed object effects the secondary cache */) 155 { 156 synchronized( this)// minimize the time we spend in synchronized blocks 157 { 158 cacheThing = null; 159 } 160 } 161 } 162 163 private Thing[] cacheThing; 164 }