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