Esempio n. 1
0
/* Wait
 *  block until a count becomes available
 *
 *  "lock" [ IN ] - externally acquired lock
 */
LIB_EXPORT rc_t CC KSemaphoreWait ( KSemaphore *self, struct KLock *lock )
{
    if ( self == NULL )
        return RC ( rcPS, rcSemaphore, rcWaiting, rcSelf, rcNull );

    if ( self -> avail == 0 )
    {
        if ( ++ self -> waiting == 1 )
        {
            self -> requested = self -> min_requested = 1;
            self -> uniform = true;
        }
        else if ( self -> requested != 1 )
        {
            self -> min_requested = 1;
            self -> uniform = false;
        }

        do
        {
            rc_t rc = KConditionWait ( self -> cond, lock );
            if ( rc != 0 )
            {
                -- self -> waiting;
                return ResetRCContext ( rc, rcPS, rcSemaphore, rcWaiting );
            }
        }
        while ( self -> avail == 0 );

        -- self -> waiting;
    }

    -- self -> avail;
    return 0;
}
Esempio n. 2
0
/* CreateLockFile
 *  attempts to create a KLockFile
 *
 *  "lock" [ OUT ] - return parameter for newly created lock file
 *
 *  "path" [ IN ] - NUL terminated string in directory-native
 *  character set denoting lock file
 */
LIB_EXPORT rc_t CC KDirectoryVCreateLockFile ( KDirectory *self,
    KLockFile **lock, const char *path, va_list args )
{
    rc_t rc;

    if ( lock == NULL )
        rc = RC ( rcFS, rcFile, rcLocking, rcParam, rcNull );
    else
    {
        if ( self == NULL )
            rc = RC ( rcFS, rcFile, rcLocking, rcSelf, rcNull );
        else if ( path == NULL )
            rc = RC ( rcFS, rcFile, rcLocking, rcPath, rcNull );
        else if ( path [ 0 ] == 0 )
            rc = RC ( rcFS, rcFile, rcLocking, rcPath, rcEmpty );
        else
        {
            char full [ 4096 ];
            rc = KDirectoryVResolvePath ( self, false, full, sizeof full, path, args );
            if ( rc == 0 )
            {
                KFile *lock_file;
                rc = KDirectoryCreateFile ( self, & lock_file, false, 0600, kcmCreate | kcmParents, "%s", full );
                if ( rc == 0 )
                {
                    rc_t rc2;

                    /* no longer need the file - not going to write to it anyway */
                    KFileRelease ( lock_file );

                    /* we have the lock */
                    rc = KLockFileMake ( lock, self, full );
                    if ( rc == 0 )
                        return 0;

                    /* must unlink lockfile */
                    rc2 = KDirectoryRemove ( self, true, "%s", full );
                    if ( rc2 != 0 )
                        /* issue a report */;
                }
                else if ( GetRCState ( rc ) == rcExists )
                {
                    /* map the rc to kproc type values */
                    rc = RC ( rcFS, rcFile, rcLocking, rcLocking, rcBusy );
                }
                else
                {
                    rc = ResetRCContext ( rc, rcFS, rcFile, rcLocking );
                }
            }
        }

        * lock = NULL;
    }

    return rc;
}
Esempio n. 3
0
/* TimedWait
 *  block until a count becomes available
 *
 *  "lock" [ IN ] - externally acquired lock
 *
 *  "tm" [ IN, NULL OKAY ] - optional timeout where
 *  NULL means timeout value of 0
 */
LIB_EXPORT rc_t CC KSemaphoreTimedWait ( KSemaphore *self,
    struct KLock *lock, struct timeout_t *tm )
{
    if ( self == NULL )
        return RC ( rcPS, rcSemaphore, rcWaiting, rcSelf, rcNull );

    if ( self -> avail == 0 )
    {
        SMSG ( "%s[%p]: avail == 0\n", __func__, self );
        if ( tm == NULL )
        {
            SMSG ( "%s[%p]: non-blocking mode - return timeout exhausted\n", __func__, self );
            return RC ( rcPS, rcSemaphore, rcWaiting, rcTimeout, rcExhausted );
        }

        if ( ++ self -> waiting == 1 )
        {
            SMSG ( "%s[%p]: first waiter\n", __func__, self );
            self -> requested = self -> min_requested = 1;
            self -> uniform = true;
        }
        else if ( self -> requested != 1 )
        {
            SMSG ( "%s[%p]: multiple waiters ( %u )\n", __func__, self, self -> waiting );
            self -> min_requested = 1;
            self -> uniform = false;
        }

        do
        {
            rc_t rc;

            SMSG ( "%s[%p]: wait on condition...\n", __func__, self );
            rc = KConditionTimedWait ( self -> cond, lock, tm );
            SMSG ( "%s[%p]:...done, rc = %R\n", __func__, self, rc );
            if ( rc != 0 )
            {
                SMSG ( "%s[%p]: timed out - decrementing wait count\n", __func__, self );
                -- self -> waiting;
                return ResetRCContext ( rc, rcPS, rcSemaphore, rcWaiting );
            }

            SMSG ( "%s[%p]: condition signaled - avail = %lu\n", __func__, self, self -> avail );
        }
        while ( self -> avail == 0 );

        SMSG ( "%s[%p]: finished waiting\n", __func__, self );
        -- self -> waiting;
    }

    SMSG ( "%s[%p]: decrementing count from %lu\n", __func__, self, self -> avail );
    -- self -> avail;
    return 0;
}
Esempio n. 4
0
/* CreateTable
 *  create a new or open an existing table under database
 *
 *  "tbl" [ OUT ] - return parameter for newly opened table
 *
 *  "member" [ IN ] - name of table member template under database
 *  the named member is a table template rather than a named table.
 *
 *  "cmode" [ IN ] - creation mode
 *
 *  "cmode_mask" [ IN ] - if a bit of "cmode_mask" is set (1) then
 *  the corresponding bit of "cmode" is used for the table,
 *  otherwise (0) the corresponding bit is taken from db and "cmode"'s
 *  bit is ignored
 *  the mask for setting mode (kcmOpen, kcmInit, kcmCreate) is at least
 *  one bit set in the mask kcmValueMask.
 *
 *  "name" [ IN ] - NUL terminated string in
 *  db-native character set giving actual table name
 */
LIB_EXPORT rc_t CC VDatabaseVCreateTableByMask ( VDatabase *self, VTable **tblp,
    const char *member, KCreateMode cmode, KCreateMode cmode_mask, const char *name, va_list args )
{
    rc_t rc;

    if ( tblp == NULL )
        rc = RC ( rcVDB, rcDatabase, rcCreating, rcParam, rcNull );
    else
    {
        if ( self == NULL )
            rc = RC ( rcVDB, rcDatabase, rcCreating, rcSelf, rcNull );
        else if ( member == NULL )
            rc = RC ( rcVDB, rcMgr, rcOpening, rcName, rcNull );
        else if ( member [ 0 ] == 0 )
            rc = RC ( rcVDB, rcMgr, rcOpening, rcName, rcEmpty );
        else if ( self -> read_only )
            rc = RC ( rcVDB, rcDatabase, rcCreating, rcDatabase, rcReadonly );
        else
        {
            rc = VTableMake ( tblp, self -> mgr, self, self -> schema );
            if ( rc == 0 )
            {
                VTable *tbl = * tblp;

                rc = KDatabaseVCreateTableByMask ( self -> kdb, & tbl -> ktbl, cmode, cmode_mask, name, args );
                if ( rc == 0 )
                {
                    rc = VTableOpenUpdate ( tbl, member );
                    if ( rc == 0 )
                    {
                        tbl -> pgsize = self -> pgsize;
                        tbl -> cmode = KDatabaseGetCmode ( self->kdb ); /* TODO: do we really want to inherit open mode from db? */
                        tbl -> checksum = KDatabaseGetChecksum ( self->kdb );
#if LAZY_OPEN_COL_NODE
                        KMDataNodeRelease ( tbl -> col_node );
                        tbl -> col_node = NULL;
#endif
                        return 0;
                    }

                    rc = ResetRCContext ( rc, rcVDB, rcDatabase, rcCreating );
                }

                VTableWhack ( tbl );
            }
        }

        * tblp = NULL;
    }
    return rc;
}
Esempio n. 5
0
/* CreateTable
 *  create a new or open an existing table using manager
 *
 *  "tbl" [ OUT ] - return parameter for newly opened table
 *
 *  "schema" [ IN ] - schema object containg table
 *  declaration to be used in creating tbl.
 *
 *  "typespec" [ IN ] - type and optionally version of table schema,
 *  e.g. 'MY_NAMESPACE:MyTable' or 'MY_NAMESPACE:MyTable#1.1'
 *
 *  "cmode" [ IN ] - creation mode
 *
 *  "path" [ IN ] - NUL terminated string in
 *  wd-native character set giving path to table
 */
LIB_EXPORT rc_t CC VDBManagerVCreateTable ( VDBManager *self, VTable **tblp,
    const VSchema *schema, const char *typespec,
    KCreateMode cmode, const char *path, va_list args )
{
    rc_t rc;

    if ( tblp == NULL )
        rc = RC ( rcVDB, rcMgr, rcCreating, rcParam, rcNull );
    else
    {
        if ( self == NULL )
            rc = RC ( rcVDB, rcMgr, rcCreating, rcSelf, rcNull );
        else if ( schema == NULL )
            rc = RC ( rcVDB, rcMgr, rcOpening, rcSchema, rcNull );
        else if ( typespec == NULL )
            rc = RC ( rcVDB, rcMgr, rcOpening, rcName, rcNull );
        else if ( typespec [ 0 ] == 0 )
            rc = RC ( rcVDB, rcMgr, rcOpening, rcName, rcEmpty );
        else
        {
            /* create object with new schema */
            rc = VTableMake ( tblp, self, NULL, schema );
            if ( rc == 0 )
            {
                VTable *tbl = * tblp;

                /* create physical object */
                rc = KDBManagerVCreateTable ( self -> kmgr, & tbl -> ktbl, cmode, path, args );
                if ( rc == 0 )
                {
                    rc = VTableOpenUpdate ( tbl, typespec );
                    if ( rc == 0 )
                    {
#if LAZY_OPEN_COL_NODE
                        KMDataNodeRelease ( tbl -> col_node );
                        tbl -> col_node = NULL;
#endif
                        return 0;
                    }

                    rc = ResetRCContext ( rc, rcVDB, rcMgr, rcCreating );
                }
                VTableWhack ( tbl );
            }
        }

        * tblp = NULL;
    }
    return rc;
}
Esempio n. 6
0
/* Unlock
 *  remove lock
 *
 *  if object is already unlocked, the operation is idempotent
 *  and returns an rc state of rcUnlocked
 *
 *  "path" [ IN ] - NUL terminated path
 */
LIB_EXPORT rc_t CC KDBManagerVUnlock ( KDBManager *self, const char *path, va_list args )
{
    rc_t rc;
    char full [ 4096 ];

    if ( self == NULL )
        rc =  RC ( rcDB, rcMgr, rcUnlocking, rcSelf, rcNull );
    else
    {
        /* get full path to object */
        rc = KDirectoryVResolvePath ( self -> wd, true,
            full, sizeof full, path, args );
        if ( rc == 0 )
        {
            /* TBD:
               Add code to validate that this path is not in a container
               object's control.  That is the last facet in the path
               is the name of the object.  To be valid the facet before
               must not be "col", "tbl", or "db" as in those cases
               the KDBManager should not be called for this object but 
               its containing object
            */

            /* if the path is not writable because it is already locked
             * we attempt to unlock it.
             *
             * if the return is 0 from Writable than it was already 
             * unlocked so we say so and thus again the
             * the return from this will contain "rcLocked" and the 
             * caller will be forced to check for zero or RCState(rcUnlocked)
             *
             * a side effect is that if the call does not return 0 it will
             * be a wrong type to lock with the DBManager
             */
            rc = KDBManagerWritableInt ( self -> wd, path );
            if ( rc == 0 )
                rc = RC ( rcDB, rcMgr, rcUnlocking, rcLock, rcUnlocked );
            else if ( GetRCState ( rc ) == rcLocked )
            {
                rc = KDBManagerCheckOpen ( self, path );
                if ( rc == 0 )
                    rc = KDBUnlockDir ( self -> wd, path );
            }
        }

        if ( rc != 0 )
            rc = ResetRCContext ( rc, rcDB, rcMgr, rcUnlocking );
    }
    return rc;
}
Esempio n. 7
0
/* Whack
 */
static
rc_t KSemaphoreWhack ( KSemaphore *self )
{
    rc_t rc;

    if ( self -> waiting != 0 )
        return RC ( rcPS, rcSemaphore, rcDestroying, rcSemaphore, rcBusy );

    rc = KConditionRelease ( self -> cond );
    if ( rc != 0 )
        return ResetRCContext ( rc, rcPS, rcSemaphore, rcDestroying );

    free ( self );
    return 0;
}
Esempio n. 8
0
/* TimedAlloc
 *  allocate a count
 *  used for resource metering
 *
 *  "lock" [ IN ] - externally acquired lock
 *
 *  "count" [ IN ] - the resource count
 *
 *  "tm" [ IN, NULL OKAY ] - optional timeout where
 *  NULL means timeout value of 0
 */
LIB_EXPORT rc_t CC KSemaphoreTimedAlloc ( KSemaphore *self,
    struct KLock *lock, uint64_t count, struct timeout_t *tm )
{
    if ( self == NULL )
        return RC ( rcPS, rcSemaphore, rcWaiting, rcSelf, rcNull );

    if ( self -> avail < count )
    {
        if ( tm == NULL )
            return RC ( rcPS, rcSemaphore, rcWaiting, rcTimeout, rcExhausted );

        if ( ++ self -> waiting == 1 )
        {
            self -> requested = self -> min_requested = count;
            self -> uniform = true;
        }
        else if ( self -> requested != count )
        {
            if ( self -> min_requested > count )
                self -> min_requested = count;
            self -> uniform = false;
        }

        do
        {
            rc_t rc;

            if ( self -> canceled )
            {
                -- self -> waiting;
                return RC ( rcPS, rcSemaphore, rcWaiting, rcSemaphore, rcCanceled );
            }

            rc = KConditionTimedWait ( self -> cond, lock, tm );
            if ( rc != 0 )
            {
                -- self -> waiting;
                return ResetRCContext ( rc, rcPS, rcSemaphore, rcWaiting );
            }
        }
        while ( self -> avail < count );

        -- self -> waiting;
    }

    self -> avail -= count;
    return 0;
}
Esempio n. 9
0
/* Wait
 *  block until a count becomes available
 *
 *  "lock" [ IN ] - externally acquired lock
 */
LIB_EXPORT rc_t CC KSemaphoreWait ( KSemaphore *self, struct KLock *lock )
{
    if ( self == NULL )
        return RC ( rcPS, rcSemaphore, rcWaiting, rcSelf, rcNull );

    if ( self -> avail == 0 )
    {
        if ( ++ self -> waiting == 1 )
        {
            self -> requested = self -> min_requested = 1;
            self -> uniform = true;
        }
        else if ( self -> requested != 1 )
        {
            self -> min_requested = 1;
            self -> uniform = false;
        }

        do
        {
            rc_t rc;

            if ( self -> canceled )
            {
                SMSG ( "%s[%p]: wait was canceled - decrementing wait count\n", __func__, self );
                -- self -> waiting;
                return RC ( rcPS, rcSemaphore, rcWaiting, rcSemaphore, rcCanceled );
            }

            rc = KConditionWait ( self -> cond, lock );
            if ( rc != 0 )
            {
                -- self -> waiting;
                return ResetRCContext ( rc, rcPS, rcSemaphore, rcWaiting );
            }
        }
        while ( self -> avail == 0 );

        -- self -> waiting;
    }

    -- self -> avail;
    return 0;
}
Esempio n. 10
0
/* CreateDB
 * VCreateDB
 *  create a new or open an existing database
 *
 *  "db" [ OUT ] - return parameter for newly opened database
 *
 *  "schema" [ IN ] - schema object containg database
 *  declaration to be used in creating db [ needed by manager ].
 *
 *  "decl" [ IN ] - type and optionally version of db schema
 *
 *  "cmode" [ IN ] - creation mode
 *
 *  "path" [ IN ] - NUL terminated string in
 *  wd-native character set giving path to database
 */
LIB_EXPORT rc_t CC VDBManagerVCreateDB ( VDBManager *self, VDatabase **dbp,
    const VSchema *schema, const char *decl,
    KCreateMode cmode, const char *path, va_list args )
{
    rc_t rc;

    if ( dbp == NULL )
        rc = RC ( rcVDB, rcMgr, rcCreating, rcParam, rcNull );
    else
    {
        if ( self == NULL )
            rc = RC ( rcVDB, rcMgr, rcCreating, rcSelf, rcNull );
        else if ( schema == NULL )
            rc = RC ( rcVDB, rcMgr, rcOpening, rcSchema, rcNull );
        else if ( decl == NULL )
            rc = RC ( rcVDB, rcMgr, rcOpening, rcName, rcNull );
        else if ( decl [ 0 ] == 0 )
            rc = RC ( rcVDB, rcMgr, rcOpening, rcName, rcEmpty );
        else
        {
            rc = VDatabaseMake ( dbp, self, NULL, schema );
            if ( rc == 0 )
            {
                VDatabase *db = * dbp;

                rc = KDBManagerVCreateDB ( self -> kmgr, & db -> kdb, cmode, path, args );
                if ( rc == 0 )
                {
                    rc = VDatabaseOpenUpdate ( db, decl );
                    if ( rc == 0 )
                        return 0;

                    rc = ResetRCContext ( rc, rcVDB, rcMgr, rcCreating );
                }

                VDatabaseWhack ( db );
            }
        }

        * dbp = NULL;
    }
    return rc;
}
Esempio n. 11
0
LIB_EXPORT rc_t CC VDatabaseVCreateDB ( VDatabase *self, VDatabase **dbp,
    const char *decl, KCreateMode cmode, const char *name, va_list args )
{
    rc_t rc;

    if ( dbp == NULL )
        rc = RC ( rcVDB, rcDatabase, rcCreating, rcParam, rcNull );
    else
    {
        if ( self == NULL )
            rc = RC ( rcVDB, rcDatabase, rcCreating, rcSelf, rcNull );
        else if ( decl == NULL )
            rc = RC ( rcVDB, rcMgr, rcOpening, rcName, rcNull );
        else if ( decl [ 0 ] == 0 )
            rc = RC ( rcVDB, rcMgr, rcOpening, rcName, rcEmpty );
        else if ( self -> read_only )
            rc = RC ( rcVDB, rcDatabase, rcCreating, rcDatabase, rcReadonly );
        else
        {
            rc = VDatabaseMake ( dbp, NULL, self, self -> schema );
            if ( rc == 0 )
            {
                VDatabase *db = * dbp;

                rc = KDatabaseVCreateDB ( self -> kdb, & db -> kdb, cmode, name, args );
                if ( rc == 0 )
                {
                    rc = VDatabaseOpenUpdate ( db, decl );
                    if ( rc == 0 )
                        return 0;

                    rc = ResetRCContext ( rc, rcVDB, rcDatabase, rcCreating );
                }

                VDatabaseWhack ( db );
            }
        }

        * dbp = NULL;
    }
    return rc;
}
Esempio n. 12
0
static rc_t deserialize_v0( BlobHeaders **dst, const uint8_t *src, uint64_t ssize ) {
    uint8_t flags;
    uint8_t version;
    uint32_t fmt;
    uint64_t osize;
    volatile uint32_t op_count;
    volatile uint32_t arg_count;
    int64_t x;
    uint64_t sz;
    rc_t rc;
    BlobHeaders *y;

    *dst = NULL;
    
    if (ssize < 2)
        return RC(rcVDB, rcHeader, rcConstructing, rcData, rcInsufficient);

    flags = *src++; --ssize;
    version = *src++; --ssize;
    
    rc = vlen_decode1(&x, src, ssize, &sz);
    if (rc)
        return ResetRCContext(rc, rcVDB, rcHeader, rcConstructing);
    src += sz; 
	ssize -= sz;
    fmt = (uint32_t)x;
    
    rc = vlen_decode1(&x, src, ssize, &sz);
    if (rc)
        return ResetRCContext(rc, rcVDB, rcHeader, rcConstructing);
    src += sz; 
	ssize -= sz;
    osize = (uint32_t)x;
    
    rc = vlen_decode1(&x, src, ssize, &sz);
    if (rc)
        return ResetRCContext(rc, rcVDB, rcHeader, rcConstructing);
    src += sz; 
	ssize -= sz;
    op_count = (uint32_t)x;
    
    rc = vlen_decode1(&x, src, ssize, &sz);
    if (rc)
        return ResetRCContext(rc, rcVDB, rcHeader, rcConstructing);
    src += sz; 
	ssize -= sz;
    arg_count = (uint32_t)x;

    rc = BlobHeadersCreateInternal(&y, op_count, arg_count);
    if (rc)
        return rc;
    
    y->data->flags = flags;
    y->data->version = version;
    y->data->fmt = fmt;
    y->data->osize = osize;
    y->data->read_only = true;

    if (op_count > 0) {
        if (ssize < op_count) {
            BlobHeadersRelease(y);
            return RC(rcVDB, rcHeader, rcConstructing, rcData, rcInsufficient);
        }
        memmove(y->data->ops, src, op_count);
        src += op_count; ssize -= op_count;
    }        
    if (arg_count > 0) {
        rc = vlen_decode(y->data->args, arg_count, src, ssize, &sz);
        if (rc) {
            BlobHeadersRelease(y);
            return ResetRCContext(rc, rcVDB, rcHeader, rcConstructing);
        }
        src += sz; ssize -= sz;
    }
    if (ssize) {
        BlobHeaders *link;
        
        rc = deserialize_v0(&link, src, ssize);
        if (rc) {
            BlobHeadersRelease(y);
            return rc;
        }
        y->link = link;
    }
    *dst = y;
    return 0;
}