Bug 594821 - Trigger a sync paint on intial window show. r=roc, a=final.
[mozilla-central.git] / netwerk / cache / nsDiskCacheBinding.cpp
blobc5be5aada077fd07c92d2f9a8fceecff690ff687
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is nsDiskCacheBinding.cpp, released
17 * May 10, 2001.
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 2001
22 * the Initial Developer. All Rights Reserved.
24 * Contributor(s):
25 * Patrick C. Beard <beard@netscape.com>
26 * Gordon Sheridan <gordon@netscape.com>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either the GNU General Public License Version 2 or later (the "GPL"), or
30 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
42 #include <limits.h>
44 #include "nscore.h"
45 #include "nsDiskCacheBinding.h"
49 /******************************************************************************
50 * static hash table callback functions
52 *****************************************************************************/
53 #ifdef XP_MAC
54 #pragma mark -
55 #pragma mark HASHTABLE CALLBACKS
56 #endif
58 struct HashTableEntry : PLDHashEntryHdr {
59 nsDiskCacheBinding * mBinding;
63 static PLDHashNumber
64 HashKey( PLDHashTable *table, const void *key)
66 return (PLDHashNumber) NS_PTR_TO_INT32(key);
70 static PRBool
71 MatchEntry(PLDHashTable * /* table */,
72 const PLDHashEntryHdr * header,
73 const void * key)
75 HashTableEntry * hashEntry = (HashTableEntry *) header;
76 return (hashEntry->mBinding->mRecord.HashNumber() == (PLDHashNumber) NS_PTR_TO_INT32(key));
79 static void
80 MoveEntry(PLDHashTable * /* table */,
81 const PLDHashEntryHdr * src,
82 PLDHashEntryHdr * dst)
84 ((HashTableEntry *)dst)->mBinding = ((HashTableEntry *)src)->mBinding;
88 static void
89 ClearEntry(PLDHashTable * /* table */,
90 PLDHashEntryHdr * header)
92 ((HashTableEntry *)header)->mBinding = nsnull;
96 /******************************************************************************
97 * Utility Functions
98 *****************************************************************************/
99 #ifdef XP_MAC
100 #pragma mark -
101 #pragma mark DISK CACHE BINDERY
102 #endif
104 nsDiskCacheBinding *
105 GetCacheEntryBinding(nsCacheEntry * entry)
107 return (nsDiskCacheBinding *) entry->Data();
111 /******************************************************************************
112 * nsDiskCacheBinding
113 *****************************************************************************/
115 NS_IMPL_THREADSAFE_ISUPPORTS0(nsDiskCacheBinding)
117 nsDiskCacheBinding::nsDiskCacheBinding(nsCacheEntry* entry, nsDiskCacheRecord * record)
118 : mCacheEntry(entry)
119 , mStreamIO(nsnull)
121 NS_ASSERTION(record->ValidRecord(), "bad record");
122 PR_INIT_CLIST(this);
123 mRecord = *record;
124 mDoomed = entry->IsDoomed();
125 mGeneration = record->Generation(); // 0 == uninitialized, or data & meta using block files
128 nsDiskCacheBinding::~nsDiskCacheBinding()
130 NS_ASSERTION(PR_CLIST_IS_EMPTY(this), "binding deleted while still on list");
131 if (!PR_CLIST_IS_EMPTY(this))
132 PR_REMOVE_LINK(this); // XXX why are we still on a list?
134 // sever streamIO/binding link
135 if (mStreamIO) {
136 mStreamIO->ClearBinding();
137 NS_RELEASE(mStreamIO);
141 nsresult
142 nsDiskCacheBinding::EnsureStreamIO()
144 if (!mStreamIO) {
145 mStreamIO = new nsDiskCacheStreamIO(this);
146 if (!mStreamIO) return NS_ERROR_OUT_OF_MEMORY;
147 NS_ADDREF(mStreamIO);
149 return NS_OK;
153 /******************************************************************************
154 * nsDiskCacheBindery
156 * Keeps track of bound disk cache entries to detect for collisions.
158 *****************************************************************************/
160 PLDHashTableOps nsDiskCacheBindery::ops =
162 PL_DHashAllocTable,
163 PL_DHashFreeTable,
164 HashKey,
165 MatchEntry,
166 MoveEntry,
167 ClearEntry,
168 PL_DHashFinalizeStub
172 nsDiskCacheBindery::nsDiskCacheBindery()
173 : initialized(PR_FALSE)
178 nsDiskCacheBindery::~nsDiskCacheBindery()
180 Reset();
184 nsresult
185 nsDiskCacheBindery::Init()
187 nsresult rv = NS_OK;
188 initialized = PL_DHashTableInit(&table, &ops, nsnull, sizeof(HashTableEntry), 0);
190 if (!initialized) rv = NS_ERROR_OUT_OF_MEMORY;
192 return rv;
195 void
196 nsDiskCacheBindery::Reset()
198 if (initialized) {
199 PL_DHashTableFinish(&table);
200 initialized = PR_FALSE;
205 nsDiskCacheBinding *
206 nsDiskCacheBindery::CreateBinding(nsCacheEntry * entry,
207 nsDiskCacheRecord * record)
209 NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
210 nsCOMPtr<nsISupports> data = entry->Data();
211 if (data) {
212 NS_ERROR("cache entry already has bind data");
213 return nsnull;
216 nsDiskCacheBinding * binding = new nsDiskCacheBinding(entry, record);
217 if (!binding) return nsnull;
219 // give ownership of the binding to the entry
220 entry->SetData(binding);
222 // add binding to collision detection system
223 nsresult rv = AddBinding(binding);
224 if (NS_FAILED(rv)) {
225 entry->SetData(nsnull);
226 return nsnull;
229 return binding;
234 * FindActiveEntry : to find active colliding entry so we can doom it
236 nsDiskCacheBinding *
237 nsDiskCacheBindery::FindActiveBinding(PRUint32 hashNumber)
239 NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
240 // find hash entry for key
241 HashTableEntry * hashEntry;
242 hashEntry = (HashTableEntry *) PL_DHashTableOperate(&table, (void*) hashNumber, PL_DHASH_LOOKUP);
243 if (PL_DHASH_ENTRY_IS_FREE(hashEntry)) return nsnull;
245 // walk list looking for active entry
246 NS_ASSERTION(hashEntry->mBinding, "hash entry left with no binding");
247 nsDiskCacheBinding * binding = hashEntry->mBinding;
248 while (binding->mCacheEntry->IsDoomed()) {
249 binding = (nsDiskCacheBinding *)PR_NEXT_LINK(binding);
250 if (binding == hashEntry->mBinding) return nsnull;
252 return binding;
257 * AddBinding
259 * Called from FindEntry() if we read an entry off of disk
260 * - it may already have a generation number
261 * - a generation number conflict is an error
263 * Called from BindEntry()
264 * - a generation number needs to be assigned
266 nsresult
267 nsDiskCacheBindery::AddBinding(nsDiskCacheBinding * binding)
269 NS_ENSURE_ARG_POINTER(binding);
270 NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
272 // find hash entry for key
273 HashTableEntry * hashEntry;
274 hashEntry = (HashTableEntry *) PL_DHashTableOperate(&table,
275 (void*) binding->mRecord.HashNumber(),
276 PL_DHASH_ADD);
277 if (!hashEntry) return NS_ERROR_OUT_OF_MEMORY;
279 if (hashEntry->mBinding == nsnull) {
280 hashEntry->mBinding = binding;
281 if (binding->mGeneration == 0)
282 binding->mGeneration = 1; // if generation uninitialized, set it to 1
284 return NS_OK;
288 // insert binding in generation order
289 nsDiskCacheBinding * p = hashEntry->mBinding;
290 PRBool calcGeneration = (binding->mGeneration == 0); // do we need to calculate generation?
291 if (calcGeneration) binding->mGeneration = 1; // initialize to 1 if uninitialized
292 while (1) {
294 if (binding->mGeneration < p->mGeneration) {
295 // here we are
296 PR_INSERT_BEFORE(binding, p);
297 if (hashEntry->mBinding == p)
298 hashEntry->mBinding = binding;
299 break;
302 if (binding->mGeneration == p->mGeneration) {
303 if (calcGeneration) ++binding->mGeneration; // try the next generation
304 else {
305 NS_ERROR("### disk cache: generations collide!");
306 return NS_ERROR_UNEXPECTED;
310 p = (nsDiskCacheBinding *)PR_NEXT_LINK(p);
311 if (p == hashEntry->mBinding) {
312 // end of line: insert here or die
313 p = (nsDiskCacheBinding *)PR_PREV_LINK(p); // back up and check generation
314 if (p->mGeneration == 255) {
315 NS_WARNING("### disk cache: generation capacity at full");
316 return NS_ERROR_UNEXPECTED;
318 PR_INSERT_BEFORE(binding, hashEntry->mBinding);
319 break;
322 return NS_OK;
327 * RemoveBinding : remove binding from collision detection on deactivation
329 void
330 nsDiskCacheBindery::RemoveBinding(nsDiskCacheBinding * binding)
332 NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
333 if (!initialized) return;
335 HashTableEntry * hashEntry;
336 void * key = (void *)binding->mRecord.HashNumber();
338 hashEntry = (HashTableEntry*) PL_DHashTableOperate(&table,
339 (void*) key,
340 PL_DHASH_LOOKUP);
341 if (!PL_DHASH_ENTRY_IS_BUSY(hashEntry)) {
342 NS_WARNING("### disk cache: binding not in hashtable!");
343 return;
346 if (binding == hashEntry->mBinding) {
347 if (PR_CLIST_IS_EMPTY(binding)) {
348 // remove this hash entry
349 (void) PL_DHashTableOperate(&table,
350 (void*) binding->mRecord.HashNumber(),
351 PL_DHASH_REMOVE);
352 return;
354 } else {
355 // promote next binding to head, and unlink this binding
356 hashEntry->mBinding = (nsDiskCacheBinding *)PR_NEXT_LINK(binding);
359 PR_REMOVE_AND_INIT_LINK(binding);
364 * ActiveBinding : PLDHashTable enumerate function to verify active bindings
367 PLDHashOperator
368 ActiveBinding(PLDHashTable * table,
369 PLDHashEntryHdr * hdr,
370 PRUint32 number,
371 void * arg)
373 nsDiskCacheBinding * binding = ((HashTableEntry *)hdr)->mBinding;
374 NS_ASSERTION(binding, "### disk cache binding = nsnull!");
376 nsDiskCacheBinding * head = binding;
377 do {
378 if (binding->IsActive()) {
379 *((PRBool *)arg) = PR_TRUE;
380 return PL_DHASH_STOP;
383 binding = (nsDiskCacheBinding *)PR_NEXT_LINK(binding);
384 } while (binding != head);
386 return PL_DHASH_NEXT;
391 * ActiveBindings : return PR_TRUE if any bindings have open descriptors
393 PRBool
394 nsDiskCacheBindery::ActiveBindings()
396 NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
397 if (!initialized) return PR_FALSE;
399 PRBool activeBinding = PR_FALSE;
400 PL_DHashTableEnumerate(&table, ActiveBinding, &activeBinding);
402 return activeBinding;