Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "sal/config.h"
21 :
22 : #include "storbios.hxx"
23 :
24 : #include "sal/types.h"
25 : #include "sal/macros.h"
26 : #include "sal/log.hxx"
27 :
28 : #include "rtl/alloc.h"
29 : #include "rtl/ref.hxx"
30 :
31 : #include "osl/diagnose.h"
32 : #include "osl/mutex.hxx"
33 :
34 : #include "store/types.h"
35 : #include "object.hxx"
36 : #include "lockbyte.hxx"
37 : #include "storcach.hxx"
38 :
39 : using namespace store;
40 :
41 : /*========================================================================
42 : *
43 : * OStoreSuperBlock.
44 : *
45 : *======================================================================*/
46 : #define STORE_MAGIC_SUPERBLOCK sal_uInt32(0x484D5343)
47 :
48 158 : struct OStoreSuperBlock
49 : {
50 : typedef OStorePageGuard G;
51 : typedef OStorePageDescriptor D;
52 : typedef OStorePageLink L;
53 :
54 : /** Representation.
55 : */
56 : G m_aGuard;
57 : D m_aDescr;
58 : sal_uInt32 m_nMarked;
59 : L m_aMarked;
60 : sal_uInt32 m_nUnused;
61 : L m_aUnused;
62 :
63 : /** theSize.
64 : */
65 : static const size_t theSize = sizeof(G) + sizeof(D) + 2 * (sizeof(L) + sizeof(sal_uInt32));
66 :
67 : /** Construction.
68 : */
69 300 : explicit OStoreSuperBlock (sal_uInt16 nPageSize)
70 : : m_aGuard (STORE_MAGIC_SUPERBLOCK),
71 : m_aDescr (nPageSize, nPageSize, STORE_MINIMUM_PAGESIZE),
72 300 : m_nMarked (store::htonl(0)),
73 : m_aMarked (0),
74 300 : m_nUnused (store::htonl(0)),
75 900 : m_aUnused (0)
76 300 : {}
77 :
78 : /** Comparison.
79 : */
80 1236 : bool operator== (const OStoreSuperBlock & rhs) const
81 : {
82 2472 : return ((m_aGuard == rhs.m_aGuard ) &&
83 2472 : (m_aDescr == rhs.m_aDescr ) &&
84 2472 : (m_nMarked == rhs.m_nMarked) &&
85 2472 : (m_aMarked == rhs.m_aMarked) &&
86 3708 : (m_nUnused == rhs.m_nUnused) &&
87 2472 : (m_aUnused == rhs.m_aUnused) );
88 : }
89 :
90 : /** unused(Count|Head|Insert|Remove|Reset).
91 : */
92 10 : sal_uInt32 unusedCount() const
93 : {
94 10 : return store::ntohl(m_nUnused);
95 : }
96 1236 : const L& unusedHead() const
97 : {
98 1236 : return m_aUnused;
99 : }
100 10 : void unusedInsert (const L& rLink)
101 : {
102 10 : sal_uInt32 nUnused = unusedCount();
103 10 : m_nUnused = store::htonl(nUnused + 1);
104 10 : m_aUnused = rLink;
105 10 : }
106 0 : void unusedRemove (const L& rLink)
107 : {
108 0 : sal_uInt32 nUnused = unusedCount();
109 0 : m_nUnused = store::htonl(nUnused - 1);
110 0 : m_aUnused = rLink;
111 0 : }
112 0 : void unusedReset()
113 : {
114 0 : m_nUnused = store::htonl(0);
115 0 : m_aUnused = L(0);
116 0 : }
117 :
118 : /** guard (external representation).
119 : */
120 158 : void guard()
121 : {
122 158 : sal_uInt32 nCRC32 = 0;
123 158 : nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
124 158 : nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G));
125 158 : m_aGuard.m_nCRC32 = store::htonl(nCRC32);
126 158 : }
127 :
128 : /** verify (external representation).
129 : */
130 2472 : storeError verify() const
131 : {
132 2472 : sal_uInt32 nMagic = store::ntohl(m_aGuard.m_nMagic);
133 2472 : if (nMagic != STORE_MAGIC_SUPERBLOCK)
134 0 : return store_E_WrongFormat;
135 :
136 2472 : sal_uInt32 nCRC32 = 0;
137 2472 : nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
138 2472 : nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G));
139 2472 : if (m_aGuard.m_nCRC32 != store::htonl(nCRC32))
140 0 : return store_E_InvalidChecksum;
141 : else
142 2472 : return store_E_None;
143 : }
144 : };
145 :
146 : /*========================================================================
147 : *
148 : * SuperBlockPage interface.
149 : *
150 : *======================================================================*/
151 : namespace store
152 : {
153 :
154 : struct SuperBlockPage
155 : {
156 : typedef OStoreSuperBlock SuperBlock;
157 :
158 : /** Representation.
159 : */
160 : SuperBlock m_aSuperOne;
161 : SuperBlock m_aSuperTwo;
162 :
163 : /** theSize.
164 : */
165 : static const size_t theSize = 2 * SuperBlock::theSize;
166 : static const sal_uInt16 thePageSize = theSize;
167 : static_assert(STORE_MINIMUM_PAGESIZE >= thePageSize, "must be at least thePageSize");
168 :
169 : /** Allocation.
170 : */
171 2 : static void * operator new (size_t n)
172 : {
173 2 : return rtl_allocateMemory (sal::static_int_cast<sal_Size>(n));
174 : }
175 446 : static void operator delete (void * p)
176 : {
177 446 : rtl_freeMemory (p);
178 446 : }
179 :
180 148 : static void * operator new (SAL_UNUSED_PARAMETER size_t, sal_uInt16 nPageSize)
181 : {
182 148 : return rtl_allocateZeroMemory (sal::static_int_cast<sal_Size>(nPageSize));
183 : }
184 : static void operator delete (void * p, SAL_UNUSED_PARAMETER sal_uInt16)
185 : {
186 : rtl_freeMemory (p);
187 : }
188 :
189 : /** Construction.
190 : */
191 150 : explicit SuperBlockPage (sal_uInt16 nPageSize = thePageSize)
192 : : m_aSuperOne(nPageSize),
193 150 : m_aSuperTwo(nPageSize)
194 150 : {}
195 :
196 : /** save.
197 : */
198 158 : storeError save (OStorePageBIOS & rBIOS, sal_uInt32 nSize = theSize)
199 : {
200 158 : m_aSuperOne.guard();
201 158 : m_aSuperTwo = m_aSuperOne;
202 158 : return rBIOS.write (0, this, nSize);
203 : }
204 :
205 : /** Page allocation.
206 : */
207 : storeError unusedHead (
208 : OStorePageBIOS & rBIOS,
209 : PageData & rPageHead);
210 :
211 : storeError unusedPop (
212 : OStorePageBIOS & rBIOS,
213 : PageData const & rPageHead);
214 :
215 : storeError unusedPush (
216 : OStorePageBIOS & rBIOS,
217 : sal_uInt32 nAddr);
218 :
219 : /** verify (with repair).
220 : */
221 : storeError verify (OStorePageBIOS & rBIOS);
222 : };
223 :
224 : } // namespace store
225 :
226 : /*========================================================================
227 : *
228 : * SuperBlockPage implementation.
229 : *
230 : *======================================================================*/
231 : /*
232 : * unusedHead(): get freelist head (alloc page, step 1).
233 : */
234 1226 : storeError SuperBlockPage::unusedHead (OStorePageBIOS & rBIOS, PageData & rPageHead)
235 : {
236 1226 : storeError eErrCode = verify (rBIOS);
237 1226 : if (eErrCode != store_E_None)
238 0 : return eErrCode;
239 :
240 : // Check freelist head.
241 1226 : OStorePageLink const aListHead (m_aSuperOne.unusedHead());
242 1226 : if (aListHead.location() == 0)
243 : {
244 : // Freelist empty, see SuperBlock::ctor().
245 1226 : rPageHead.location (STORE_PAGE_NULL);
246 1226 : return store_E_None;
247 : }
248 :
249 : // Load PageHead.
250 0 : eErrCode = rBIOS.read (aListHead.location(), &rPageHead, PageData::theSize);
251 0 : if (eErrCode != store_E_None)
252 0 : return eErrCode;
253 :
254 0 : eErrCode = rPageHead.verify (aListHead.location());
255 0 : if (eErrCode != store_E_None)
256 0 : return eErrCode;
257 :
258 : // Verify page is unused.
259 0 : sal_uInt32 const nAddr = rPageHead.m_aUnused.location();
260 0 : if (nAddr == STORE_PAGE_NULL)
261 : {
262 : SAL_WARN("store", "store::SuperBlock::unusedHead(): page not free");
263 :
264 : // Page in use.
265 0 : rPageHead.location (STORE_PAGE_NULL);
266 :
267 : // Recovery: Reset freelist to empty.
268 0 : m_aSuperOne.unusedReset();
269 0 : eErrCode = save (rBIOS);
270 : }
271 0 : return eErrCode;
272 : }
273 :
274 : /*
275 : * unusedPop(): pop freelist head (alloc page, step 2).
276 : */
277 0 : storeError SuperBlockPage::unusedPop (OStorePageBIOS & rBIOS, PageData const & rPageHead)
278 : {
279 0 : sal_uInt32 const nAddr = rPageHead.m_aUnused.location();
280 : OSL_PRECOND(nAddr != STORE_PAGE_NULL, "store::SuperBlock::unusedPop(): page not free");
281 0 : if (nAddr == STORE_PAGE_NULL)
282 0 : return store_E_CantSeek;
283 :
284 : // Pop from FreeList.
285 0 : OStorePageLink const aListHead (nAddr);
286 0 : m_aSuperOne.unusedRemove (aListHead);
287 0 : return save (rBIOS);
288 : }
289 :
290 : /*
291 : * unusedPush(): push new freelist head.
292 : */
293 10 : storeError SuperBlockPage::unusedPush (OStorePageBIOS & rBIOS, sal_uInt32 nAddr)
294 : {
295 10 : storeError eErrCode = verify (rBIOS);
296 10 : if (eErrCode != store_E_None)
297 0 : return eErrCode;
298 :
299 10 : PageData aPageHead;
300 10 : eErrCode = rBIOS.read (nAddr, &aPageHead, PageData::theSize);
301 10 : if (eErrCode != store_E_None)
302 0 : return eErrCode;
303 :
304 10 : eErrCode = aPageHead.verify (nAddr);
305 10 : if (eErrCode != store_E_None)
306 0 : return eErrCode;
307 :
308 10 : aPageHead.m_aUnused = m_aSuperOne.unusedHead();
309 10 : aPageHead.guard (nAddr);
310 :
311 10 : eErrCode = rBIOS.write (nAddr, &aPageHead, PageData::theSize);
312 10 : if (eErrCode != store_E_None)
313 0 : return eErrCode;
314 :
315 10 : OStorePageLink const aListHead (nAddr);
316 10 : m_aSuperOne.unusedInsert(aListHead);
317 10 : return save (rBIOS);
318 : }
319 :
320 : /*
321 : * verify (with repair).
322 : */
323 1236 : storeError SuperBlockPage::verify (OStorePageBIOS & rBIOS)
324 : {
325 : // Verify 1st copy.
326 1236 : storeError eErrCode = m_aSuperOne.verify();
327 1236 : if (eErrCode == store_E_None)
328 : {
329 : // Ok. Verify 2nd copy.
330 1236 : eErrCode = m_aSuperTwo.verify();
331 1236 : if (eErrCode == store_E_None)
332 : {
333 : // Ok. Ensure identical copies (1st copy wins).
334 1236 : if (!(m_aSuperOne == m_aSuperTwo))
335 : {
336 : // Different. Replace 2nd copy with 1st copy.
337 0 : m_aSuperTwo = m_aSuperOne;
338 :
339 : // Write back.
340 0 : if (rBIOS.isWriteable())
341 0 : eErrCode = rBIOS.write (0, this, theSize);
342 : else
343 0 : eErrCode = store_E_None;
344 : }
345 : }
346 : else
347 : {
348 : // Failure. Replace 2nd copy with 1st copy.
349 0 : m_aSuperTwo = m_aSuperOne;
350 :
351 : // Write back.
352 0 : if (rBIOS.isWriteable())
353 0 : eErrCode = rBIOS.write (0, this, theSize);
354 : else
355 0 : eErrCode = store_E_None;
356 : }
357 : }
358 : else
359 : {
360 : // Failure. Verify 2nd copy.
361 0 : eErrCode = m_aSuperTwo.verify();
362 0 : if (eErrCode == store_E_None)
363 : {
364 : // Ok. Replace 1st copy with 2nd copy.
365 0 : m_aSuperOne = m_aSuperTwo;
366 :
367 : // Write back.
368 0 : if (rBIOS.isWriteable())
369 0 : eErrCode = rBIOS.write (0, this, theSize);
370 : else
371 0 : eErrCode = store_E_None;
372 : }
373 : else
374 : {
375 : // Double Failure.
376 : OSL_TRACE("OStoreSuperBlockPage::verify(): double failure.");
377 : }
378 : }
379 :
380 : // Done.
381 1236 : return eErrCode;
382 : }
383 :
384 : /*========================================================================
385 : *
386 : * OStorePageBIOS::Ace implementation.
387 : *
388 : *======================================================================*/
389 150 : OStorePageBIOS::Ace::Ace()
390 150 : : m_next (this), m_prev (this), m_addr (STORE_PAGE_NULL), m_used (0)
391 150 : {}
392 :
393 148 : OStorePageBIOS::Ace::~Ace()
394 : {
395 148 : m_next->m_prev = m_prev, m_prev->m_next = m_next;
396 148 : }
397 :
398 : int
399 279 : SAL_CALL OStorePageBIOS::Ace::constructor (
400 : void * obj, SAL_UNUSED_PARAMETER void * /* arg */)
401 : {
402 279 : Ace * ace = static_cast<Ace*>(obj);
403 279 : ace->m_next = ace->m_prev = ace;
404 279 : return 1;
405 : }
406 :
407 : OStorePageBIOS::Ace *
408 2650 : OStorePageBIOS::Ace::find (OStorePageBIOS::Ace * head, sal_uInt32 addr)
409 : {
410 : OStorePageBIOS::Ace * entry;
411 2732 : for (entry = head->m_next; entry != head; entry = entry->m_next)
412 : {
413 1407 : if (entry->m_addr >= addr)
414 1325 : return entry;
415 : }
416 1325 : return head;
417 : }
418 :
419 : void
420 1325 : OStorePageBIOS::Ace::insert (OStorePageBIOS::Ace * head, OStorePageBIOS::Ace * entry)
421 : {
422 : // insert entry at queue tail (before head).
423 1325 : entry->m_next = head;
424 1325 : entry->m_prev = head->m_prev;
425 1325 : head->m_prev = entry;
426 1325 : entry->m_prev->m_next = entry;
427 1325 : }
428 :
429 : /*========================================================================
430 : *
431 : * OStorePageBIOS::AceCache interface.
432 : *
433 : *======================================================================*/
434 : namespace store
435 : {
436 :
437 : class OStorePageBIOS::AceCache
438 : {
439 : rtl_cache_type * m_ace_cache;
440 :
441 : public:
442 : static AceCache & get();
443 :
444 : OStorePageBIOS::Ace *
445 : create (sal_uInt32 addr, sal_uInt32 used = 1);
446 :
447 : void
448 : destroy (OStorePageBIOS::Ace * ace);
449 :
450 : protected:
451 : AceCache();
452 : ~AceCache();
453 : };
454 :
455 : } // namespace store
456 :
457 : /*========================================================================
458 : *
459 : * OStorePageBIOS::AceCache implementation.
460 : *
461 : *======================================================================*/
462 : extern "C" typedef int (SAL_CALL * ace_constructor_type)(void*,void*);
463 :
464 : OStorePageBIOS::AceCache &
465 2650 : OStorePageBIOS::AceCache::get()
466 : {
467 2650 : static AceCache g_ace_cache;
468 2650 : return g_ace_cache;
469 : }
470 :
471 146 : OStorePageBIOS::AceCache::AceCache()
472 : {
473 : m_ace_cache = rtl_cache_create (
474 : "store_ace_cache",
475 : sizeof (OStorePageBIOS::Ace),
476 : 0, // objalign
477 : reinterpret_cast<ace_constructor_type>( OStorePageBIOS::Ace::constructor),
478 : 0, // destructor,
479 : 0, // reclaim,
480 : 0, // userarg,
481 : 0, // default source,
482 : 0 // flags
483 146 : );
484 146 : }
485 :
486 146 : OStorePageBIOS::AceCache::~AceCache()
487 : {
488 146 : rtl_cache_destroy (m_ace_cache), m_ace_cache = 0;
489 146 : }
490 :
491 : OStorePageBIOS::Ace *
492 1325 : OStorePageBIOS::AceCache::create (sal_uInt32 addr, sal_uInt32 used)
493 : {
494 1325 : Ace * ace = static_cast<Ace*>(rtl_cache_alloc (m_ace_cache));
495 1325 : if (ace != 0)
496 : {
497 : // verify invariant state.
498 : OSL_ASSERT((ace->m_next == ace) && (ace->m_prev == ace));
499 :
500 : // initialize.
501 1325 : ace->m_addr = addr;
502 1325 : ace->m_used = used;
503 : }
504 1325 : return ace;
505 : }
506 :
507 : void
508 1325 : OStorePageBIOS::AceCache::destroy (OStorePageBIOS::Ace * ace)
509 : {
510 1325 : if (ace != 0)
511 : {
512 : // remove from queue (if any).
513 1325 : ace->m_next->m_prev = ace->m_prev, ace->m_prev->m_next = ace->m_next;
514 :
515 : // restore invariant state.
516 1325 : ace->m_next = ace->m_prev = ace;
517 :
518 : // return to cache.
519 1325 : rtl_cache_free (m_ace_cache, ace);
520 : }
521 1325 : }
522 :
523 : /*========================================================================
524 : *
525 : * OStorePageBIOS implementation.
526 : *
527 : *======================================================================*/
528 : /*
529 : * OStorePageBIOS.
530 : */
531 150 : OStorePageBIOS::OStorePageBIOS()
532 : : m_xLockBytes (NULL),
533 : m_pSuper (NULL),
534 150 : m_bWriteable (false)
535 : {
536 150 : }
537 :
538 : /*
539 : * ~OStorePageBIOS.
540 : */
541 296 : OStorePageBIOS::~OStorePageBIOS()
542 : {
543 148 : cleanup_Impl();
544 148 : }
545 :
546 : /*
547 : * initialize.
548 : * Precond: none.
549 : */
550 150 : storeError OStorePageBIOS::initialize (
551 : ILockBytes * pLockBytes,
552 : storeAccessMode eAccessMode,
553 : sal_uInt16 & rnPageSize)
554 : {
555 : // Acquire exclusive access.
556 150 : osl::MutexGuard aGuard (m_aMutex);
557 :
558 : // Initialize.
559 150 : storeError eErrCode = initialize_Impl (pLockBytes, eAccessMode, rnPageSize);
560 150 : if (eErrCode != store_E_None)
561 : {
562 : // Cleanup.
563 2 : cleanup_Impl();
564 : }
565 150 : return eErrCode;
566 : }
567 :
568 : /*
569 : * initialize_Impl.
570 : * Internal: Precond: exclusive access.
571 : */
572 150 : storeError OStorePageBIOS::initialize_Impl (
573 : ILockBytes * pLockBytes,
574 : storeAccessMode eAccessMode,
575 : sal_uInt16 & rnPageSize)
576 : {
577 : // Cleanup.
578 150 : cleanup_Impl();
579 :
580 : // Initialize.
581 150 : m_xLockBytes = pLockBytes;
582 150 : if (!m_xLockBytes.is())
583 0 : return store_E_InvalidParameter;
584 150 : m_bWriteable = (eAccessMode != store_AccessReadOnly);
585 :
586 : // Check access mode.
587 150 : storeError eErrCode = store_E_None;
588 150 : if (eAccessMode != store_AccessCreate)
589 : {
590 : // Load SuperBlock page.
591 2 : if ((m_pSuper = new SuperBlockPage()) == 0)
592 0 : return store_E_OutOfMemory;
593 :
594 2 : eErrCode = read (0, m_pSuper, SuperBlockPage::theSize);
595 2 : if (eErrCode == store_E_None)
596 : {
597 : // Verify SuperBlock page (with repair).
598 0 : eErrCode = m_pSuper->verify (*this);
599 : }
600 : }
601 : else
602 : {
603 : // Truncate to zero length.
604 148 : eErrCode = m_xLockBytes->setSize(0);
605 148 : if (eErrCode != store_E_None)
606 0 : return eErrCode;
607 :
608 : // Mark as not existing.
609 148 : eErrCode = store_E_NotExists;
610 : }
611 :
612 150 : if (eErrCode != store_E_None)
613 : {
614 : // Check reason.
615 150 : if (eErrCode != store_E_NotExists)
616 0 : return eErrCode;
617 :
618 : // Check mode.
619 150 : if (eAccessMode == store_AccessReadOnly)
620 2 : return store_E_NotExists;
621 148 : if (eAccessMode == store_AccessReadWrite)
622 0 : return store_E_NotExists;
623 :
624 : // Check PageSize.
625 148 : if ((STORE_MINIMUM_PAGESIZE > rnPageSize) || (rnPageSize > STORE_MAXIMUM_PAGESIZE))
626 0 : return store_E_InvalidParameter;
627 148 : rnPageSize = ((rnPageSize + STORE_MINIMUM_PAGESIZE - 1) & ~(STORE_MINIMUM_PAGESIZE - 1));
628 :
629 : // Create initial page (w/ SuperBlock).
630 148 : if ((m_pSuper = new(rnPageSize) SuperBlockPage(rnPageSize)) == 0)
631 0 : return store_E_OutOfMemory;
632 148 : eErrCode = m_pSuper->save (*this, rnPageSize);
633 : }
634 148 : if (eErrCode == store_E_None)
635 : {
636 : // Obtain page size.
637 148 : rnPageSize = store::ntohs(m_pSuper->m_aSuperOne.m_aDescr.m_nSize);
638 :
639 : // Create page allocator.
640 148 : eErrCode = m_xLockBytes->initialize (m_xAllocator, rnPageSize);
641 148 : if (eErrCode != store_E_None)
642 0 : return eErrCode;
643 :
644 : // Create page cache.
645 148 : eErrCode = PageCache_createInstance (m_xCache, rnPageSize);
646 : }
647 148 : return eErrCode;
648 : }
649 :
650 : /*
651 : * cleanup_Impl.
652 : * Internal: Precond: exclusive access.
653 : */
654 446 : void OStorePageBIOS::cleanup_Impl()
655 : {
656 : // Check referer count.
657 446 : if (m_ace_head.m_used > 0)
658 : {
659 : // Report remaining referer count.
660 : SAL_INFO("store", "referer count: " << m_ace_head.m_used);
661 0 : for (Ace * ace = m_ace_head.m_next; ace != &m_ace_head; ace = m_ace_head.m_next)
662 : {
663 0 : m_ace_head.m_used -= ace->m_used;
664 0 : AceCache::get().destroy (ace);
665 : }
666 : OSL_ENSURE(m_ace_head.m_used == 0, "store::PageBIOS::cleanup_Impl(): logic error");
667 : }
668 :
669 : // Release SuperBlock page.
670 446 : delete m_pSuper, m_pSuper = 0;
671 :
672 : // Release PageCache.
673 446 : m_xCache.clear();
674 :
675 : // Release PageAllocator.
676 446 : m_xAllocator.clear();
677 :
678 : // Release LockBytes.
679 446 : m_xLockBytes.clear();
680 446 : }
681 :
682 : /*
683 : * read.
684 : * Low Level: Precond: initialized, exclusive access.
685 : */
686 12 : storeError OStorePageBIOS::read (
687 : sal_uInt32 nAddr, void *pData, sal_uInt32 nSize)
688 : {
689 : // Check precond.
690 12 : if (!m_xLockBytes.is())
691 0 : return store_E_InvalidAccess;
692 :
693 : // Read Data.
694 12 : return m_xLockBytes->readAt (nAddr, pData, nSize);
695 : }
696 :
697 : /*
698 : * write.
699 : * Low Level: Precond: initialized, writeable, exclusive access.
700 : */
701 168 : storeError OStorePageBIOS::write (
702 : sal_uInt32 nAddr, const void *pData, sal_uInt32 nSize)
703 : {
704 : // Check precond.
705 168 : if (!m_xLockBytes.is())
706 0 : return store_E_InvalidAccess;
707 168 : if (!m_bWriteable)
708 0 : return store_E_AccessViolation;
709 :
710 : // Write Data.
711 168 : return m_xLockBytes->writeAt (nAddr, pData, nSize);
712 : }
713 :
714 : /*
715 : * acquirePage.
716 : * Precond: initialized.
717 : */
718 1325 : storeError OStorePageBIOS::acquirePage (
719 : const OStorePageDescriptor& rDescr, storeAccessMode eMode)
720 : {
721 : // Acquire exclusive access.
722 1325 : osl::MutexGuard aGuard (m_aMutex);
723 :
724 : // Check precond.
725 1325 : if (!m_xLockBytes.is())
726 0 : return store_E_InvalidAccess;
727 :
728 : // Check access mode.
729 1325 : if (!(m_bWriteable || (eMode == store_AccessReadOnly)))
730 0 : return store_E_AccessViolation;
731 :
732 : // Find access control list entry.
733 1325 : Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr);
734 1325 : if (ace->m_addr == rDescr.m_nAddr)
735 : {
736 : // Acquire existing entry (with ShareDenyWrite).
737 0 : if (eMode == store_AccessReadOnly)
738 0 : ace->m_used += 1;
739 : else
740 0 : return store_E_AccessViolation;
741 : }
742 : else
743 : {
744 : // Insert new entry.
745 1325 : Ace * entry = AceCache::get().create (rDescr.m_nAddr, 1);
746 1325 : if (!entry)
747 0 : return store_E_OutOfMemory;
748 1325 : Ace::insert (ace, entry);
749 : }
750 :
751 : // Increment total referer count and finish.
752 1325 : m_ace_head.m_used += 1;
753 1325 : return store_E_None;
754 : }
755 :
756 : /*
757 : * releasePage.
758 : * Precond: initialized.
759 : */
760 1325 : storeError OStorePageBIOS::releasePage (const OStorePageDescriptor& rDescr)
761 : {
762 : // Acquire exclusive access.
763 1325 : osl::MutexGuard aGuard (m_aMutex);
764 :
765 : // Check precond.
766 1325 : if (!m_xLockBytes.is())
767 0 : return store_E_InvalidAccess;
768 :
769 : // Find access control list entry.
770 1325 : Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr);
771 1325 : if (ace->m_addr != rDescr.m_nAddr)
772 0 : return store_E_NotExists;
773 :
774 : // Release existing entry.
775 1325 : if (ace->m_used > 1)
776 0 : ace->m_used -= 1;
777 : else
778 1325 : AceCache::get().destroy (ace);
779 :
780 : // Decrement total referer count and finish.
781 1325 : m_ace_head.m_used -= 1;
782 1325 : return store_E_None;
783 : }
784 :
785 : /*
786 : * getRefererCount.
787 : * Precond: none.
788 : */
789 0 : sal_uInt32 OStorePageBIOS::getRefererCount()
790 : {
791 : // Acquire exclusive access.
792 0 : osl::MutexGuard aGuard (m_aMutex);
793 :
794 : // Obtain total referer count.
795 0 : return m_ace_head.m_used;
796 : }
797 :
798 : /*
799 : * allocate.
800 : * Precond: initialized, writeable.
801 : */
802 1226 : storeError OStorePageBIOS::allocate (
803 : OStorePageObject& rPage, Allocation eAlloc)
804 : {
805 : // Acquire exclusive access.
806 1226 : osl::MutexGuard aGuard (m_aMutex);
807 :
808 : // Check precond.
809 1226 : if (!m_xLockBytes.is())
810 0 : return store_E_InvalidAccess;
811 1226 : if (!m_bWriteable)
812 0 : return store_E_AccessViolation;
813 :
814 : // Check allocation type.
815 1226 : storeError eErrCode = store_E_None;
816 1226 : if (eAlloc != ALLOCATE_EOF)
817 : {
818 : // Try freelist head.
819 1226 : PageData aPageHead;
820 1226 : eErrCode = m_pSuper->unusedHead (*this, aPageHead);
821 1226 : if (eErrCode != store_E_None)
822 0 : return eErrCode;
823 :
824 1226 : sal_uInt32 const nAddr = aPageHead.location();
825 1226 : if (nAddr != STORE_PAGE_NULL)
826 : {
827 : // Save page.
828 0 : eErrCode = saveObjectAt_Impl (rPage, nAddr);
829 0 : if (eErrCode != store_E_None)
830 0 : return eErrCode;
831 :
832 : // Pop freelist head and finish.
833 0 : return m_pSuper->unusedPop (*this, aPageHead);
834 : }
835 : }
836 :
837 : // Allocate from EOF. Determine current size.
838 1226 : sal_uInt32 nSize = STORE_PAGE_NULL;
839 1226 : eErrCode = m_xLockBytes->getSize (nSize);
840 1226 : if (eErrCode != store_E_None)
841 0 : return eErrCode;
842 :
843 : // Save page at current EOF.
844 1226 : return saveObjectAt_Impl (rPage, nSize);
845 : }
846 :
847 : /*
848 : * free.
849 : * Precond: initialized, writeable.
850 : */
851 10 : storeError OStorePageBIOS::free (sal_uInt32 nAddr)
852 : {
853 : // Acquire exclusive access.
854 10 : osl::MutexGuard aGuard (m_aMutex);
855 :
856 : // Check precond.
857 10 : if (!m_xLockBytes.is())
858 0 : return store_E_InvalidAccess;
859 10 : if (!m_bWriteable)
860 0 : return store_E_AccessViolation;
861 :
862 : // Invalidate cache.
863 10 : (void) m_xCache->removePageAt (nAddr);
864 :
865 : // Push onto freelist.
866 10 : return m_pSuper->unusedPush (*this, nAddr);
867 : }
868 :
869 : /*
870 : * loadObjectAt.
871 : * Precond: initialized, readable.
872 : */
873 556 : storeError OStorePageBIOS::loadObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr)
874 : {
875 : // Acquire exclusive access.
876 556 : osl::MutexGuard aGuard (m_aMutex);
877 :
878 : // Check precond.
879 556 : if (!m_xLockBytes.is())
880 0 : return store_E_InvalidAccess;
881 :
882 556 : return loadObjectAt_Impl (rPage, nAddr);
883 : }
884 :
885 : /*
886 : * loadObjectAt_Impl.
887 : * Internal: Precond: initialized, readable, exclusive access.
888 : */
889 556 : storeError OStorePageBIOS::loadObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr)
890 : {
891 556 : storeError eErrCode = m_xCache->lookupPageAt (rPage.get(), nAddr);
892 556 : if (eErrCode != store_E_NotExists)
893 408 : return eErrCode;
894 :
895 : // Read page.
896 148 : eErrCode = m_xLockBytes->readPageAt (rPage.get(), nAddr);
897 148 : if (eErrCode != store_E_None)
898 148 : return eErrCode;
899 :
900 : // Verify page.
901 0 : eErrCode = rPage.verify (nAddr);
902 0 : if (eErrCode != store_E_None)
903 0 : return eErrCode;
904 :
905 : // Mark page as clean.
906 0 : rPage.clean();
907 :
908 : // Cache page.
909 0 : return m_xCache->insertPageAt (rPage.get(), nAddr);
910 : }
911 :
912 : /*
913 : * saveObjectAt.
914 : * Precond: initialized, writeable.
915 : */
916 1514 : storeError OStorePageBIOS::saveObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr)
917 : {
918 : // Acquire exclusive access.
919 1514 : osl::MutexGuard aGuard (m_aMutex);
920 :
921 : // Check precond.
922 1514 : if (!m_xLockBytes.is())
923 0 : return store_E_InvalidAccess;
924 1514 : if (!m_bWriteable)
925 0 : return store_E_AccessViolation;
926 :
927 : // Save Page.
928 1514 : return saveObjectAt_Impl (rPage, nAddr);
929 : }
930 :
931 : /*
932 : * saveObjectAt_Impl.
933 : * Internal: Precond: initialized, writeable, exclusive access.
934 : */
935 2740 : storeError OStorePageBIOS::saveObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr)
936 : {
937 : // Guard page (incl. set location).
938 2740 : storeError eErrCode = rPage.guard (nAddr);
939 2740 : if (eErrCode != store_E_None)
940 0 : return eErrCode;
941 :
942 : // Write page.
943 2740 : eErrCode = m_xLockBytes->writePageAt(rPage.get(), nAddr);
944 2740 : if (eErrCode != store_E_None)
945 0 : return eErrCode;
946 :
947 : // Mark page as clean.
948 2740 : rPage.clean();
949 :
950 : // Cache page.
951 2740 : return m_xCache->updatePageAt (rPage.get(), nAddr);
952 : }
953 :
954 : /*
955 : * close.
956 : * Precond: none.
957 : */
958 146 : storeError OStorePageBIOS::close()
959 : {
960 : // Acquire exclusive access.
961 146 : osl::MutexGuard aGuard (m_aMutex);
962 :
963 : // Cleanup.
964 146 : cleanup_Impl();
965 :
966 : // Done.
967 146 : return store_E_None;
968 : }
969 :
970 : /*
971 : * flush.
972 : * Precond: initialized.
973 : */
974 2 : storeError OStorePageBIOS::flush()
975 : {
976 : // Acquire exclusive access.
977 2 : osl::MutexGuard aGuard (m_aMutex);
978 :
979 : // Check precond.
980 2 : if (!m_xLockBytes.is())
981 0 : return store_E_InvalidAccess;
982 :
983 : // Flush LockBytes and finish.
984 2 : return m_xLockBytes->flush();
985 : }
986 :
987 : /*
988 : * size.
989 : * Precond: initialized.
990 : */
991 0 : storeError OStorePageBIOS::size (sal_uInt32 &rnSize)
992 : {
993 : // Acquire exclusive access.
994 0 : osl::MutexGuard aGuard (m_aMutex);
995 :
996 : // Initialize [out] param.
997 0 : rnSize = 0;
998 :
999 : // Check precond.
1000 0 : if (!m_xLockBytes.is())
1001 0 : return store_E_InvalidAccess;
1002 :
1003 : // Obtain LockBytes size.
1004 0 : return m_xLockBytes->getSize (rnSize);
1005 : }
1006 :
1007 : /*
1008 : * scanBegin.
1009 : * Precond: initialized.
1010 : */
1011 0 : storeError OStorePageBIOS::scanBegin (
1012 : ScanContext &rCtx, sal_uInt32 nMagic)
1013 : {
1014 : // Acquire exclusive access.
1015 0 : osl::MutexGuard aGuard (m_aMutex);
1016 :
1017 : // Initialize [out] param.
1018 0 : rCtx.m_aDescr = OStorePageDescriptor(0, 0, 0);
1019 0 : rCtx.m_nSize = 0;
1020 0 : rCtx.m_nMagic = nMagic;
1021 :
1022 : // Check precond.
1023 0 : if (!m_xLockBytes.is())
1024 0 : return store_E_InvalidAccess;
1025 :
1026 : // Check SuperBlock page.
1027 0 : storeError eErrCode = m_pSuper->verify (*this);
1028 0 : if (eErrCode != store_E_None)
1029 : {
1030 : // Damaged. Determine page size (NYI).
1031 : OSL_TRACE ("OStorePageBIOS::scanBegin(): damaged.\n");
1032 0 : return eErrCode;
1033 : }
1034 :
1035 : // Setup Context descriptor.
1036 0 : rCtx.m_aDescr = m_pSuper->m_aSuperOne.m_aDescr;
1037 0 : rCtx.m_aDescr.m_nSize = store::ntohs(rCtx.m_aDescr.m_nSize);
1038 0 : rCtx.m_aDescr.m_nAddr = rCtx.m_aDescr.m_nSize;
1039 :
1040 : // Setup Context size.
1041 0 : eErrCode = size (rCtx.m_nSize);
1042 0 : if (eErrCode != store_E_None)
1043 0 : rCtx.m_nSize = ((sal_uInt32)(~0));
1044 :
1045 : // Done.
1046 0 : return store_E_None;
1047 : }
1048 :
1049 : /*
1050 : * scanNext.
1051 : * Precond: initialized.
1052 : */
1053 0 : storeError OStorePageBIOS::scanNext (
1054 : ScanContext &rCtx, OStorePageObject &rPage)
1055 : {
1056 : // Acquire exclusive access.
1057 0 : osl::MutexGuard aGuard (m_aMutex);
1058 :
1059 : // Check precond.
1060 0 : if (!m_xLockBytes.is())
1061 0 : return store_E_InvalidAccess;
1062 :
1063 : // Setup PageHead.
1064 0 : PageData aPageHead;
1065 :
1066 : // Check context.
1067 0 : while (rCtx.isValid())
1068 : {
1069 : // Assign next location.
1070 0 : sal_uInt32 nAddr = rCtx.m_aDescr.m_nAddr;
1071 0 : rCtx.m_aDescr.m_nAddr += rCtx.m_aDescr.m_nSize;
1072 :
1073 : // Read PageHead.
1074 0 : storeError eErrCode = read (nAddr, &aPageHead, PageData::theSize);
1075 0 : if (eErrCode != store_E_None)
1076 0 : continue;
1077 :
1078 : // Verify PageHead.
1079 0 : eErrCode = aPageHead.verify (nAddr);
1080 0 : if (eErrCode != store_E_None)
1081 0 : continue;
1082 :
1083 : // Check PageHead Magic number.
1084 0 : if (aPageHead.m_aGuard.m_nMagic != rCtx.m_nMagic)
1085 0 : continue;
1086 :
1087 : // Check PageHead Unused link.
1088 0 : if (aPageHead.m_aUnused.m_nAddr != STORE_PAGE_NULL)
1089 0 : continue;
1090 :
1091 : // Load page.
1092 0 : eErrCode = loadObjectAt_Impl (rPage, nAddr);
1093 0 : if (eErrCode != store_E_None)
1094 0 : continue;
1095 :
1096 : // Deliver page.
1097 0 : return store_E_None;
1098 : }
1099 :
1100 : // Done.
1101 0 : return store_E_CantSeek;
1102 : }
1103 :
1104 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|