database.cpp

来自「FastDb是高效的内存数据库系统」· C++ 代码 · 共 2,469 行 · 第 1/5 页

CPP
2,469
字号



  case dbvmFuncInt2Bool:
    execute(expr->func.arg[0], iattr, sattr);
    sattr.bvalue = (*(bool(*)(db_int8))expr->func.fptr)(sattr.ivalue);
    return;

  case dbvmFuncReal2Bool:
    execute(expr->func.arg[0], iattr, sattr);
    sattr.bvalue = (*(bool(*)(real8))expr->func.fptr)(sattr.fvalue);
    return;

  case dbvmFuncStr2Bool:
    execute(expr->func.arg[0], iattr, sattr);
    sattr.bvalue =
      (*(bool(*)(char const*))expr->func.fptr)(sattr.array.base);
    return;

  case dbvmFuncInt2Int:
    execute(expr->func.arg[0], iattr, sattr);
    sattr.ivalue = (*(db_int8(*)(db_int8))expr->func.fptr)(sattr.ivalue);
    return;

  case dbvmFuncReal2Int:
    execute(expr->func.arg[0], iattr, sattr);
    sattr.ivalue = (*(db_int8(*)(real8))expr->func.fptr)(sattr.fvalue);
    return;

  case dbvmFuncStr2Int:
    execute(expr->func.arg[0], iattr, sattr);
    sattr.ivalue =
      (*(db_int8(*)(char const*))expr->func.fptr)(sattr.array.base);
    return;

  case dbvmFuncInt2Real:
    execute(expr->func.arg[0], iattr, sattr);
    sattr.fvalue = (*(real8(*)(db_int8))expr->func.fptr)(sattr.ivalue);
    return;

  case dbvmFuncReal2Real:
    execute(expr->func.arg[0], iattr, sattr);
    sattr.fvalue = (*(real8(*)(real8))expr->func.fptr)(sattr.fvalue);
    return;

  case dbvmFuncStr2Real:
    execute(expr->func.arg[0], iattr, sattr);
    sattr.fvalue =
      (*(real8(*)(char const*))expr->func.fptr)(sattr.array.base);
    return;

  case dbvmFuncInt2Str:
    execute(expr->func.arg[0], iattr, sattr);
    copyString(iattr, sattr,
               (*(char*(*)(db_int8))expr->func.fptr)(sattr.ivalue));
    return;

  case dbvmFuncReal2Str:
    execute(expr->func.arg[0], iattr, sattr);
    copyString(iattr, sattr,
               (*(char*(*)(real8))expr->func.fptr)(sattr.fvalue));
    return;

  case dbvmFuncStr2Str:
    execute(expr->func.arg[0], iattr, sattr);
    copyString(iattr, sattr,
               (*(char*(*)(char const*))expr->func.fptr)(sattr.array.base));
    return;

  case dbvmInArrayBool:
    execute(expr->operand[0], iattr, sattr);
    execute(expr->operand[1], iattr, sattr2);
    searchArrayOfBool(sattr, sattr2);
    return;

  case dbvmInArrayInt1:
    execute(expr->operand[0], iattr, sattr);
    execute(expr->operand[1], iattr, sattr2);
    searchArrayOfInt1(sattr, sattr2);
    return;

  case dbvmInArrayInt2:
    execute(expr->operand[0], iattr, sattr);
    execute(expr->operand[1], iattr, sattr2);
    searchArrayOfInt2(sattr, sattr2);
    return;

  case dbvmInArrayInt4:
    execute(expr->operand[0], iattr, sattr);
    execute(expr->operand[1], iattr, sattr2);
    searchArrayOfInt4(sattr, sattr2);
    return;

  case dbvmInArrayInt8:
    execute(expr->operand[0], iattr, sattr);
    execute(expr->operand[1], iattr, sattr2);
    searchArrayOfInt8(sattr, sattr2);
    return;

  case dbvmInArrayReal4:
    execute(expr->operand[0], iattr, sattr);
    execute(expr->operand[1], iattr, sattr2);
    searchArrayOfReal4(sattr, sattr2);
    return;

  case dbvmInArrayReal8:
    execute(expr->operand[0], iattr, sattr);
    execute(expr->operand[1], iattr, sattr2);
    searchArrayOfReal8(sattr, sattr2);
    return;

  case dbvmInArrayString:
    execute(expr->operand[0], iattr, sattr);
    execute(expr->operand[1], iattr, sattr2);
    searchArrayOfString(sattr, sattr2);
    return;

  case dbvmInArrayReference:
    execute(expr->operand[0], iattr, sattr);
    execute(expr->operand[1], iattr, sattr2);
    searchArrayOfReference(sattr, sattr2);
    return;

  case dbvmInString:
    execute(expr->operand[0], iattr, sattr);
    execute(expr->operand[1], iattr, sattr2);
    searchInString(sattr, sattr2);
    return;

  default:
    assert(false);
  }
}


void dbDatabase::handleError(dbErrorClass error, char const* msg, int arg)
{
  if (errorHandler != NULL)
  {
    (*errorHandler)(error, msg, arg);
  }

#ifdef THROW_EXCEPTION_ON_ERROR
  if (error != NoError)
  {
    if (error == DatabaseOpenError)
    {
      fprintf(stderr, "%s\n", msg);
    }
    else
    {
      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;

  case InconsistentInverseReference:
    fprintf(stderr, "%s\n", msg);
    return;

  case DatabaseReadOnly:
    fprintf(stderr, "Attempt to modify readonly database");
    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 < itemsof(metaTableFields); i++)
  {
    varyingSize += strlen(metaTableFields[i].name) + 3;

  }

  offs_t metaTableOffs = allocate(sizeof(dbTable)
                                  + sizeof(dbField)*itemsof(metaTableFields)
                                  + varyingSize);
  index[0][dbMetaTableId] = metaTableOffs;
  dbTable* table = (dbTable*)(baseAddr + metaTableOffs);
  table->size = sizeof(dbTable) + sizeof(dbField)*itemsof(metaTableFields)
                + varyingSize;
  table->next = table->prev = 0;
  int offs = sizeof(dbTable) + sizeof(dbField)*itemsof(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 = itemsof(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 < itemsof(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();
    commitThreadSyncEvent.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;

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

  fileSize = DOALIGN(fileSize, dbBitmapSegmentSize);
#ifdef DISKLESS_CONFIGURATION

  mmapSize = fileSize;
#else

  mmapSize = 0;
#endif

  for (int i = dbBitmapId + dbBitmapPages; --i >= 0;)
  {
    bitmapPageAvailableSpace[i] = INT_MAX;
  }

  currRBitmapPage = currPBitmapPage = dbBitmapId;
  currRBitmapOffs = currPBitmapOffs = 0;
  reservedChain = NULL;
  tables = NULL;
  modified = false;
  threadContextList.reset();
  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;
    }

    if (accessType == dbConcurrentUpdate)
    {
      sprintf(name, "%s.mcs", dbName);

      if (!mutatorCS.create(name, &monitor->mutatorSem))
      {
        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->forceCommitCount = 0;
    monitor->lastDeadlockRecoveryTime = 0;
    monitor->delayedCommitContext = NULL;
    monitor->concurrentTransId = 1;
    monitor->commitInProgress = false;
    monitor->uncommittedChanges = false;
    memset(monitor->dirtyPagesMap, 0, dbDirtyPageBitmapSize);

⌨️ 快捷键说明

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