예제 #1
0
파일: ketama.c 프로젝트: 4399data/ketama
/** \brief Initialize a semaphore.
  * \param key Semaphore key to use.
  * \return The freshly allocated semaphore handle. */
static int
ketama_sem_init( key_t key )
{
    if (sem_ids == NULL) {
        init_sem_id_tracker();
    }

    int sem_set_id;

    sem_set_id = semget( key, 1, 0 );
	track_sem_id(sem_set_id);

    if ( sem_set_id == -1 )
    {
        // create a semaphore set with ID SEM_ID
        sem_set_id = semget( key, 1, IPC_CREAT | 0666 );
        track_sem_id(sem_set_id);

		if ( sem_set_id == -1 )
        {
            strcpy( k_error, "Could not open semaphore!" );
            return 0;
        }

        ketama_sem_unlock( sem_set_id );
    }

    return sem_set_id;
}
예제 #2
0
파일: ketama.c 프로젝트: wayfair/ketama
/** \brief Locks the semaphore only after it is unlocked by another process.
  * \param sem_set_id The semaphore handle that you want to lock. */
static void
ketama_sem_safely_lock( int sem_set_id )
{
    int sanity = 0;
    while ( semctl( sem_set_id, 0, GETVAL, 0 ) == 2 )
    {
        // wait for the continuum creator to finish, but don't block others
        usleep( 5 );

        // if we are waiting for > 1 second, take drastic action:
        if(++sanity > 200000)
        {
            usleep( rand()%50000 );
            ketama_sem_unlock( sem_set_id );
            break;
        }
    }

    ketama_sem_lock( sem_set_id );
}
예제 #3
0
파일: ketama.c 프로젝트: lsm/zir
int
ketama_roll( ketama_continuum* contptr, char* filename )
{
    strcpy( k_error, "" );

    key_t key;
    int shmid;
    int *data;
    int sem_set_id;

//     setlogmask( LOG_UPTO ( LOG_NOTICE | LOG_ERR | LOG_INFO ) );
//     openlog( "ketama", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1 );

    key = ftok( filename, 'R' );
    if ( key == -1 )
    {
        sprintf( k_error, "Invalid filename specified: %s", filename );
        return 0;
    }

    *contptr = malloc( sizeof( continuum ) );
    (*contptr)->numpoints = 0;
    (*contptr)->array = 0;
    (*contptr)->modtime = 0;

    sem_set_id = ketama_sem_init( key );

    int sanity = 0;
    while ( semctl( sem_set_id, 0, GETVAL, 0 ) == 2 )
    {
        // wait for the continuum creator to finish, but don't block others
        usleep( 5 );

        // if we are waiting for > 1 second, take drastic action:
        if(++sanity > 1000000)
	{
            usleep( rand()%50000 );
            ketama_sem_unlock( sem_set_id );
	    break;
        }
    }

    time_t modtime = file_modtime( filename );
    time_t* fmodtime = 0;
    while ( !fmodtime || modtime != *fmodtime )
    {
        shmid = shmget( key, MC_SHMSIZE, 0 ); // read only attempt.
        data = shmat( shmid, (void *)0, SHM_RDONLY );

        if ( data == (void *)(-1) || (*contptr)->modtime != 0 )
        {
            ketama_sem_lock( sem_set_id );

//          if ( (*contptr)->modtime == 0 )
//              syslog( LOG_INFO, "Shared memory empty, creating and populating...\n" );
//          else
//              syslog( LOG_INFO, "Server definitions changed, reloading...\n" );

            if ( !ketama_create_continuum( key, filename ) )
            {
//                 strcpy( k_error, "Ketama_create_continuum() failed!" );
                ketama_sem_unlock( sem_set_id );
                return 0;
            }
/*          else
                syslog( LOG_INFO, "ketama_create_continuum() successfully finished.\n" );*/
    
            shmid = shmget( key, MC_SHMSIZE, 0 ); // read only attempt.
            data = shmat( shmid, (void *)0, SHM_RDONLY );
            ketama_sem_unlock( sem_set_id );
        }
    
        if ( data == (void *)(-1) )
        {
            strcpy( k_error, "Failed miserably to get pointer to shmemdata!" );
            return 0;
        }

        (*contptr)->numpoints = *data;
        (*contptr)->modtime = ++data;
        (*contptr)->array = data + sizeof( void* );
        fmodtime = (time_t*)( (*contptr)->modtime );
    }

    return 1;
}
예제 #4
0
파일: ketama.c 프로젝트: wayfair/ketama
int
reconstruct_continuum(key_t key, serverinfo* slist, int numservers, mcs* ring, int numpoints, unsigned long memory, time_t fmodtime) {
    int shmid, sem_set_id;
    continuum* data;  // Pointer to shmem location

    // sort the ring in ascending order of "point"
    qsort( (void*) ring, numpoints, sizeof( mcs ), (compfn)ketama_compare );

    // attempt to obtain the shared memory ID assigned to this key, and create a segment if it doesn't exist
    shmid = shmget( key, MC_SHMSIZE, 0644 | IPC_CREAT );
    if ( shmid == -1 ) {
        snprintf( k_error, sizeof(k_error), "Ketama: reconstruct_continuum failed to get valid shared memory segment with errno: %d.\n", errno );
        syslog1( LOG_INFO, k_error );
        return 0;
    }

    // lock the semaphore to prevent other writing to the shared memory segment
    sem_set_id = ketama_sem_init( key );
    ketama_sem_safely_lock( sem_set_id );
    int invalid_write = 0;

    // create an attachment in virtual memory to the shared memory segment, and failout if that an error is returned
    data = (continuum*) shmat( shmid, (void *)0, 0 );
    if ( data == (void *)(-1) ) {
        snprintf( k_error, sizeof(k_error), "Ketama: reconstruct_continuum failed to attach writable shared memory segment with errno: %d.\n", errno );
        invalid_write = 1;
    }

    // verify that the mcs array can hold this many points
    if ( sizeof(data->array) < sizeof(mcs) * numpoints ) {
        snprintf( k_error, sizeof(k_error), "Ketama: reconstruct_continuum tried to exceed size of mcs array.\n" );
        ketama_shmdt(data);
        invalid_write = 1;
    }

    // verify that the serverinfo array can hold this many servers
    if ( sizeof(data->slist) < sizeof(serverinfo) * numservers ) {
        snprintf( k_error, sizeof(k_error), "Ketama: reconstruct_continuum tried to exceed size of servers array.\n" );
        ketama_shmdt(data);
        invalid_write = 1;
    }

    // gracefully failout if any of the preceeding checks discovered errors
    if (invalid_write) {
        syslog1( LOG_INFO, k_error );
        free(ring);
        free(slist);
        ketama_sem_unlock( sem_set_id );
        return 0;
    }

    // record the new data into the shared memory segment
    data->numpoints = numpoints;
    data->numservers = numservers;
    data->memtotal = memory;
    data->fmodtime = fmodtime;
    memcpy( data->array, ring, sizeof( mcs ) * numpoints );
    memcpy( data->slist, slist, sizeof( serverinfo ) * numservers );
    syslog( LOG_INFO, "Ketama: copied mcs array into %p from %p and slist into %p from %p.\n", data->array, ring, data->slist, slist );

    data->cont_version++;
    data->cont_modtime = time(NULL);

    // We detatch here because we will re-attach in read-only mode to actually use it.
    if (ketama_shmdt(data) == -1) {
        snprintf( k_error, sizeof(k_error), "Ketama: reconstruct_continuum failed to detatch from shared memory with errno: %d.\n", errno );
        syslog1( LOG_INFO, k_error );
    }
    // unlock the semaphore
    ketama_sem_unlock( sem_set_id );

    // clean up
    free(ring);
    free(slist);

    return 1;
}
예제 #5
0
파일: ketama.c 프로젝트: wayfair/ketama
/** \brief Generates the continuum of servers (each server as many points on a circle).
  * \param key Shared memory key for storing the newly created continuum.
  * \param filename Server definition file, which will be parsed to create this continuum.
  * \param contptr The value of this pointer will contain the retrieved continuum resource.
  * \return 0 on failure, 1 on success. */
static int
ketama_create_continuum(key_t key, char* filename, ketama_continuum* contptr)
{
    int shmid, sem_set_id;
    int numservers = 0;
    unsigned long memory;
    serverinfo* slist;
    continuum* data;

    // if filename is not a user-specific key, init a shared memory segment from the pathname, if it's valid
    if (strncmp(filename, "key:", 4) != 0) {
        // get the list of servers from the provided file
        slist = read_server_definitions( filename, &numservers, &memory );

        // Check numservers first; if it is zero then there is no error message and we need to set one.
        if ( numservers < 1 ) {
            snprintf( k_error, sizeof(k_error), "Ketama: No valid server definitions in file %s", filename );
            syslog1( LOG_INFO, k_error );
            return 0;
        } else if ( slist == NULL ) {
            // read_server_definitions must've set error message.
            return 0;
        }

        // log the sucessful file read
        syslog( LOG_INFO, "Ketama: Server definitions read: %u servers, total memory: %lu.\n", numservers, memory );

        time_t fmodtime = file_modtime( filename );

        // attempt to load the continuum and log an error if this fails
        if ( !load_continuum( key, slist, numservers, memory, fmodtime ) ) {
            snprintf( k_error, sizeof(k_error), "Ketama: ketama_create_continuum failed to load the continuum.\n" );
            syslog1( LOG_INFO, k_error );
            return 0;
        }
    }

    // attempt to obtain the shared memory ID assigned to this key, and create a segment if it doesn't exist
    shmid = shmget( key, MC_SHMSIZE, 0644 | IPC_CREAT );
    if ( shmid == -1 ) {
        snprintf( k_error, sizeof(k_error), "Ketama: ketama_create_continuum failed to get valid shared memory segment with errno: %d.\n", errno );
        syslog1( LOG_INFO, k_error );
        return 0;
    }

    // lock the semaphore to prevent other writing to the shared memory segment
    sem_set_id = ketama_sem_init( key );
    ketama_sem_safely_lock( sem_set_id );

    // create an attachment in virtual memory to the shared memory segment, and failout if that an error is returned
    data = (continuum*) shmat( shmid, (void *)0, 0 );
    if ( data == (void *)(-1) ) {
        snprintf( k_error, sizeof(k_error), "Ketama: ketama_create_continuum failed to attach writable shared memory segment with errno: %d.\n", errno );
        syslog1( LOG_INFO, k_error  );
        ketama_sem_unlock( sem_set_id );
        return 0;
    }

    // if filename is not a path, init an empty shared memory segment, otherwise just record the filename
    if (strncmp(filename, "key:", 4) == 0) {
        data->fmodtime = 0;
        data->cont_version = 1;
        data->cont_modtime = time(NULL);
    }
    snprintf(data->cont_filename, sizeof(data->cont_filename), "%s", filename);

    // attempt to detach the shared memory segment and throw an error if one is received
    if (ketama_shmdt(data) == -1) {
        snprintf( k_error, sizeof(k_error), "Ketama: ketama_create_continuum failed to detatch from shared memory with errno: %d.\n", errno );
        syslog1( LOG_INFO, k_error );
    }

    // unlock the semaphore
    ketama_sem_unlock( sem_set_id );

    // rerun ketama_roller with the roller flag on to validate the loaded continuum
    return ketama_roller( contptr, filename, 1);
}