⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 database.cpp

📁 实现内存数据库的源代码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
	searchInString(sattr, sattr2);
	return;

      default:
	assert(false);
    }
}


void dbDatabase::handleError(dbErrorClass error, char const* msg, int arg)
{
#ifdef THROW_EXCEPTION_ON_ERROR
    if (error != NoError) {
	throw dbException(error, msg, arg);
    }
#else
    char buf[256];
    switch (error) { 
      case QueryError:
	fprintf(stderr, "%s in position %d\n", msg, arg);
	return;
      case ArithmeticError:
	fprintf(stderr, "%s\n", msg);
	break;
      case IndexOutOfRangeError:
	fprintf(stderr, "Index %d is out of range\n", arg);
	break;
      case DatabaseOpenError:
	fprintf(stderr, "%s\n", msg);
	return;
      case FileError:
	fprintf(stderr, "%s: %s\n", msg, 
		dbFile::errorText(arg, buf, sizeof(buf)));
	break;
      case OutOfMemoryError:
	fprintf(stderr,"Not enough memory: failed to allocate %d bytes\n",arg);
	break;
      case NullReferenceError:
	fprintf(stderr, "Null object reference is accessed\n");
	break;
      case Deadlock:
	fprintf(stderr, "Deadlock is caused by upgrading shared locks to exclusive");
	break;
      case LockRevoked:
	fprintf(stderr, "Lock is revoked by some other client");
	break;	
      default:
	return;
    }	
    abort();
#endif
}

void dbDatabase::initializeMetaTable()
{
    static struct { 
	char const* name;
	int         type;
	int         size;
	int         offs;
    } metaTableFields[] = { 
	{ "name", dbField::tpString, sizeof(dbVarying), 
	  offsetof(dbTable, name)},
	{ "fields", dbField::tpArray, sizeof(dbVarying), 
	  offsetof(dbTable, fields)},
	{ "fields[]", dbField::tpStructure, sizeof(dbField), 0},
	{ "fields[].name", dbField::tpString, sizeof(dbVarying), 
	  offsetof(dbField, name)},
	{ "fields[].tableName",dbField::tpString,sizeof(dbVarying), 
	  offsetof(dbField, tableName)},
	{ "fields[].inverse", dbField::tpString, sizeof(dbVarying), 
	  offsetof(dbField, inverse)},
	{ "fields[].type", dbField::tpInt4, 4, offsetof(dbField, type)},
	{ "fields[].offset", dbField::tpInt4, 4, offsetof(dbField, offset)},
	{ "fields[].size", dbField::tpInt4, 4, offsetof(dbField, size)},
	{ "fields[].hashTable", dbField::tpReference, sizeof(oid_t), 
	  offsetof(dbField, hashTable)},
	{ "fields[].tTree", dbField::tpReference, sizeof(oid_t), 
	  offsetof(dbField, tTree)},
	{ "fixedSize", dbField::tpInt4, 4, offsetof(dbTable, fixedSize)},
	{ "nRows", dbField::tpInt4, 4, offsetof(dbTable, nRows)},
	{ "nColumns", dbField::tpInt4, 4, offsetof(dbTable, nColumns)},
	{ "firstRow", dbField::tpReference, sizeof(oid_t), offsetof(dbTable, firstRow)},
	{ "lastRow", dbField::tpReference, sizeof(oid_t), offsetof(dbTable, lastRow)}
 #ifdef AUTOINCREMENT_SUPPORT
       ,{ "count", dbField::tpInt4, 4, offsetof(dbTable, count)}
 #endif
    };

    unsigned i;
    size_t varyingSize = strlen(dbMetaTableName)+1;
    for (i = 0; i < items(metaTableFields); i++) { 
	varyingSize += strlen(metaTableFields[i].name) + 3;
	
    }
    offs_t metaTableOffs = allocate(sizeof(dbTable)
				    + sizeof(dbField)*items(metaTableFields)
				    + varyingSize);
    index[0][dbMetaTableId] = metaTableOffs;
    dbTable* table = (dbTable*)(baseAddr + metaTableOffs);
    table->size = sizeof(dbTable) + sizeof(dbField)*items(metaTableFields)
	        + varyingSize;
    table->next = table->prev = 0;
    int offs = sizeof(dbTable) + sizeof(dbField)*items(metaTableFields);
    table->name.offs = offs;
    table->name.size = strlen(dbMetaTableName)+1;
    strcpy((char*)table + offs, dbMetaTableName);
    offs += table->name.size;
    table->fields.offs = sizeof(dbTable);
    table->fields.size = items(metaTableFields);
    table->fixedSize = sizeof(dbTable);
    table->nRows = 0;
    table->nColumns = 5;
    table->firstRow = 0;
    table->lastRow = 0;
#ifdef AUTOINCREMENT_SUPPORT
    table->count = 0;
#endif

    dbField* field = (dbField*)((char*)table + table->fields.offs);
    offs -= sizeof(dbTable);
    for (i = 0; i < items(metaTableFields); i++) { 
	field->name.offs = offs;
	field->name.size = strlen(metaTableFields[i].name) + 1;
	strcpy((char*)field + offs, metaTableFields[i].name);
	offs += field->name.size;

	field->tableName.offs = offs;
	field->tableName.size = 1;
        *((char*)field + offs++) = '\0';
	
	field->inverse.offs = offs;
	field->inverse.size = 1;
	*((char*)field + offs++) = '\0';
	
	field->type = metaTableFields[i].type;
	field->size = metaTableFields[i].size;
	field->offset = metaTableFields[i].offs;
	field->hashTable = 0;
	field->tTree = 0;
	field += 1;
	offs -= sizeof(dbField);
    }
}

bool dbDatabase::open(char const* dbName, char const* fiName, 
		      time_t waitLockTimeoutMsec, time_t commitDelaySec)
{
    dbWaitLockTimeout = waitLockTimeoutMsec;
    delete[] databaseName;
    delete[] fileName;
    commitDelay = 0;
    commitTimeout = 0;
    commitTimerStarted = 0;
    backupFileName = NULL;
    backupPeriod = 0;
    opened = false;
    stopDelayedCommitThread = false;
    databaseNameLen = strlen(dbName);
    char* name = new char[databaseNameLen+16];
    sprintf(name, "%s.in", dbName);
    databaseName = name;
    if (fiName == NULL) { 
	fileName = new char[databaseNameLen + 5];
	sprintf(fileName, "%s.fdb", dbName);
    } else { 
	fileName = new char[strlen(fiName)+1];
	strcpy(fileName, fiName);
    }

    dbInitializationMutex::initializationStatus status;
    status = initMutex.initialize(name);
    if (status == dbInitializationMutex::InitializationError) { 
	handleError(DatabaseOpenError, 
		    "Failed to start database initialization");
	return false;
    }
    sprintf(name, "%s.dm", dbName);
    if (!shm.open(name)) { 
	handleError(DatabaseOpenError, "Failed to open database monitor");
	return false;
    }
    monitor = shm.get();
    sprintf(name, "%s.ws", dbName);
    if (!writeSem.open(name)) { 
	handleError(DatabaseOpenError, 
		    "Failed to initialize database writers semaphore");
	return false;
    }
    sprintf(name, "%s.rs", dbName);
    if (!readSem.open(name)) { 
	handleError(DatabaseOpenError, 
		    "Failed to initialize database readers semaphore");
	return false;
    }
    sprintf(name, "%s.us", dbName);
    if (!upgradeSem.open(name)) { 
	handleError(DatabaseOpenError, 
		    "Failed to initialize database upgrade semaphore");
	return false;
    }
    sprintf(name, "%s.bce", dbName);
    if (!backupCompletedEvent.open(name)) { 
	handleError(DatabaseOpenError, 
		    "Failed to initialize database backup completed event");
	return false;
    }    
    if (commitDelaySec != 0) { 
	sprintf(name, "%s.dce", dbName);
	if (!delayedCommitStopTimerEvent.open(name)) { 
	    handleError(DatabaseOpenError, 
			"Failed to initialize delayed commit event");
	    return false;
	}    
	delayedCommitStartTimerEvent.open();
    }
    backupInitEvent.open();
    backupFileName = NULL;

    allocatedSize = 0;
    size_t indexSize = initIndexSize < dbFirstUserId 
	? size_t(dbFirstUserId) : initIndexSize;
    indexSize = DOALIGN(indexSize, dbHandlesPerPage);
	    
    size_t fileSize = initSize ? initSize : dbDefaultInitDatabaseSize;
    fileSize = DOALIGN(fileSize, dbBitmapSegmentSize);

    if (fileSize < indexSize*sizeof(offs_t)*4) {
	fileSize = indexSize*sizeof(offs_t)*4;
    }

    for (int i = dbBitmapId + dbBitmapPages; --i >= 0;) { 
	bitmapPageAvailableSpace[i] = INT_MAX;
    }
    currRBitmapPage = currPBitmapPage = dbBitmapId;
    currRBitmapOffs = currPBitmapOffs = 0;
    reservedChain = NULL;
    tables = NULL;
    modified = false;
    attach();

    if (status == dbInitializationMutex::NotYetInitialized) { 
	sprintf(name, "%s.cs", dbName);
	if (!cs.create(name, &monitor->sem)) { 
	    handleError(DatabaseOpenError,
			"Failed to initialize database monitor");
	    return false;
	}
	readSem.reset();
	writeSem.reset();
	upgradeSem.reset();
	monitor->nReaders = 0;
	monitor->nWriters = 0;
	monitor->nWaitReaders = 0;
	monitor->nWaitWriters = 0;
	monitor->waitForUpgrade = false;
	monitor->version = version = 1;
	monitor->users = 0;
	monitor->backupInProgress = 0;
	monitor->lastDeadlockRecoveryTime = 0;
	monitor->delayedCommitContext = NULL;
	monitor->concurrentTransId = 1;
	monitor->commitInProgress = false;
	memset(monitor->dirtyPagesMap, 0, dbDirtyPageBitmapSize);
    
	sprintf(databaseName, "%s.%d", dbName, version);
	if (file.open(fileName, databaseName, 
		      accessType == dbReadOnly, fileSize) != dbFile::ok)
	{
	    handleError(DatabaseOpenError, "Failed to create database file");
	    return false;
	}
	baseAddr = (byte*)file.getAddr();
	fileSize = file.getSize();
	header = (dbHeader*)baseAddr;
	updatedRecordId = 0;
	
	if ((unsigned)header->curr > 1) { 
	    handleError(DatabaseOpenError, "Database file was corrupted: "
			"invalid root index");
	    return false;
	}
	if (header->initialized != 1) {
	    if (accessType == dbReadOnly) { 
		handleError(DatabaseOpenError, "Can not open uninitialized "
			    "file in read only mode");
		return false;
	    }
	    monitor->curr = header->curr = 0;
	    header->size = fileSize;
	    size_t used = dbPageSize;
	    header->root[0].index = used;
	    header->root[0].indexSize = indexSize;
	    header->root[0].indexUsed = dbFirstUserId;
	    header->root[0].freeList = 0;
	    used += indexSize*sizeof(offs_t);
	    header->root[1].index = used;
	    header->root[1].indexSize = indexSize;
	    header->root[1].indexUsed = dbFirstUserId;
	    header->root[1].freeList = 0;
	    used += indexSize*sizeof(offs_t);

	    header->root[0].shadowIndex = header->root[1].index;
	    header->root[1].shadowIndex = header->root[0].index;
	    header->root[0].shadowIndexSize = indexSize;
	    header->root[1].shadowIndexSize = indexSize;
	    
	    header->majorVersion= FASTDB_MAJOR_VERSION;
	    header->minorVersion = FASTDB_MINOR_VERSION;

	    index[0] = (offs_t*)(baseAddr + header->root[0].index);
	    index[1] = (offs_t*)(baseAddr + header->root[1].index);
	    index[0][dbInvalidId] = dbFreeHandleMarker;

	    size_t bitmapPages = 
		(used + dbPageSize*(dbAllocationQuantum*8-1) - 1)
		/ (dbPageSize*(dbAllocationQuantum*8-1));
	    memset(baseAddr+used, 0xFF, (used + bitmapPages*dbPageSize)
		                        / (dbAllocationQuantum*8));
	    size_t i;
	    for (i = 0; i < bitmapPages; i++) { 
		index[0][dbBitmapId + i] = used + dbPageObjectMarker;
		used += dbPageSize;
	    }
	    while (i < dbBitmapPages) { 
		index[0][dbBitmapId+i] = dbFreeHandleMarker;
		i += 1;
	    }
	    currIndex = index[0];
	    currIndexSize = dbFirstUserId;
	    committedIndexSize = 0;
	    initializeMetaTable();
	    header->dirty = true;
	    memcpy(index[1], index[0], currIndexSize*sizeof(offs_t));
	    file.markAsDirty(0, used);
	    file.flush();
	    header->initialized = true;
	    file.markAsDirty(0, sizeof(dbHeader));
	    file.flush();
	} else {
	    monitor->curr = header->curr;
	    if (header->dirty) { 
		TRACE_MSG(("Database was not normally closed: "
			   "start recovery\n"));
		if (accessType == dbReadOnly) { 
		    handleError(DatabaseOpenError,
				"Can not open dirty file in read only moode");
		    return false;
		}
		recovery();
		TRACE_MSG(("Recovery completed\n"));
	    } else { 
		if (file.getSize() != header->size) { 
		    handleError(DatabaseOpenError, "Database file was "
				"corrupted: file size in header differs "
				"from actual file size");
		    return false;
		}
	    }	    
	}
	if (!loadScheme(true)) { 
	    return false;
	}
	initMutex.done();
    } else { 
	sprintf(name, "%s.cs", dbName);
	if (!cs.open(name, &monitor->sem)) { 
	    handleError(DatabaseOpenError, "Failed to open shared semaphore");
	    return false;
	}
	version = 0;
	if (!loadScheme(false)) { 
	    return false;
	}
    }
    monitor->users += 1;
    opened = true;

    if (commitDelaySec != 0) { 
	commitTimeout = commitDelay = commitDelaySec;
	commitThread.create(delayedCommitProc, this);
    }
    return true;
}

void dbDatabase::scheduleBackup(char const* fileName, time_t period)
{
    if (backupFileName == NULL) { 
	backupFileName = new char[strlen(fileName) + 1];
	strcpy(backupFileName, fileName);
	backupPeriod = period;
	backupThread.create(backupSchedulerProc, this);
    }
}
 
void dbDatabase::backupScheduler() 
{ 
    backupThread.setPriority(dbThread::THR_PRI_LOW);
    dbCriticalSection cs(backupMutex); 
    while (true) { 
	time_t timeout = backupPeriod;
	if (backupFileName[strlen(backupFileName)-1] != '?') {
	    struct stat st;
	    if (::stat(backupFileName, &st) == 0) { 
		time_t howOld = time(NULL) - st.st_atime;
		if (timeout < howOld) { 
		    timeout = 0;
		} else { 
		    timeout -= howOld;
		}
	    }
	}
	
	backupInitEvent.wait(backupMutex, timeout);
	
	if (backupFileName != NULL) { 
	    if (backupFileName[strlen(backupFileName)-1] == '?') {
		time_t currTime = time(NULL);
		char* fileName = new char[strlen(backupFileName) + 32];
		struct tm* t = localtime(&currTime);
		sprintf(fileName, "%.*s-%04d.%02d.%02d_%02d.%02d.%02d", 
			(int)strlen(backupFileName)-1, backupFileName,
			t->tm_year + 1900, t->tm_mon+1, t->tm_mday, 
			t->tm_hour, t->tm_min, t->tm_sec);
		backup(fileName, false);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -