/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* * $XConsortium: page.cc /main/6 1996/08/15 14:14:45 cde-hal $ * * Copyright (c) 1992 HaL Computer Systems, Inc. All rights reserved. * UNPUBLISHED -- rights reserved under the Copyright Laws of the United * States. Use of a copyright notice is precautionary only and does not * imply publication or disclosure. * * This software contains confidential information and trade secrets of HaL * Computer Systems, Inc. Use, disclosure, or reproduction is prohibited * without the prior express written permission of HaL Computer Systems, Inc. * * RESTRICTED RIGHTS LEGEND * Use, duplication, or disclosure by the Government is subject to * restrictions as set forth in subparagraph (c)(l)(ii) of the Rights in * Technical Data and Computer Software clause at DFARS 252.227-7013. * HaL Computer Systems, Inc. * 1315 Dell Avenue, Campbell, CA 95008 * */ #include "storage/page.h" ///////////////////////////////////////////////////////////// // SLOT_HEADER_SIZE is defined for these fields: //(sizeof(fwd_ptr) + sizeof(header.int_view) + sizeof(int)) // // Note: the last int field is not used. It is here for // backward compatibility. qfc 12-13-95 ///////////////////////////////////////////////////////////// #define SLOT_HEADER_SIZE (sizeof(mmdb_pos_t) + sizeof(unsigned int) + sizeof(int)) spointer_t::spointer_t(char* page_base, int slot): swapped(false) { page_image = page_base + sizeof(count_t) + (slot-1)*SLOT_HEADER_SIZE; memcpy((char*)&fwd_ptr, page_image, sizeof(fwd_ptr)); memcpy( (char*)&header.int_view, page_image+sizeof(fwd_ptr), sizeof(header.int_view) ); #ifdef PAGE_DEBUG MESSAGE(cerr, "spointer_t::spointer_t() [1]"); debug(cerr, slot); debug(cerr, (int)(void*)page_base); debug(cerr, (int)(void*)page_image); #endif } spointer_t::spointer_t(char* page_base, int slot_num, int ofst, int len) : fwd_ptr(0), swapped(false) { header.bit_view.spointer = ofst; header.bit_view.length = len; set_mode(DELETED, false); set_mode(IS_OBJECT, false); set_mode(UPDATED, true); page_image = page_base + sizeof(count_t) + (slot_num-1) * SLOT_HEADER_SIZE; } spointer_t::~spointer_t() { //MESSAGE(cerr, "spointer_t::~spointer_t()"); //debug(cerr, header.bit_view.spointer); if ( swapped == true || get_mode(UPDATED) == true ) { memcpy(page_image, (char*)&fwd_ptr, sizeof(fwd_ptr)); memcpy(page_image+sizeof(fwd_ptr), (char*)&(header.int_view), sizeof(header.int_view) ); } } void spointer_t::set_mode(spointer_mode m, Boolean b) { switch ( m ) { case IS_OBJECT: header.bit_view.is_object = ( b == true ) ? 1 : 0; header.bit_view.updated = 1; break; case FIRST_RECD: header.bit_view.first_recd = ( b == true ) ? 1 : 0; header.bit_view.updated = 1; break; case DELETED: header.bit_view.deleted = ( b == true ) ? 1 : 0; header.bit_view.updated = 1; break; case UPDATED: header.bit_view.updated = ( b == true ) ? 1 : 0; break; default: MESSAGE(cerr, "page::set_mode(): invalid mode"); throw( intException((int)m) ); break; } } Boolean spointer_t::get_mode(spointer_mode m) { switch ( m ) { case IS_OBJECT: return ( header.bit_view.is_object == 1 ) ? true : false; case FIRST_RECD: return ( header.bit_view.first_recd == 1 ) ? true : false; case DELETED: return ( header.bit_view.deleted == 1 ) ? true : false; case UPDATED: return ( header.bit_view.updated == 1 ) ? true : false; default: MESSAGE(cerr, "page::get_mode(): invalid mode"); throw( intException((int)m) ); break; } } static int align_offset; page::page(int buf_sz, int pid, Boolean swap_order) : buffer( buf_sz ), pageid(pid), dirty(false), num_locks(0), v_swap_order(swap_order) { v_memalign_offset = align_offset; clean_all(); } page::~page() { align_offset = v_memalign_offset; } /***************************/ // /***************************/ void page::clean_all() { v_eptr = v_base + buf_sz(); set_count(1); ////////////////////////////////////////// // use spointer_t's dstr to write slot info to page. ////////////////////////////////////////// spointer_t x(v_base, 1, buf_sz(), buf_sz()-sizeof(count_t)-2*SLOT_HEADER_SIZE ); } /************************************* * Get the ith string pointer from the * page. **************************************/ spointer_t* page::get_spointer(int slot_num) const { if ( !INRANGE(slot_num, 1, count()) ) { throw( boundaryException(1, count(), slot_num)); } return new spointer_t(v_base, slot_num); } ////////////////////////////// // Get a string from the page. ////////////////////////////// Boolean page::get( int slot_num, buffer& target, int offset, int bytes_to_read ) const { /* MESSAGE(cerr, "in page::get()"); debug(cerr, slot_num); debug(cerr, offset); debug(cerr, bytes_to_read); */ if ( ! INRANGE(slot_num, 1, count()-1) ) throw( boundaryException(1, count()-1, slot_num) ); spointer_t slot_info(v_base, slot_num); if ( slot_info.get_mode(spointer_t::DELETED) == true ) { MESSAGE(cerr, "page::get(): get a deleted slot"); return false; } int string_len = slot_info.string_leng(); //debug(cerr, string_len); if ( bytes_to_read == 0 ) bytes_to_read = string_len; //debug(cerr, bytes_to_read); if ( bytes_to_read + offset > slot_info.string_leng() ) { MESSAGE(cerr, "page::get(): too many bytes to read"); throw( boundaryException(0, slot_info.string_leng(), bytes_to_read + offset) ); } offset += slot_info.string_ofst(); /* MESSAGE(cerr, "page::get()"); debug(cerr, offset); debug(cerr, long(v_base + offset)); debug(cerr, bytes_to_read); for (int ki=0; ki string_ofst() - size; #ifdef NO_COPY int left_shift_delta = end_ptr % 4; end_ptr -= left_shift_delta; size += left_shift_delta; #endif int new_blank_len = slot_info -> string_leng() ; if ( new_blank_len < size ) { delete slot_info; return false; } slot_info -> set_string_ofst( end_ptr ); slot_info -> set_string_leng( size ); slot_info -> set_mode(spointer_t::DELETED, false); slot_info -> set_forward_ptr(0); delete slot_info; if ( slot_num == count() ) { //MESSAGE(cerr, "slot_num == count() case:"); new_blank_len -= size; //debug(cerr, new_blank_len); if ( new_blank_len < (int)(2*SLOT_HEADER_SIZE + 10) ) new_blank_len = 0; else new_blank_len -= SLOT_HEADER_SIZE; // space allocated for new // free space slot //debug(cerr, new_blank_len); /* MESSAGE(cerr, "in page::alloc"); debug(cerr, size); debug(cerr, i_th -> string_leng()); debug(cerr, i_th -> string_ofst()); debug(cerr, new_blank_len); */ /////////////////////////////// // append a new slot to the end /////////////////////////////// set_count(count()+1); spointer_t* z = new spointer_t(v_base, count(), end_ptr, new_blank_len); delete z; //debug(cerr, free_bytes()); //MESSAGE(cerr, "page::alloc done"); /* MESSAGE(cerr, "in page::alloc"); debug(cerr, end_ptr); debug(cerr, size); */ } str_ptr = v_base + end_ptr; //debug(cerr, int(base)); //debug(cerr, i_th -> string_ofst()); //debug(cerr, slot_num); //debug(cerr, long(str_ptr)); //debug(cerr, long(v_base)); //debug(cerr, end_ptr); //if ( count() >= 1 ) { //spointer_t first_slot(v_base, 1); //debug(cerr, first_slot.string_ofst()); //debug(cerr, first_slot.string_leng()); //} dirty = true; return true; } Boolean page::get_str_ptr( int slot_num, char*& str, int& len ) { if ( ! INRANGE(slot_num, 1, count()-1) ) throw(boundaryException( 1, count()-1, slot_num)); spointer_t slot_info(v_base, slot_num); str = slot_info.string_ofst() + v_base; len = slot_info.string_leng(); /* MESSAGE(cerr, "page::get_str_ptr(), result:"); debug(cerr, slot_info.string_ofst()); debug(cerr, slot_info.string_leng()); */ return true; } // return number of free bytes on the page int page::free_bytes() const { spointer_t slot_info(v_base, count()); return slot_info.string_leng() - SLOT_HEADER_SIZE - 10; } int page::free_slots() const // return number of free slots on the page { spointer_t *x; int sum = 0; int ind = first(); while ( ind ) { x = new spointer_t(v_base, ind); if ( x -> get_mode(spointer_t::DELETED) == true ) sum++; delete x; next(ind); } return sum; } void page::next(int& ind) const // return next index relative to 'ind' { if ( ind >= count()-1 ) ind = 0; else ind ++; } void page::prev(int& ind) const // return prev index relative to 'ind' { if ( ind == 1 ) ind = 0; else ind --; } void page::_swap_order(Boolean swap_count_field_first) { if ( v_swap_order == true ) { /* MESSAGE(cerr, "page::_swap_order()"); debug(cerr, pageid); */ int& x = *((count_t*)v_base); // use this version to point at // the count field //debug(cerr, x); if ( swap_count_field_first == true ) { ORDER_SWAP_UINT(x); // swap the count field first //MESSAGE(cerr, "swap earlier"); //debug(cerr, x); } for ( int i=1; i<=x; i++ ) { //debug(cerr, i); spointer_t slot_info(v_base, i); //debug(cerr, hex(slot_info.header.int_view)); //debug(cerr, slot_info.string_ofst()); slot_info.swap_order(); //debug(cerr, hex(slot_info.header.int_view)); //debug(cerr, slot_info.string_ofst()); } if ( swap_count_field_first == false ) { ORDER_SWAP_UINT(x); // swap the count field second //MESSAGE(cerr, "swap later"); //debug(cerr, x); } } } ostream& operator<<(ostream&s, page& p) { buffer lbuf; debug(s, int(p.dirty)); debug(s, p.count()); debug(s, p.pageid); debug(s, p.free_bytes()); debug(s, long(p.v_base)); debug(s, long(p.v_eptr)); int ind = p.first(); while ( ind ) { debug(s, int(ind)); lbuf.reset(); if ( p.get(ind, lbuf, 0) == true ) { s << lbuf; s << "\n"; } p.next(ind); } return s; } void* page::operator new( size_t sz ) { int alignment_overhead = sizeof(char*); char* p = ::new char[alignment_overhead+sz]; if ( p ) { align_offset = int(alignment_overhead - long(p) % alignment_overhead); return (void*)(p + align_offset); } else { MESSAGE(cerr, "page::new() memalign call failed"); throw(systemException(errno)); } } void page::operator delete( void* p, size_t ) { if ( p ) free((char*)((char*)p - align_offset)); } /* int page::cdr_sizeof() { return sizeof(pageid) + v_bufsz; } io_status page::cdrIn(buffer& buf) { buf.put(pageid); buffer::cdrIn(buf); return done; } io_status page::cdrOut(buffer& buf) { buf.get(pageid); buffer::cdrOut(buf); return done; } */