Exemple #1
0
/*
 * Opens the backend database.
 *
 * ARGUMENTS:
 *      backend         Pointer to pointer to backend structure.  Shall not be
 *                      NULL.  Upon successful return, "*backend" will be set.
 *                      The client should call "beClose(*backend)" when the
 *                      backend is no longer needed.
 *      dir             Pathname of the parent directory of the database.
 *                      Shall not be NULL.  The client can free it upon return.
 *      forWriting      Open the database for writing? 0 <=> no
 * RETURNS:
 *      0               Success.  "*backend" is set.
 *      ENOMEM          System error.  "log_start()" called.
 *      EIO             Backend database error.  "log_start()" called.
 */
RegStatus
beOpen(
    Backend** const     backend,
    const char* const   dir,
    int                 forWriting)
{
    RegStatus   status;
    Backend*    back = (Backend*)malloc(sizeof(Backend));

    assert(NULL != dir);

    if (NULL == back) {
        log_serror("Couldn't allocate %lu bytes", (long)sizeof(Backend));
        status = ENOMEM;
    }
    else {
        DB_ENV*         env;
        DB*             db;
        StringBuf*      path;

        if (0 == (status = sb_new(&path, PATH_MAX))) {
            if (0 == (status = sb_cat(path, dir, "/", DB_DIRNAME))) {
                if (0 == (status = createDbHandle(path, &env, &db))) {
                    if (status = db->open(db, NULL, DB_FILENAME, NULL,
                                          DB_BTREE, forWriting ? DB_CREATE : DB_RDONLY, 0)) {
                        log_add("Couldn't open database \"%s\" in \"%s\" "
                                "for %s", DB_FILENAME, path,
                                forWriting ? "writing" : "reading");
                        status = EIO;
                    }
                    else {
                        back->db = db;
                        back->cursor.dbCursor = NULL;
                        *backend = back;    /* success */
                    }                       /* "db" opened */

                    /*
                     * According to the documentation on DB->open(), if that
                     * call fails, then DB->close() must be called to discard
                     * the DB handle, so DB->close() is the termination
                     * counterpart of db_create() rather than of DB->open().
                     */
                    if (status) {
                        (void)db->close(db, 0);
                        (void)env->close(env, 0);
                    }
                }                       /* "env" allocated */
            }                           /* DB directory pathname created */

            sb_free(path);
        }                               /* "path" allocated */

        if (status)
            free(back);
    }                                   /* "back" allocated */

    return status;
}
Exemple #2
0
/**
 * Allocates memory. Thread safe.
 *
 * @param nbytes        Number of bytes to allocate.
 * @param msg           Message to print on error. Should complete the sentence
 *                      "Couldn't allocate <n> bytes for ...".
 * @param file          Name of the file.
 * @param line          Line number in the file.
 * @retval NULL         Out of memory. \c log_start() called.
 * @return              Pointer to the allocated memory.
 */
void* log_malloc(
    const size_t        nbytes,
    const char* const   msg,
    const char* const   file,
    const int           line)
{
    void* obj = malloc(nbytes);

    if (obj == NULL)
        log_serror(LOG_FMT("Couldn't allocate %lu bytes for %s"), file, line,
                nbytes, msg);

    return obj;
}
Exemple #3
0
/*
 * Creates a database environment handle
 *
 * ARGUMENTS:
 *      path            Pathname of the database directory.  Shall not be NULL.
 *                      The client can free it upon return.
 *      dbEnv           Pointer to a pointer to the database environment.  Shall
 *                      not be NULL.  "*dbEnv" is set upon successful return.
 * RETURNS:
 *      0               Success.  "*dbEnv" is set.
 *      ENOMEM          System error.  "log_start()" called.
 *      EIO             Backend database error.  "log_start()" called.
 */
static RegStatus
createEnvHandle(
    const char* const   path,
    DB_ENV** const      dbEnv)
{
    RegStatus   status;
    DB_ENV*     env;

    assert(NULL != path);

    log_clear();

    if (status = db_env_create(&env, 0)) {
        log_serror("Couldn't create environment handle for database: %s",
                   db_strerror(status));
        status = ENOMEM;
    }
    else {
        env->set_errcall(env, logDbError);

        if (status = env->set_isalive(env, is_alive)) {
            log_add("Couldn't register \"is_alive()\" function for "
                    "database \"%s\"", path);
            status = EIO;
        }
        else {
            static const unsigned      threadCount = 256;

            if (status = env->set_thread_count(env, threadCount)) {
                log_add("Couldn't set thread count to %u for database \"%s\"",
                        threadCount, path);
                status = EIO;
            }
            else {
                *dbEnv = env;
            }
        }

        if (status)
            (void)env->close(env, 0);
    }                                   /* "env" allocated */

    return status;
}
Exemple #4
0
/*
 * Constructs a path name for the database.
 *
 * Arguments:
 *      path            Pathname of the database directory.  Shall not be NULL.
 *                      The client can free it upon return.
 *      ext             Extension for the database path name.
 * Returns:
 *      NULL            System error.  "log_start()" called.
 *      else            Pointer to the path name of the database.  The
 *                      client should call "free()" when the path name is no
 *                      longer needed.
 */
static char*
makeDatabasePath(
    const char* const   path,
    const char* const   ext)
{
    static const size_t lenFilename = sizeof(DB_FILENAME) - 1;
    size_t              lenPath = strlen(path);
    size_t              len = strlen(path) + 1 + lenFilename + strlen(ext) + 1;
    char*               buf = (char*)malloc(len);

    if (NULL == buf) {
        log_serror("Couldn't allocate %lu bytes", (unsigned long)len);
    }
    else {
        (void)strcpy(strcpy(strcpy(strcpy(buf, path) + lenPath, "/") + 1,
                            DB_FILENAME) + lenFilename, ext);
    }

    return buf;
}
Exemple #5
0
/*
 * Sets the cursor to reference the first entry in the backend
 * database whose key is greater than or equal to a given key.
 *
 * ARGUMENTS:
 *      backend         Pointer to the backend database.  Shall have been
 *                      set by beOpen().  Shall not be NULL.
 *      key             Pointer to the starting key.  Shall not be NULL.  The
 *                      empty string obtains the first entry in the database,
 *                      if it exists.
 * RETURNS
 *      0               Success.
 *      EINVAL          The cursor is not initialized.
 *      ENOENT          The database is empty.
 *      EIO             Backend database error.  "log_start()" called.
 *      ENOMEM          System error.  "log_start()" called.
 */
RegStatus
beFirstEntry(
    Backend* const      backend,
    const char* const   key)
{
    RegStatus   status;
    Cursor*     cursor;

    assert(NULL != backend);
    assert(NULL != key);

    cursor = &backend->cursor;

    if (!cursor->dbCursor) {
        log_start("Cursor for backend database \"%s\" not initialized",
                  getPath(backend->db));
        status = EINVAL;
    }
    else {
        char* const dupKey = strdup(key);

        if (NULL == dupKey) {
            log_serror("Couldn't allocate %lu bytes", (long)strlen(key));
            status = ENOMEM;
        }
        else {
            backend->cursor.key.data = dupKey;
            backend->cursor.key.size = strlen(dupKey) + 1;

            if (EIO == (status = setCursor(&backend->cursor, DB_SET_RANGE))) {
                log_add("Couldn't set cursor for database \"%s\" to first "
                        "entry on or after key \"%s\"", getPath(backend->db), key);
            }
        }                               /* "dupKey" allocated */
    }

    return status;
}
Exemple #6
0
/*
 * Returns a new instance of an LDM proxy. Can take a while because it
 * establishes a connection to the LDM.
 *
 * Arguments:
 *      host            Identifier of the host on which an LDM server is
 *                      running.
 *      instance        Pointer to a pointer to the new instance. "*instance"
 *                      is set upon successful return.
 * Returns:
 *      0               Success. "*instance" is set.
 *      LP_SYSTEM       System error. "log_start()" called.
 *      LP_TIMEDOUT     Connection attempt timed-out. "log_start()" called.
 *      LP_HOSTUNREACH  Host is unreachable. "log_start()" called.
 *      LP_RPC_ERROR    RPC error. "log_start()" called.
 *      LP_LDM_ERROR    LDM error. "log_start()" called.
 */
LdmProxyStatus
lp_new(
    const char* const   host,
    LdmProxy** const    instance)
{
    LdmProxyStatus      status = 0;     /* success */
    size_t              nbytes = sizeof(LdmProxy);
    LdmProxy*           proxy = (LdmProxy*)malloc(nbytes);

    if (NULL == proxy) {
        log_serror("Couldn't allocate %lu bytes for new LdmProxy", nbytes);
        status = LP_SYSTEM;
    }
    else {
        proxy->host = strdup(host);

        if (NULL == proxy->host) {
            LOG_SERROR1("Couldn't duplicate string \"%s\"", host);
            status = LP_SYSTEM;
        }
        else {
            CLIENT*         clnt = NULL;
            ErrorObj*       error = ldm_clnttcp_create_vers(host, LDM_PORT, 6,
                    &clnt, NULL, NULL);

            if (!error) {
                proxy->version = 6;
                proxy->hiya = my_hiya_6;
                proxy->send = my_send_6;
                proxy->flush = my_flush_6;
            }
            else if (LDM_CLNT_BAD_VERSION == err_code(error)) {
                /* Couldn't connect due to protocol version. */
                err_free(error);

                error = ldm_clnttcp_create_vers(host, LDM_PORT, 5,
                        &clnt, NULL, NULL);

                if (!error) {
                    proxy->version = 5;
                    proxy->hiya = my_hiya_5;
                    proxy->send = my_send_5;
                    proxy->flush = my_flush_5;
                }
            }

            if (error) {
                LOG_START1("%s", err_message(error));
                err_free(error);
                free(proxy->host);
                status = convertStatus(error);
            }
            else {
                proxy->clnt = clnt;
                proxy->rpcTimeout = rpcTimeout;
            }
        }                                       /* "proxy->host" allocated */

        if (LP_OK == status) {
            *instance = proxy;
        }
        else {
            free(proxy);
        }
    }                                           /* "proxy" allocated */

    return status;
}