13713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick/* 23713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Copyright (C) 2011 The Android Open Source Project 33713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * 43713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Licensed under the Apache License, Version 2.0 (the "License"); 53713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * you may not use this file except in compliance with the License. 63713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * You may obtain a copy of the License at 73713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * 83713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * http://www.apache.org/licenses/LICENSE-2.0 93713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * 103713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Unless required by applicable law or agreed to in writing, software 113713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * distributed under the License is distributed on an "AS IS" BASIS, 123713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * See the License for the specific language governing permissions and 143713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * limitations under the License. 153713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick */ 163713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 173713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickpackage com.android.volley; 183713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1998b742c331fd68b7801853c22f710362603535f0Jorim Jaggiimport android.os.Process; 2098b742c331fd68b7801853c22f710362603535f0Jorim Jaggi 213713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.util.concurrent.BlockingQueue; 223713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 233713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick/** 243713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Provides a thread for performing cache triage on a queue of requests. 253713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * 263713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Requests added to the specified cache queue are resolved from cache. 273713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Any deliverable response is posted back to the caller via a 283713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * {@link ResponseDelivery}. Cache misses and responses that require 293713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * refresh are enqueued on the specified network queue for processing 303713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * by a {@link NetworkDispatcher}. 313713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick */ 323713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick@SuppressWarnings("rawtypes") 333713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickpublic class CacheDispatcher extends Thread { 343713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 353713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick private static final boolean DEBUG = VolleyLog.DEBUG; 363713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 373713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** The queue of requests coming in for triage. */ 383713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick private final BlockingQueue<Request> mCacheQueue; 393713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 403713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** The queue of requests going out to the network. */ 413713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick private final BlockingQueue<Request> mNetworkQueue; 423713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 433713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** The cache to read from. */ 443713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick private final Cache mCache; 453713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 463713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** For posting responses. */ 473713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick private final ResponseDelivery mDelivery; 483713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 493713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** Used for telling us to die. */ 503713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick private volatile boolean mQuit = false; 513713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 523713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** 533713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Creates a new cache triage dispatcher thread. You must call {@link #start()} 543713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * in order to begin processing. 553713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * 563713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * @param cacheQueue Queue of incoming requests for triage 573713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * @param networkQueue Queue to post requests that require network to 583713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * @param cache Cache interface to use for resolution 593713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * @param delivery Delivery interface to use for posting responses 603713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick */ 613713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public CacheDispatcher( 623713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick BlockingQueue<Request> cacheQueue, BlockingQueue<Request> networkQueue, 633713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick Cache cache, ResponseDelivery delivery) { 643713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mCacheQueue = cacheQueue; 653713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mNetworkQueue = networkQueue; 663713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mCache = cache; 673713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mDelivery = delivery; 683713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 693713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 703713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** 713713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Forces this dispatcher to quit immediately. If any requests are still in 723713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * the queue, they are not guaranteed to be processed. 733713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick */ 743713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public void quit() { 753713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mQuit = true; 763713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick interrupt(); 773713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 783713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 793713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick @Override 803713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public void run() { 813713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick if (DEBUG) VolleyLog.v("start new dispatcher"); 8298b742c331fd68b7801853c22f710362603535f0Jorim Jaggi Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 833713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 843713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Make a blocking call to initialize the cache. 853713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mCache.initialize(); 863713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 873713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick while (true) { 883713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick try { 893713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Get a request from the cache triage queue, blocking until 903713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // at least one is available. 913713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick final Request request = mCacheQueue.take(); 923713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick request.addMarker("cache-queue-take"); 933713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 943713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // If the request has been canceled, don't bother dispatching it. 953713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick if (request.isCanceled()) { 963713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick request.finish("cache-discard-canceled"); 973713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick continue; 983713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 993713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1003713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Attempt to retrieve this item from cache. 1013713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick Cache.Entry entry = mCache.get(request.getCacheKey()); 1023713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick if (entry == null) { 1033713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick request.addMarker("cache-miss"); 1043713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Cache miss; send off to the network dispatcher. 1053713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mNetworkQueue.put(request); 1063713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick continue; 1073713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1083713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1093713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // If it is completely expired, just send it to the network. 1103713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick if (entry.isExpired()) { 1113713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick request.addMarker("cache-hit-expired"); 1123713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick request.setCacheEntry(entry); 1133713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mNetworkQueue.put(request); 1143713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick continue; 1153713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1163713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1173713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // We have a cache hit; parse its data for delivery back to the request. 1183713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick request.addMarker("cache-hit"); 1193713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick Response<?> response = request.parseNetworkResponse( 1203713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick new NetworkResponse(entry.data)); 1213713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick request.addMarker("cache-hit-parsed"); 1223713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1233713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick if (!entry.refreshNeeded()) { 1243713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Completely unexpired cache hit. Just deliver the response. 1253713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mDelivery.postResponse(request, response); 1263713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } else { 1273713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Soft-expired cache hit. We can deliver the cached response, 1283713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // but we need to also send the request to the network for 1293713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // refreshing. 1303713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick request.addMarker("cache-hit-refresh-needed"); 1313713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick request.setCacheEntry(entry); 1323713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1333713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Mark the response as intermediate. 1343713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick response.intermediate = true; 1353713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1363713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Post the intermediate response back to the user and have 1373713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // the delivery then forward the request along to the network. 1383713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mDelivery.postResponse(request, response, new Runnable() { 1393713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick @Override 1403713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public void run() { 1413713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick try { 1423713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mNetworkQueue.put(request); 1433713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } catch (InterruptedException e) { 1443713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Not much we can do about this. 1453713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1463713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1473713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick }); 1483713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1493713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1503713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } catch (InterruptedException e) { 1513713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // We may have been interrupted because it was time to quit. 1523713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick if (mQuit) { 1533713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick return; 1543713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1553713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick continue; 1563713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1573713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1583713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1593713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick} 160