Esempio n. 1
0
/**
 * @brief: random test 2, unoverlapped range lock and unlock
 *
 */
void random_test2(){
  int i, j;
 
  for(j = 0; j < 2; j++){
    treeInit();
  
    /*
     *to check the lock
     */
    for(i = 0; i < MAX_NODES; i++){
      unsigned start_lba = i*5;
      unsigned end_lba   = start_lba + 4;
      unsigned type      = rand()%2;
      lockRequest(start_lba, end_lba, type, 1, 0);
    }
  
    //treeDump(rootArray[0]);

    /*
     *to check the unlock
     */
    for(i = 0; i < MAX_NODES -2; i++){
      printf("\n\ndeleting case %d with", i+ 1);
      int index = (MAX_NODES - i - 1);
      printf("  event index %d\n", nodes[index].eventIndex);
      lockRelease(&nodes[index], 0);
    }
     treeDump(rootArray[0]);

    /*
     *to check the index overflow
     */
    for(i = 0; i < MAX_NODES; i++){
      unsigned start_lba = i*5;
      unsigned end_lba   = start_lba + 4;
      unsigned type      = rand()%2;
      lockRequest(start_lba, end_lba, type, 1, 0);
      treeDump(rootArray[0]);
    }
    printf("\n");
  }
}
Esempio n. 2
0
/***********************************************************************************************************************************
Get an archive file from the repository (WAL segment, history file, etc.)
***********************************************************************************************************************************/
int
cmdArchiveGet(void)
{
    FUNCTION_LOG_VOID(logLevelDebug);

    // Set the result assuming the archive file will not be found
    int result = 1;

    MEM_CONTEXT_TEMP_BEGIN()
    {
        // Check the parameters
        const StringList *commandParam = cfgCommandParam();

        if (strLstSize(commandParam) != 2)
        {
            if (strLstSize(commandParam) == 0)
                THROW(ParamRequiredError, "WAL segment to get required");

            if (strLstSize(commandParam) == 1)
                THROW(ParamRequiredError, "path to copy WAL segment required");

            THROW(ParamInvalidError, "extra parameters found");
        }

        // Get the segment name
        String *walSegment = strBase(strLstGet(commandParam, 0));

        // Destination is wherever we were told to move the WAL segment
        const String *walDestination =
            walPath(strLstGet(commandParam, 1), cfgOptionStr(cfgOptPgPath), STR(cfgCommandName(cfgCommand())));

        // Async get can only be performed on WAL segments, history or other files must use synchronous mode
        if (cfgOptionBool(cfgOptArchiveAsync) && walIsSegment(walSegment))
        {
            bool found = false;                                         // Has the WAL segment been found yet?
            bool queueFull = false;                                     // Is the queue half or more full?
            bool forked = false;                                        // Has the async process been forked yet?
            bool confessOnError = false;                                // Should we confess errors?

            // Loop and wait for the WAL segment to be pushed
            Wait *wait = waitNew((TimeMSec)(cfgOptionDbl(cfgOptArchiveTimeout) * MSEC_PER_SEC));

            do
            {
                // Check for errors or missing files.  For archive-get ok indicates that the process succeeded but there is no WAL
                // file to download.
                if (archiveAsyncStatus(archiveModeGet, walSegment, confessOnError))
                {
                    storageRemoveP(
                        storageSpoolWrite(),
                        strNewFmt(STORAGE_SPOOL_ARCHIVE_IN "/%s" STATUS_EXT_OK, strPtr(walSegment)), .errorOnMissing = true);
                    break;
                }

                // Check if the WAL segment is already in the queue
                found = storageExistsNP(storageSpool(), strNewFmt(STORAGE_SPOOL_ARCHIVE_IN "/%s", strPtr(walSegment)));

                // If found then move the WAL segment to the destination directory
                if (found)
                {
                    // Source is the WAL segment in the spool queue
                    StorageFileRead *source = storageNewReadNP(
                        storageSpool(), strNewFmt(STORAGE_SPOOL_ARCHIVE_IN "/%s", strPtr(walSegment)));

                    // A move will be attempted but if the spool queue and the WAL path are on different file systems then a copy
                    // will be performed instead.
                    //
                    // It looks scary that we are disabling syncs and atomicity (in case we need to copy intead of move) but this
                    // is safe because if the system crashes Postgres will not try to reuse a restored WAL segment but will instead
                    // request it again using the restore_command. In the case of a move this hardly matters since path syncs are
                    // cheap but if a copy is required we could save a lot of writes.
                    StorageFileWrite *destination = storageNewWriteP(
                        storageLocalWrite(), walDestination, .noCreatePath = true, .noSyncFile = true, .noSyncPath = true,
                        .noAtomic = true);

                    // Move (or copy if required) the file
                    storageMoveNP(storageSpoolWrite(), source, destination);

                    // Return success
                    result = 0;

                    // Get a list of WAL segments left in the queue
                    StringList *queue = storageListP(
                        storageSpool(), STORAGE_SPOOL_ARCHIVE_IN_STR, .expression = WAL_SEGMENT_REGEXP_STR);

                    if (strLstSize(queue) > 0)
                    {
                        // Get size of the WAL segment
                        uint64_t walSegmentSize = storageInfoNP(storageLocal(), walDestination).size;

                        // Use WAL segment size to estimate queue size and determine if the async process should be launched
                        queueFull = strLstSize(queue) * walSegmentSize > cfgOptionUInt64(cfgOptArchiveGetQueueMax) / 2;
                    }
                }

                // If the WAL segment has not already been found then start the async process to get it.  There's no point in
                // forking the async process off more than once so track that as well.  Use an archive lock to prevent forking if
                // the async process was launched by another process.
                if (!forked && (!found || !queueFull)  &&
                    lockAcquire(cfgOptionStr(cfgOptLockPath), cfgOptionStr(cfgOptStanza), cfgLockType(), 0, false))
                {
                    // Get control info
                    PgControl pgControl = pgControlFromFile(cfgOptionStr(cfgOptPgPath));

                    // Create the queue
                    storagePathCreateNP(storageSpoolWrite(), STORAGE_SPOOL_ARCHIVE_IN_STR);

                    // The async process should not output on the console at all
                    KeyValue *optionReplace = kvNew();

                    kvPut(optionReplace, VARSTR(CFGOPT_LOG_LEVEL_CONSOLE_STR), VARSTRDEF("off"));
                    kvPut(optionReplace, VARSTR(CFGOPT_LOG_LEVEL_STDERR_STR), VARSTRDEF("off"));

                    // Generate command options
                    StringList *commandExec = cfgExecParam(cfgCmdArchiveGetAsync, optionReplace);
                    strLstInsert(commandExec, 0, cfgExe());

                    // Clean the current queue using the list of WAL that we ideally want in the queue.  queueNeed()
                    // will return the list of WAL needed to fill the queue and this will be passed to the async process.
                    const StringList *queue = queueNeed(
                        walSegment, found, cfgOptionUInt64(cfgOptArchiveGetQueueMax), pgControl.walSegmentSize,
                        pgControl.version);

                    for (unsigned int queueIdx = 0; queueIdx < strLstSize(queue); queueIdx++)
                        strLstAdd(commandExec, strLstGet(queue, queueIdx));

                    // Release the lock so the child process can acquire it
                    lockRelease(true);

                    // Fork off the async process
                    if (forkSafe() == 0)
                    {
                        // Disable logging and close log file
                        logClose();

                        // Detach from parent process
                        forkDetach();

                        // Execute the binary.  This statement will not return if it is successful.
                        THROW_ON_SYS_ERROR(
                            execvp(strPtr(cfgExe()), (char ** const)strLstPtr(commandExec)) == -1,
                            ExecuteError, "unable to execute '" CFGCMD_ARCHIVE_GET_ASYNC "'");
                    }

                    // Mark the async process as forked so it doesn't get forked again.  A single run of the async process should be
                    // enough to do the job, running it again won't help anything.
                    forked = true;
                }

                // Exit loop if WAL was found
                if (found)
                    break;

                // Now that the async process has been launched, confess any errors that are found
                confessOnError = true;
            }
            while (waitMore(wait));
        }
        // Else perform synchronous get
        else
        {
Esempio n. 3
0
/***********************************************************************************************************************************
Do cleanup and return result code
***********************************************************************************************************************************/
int
exitSafe(int result, bool error, SignalType signalType)
{
    FUNCTION_LOG_BEGIN(logLevelDebug);
        FUNCTION_LOG_PARAM(INT, result);
        FUNCTION_LOG_PARAM(BOOL, error);
        FUNCTION_LOG_PARAM(ENUM, signalType);
    FUNCTION_LOG_END();

    // Report error if one was thrown
    if (error)
    {
        // Don't log the error if it has already been logged by Perl
#ifdef HAVE_LIBPERL
        if (strcmp(errorMessage(), PERL_EMBED_ERROR) != 0)
        {
#endif
            LogLevel logLevel = errorCode() == errorTypeCode(&AssertError) ? logLevelAssert : logLevelError;

            // Assert errors always output a stack trace
            if (logLevel == logLevelAssert)
                LOG(logLevel, errorCode(), "%s\nSTACK TRACE:\n%s", errorMessage(), errorStackTrace());
            else
            {
                // Log just the error to non-debug levels
                LOG_INTERNAL(logLevel, LOG_LEVEL_MIN, logLevelDetail, 0, errorCode(), errorMessage());

                // Log the stack trace debug levels
                if (logAny(logLevelDebug))
                {
                    LOG_INTERNAL(
                        logLevel, logLevelDebug, LOG_LEVEL_MAX, 0, errorCode(), "%s\nSTACK TRACE:\n%s", errorMessage(),
                        errorStackTrace());
                }
            }
#ifdef HAVE_LIBPERL
        }
#endif

        result = errorCode();
    }

    // Free protocol objects but ignore errors
    TRY_BEGIN()
    {
        protocolFree();
    }
    TRY_END();

    // Free Perl but ignore errors
#ifdef HAVE_LIBPERL
    TRY_BEGIN()
    {
        perlFree(result);
    }
    TRY_END();
#endif

    // Log command end if a command is set
    if (cfgCommand() != cfgCmdNone)
    {
        String *errorMessage = NULL;

        // On error generate an error message
        if (result != 0)
        {
            // On process terminate
            if (result == errorTypeCode(&TermError))
            {
                errorMessage = strNew("terminated on signal ");

                // Terminate from a child
                if (signalType == signalTypeNone)
                    strCat(errorMessage, "from child process");
                // Else terminated directly
                else
                    strCatFmt(errorMessage, "[SIG%s]", exitSignalName(signalType));
            }
            // Standard error exit message
            else if (error)
                errorMessage = strNewFmt("aborted with exception [%03d]", result);
        }

        cmdEnd(result, errorMessage);
    }

    // Release any locks but ignore errors
    TRY_BEGIN()
    {
        lockRelease(false);
    }
    TRY_END();

    // Return result - caller should immediate pass this result to exit()
    FUNCTION_LOG_RETURN(INT, result);
}
Esempio n. 4
0
/**
 * @brief: Test one example
*/
void test_case1(){
  treeInit();

  tree_node_t *n1,*n2, *n3, *n4, *n5, *n6;
  n1 = allocNodes();
  n2 = allocNodes();
  n3 = allocNodes();
  n4 = allocNodes();
  n5 = allocNodes();
  n6 = allocNodes();
  
 /**
  * Event 1: R [ 1- 40]
  */
  n1->eventIndex = 1;
  n1->start_lba  = 1;
  n1->end_lba    = 40;
  n1->type       = 0;
  

  /**
  * Event 2: W [ 1- 10]
  */
  n2->eventIndex = 2;
  n2->start_lba  = 1;
  n2->end_lba    = 10;
  n2->type       = 1;

 /**
  * Event 3: W [ 8- 20]
  */
  n3->eventIndex = 3;
  n3->start_lba  = 8;
  n3->end_lba    = 20;
  n3->type       = 1;

  
 /**
  * Event 4: W [ 21- 30]
  */
  n4->eventIndex = 4;
  n4->start_lba  = 21;
  n4->end_lba    = 30;
  n4->type       = 1; 

 /**
  * Event 5: W [ 31- 40]
  */
  n5->eventIndex = 5;
  n5->start_lba  = 31;
  n5->end_lba    = 40;
  n5->type       = 1;

  /**
   * Event 6: R [ 1- 40]
   */
  n6->eventIndex = 6;
  n6->start_lba  = 1;
  n6->end_lba    = 40;
  n6->type       = 0;
  
  /*insert all events, it should be a linked list
   * event 1 R[1-40] -->event 2 W[1-10] -->event 3 W[8-20] -->event 4 W[21-30] -->event 5 W[31-40] -->event 6 R[1-40]
   */
  insertNode(&rootArray[0], n1, 1);
  insertNode(&rootArray[0], n2, 1);
  insertNode(&rootArray[0], n3, 1);
  insertNode(&rootArray[0], n4, 1);
  insertNode(&rootArray[0], n5, 1);
  insertNode(&rootArray[0], n6, 1);

  treeDump(rootArray[0]);

  printf("remove n1\n");
  lockRelease(n1, 0);
 /*
  * the avl tree should be:
  *            event 4 --> event 6
  *                 / \
  *event 3 <- event 2 event 5
  */
  treeDump(rootArray[0]);

  /**
   * delete event 6, and it should be rejected.
   */
  printf("----\n\n");
  printf("remove n6\n");
  lockRelease(n6, 0);
  treeDump(rootArray[0]);
  /*
   * delete event 2, and the AVL tree should be like this
   * 
   * event 4 --> event 3 -->event 6
   *  \
   *  event 5
   */
  printf("---\n\n");
  printf("remove n2\n");
  lockRelease(n2, 0);
  treeDump(rootArray[0]);
  
  /*
   * delete event 4, and the AVL tree should be like this
   *  
   *  event 5 ->event 6
   *  /
   * event 3
   */
  printf("--\n\n");
  printf("remove n4\n");
  lockRelease(n4, 0);
  treeDump(rootArray[0]);
  
  /*
   * delete event 5, and the AVL tree should be like this
   *
   * event 3 -->event 6
   *  
   */
  printf("---\n\n");
  printf("remove n5\n");
  lockRelease(n5, 0);
  treeDump(rootArray[0]);
  
  /*
   * delete event 3, and the AVL tree should be like this.
   *
   * event 6
   */
  printf("--\n\n");
  printf("remove n3\n");
  lockRelease(n3, 0);
  treeDump(rootArray[0]);
}