dtinfo subdirectory DtMmdb
[oweals/cde.git] / cde / programs / dtinfo / DtMmdb / storage / page_storage.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*
24  * $XConsortium: page_storage.C /main/8 1996/10/04 10:49:57 drk $
25  *
26  * Copyright (c) 1992 HAL Computer Systems International, Ltd.
27  * All rights reserved.  Unpublished -- rights reserved under
28  * the Copyright Laws of the United States.  USE OF A COPYRIGHT
29  * NOTICE IS PRECAUTIONARY ONLY AND DOES NOT IMPLY PUBLICATION
30  * OR DISCLOSURE.
31  * 
32  * THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION AND TRADE
33  * SECRETS OF HAL COMPUTER SYSTEMS INTERNATIONAL, LTD.  USE,
34  * DISCLOSURE, OR REPRODUCTION IS PROHIBITED WITHOUT THE
35  * PRIOR EXPRESS WRITTEN PERMISSION OF HAL COMPUTER SYSTEMS
36  * INTERNATIONAL, LTD.
37  * 
38  *                         RESTRICTED RIGHTS LEGEND
39  * Use, duplication, or disclosure by the Government is subject
40  * to the restrictions as set forth in subparagraph (c)(l)(ii)
41  * of the Rights in Technical Data and Computer Software clause
42  * at DFARS 252.227-7013.
43  *
44  *          HAL COMPUTER SYSTEMS INTERNATIONAL, LTD.
45  *                  1315 Dell Avenue
46  *                  Campbell, CA  95008
47  * 
48  */
49
50
51 #include "storage/page.h"
52 #include "storage/page_storage.h"
53 #include "storage/version.h"
54 #include "utility/db_version.h"
55
56 #define db_type "MMDB"
57 #define db_type_sz strlen(db_type)
58
59 #define db_order_sz sizeof(char)
60
61 int page_storage::dv_sz = 0;
62 int page_storage::abs_off = 0;
63
64 #ifndef C_API
65 page_cache_global_part page_storage::f_global_pcache;
66 #else
67 page_cache_global_part* page_storage::f_global_pcache_ptr = 0;
68 #endif
69
70
71 static char* db_version = 0;
72 static char* data_version = 0;
73
74 str_index_record_t::str_index_record_t(int offset, mmdb_pos_t lc) 
75 : str_offset(offset), loc(lc)
76 {
77 }
78
79 void delete_str_index_record(const void* t)
80 {
81    delete ((str_index_record_t*)t);
82 }
83
84 extern void_ptr_array g_store_array;
85 extern Boolean g_transaction_on;
86
87 //////////////////////////////
88 //
89 //////////////////////////////
90 store_trans::store_trans(char* p, char* n, int psz) : 
91 path(p), name(n), status(DISABLED), 
92 log_store(0), log_index(0), max_pages(0), page_sz(psz)
93 {
94 }
95
96 store_trans::~store_trans()
97 {
98 /*
99 MESSAGE(cerr, "dstr store_trans object");
100 debug(cerr, status);
101 debug(cerr, DISABLED);
102 debug(cerr, int(log_store));
103 */
104
105    if ( status == DISABLED && log_store ) {
106       delete log_store;
107       del_file(form("%s.log", name), path);
108    }
109    delete log_index;
110 }
111
112 void store_trans::init(rep_policy* policy)
113 {
114    if ( log_store == 0 ) {
115       log_store = new unixf_storage(path, form("%s.log", name), policy);
116
117       if ( ! (*log_store) )
118          throw(streamException(log_store -> rdstate()));
119    }
120
121    if ( log_index == 0 ) {
122       log_index = new imp_die;
123    }
124 }
125
126 void store_trans::quit()
127 {
128    if ( log_store )
129       log_store -> truncate(0);
130
131    if ( log_index )
132       log_index -> clean();
133 }
134
135 ///////////////////////////////////
136 // Constructor 
137 ///////////////////////////////////
138 page_storage::page_storage( char* _path, char* _name,
139                             unixf_storage* store, int pg_sz, 
140                             int/*no_pages*/, mmdb_byte_order_t create_order) :  
141         abs_storage(_path, _name, PAGE_STORAGE_CODE),
142         trans_info(page_storage::path, page_storage::name, pg_sz),
143         page_sz(pg_sz), 
144         f_local_pcache(30),
145         v_db_order(create_order), v_buf(0),
146         pagings(0),
147         total_page_access(0)
148 {
149
150 //debug(cerr, my_name());
151 //debug(cerr, (void*)this);
152 //#ifdef C_API
153    if ( dv_sz == 0 ) {
154       dv_sz = db_type_sz + mm_version::version_bytes() + db_order_sz;
155       abs_off = dv_sz;
156    }
157 //#endif
158
159
160    storage_ptr = store;
161
162    int bts = ((unixf_storage*)storage_ptr) -> bytes();
163
164    v_server_order = byte_order();
165 //debug(cerr, v_server_order);
166
167    if ( bts == 0 ) {
168 //////////////////////
169 // empty store file
170 //////////////////////
171
172        if ( db_version == 0 ) {
173           db_version = new char[dv_sz];
174
175           memcpy(db_version, db_type, db_type_sz);
176
177           mm_version x(MAJOR, MINOR);
178
179           x.to_byte_string(db_version+db_type_sz, 
180                            (v_db_order != v_server_order) ? true : false
181                           );
182
183           char z = v_db_order;
184           memcpy(db_version+db_type_sz+mm_version::version_bytes(), 
185                  &z, db_order_sz);
186        } 
187
188        storage_ptr -> updateString( 0, db_version, dv_sz, 0, true);
189
190        v_swap_order = (v_db_order != v_server_order) ? true : false;
191
192    } else {
193 ///////////////////
194 // store exists.
195 ///////////////////
196
197       bts -= abs_off;
198
199       if ( data_version == 0 ) {
200           data_version = new char[dv_sz];
201       }
202
203       storage_ptr -> readString(0, data_version, dv_sz);
204
205 /////////////////////////////////
206 // "MMDB" magic number testing
207 /////////////////////////////////
208       if ( memcmp(data_version, db_type, db_type_sz) != 0 ) {
209          throw(stringException(
210             form("bad magic number. corrupted store %s/%s", _path, _name)
211                               )
212               );
213       }
214
215 ///////////////////////////////
216 // get db byte order
217 ///////////////////////////////
218       char z;
219       memcpy(&z, 
220              data_version + db_type_sz + mm_version::version_bytes(), 
221              db_order_sz
222             );
223       
224       v_db_order = int(z);
225
226       if ( v_db_order != mmdb_big_endian && v_db_order != mmdb_little_endian ) {
227          debug(cerr, v_db_order);
228          throw(stringException(
229               "data is in neither big endian nor little endian format"
230                               ));
231       }
232
233
234 ///////////////////////////////
235 // test version
236 ///////////////////////////////
237       v_swap_order = (v_db_order != v_server_order) ? true : false;
238
239       mm_version dv(data_version+db_type_sz, v_swap_order);
240
241       f_version = dv;
242
243       mm_version cv(MAJOR, MINOR);
244
245       if ( cv < dv ) {
246          cerr << "code major = " << cv.major_version() << "\n";
247          cerr << "code minor = " << cv.minor_version() << "\n";
248          cerr << "data major = " << dv.major_version() << "\n";
249          cerr << "data minor = " << dv.minor_version() << "\n";
250          throw(stringException(
251             form("data and code version mismatch on store %s/%s", _path, _name)
252                               )
253               );
254       }
255
256    }
257
258 //debug(cerr, v_db_order);
259
260
261    total_pages = bts / page_sz;
262
263    f_local_pcache.init_heap(this);
264
265    set_mode(HEALTH, true);
266 }
267
268 /***********************************************************/
269 // Destructor 
270 /***********************************************************/
271 page_storage::~page_storage()
272 {
273 //MESSAGE(cerr, "dstr page_storage");
274 //debug(cerr, my_name());
275
276    delete v_buf;
277    delete storage_ptr;
278
279    delete data_version;
280    data_version = 0;
281
282    delete db_version;
283    db_version = 0;
284
285    f_local_pcache.quit_heap(this);
286
287    f_global_pcache.remove_pages(this);
288
289 /*
290 MESSAGE(cerr, my_name());
291 debug(cerr, total_page_access);
292 debug(cerr, pagings);
293 debug(cerr, float(pagings)/total_page_access);
294 */
295 }
296
297 void page_storage::remove()
298 {
299    storage_ptr -> remove();
300 }
301
302 void page_storage::sync()
303 {
304
305 /*
306 MESSAGE(cerr, "page_storage::sync()");
307 debug(cerr, my_path());
308 debug(cerr, my_name());
309 debug(cerr, pages());
310 debug(cerr, int(this));
311 */
312
313
314   long ind = f_global_pcache.f_replace_policy.first();
315
316   while ( ind != 0 ) {
317      lru_page *p= (lru_page*)(f_global_pcache.f_replace_policy)(ind, ACTIVE);
318      if  ( p -> f_store == this ) 
319         sync( p );
320      f_global_pcache.f_replace_policy.next(ind);
321    }
322
323 //MESSAGE(cerr, "page_storage::sync() done");
324 }
325
326 void page_storage::sync( int page_num )
327 {
328    sync((*this)(page_num, READ));
329 }
330
331 void page_storage::sync( page* p )
332 {
333    if ( p == 0 || p -> page_id() <= 0 ) {
334       throw(stringException("null page pointer"));
335    }
336
337    if ( p -> dirty == true ) {
338
339
340 //cerr << "dirty PAGE swapped out " << p -> page_id();
341 //cerr << " " << my_name() << "\n";
342
343       int offset = ( p -> page_id() - 1 ) * page_sz ;
344
345 #ifdef PORTABLE_DB
346       p -> _swap_order(false);
347 #endif
348
349 //debug(cerr, *p);
350
351 #ifdef DEBUG
352       fprintf(stderr, "purging page at %p size=%d into %s/%s @ %s:%d\n",
353                         p -> page_base(), page_sz,
354                         storage_ptr->my_path(), storage_ptr->my_name(),
355                         __FILE__, __LINE__);
356 #endif
357       storage_ptr -> updateString( abs_off + mmdb_pos_t(offset),
358                                    p -> page_base(),
359                                    page_sz, 0, true
360                                  );
361 #ifdef PORTABLE_DB
362 //////////////////////////////////////////////////////////////
363 // flip back to original. as the server will not quit after
364 // the sync.   
365 //////////////////////////////////////////////////////////////
366       p -> _swap_order(true); 
367 #endif
368
369       p -> dirty = false;
370    }
371 }
372
373 //static Boolean xflag = false;
374 /***********************************************************/
375 // readString(). 
376 /***********************************************************/
377 int 
378 page_storage::readString(mmdb_pos_t loc, char* base, int len, int str_offset)
379 {
380 /*
381 int xstring_ofst = str_offset;
382 int xloc = loc;
383 int xlen = len;
384
385 MESSAGE(cerr, "page_storage: readString");
386 debug(cerr, my_path());
387 debug(cerr, my_name());
388 debug(cerr, loc);
389 debug(cerr, int(base));
390 debug(cerr, len);
391 debug(cerr, str_offset);
392 */
393
394    buffer in_cache(0);
395    in_cache.set_chunk(base, len);
396
397    spointer_t *slot_info;
398
399    while ( len > 0 ) {
400
401       if ( loc == 0 ) {
402          throw(stringException("damaged store."));
403       }
404
405       int page_num  = PAGE_ID( loc, page_sz );
406       int page_slot  = PAGE_IDX( loc, page_sz );
407
408 //debug(cerr, page_num);
409 //debug(cerr, page_slot);
410  
411       page *y = (*this)(page_num, READ);
412
413       slot_info = y -> get_spointer(page_slot);
414
415       int str_leng = slot_info -> string_leng();
416       loc  = slot_info -> forward_ptr();
417 /*
418 MESSAGE(cerr, "slot info:");
419 debug(cerr, str_leng);
420 debug(cerr, loc);
421 debug(cerr, slot_info -> string_ofst());
422 */
423
424       delete slot_info;
425
426       if ( str_offset >= str_leng ) {
427
428           str_offset -= str_leng;
429
430       } else {
431           int bytes_read = MIN(len, str_leng - str_offset);
432
433 /*
434 debug(cerr, len);
435 debug(cerr, bytes_read);
436 */
437
438           y -> get( page_slot, in_cache, str_offset, bytes_read );
439
440           len -= bytes_read;
441
442           str_offset = 0;
443       }
444    }
445
446 //MESSAGE(cerr, "page_storage:: readString done");
447
448    return 0;
449 }
450
451 int 
452 page_storage::get_str_ptr(mmdb_pos_t loc, char*& str, 
453                           int& len) 
454 {
455    int page_num  = PAGE_ID( loc, page_sz );
456    int page_slot  = PAGE_IDX( loc, page_sz );
457
458
459 //MESSAGE(cerr, "IN get_str_ptr()");
460 //debug(cerr, my_path());
461 //debug(cerr, my_name());
462 //debug(cerr, page_num);
463 //debug(cerr, page_slot);
464
465
466    page *y = (*this)(page_num, READ);
467
468    spointer_t* slot_info =  y -> get_spointer(page_slot);
469
470 //debug(cerr, int(slot_info -> get_mode(spointer_t::DELETED)));
471 /*
472 if ( page_num == 1 && page_slot == 1 ) {
473 debug(cerr, hex(slot_info -> header.int_view));
474 debug(cerr, hex(slot_info -> header.bit_view.spointer));
475 debug(cerr, hex(slot_info -> header.bit_view.length));
476 debug(cerr, hex(slot_info -> header.bit_view.deleted));
477 debug(cerr, hex(slot_info -> header.bit_view.first_recd));
478 debug(cerr, hex(slot_info -> header.bit_view.updated));
479 debug(cerr, hex(slot_info -> header.bit_view.is_object));
480 }
481 */
482
483
484    if ( slot_info -> get_mode(spointer_t::DELETED) == true ) {
485       delete slot_info;
486       throw(stringException("read deleted byte string"));
487    }
488
489    delete slot_info;
490    y -> get_str_ptr(page_slot, str, len);
491
492    return 0;
493 }
494
495 int page_storage::insertString(mmdb_pos_t& loc, const char* base, int len, Boolean flush_opt)
496 {
497 /*
498 cerr << "insert: len="  << len << "\n";
499 int u3 = len;
500 */
501
502
503 #ifdef STORAGE_DEBUG
504 MESSAGE(cerr, "page_storage insertString");
505 debug(cerr, len);
506 #endif
507
508    buffer temp_buf(0); 
509    int page_num = 0;
510    int page_oft = 0;
511
512    int str_offset = len;
513    int sec_len;
514
515    Boolean first_recd = true;
516    Boolean new_page;
517
518    while ( str_offset > 0 ) {
519
520       loc = (page_num != 0 ) ? 
521              FORM_PAGE_REF(page_num, page_oft, page_sz) :
522              0;
523
524       fbytes_t* v = f_local_pcache.find_host_page(this, new_page) ;
525       page_num = v -> page_num;
526
527       page* y = (*this)(page_num, WRITE);
528
529       sec_len = MIN(len, y -> free_bytes());
530
531       str_offset -= sec_len;
532
533
534       temp_buf.set_chunk((char*)(base + str_offset), sec_len);
535       temp_buf.set_content_sz(sec_len);
536
537       y -> put( page_oft, temp_buf );
538
539       spointer_t *x = y -> get_spointer(page_oft);
540       x -> set_mode(spointer_t::FIRST_RECD, first_recd);
541       x -> set_forward_ptr(loc);
542       delete x;
543
544       v -> free_bytes = y -> free_bytes();
545       f_local_pcache.adjust_heap(v, new_page);
546
547       if ( flush_opt == true ) sync(page_num);
548
549       first_recd = false;
550       len -= sec_len;
551    }
552
553
554 #ifdef STORAGE_DEBUG
555 MESSAGE(cerr, "FINAL LOC COMPONENT");
556 debug(cerr, page_oft);
557 debug(cerr, page_sz);
558 debug(cerr, page_num);
559 #endif
560
561    loc = FORM_PAGE_REF(page_num, page_oft, page_sz);
562
563
564
565 /*
566       int u1 = PAGE_ID( loc, page_sz );
567       int u2 = PAGE_IDX( loc, page_sz );
568 cerr << "insert:" << page_num << "." << page_oft << " " << u3 << "\n";
569 */
570
571
572
573    return 0;
574 }
575
576 /***********************************************************/
577 // updateString(). 
578 /***********************************************************/
579 int 
580 page_storage::updateString(mmdb_pos_t loc, const char* base, int len, 
581                            int string_ofst, Boolean flush_opt)
582 {
583 /*
584       int u1 = PAGE_ID( loc, page_sz );
585       int u2 = PAGE_IDX( loc, page_sz );
586 cerr << "update:" << u1 << "." << u2 << " " << len << " " << string_ofst << "\n";
587 */
588
589
590 /*
591 MESSAGE(cerr, "update string");
592 debug(cerr, name);
593 debug(cerr, loc);
594 */
595
596    int page_num =0;
597    int slot_num =0;
598    int offset = 0;
599    page* y = 0;
600    spointer_t *x = 0;
601
602    while ( len > 0 && loc != 0 ) {
603
604       page_num  = PAGE_ID( loc, page_sz );
605       slot_num = PAGE_IDX( loc, page_sz );
606 //debug(cerr, page_num);
607 //debug(cerr, slot_num);
608
609       y = (*this)(page_num, WRITE); 
610
611       x = y -> get_spointer(slot_num);
612
613 /*
614 debug(cerr, x -> forward_ptr());
615 debug(cerr, x -> string_leng());
616 debug(cerr, x -> string_ofst());
617 */
618
619       loc = x -> forward_ptr();
620       int this_len = x -> string_leng();
621       delete x;
622
623       if ( string_ofst >= this_len ) {
624          string_ofst -= this_len;
625          continue;
626       }
627
628       int update_len = MIN(len, this_len - string_ofst);
629
630       buffer sbuf(0);
631       sbuf.set_chunk((char*)(base+offset), update_len);
632       sbuf.set_content_sz(update_len);
633
634       y -> update_slot(slot_num, sbuf, string_ofst);
635
636       if ( flush_opt == true ) sync(page_num);
637
638       string_ofst = 0;
639       offset += update_len;
640       len -= update_len;
641    }
642
643    if ( len > 0 ) {
644
645 //debug(cerr, len);
646 //debug(cerr, offset);
647
648 /*****************************/
649 // the update is an expanding
650 /*****************************/
651       mmdb_pos_t new_loc;
652       insertString(new_loc, base+offset, len, flush_opt) ;
653
654       y = (*this)(page_num, WRITE); 
655       x = y -> get_spointer(slot_num);
656       x -> set_forward_ptr(new_loc);
657       delete x;
658
659       page_num = PAGE_ID( new_loc, page_sz );
660       slot_num = PAGE_IDX( new_loc, page_sz );
661       y = (*this)(page_num, WRITE); 
662       x = y -> get_spointer(slot_num);
663       x -> set_mode(spointer_t::FIRST_RECD, false);
664       delete x;
665
666       y -> dirty = true;
667
668       return 0;
669    }
670
671 //   if ( loc != 0 ) {
672
673 /*****************************/
674 // the update is a shrinking 
675 /*****************************/
676 //      y = (*this)(page_num); 
677 //      x = y -> get_spointer(slot_num);
678 //      x -> set_forward_ptr(0);
679 //      return deleteString(loc);
680 //   }
681
682
683    return 0;
684 }
685
686 /***********************************************************/
687 // deleteString(). 
688 /***********************************************************/
689 int page_storage::deleteString(mmdb_pos_t loc, Boolean flush_opt)
690 {
691    while ( loc != 0 ) {
692       int page_num  = PAGE_ID( loc, page_sz );
693       int slot_num = PAGE_IDX( loc, page_sz );
694 //debug(cerr, page_num);
695 //debug(cerr, slot_num);
696
697       page* y = (*this)(page_num, WRITE); 
698
699       spointer_t *x = y -> get_spointer(slot_num);
700
701       if ( x -> get_mode(spointer_t::DELETED) == true )
702           return 0;
703
704       loc = x -> forward_ptr();
705 //debug(cerr, loc);
706       delete x;
707
708       y -> del_slot(slot_num);
709
710       if ( flush_opt == true ) sync(page_num);
711    }
712
713    return 0;
714 }
715
716 /***********************************************************/
717 // allocate a chunk on a page. 
718 /***********************************************************/
719 int 
720 page_storage::allocString(mmdb_pos_t& loc, int len, char*& string_ptr, int mode)
721 {
722 //MESSAGE(cerr, "AllocString:");
723 //debug(cerr, my_name());
724 //debug(cerr, len);
725
726    if ( len > page_sz ) {
727       MESSAGE(cerr, "allocString(): string too long");
728       throw(boundaryException(0, page_sz, len));
729    }
730
731    Boolean new_page;
732
733    fbytes_t* v = f_local_pcache.find_host_page(this, new_page, len) ;
734
735    page* x = (*this)(v -> page_num, WRITE);
736
737    int slot_num;
738
739    x->alloc_slot(slot_num, len, string_ptr);
740
741    spointer_t* slot_info = x -> get_spointer(slot_num);
742    slot_info -> add_mode(mode);
743    delete slot_info;
744
745
746    v -> free_bytes = x -> free_bytes();
747    f_local_pcache.adjust_heap(v, new_page);
748
749    loc = FORM_PAGE_REF(v -> page_num, slot_num, page_sz);
750
751 #ifdef STORAGE_DEBUG
752 MESSAGE(cerr,  "in allocString(): final params");
753 debug(cerr,  int(x -> dirty));
754 debug(cerr,  page_num);
755 debug(cerr,  slot_num);
756 debug(cerr,  my_name());
757 debug(cerr,  loc);
758 debug(cerr,  int(string_ptr));
759 #endif
760
761
762 // int u1 = PAGE_ID( loc, page_sz );
763 // int u2 = PAGE_IDX( loc, page_sz );
764 // cerr << "Allocated ID=" << u1 << "." << u2 << " " << len << "\n";
765
766    return 0;
767 }
768
769
770 int page_storage::appendString(mmdb_pos_t loc, const char* base, int len, Boolean)
771 {
772 /*
773       int u1 = PAGE_ID( loc, page_sz );
774       int u2 = PAGE_IDX( loc, page_sz );
775 cerr << "append:" << u1 << "." << u2 << " " << len << "\n";
776 */
777
778
779
780    int page_num = 0;
781    int slot_num = 0;
782    page* y;
783    spointer_t *x;
784
785    while ( loc != 0 ) {
786
787       page_num  = PAGE_ID( loc, page_sz );
788       slot_num = PAGE_IDX( loc, page_sz );
789
790       y = (*this)(page_num, READ);
791       x = y -> get_spointer(slot_num);
792
793       loc = x -> forward_ptr();
794       delete x;
795    }
796
797    insertString(loc, base, len) ;
798
799    y = (*this)(page_num, WRITE);
800    x = y -> get_spointer(slot_num);
801    x -> set_forward_ptr(loc);
802    delete x;
803
804    page_num = PAGE_ID( loc, page_sz );
805    slot_num = PAGE_IDX( loc, page_sz );
806    y = (*this)(page_num, WRITE);
807    x = y -> get_spointer(slot_num);
808    x -> set_mode(spointer_t::FIRST_RECD, false);
809    delete x;
810
811    return 0;
812 }
813
814 /***********************************************************/
815 // create new page frame. 
816 /***********************************************************/
817 int page_storage::add_page_frames(int pages)
818 {
819    total_pages += pages;
820
821 //////////////////////////////////////
822 // prepare the new page in the cache
823 //////////////////////////////////////
824    for (int i=1; i<=pages; i++)
825       operator()(total_pages+i-pages, WRITE);
826
827    return 0;
828 }
829
830 /***********************************************************/
831 // return the mmdb_pos_t of the first page. 
832 /***********************************************************/
833 int page_storage::first() const
834 {
835    return ( total_pages > 0 ) ? 1 : 0;
836 }
837
838 //////////////////////////////////////////
839 /* ind should be the page id            */
840 //////////////////////////////////////////
841 page* page_storage::operator()(int ind, enum access mode) 
842 {
843 /*
844 if ( mode == WRITE ) {
845 MESSAGE(cerr, "opera(): write mode");
846 debug(cerr, ind);
847 debug(cerr, name);
848 }
849 */
850
851 /*
852 if ( mode == WRITE ) {
853 char* s = name + strlen(name) - 11;
854 debug(cerr, s);
855 if ( strcmp(s, "index.store") == 0 )
856 debug(cerr, name);
857 }
858 */
859
860 //cerr << "Try to get page " << ind << " from " << my_name() << "\n";
861
862    if ( ! INRANGE( ind,  1, pages() ) ) {
863       debug(cerr, my_path());
864       debug(cerr, my_name());
865       MESSAGE(cerr, 
866               form("page_storage:: operator(): mmdb_pos_t %d out of range.", ind)
867              );
868       throw(boundaryException(1, pages(), ind));
869    } 
870
871    page* p = f_local_pcache.in_cache(this, ind);
872    
873    if ( p == 0 ) {
874    
875 //cerr << "swapping in a page " << ind << endl;
876      p = f_global_pcache.load_new_page( this, ind, 
877                 (v_db_order==v_server_order) ? false : true
878                                       );
879    
880    }
881    
882 /*
883 debug(cerr, my_name());
884 debug(cerr, p -> count());
885 debug(cerr, int(mode));
886 debug(cerr, int(WRITE));
887 */
888    if ( mode == WRITE ) {
889       p -> dirty = true;
890       save_to_log(p);
891    }
892
893    return p;
894 }
895
896 /***********************************************************/
897 // update ind to the mmdb_pos_t of next page.
898 /***********************************************************/
899 void page_storage::next(int& ind) const
900 {
901    if ( ind >= pages() )
902       ind = 0;
903    else
904       ind++;
905 }
906
907 io_status page_storage::asciiOut(ostream& out)  
908 {
909    int ind = first();
910    while ( ind != 0  ) {
911 #ifdef DEBUG
912       page* p = (*this)(ind, READ);
913       debug(out, *p);
914 #endif
915       next(ind);
916    }
917    return done;
918
919 /*
920    debug(cerr, pagings);
921    pagings = 0;
922 */
923 }
924
925 Boolean 
926 page_storage::seek_loc(mmdb_pos_t& loc, const direction d, int smd)
927 {
928    if ( d == positive ) {
929        return seek_loc_positive(loc, smd);
930    } else {
931        return seek_loc_negative(loc, smd);
932    }
933 }
934
935 Boolean page_storage::seek_loc_positive(mmdb_pos_t& loc, int smd)
936 {
937    int pgs = pages();
938
939    int page_num = PAGE_ID( loc, page_sz );
940    int page_slot = PAGE_IDX( loc, page_sz );
941
942    while ( page_num <= pgs ) {
943
944       page* x = (*this)(page_num, READ);
945
946       if ( page_slot == 0 )
947          page_slot = x -> first();
948       else
949          x -> next( page_slot );
950
951       spointer_t *y;
952
953       while ( page_slot && (y = x -> get_spointer(page_slot)) != 0 ) {
954          if ( y -> get_mode(spointer_t::DELETED) == false &&
955               y -> test_mode(smd) == true ) {
956             loc = FORM_PAGE_REF(page_num, page_slot, page_sz);
957             delete y;
958             return true;
959          } else {
960             delete y;
961             x -> next(page_slot);
962          }
963       }
964
965       page_num++;
966       page_slot = 0;
967    }
968
969    return false;
970 }
971
972 Boolean page_storage::seek_loc_negative(mmdb_pos_t& loc, int smd)
973 {
974    int page_num = PAGE_ID( loc, page_sz );
975    int page_slot = PAGE_IDX( loc, page_sz );
976
977    while ( page_num > 0 ) {
978
979       page* x = (*this)(page_num, READ);
980
981       if ( page_slot == 0 )
982          page_slot = x -> count() - 1;
983       else
984          x -> prev(page_slot);
985
986       spointer_t *y;
987
988       while ( page_slot && (y = x -> get_spointer(page_slot)) != 0 ) 
989       {
990          if ( y -> get_mode(spointer_t::DELETED) == false &&
991               y -> test_mode(smd) == true ) {
992             loc = FORM_PAGE_REF(page_num, page_slot, page_sz);
993             delete y;
994             return true;
995          } else {
996             delete y;
997             x -> prev(page_slot);
998          }
999       }
1000
1001       page_num--;
1002       page_slot = 0;
1003    }
1004
1005    return false;
1006 }
1007
1008 void page_storage::reset_paging_count()
1009 {
1010 /*
1011    if ( storage_ptr -> rdbuf() -> is_open() ) {
1012       cerr << storage_ptr -> my_name() << " has not been closed\n";
1013       storage_ptr -> close();
1014    } else {
1015       cerr << storage_ptr -> my_name() << " is already closed\n";
1016    }
1017 */
1018    pagings = 0;
1019    
1020 }
1021    
1022 int page_storage::paging_count() const
1023 {
1024    return pagings;
1025 }
1026
1027 mmdb_pos_t page_storage::first_loc()
1028 {
1029    if ( pages() >= 1 && (*this)(1, READ) -> count() != 0 )
1030       return FORM_PAGE_REF(1, 1, page_sz);
1031    else
1032       return 0;
1033 }
1034
1035 mmdb_pos_t page_storage::last_loc()
1036 {
1037    int pgs = pages();
1038     
1039    if ( pgs == 0 ) 
1040       return 0;
1041
1042    for ( int i=pgs; i>0; i-- ) {
1043       int ct = (*this)(i, READ) -> count();
1044       if ( ct > 0 )
1045          return FORM_PAGE_REF(i, ct, page_sz);
1046    }
1047
1048    return 0;
1049 }
1050
1051 int 
1052 page_storage::get_str_locs(mmdb_pos_t str_loc, 
1053                            str_index_record_tPtr*& vector, int& vector_len
1054                           )
1055 {
1056    int vector_sz = 20;
1057    vector = new str_index_record_tPtr[vector_sz];
1058
1059    int num_pieces = 0;
1060    int str_offset = 0;
1061    spointer_t *x = 0;
1062
1063    while ( str_loc > 0 ) {
1064
1065       if ( num_pieces >= vector_sz ) {
1066          vector_sz *= 2;
1067          vector = (str_index_record_tPtr*)realloc(
1068                         (char*)vector, 
1069                         vector_sz*sizeof(str_index_record_tPtr)
1070                   );
1071       }
1072
1073       vector[num_pieces++] = 
1074           new str_index_record_t(str_offset, str_loc);
1075
1076       int page_num  = PAGE_ID( str_loc, page_sz );
1077       int page_slot  = PAGE_IDX( str_loc, page_sz );
1078
1079       page *y = (*this)(page_num, READ);
1080
1081       x = y -> get_spointer(page_slot);
1082
1083       str_offset += x -> string_leng();
1084       str_loc  = x -> forward_ptr();
1085
1086       delete x;
1087    }
1088
1089    vector_len = num_pieces;
1090    return 0;
1091 }
1092
1093 int page_storage::set_page_dirty(mmdb_pos_t loc)
1094 {
1095 MESSAGE(cerr, "set page dirty: page loc is");
1096 debug(cerr, loc);
1097
1098    page* x = (*this)(PAGE_ID( loc, page_sz ), WRITE);
1099    x -> dirty = true;
1100    return 0;
1101 }
1102
1103 Boolean page_storage::io_mode(int mode)
1104 {
1105    if ( storage_ptr )
1106       return storage_ptr -> io_mode(mode);
1107    else
1108       return false;
1109 }
1110
1111 void page_storage::begin_trans()
1112 {
1113    mtry {
1114       if ( trans_info.status == store_trans::ENABLED )
1115          throw(stringException("trans is still in progress"));
1116    
1117       trans_info.init(policy);
1118       trans_info.set_max_pages(total_pages);
1119    
1120       trans_info.status = store_trans::ENABLED;
1121    
1122       int l_max_pages = trans_info.max_pages;
1123       if ( swap_order() == true )
1124           ORDER_SWAP_UINT(l_max_pages);
1125    
1126       trans_info.log_store -> 
1127         updateString(0, (char*)&l_max_pages, sizeof(l_max_pages), 0, true);
1128   }
1129
1130   mcatch (mmdbException&, e) {
1131 // workaround for solaris's /SUNWspro/bin/CC compiler.
1132      beginTransException x;
1133      throw(x);
1134      //throw(beginTransException());
1135   }
1136   end_try;
1137 }
1138
1139 void page_storage::commit_trans()
1140 {
1141 //////////////////////////////
1142 // sync the touched pages
1143 //////////////////////////////
1144    mtry {
1145       int ind = trans_info.log_index -> first_bucket();
1146    
1147       while ( ind != -1 ) {
1148    
1149          imp_bucket* bucket = trans_info.log_index -> get_bucket(ind);
1150    
1151          if ( bucket ) {
1152              long b_ind = bucket -> first();
1153              while ( b_ind != 0 ) {
1154                 data_t* z = (*bucket)(b_ind);
1155    //debug(cerr, ((page*)(z -> dt)) -> count());
1156                 sync((page*)(z -> dt));
1157                 bucket -> next(b_ind);
1158              }
1159          }
1160          trans_info.log_index -> next_bucket(ind);
1161       }
1162    
1163       trans_info.quit();
1164    
1165       trans_info.status = store_trans::DISABLED;
1166    }
1167
1168    mcatch (mmdbException &,e) {
1169 // workaround for solaris's /SUNWspro/bin/CC compiler.
1170       commitTransException x;
1171       throw(x);
1172    } end_try;
1173 }
1174
1175 void page_storage::roll_back()
1176 {
1177    mtry
1178    {
1179       if ( exist_file(form("%s.log", name), path) == false ) 
1180          return;
1181    
1182    MESSAGE(cerr, "roll_back() begins");
1183    
1184       trans_info.init(policy); // init the log store
1185                  
1186    //////////////////////////////////
1187    // verify the log is in good shape
1188    //////////////////////////////////
1189       int m;
1190       unsigned int log_bytes = trans_info.log_store -> bytes();
1191    
1192       if ( trans_info.log_store && 
1193            (*trans_info.log_store) &&
1194            log_bytes > sizeof(m) ) 
1195       {
1196    
1197    //////////////////////////////////
1198    // truncate the store to previous
1199    // length
1200    //////////////////////////////////
1201          trans_info.log_store -> readString(0, (char*)&m, sizeof(m));
1202    
1203          if ( swap_order() == true )
1204             ORDER_SWAP_UINT(m);
1205    
1206          trans_info.set_max_pages(m); // init the log store
1207    
1208          ((unixf_storage*)storage_ptr) -> truncate(abs_off + m*page_sz); 
1209    
1210    //debug(cerr, m);
1211    //////////////////////////////////
1212    // restore the store to previous
1213    // state
1214    //////////////////////////////////
1215          int l_pid = 0;
1216    
1217          if ( (log_bytes - sizeof(m)) % (page_sz+sizeof(l_pid)) != 0 )
1218             throw(stringException("corrupted transaction log"));
1219    
1220          int u = (log_bytes - sizeof(m)) / (page_sz+sizeof(l_pid));
1221    //debug(cerr, u);
1222    
1223    
1224          buffer log_buf(page_sz);
1225          for ( int i=0; i<u; i++ ) {
1226    
1227              int offset = sizeof(m) + i*(page_sz + sizeof(l_pid));
1228    
1229              trans_info.log_store -> 
1230                    readString(offset,                        // page id
1231                               (char*)&l_pid, sizeof(l_pid)
1232                              );
1233    
1234              if ( swap_order() == true ) // swap byte order if necessary
1235                    ORDER_SWAP_UINT(l_pid);
1236    
1237              trans_info.log_store -> 
1238                    readString(offset + sizeof(l_pid),        // page content
1239                               log_buf.get_base(),
1240                               page_sz
1241                              );
1242    
1243    
1244              storage_ptr -> updateString( abs_off + (l_pid-1)*page_sz, 
1245                                           log_buf.get_base(),
1246                                           page_sz,
1247                                           0, 
1248                                           true
1249                                         );
1250          }
1251       }
1252    
1253    ///////////////////////////////////////////////
1254    // make sure the cached pages are not synced
1255    ///////////////////////////////////////////////
1256    
1257       long ind = f_global_pcache.f_replace_policy.first();
1258    
1259       while ( ind != 0 ) {
1260         lru_page *p = (lru_page*)
1261                 (f_global_pcache.f_replace_policy)(ind, ACTIVE);
1262
1263         if ( p -> f_store == this )
1264            p -> dirty = false;
1265         f_global_pcache.f_replace_policy.next(ind);
1266       }
1267    
1268       trans_info.quit(); // remove the log store
1269    
1270       trans_info.status = store_trans::DISABLED;
1271   }
1272
1273   mcatch (mmdbException &,e)
1274   {
1275 // workaround for solaris's /SUNWspro/bin/CC compiler.
1276       rollbackTransException x;
1277       throw(x);
1278   } end_try;
1279
1280 MESSAGE(cerr, "roll_back() completes");
1281 }
1282
1283 void page_storage::save_to_log(page* p)
1284 {
1285 /*
1286 MESSAGE(cerr, "About to save to log");
1287 debug(cerr, my_name());
1288 debug(cerr, int(trans_info.status));
1289 debug(cerr, int(store_trans::ENABLED));
1290 debug(cerr, trans_info.max_pages);
1291 */
1292
1293    if ( trans_info.status == store_trans::ENABLED &&
1294         INRANGE(p -> page_id(), 1, trans_info.max_pages)
1295       ) 
1296    {
1297       //assert ( trans_info.log_store );
1298       //assert ( trans_info.log_index );
1299
1300       if ( trans_info.log_store  == 0 || trans_info.log_index == 0 )
1301          throw(stringException("corrupted store"));
1302    
1303       int l_pid = p -> page_id();
1304       data_t pkey(l_pid, voidPtr(p));
1305
1306    
1307       if ( trans_info.log_index -> member(pkey) == false ) {
1308 //MESSAGE(cerr, form("Save_to_log pid=%d, pcnt = %d, name=%s", 
1309 //        l_pid, p -> count(), name));
1310
1311          int log_bytes_before = trans_info.log_store -> bytes();
1312    
1313          mtry {
1314             if ( swap_order() == true ) // swap to desired order
1315                ORDER_SWAP_UINT(l_pid);
1316
1317             trans_info.log_store -> 
1318                appendString( 0, (char*)&l_pid, sizeof(l_pid), false );
1319
1320             if ( swap_order() == true ) // swap back
1321                ORDER_SWAP_UINT(l_pid);
1322              
1323             p -> _swap_order(false); 
1324
1325             trans_info.log_store -> 
1326                appendString( 0, p -> page_base(), page_sz, true );
1327
1328 //debug(cerr,  trans_info.log_store -> bytes());
1329             p -> _swap_order(true); 
1330    
1331             trans_info.log_index -> insert(pkey);
1332          }
1333
1334          mcatch (mmdbException&, e) {
1335             trans_info.log_store -> truncate(log_bytes_before);
1336             rethrow;
1337          }
1338          end_try;
1339
1340       } 
1341 //    else
1342 //MESSAGE(cerr, form("Not save_to_log pid=%d, name=%s", l_pid, name));
1343
1344    }
1345 }
1346
1347 buffer& page_storage::aux_buf() 
1348
1349    if ( v_buf == 0 )
1350       v_buf = new buffer(LBUFSIZ);
1351    return *v_buf; 
1352 }
1353