/********************************************************************* * * * Copyright (c) 1997,1998, 1999 * * Multimedia DB Group and DEIS - CSITE-CNR, * * University of Bologna, Bologna, ITALY. * * * * All Rights Reserved. * * * * Permission to use, copy, and distribute this software and its * * documentation for NON-COMMERCIAL purposes and without fee is * * hereby granted provided that this copyright notice appears in * * all copies. * * * * THE AUTHORS MAKE NO REPRESENTATIONS OR WARRANTIES ABOUT THE * * SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING * * BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. THE AUTHOR * * SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A * * RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * * DERIVATIVES. * * * *********************************************************************/ #include #include #include #ifdef UNIX #include #else #include #endif #ifdef UNIX #define O_BINARY 0 #endif #include "MTfile.h" extern int IOread, IOwrite; // The first page in the file has these "magic words" // and the head of the deleted page list. static char magic[]="GiST data file"; void MTfile::Create(const char *filename) { if(IsOpen()) return; /*#d##D# fileHandle=open(filename, O_RDWR|O_BINARY); if(fileHandle>=0) { close(fileHandle); return; } */ fileHandle=open(filename, O_BINARY|O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE); if(fileHandle<0) return; SetOpen(1); /* Reserve page 0 */ char *page=new char[PageSize()]; memset(page, 0, PageSize()); memcpy(page, magic, sizeof magic); write(fileHandle, page, PageSize()); delete page; } void MTfile::Open(const char *filename) { char *page; if(IsOpen()) return; fileHandle=open(filename, O_RDWR|O_BINARY); if(fileHandle<0) return; // Verify that the magic words are there page=new char[PageSize()]; read(fileHandle, page, PageSize()); if(memcmp(page, magic, sizeof(magic))) { close(fileHandle); delete page; return; } delete page; SetOpen(1); } void MTfile::Close() { if(!IsOpen()) return; Sync(); close(fileHandle); SetOpen(0); } MTfile::~MTfile() { setcache (0); } void MTfile::setcache(unsigned int pages) { Sync(); if (cachesize) { for (int i = cachesize; i--; ) delete [] cache[i].buf; delete [] cache; } cachesize = pages; if (cachesize) { cache = new Page[pages]; for (int i = cachesize; i--; ) { cache[i].seq = 0; cache[i].dirty = 0; cache[i].page = (GiSTpage) -1; cache[i].buf = new char[PageSize()]; } } } static unsigned int seq; MTfile::Page *MTfile::newpage(GiSTpage page) { Page *p = &cache[0]; for (int i = cachesize; --i; ) { if (cache[i].seq < p->seq) p = &cache[i]; } if (p->dirty) flushpage (p); p->seq = ++seq; //min->dirty = 0; p->page = page; return p; } MTfile::Page *MTfile::findpage(GiSTpage page) { for (int i = cachesize; i--; ) if (cache[i].page == page) return &cache[i]; return 0; } void MTfile::flushpage(Page *p) { assert (IsOpen()); lseek (fileHandle, p->page*PageSize(), SEEK_SET); write (fileHandle, p->buf, PageSize()); p->dirty = 0; IOwrite++; } void MTfile::Read(GiSTpage page, char *buf) { if(IsOpen()) { Page *p = findpage (page); if (p) { p->seq = ++seq; memcpy (buf, p->buf, PageSize ()); return; } lseek(fileHandle, page*PageSize(), SEEK_SET); read(fileHandle, buf, PageSize()); IOread++; p = newpage (page); memcpy (p->buf, buf, PageSize()); } } void MTfile::Write(GiSTpage page, const char *buf) { Page *p = findpage (page); if (!p) p = newpage (page); memcpy (p->buf, buf, PageSize ()); p->seq = ++seq; p->dirty++; } void MTfile::Sync() { for (int i = cachesize; i--; ) if (cache[i].dirty) flushpage (&cache[i]); } GiSTpage MTfile::Allocate() { GiSTpage page; char *buf; if(!IsOpen()) return (0); // See if there's a deleted page buf=new char[PageSize()]; Read(0, buf); memcpy(&page, buf+sizeof(magic), sizeof(GiSTpage)); if(page) { // Reclaim this page Read(page, buf); Write(0, buf); } else { page=lseek(fileHandle, 0, SEEK_END)/PageSize(); memset(buf, 0, PageSize()); write(fileHandle, buf, PageSize()); } delete buf; return page; } void MTfile::Deallocate(GiSTpage page) { char *buf; GiSTpage temp; if(!IsOpen()) return; // Get the old head of the list buf=new char[PageSize()]; Read(0, buf); memcpy(&temp, buf+sizeof(magic), sizeof(GiSTpage)); // Write the new head of the list memcpy(buf+sizeof(magic), &page, sizeof(GiSTpage)); Write(0, buf); // In our new head, put link to old head memcpy(buf+sizeof(magic), &temp, sizeof(GiSTpage)); Write(page, buf); delete buf; }