/* * keysdb.c - fixed radix-cache implementation * * Copyright (c) 2008,2009,2010,2011,2012 Ghassan Almaless * Copyright (c) 2011,2012 UPMC Sorbonne Universites * * This file is part of ALMOS-kernel. * * ALMOS-kernel is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2.0 of the License. * * ALMOS-kernel is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ALMOS-kernel; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #define KEYS_PER_REC_LOG2 6 //////////////////////////////////// error_t keysdb_init( keysdb_t * db ) uint32_t key_width ) { page_t * page; kmem_req_t req; db->records_nr = CONFIG_PMM_PAGE_SIZE / sizeof(keys_record_t*); db->records_bits = bits_log2(db->records_nr); db->keys_nr = KEYS_PER_RECORD; db->keys_bits = bits_log2( db->keys_nr ); // allocates one single page req.type = KMEM_PAGE; req.size = 0; req.flags = AF_USER | AF_ZERO; page = kmem_alloc(&req); if(page == NULL) return ENOMEM; db->root = ppm_page2addr( page ); db->page = page; return 0; } /////////////////////////////////////// void keysdb_destroy( keysdb_t * db ) { kmem_req_t req; uint32_t i; req.type = KMEM_KEYSREC; for( i=0 ; i < db->records_nr ; i++ ) { if(db->root[i] == NULL) continue; req.ptr = db->root[i]; kmem_free(&req); } req.type = KMEM_PAGE; req.ptr = db->page; kmem_free(&req); } ////////////////////////////////// void keysdb_print( keysdb_t * db, char * name ) { uint32_t i; uint32_t j; keys_record_t * rec; printk(INFO, "%s / keys_per_record = %d / records = %d\n", name, db->keys_nr , db->records_nr ); for( i=0 ; i < db->records_nr; i++ ) { rec = db_root[i]; if( rec == NULL ) continue; printk(INFO, "record[%d] @ = 0x%x] [", index , rec ); for( j=0; j < db->keys_nr ; i++) printk(INFO, " val[%d] = %x\n", j , rec->tbl[j]); } } ///////////////////////////////////// error_t keysdb_insert( keysdb_t * db, uint32_t key, void * value ) { // Check key if( key >> (db->keys_bits + db->records_bits) ) return EINVAL; // compute indexes uint32_t bits = db->keys_bits; uint32_t rec_index = key >> bits; // index in records table uint32_t key_index = key & ((1 << bits) - 1); // index in record kmem_req_t req; // kmem request for new record keys_record_t * rec; // pointer on selected record bool_t isAtomic; // get address of pointer on the selected record in first level table. // it can be NULL if the selected record has not be allocated yet. volatile keys_record_t ** recptr = &db->root[record_index]; // we must allocate memory for the selected record if record pointer is NULL, // and atomically update the records table with the new record pointer. while( *recptr == NULL ) { // allocate memory for record req.type = KMEM_KEYSREC; req.size = sizeof(keys_record_t); req.flags = AF_USER | AF_ZERO; rec = kmem_alloc(&req); if( rec == NULL) return ENOMEM; // try to update records array isAtomic = cpu_atomic_cas( &db->root[record_index] , 0 , (uint32_t)rec ); // release record memory if not atomic if( isAtomic == false ) { req.ptr = rec; kmem_free(&req); } } // get pointer on selected record. rec = db->root[record_index]; // check selected slot empty in selected record if(rec->tbl[key_index] != NULL) return EEXIST; // register the value rec->tbl[key_index] = value; return 0; } //////////////////////////////////// void * keysdb_remove( keysdb_t * db, uint32_t key ) { // compute indexes uint32_t bits = db->keys_bits; uint32_t rec_index = key >> bits; // index in records table uint32_t key_index = key & ((1 << bits) - 1); // index in record // get record pointer keys_record_t * rec = db->root[record_index]; if(rec == NULL) return NULL; // get value void * value = rec->tbl[key_index]; // reset selected slot rec->tbl[key_index] = NULL; cpu_wbflush(); return value; } //////////////////////////////////// void * keysdb_lookup( keysdb_t * db, uint32_t key ) { // compute indexes uint32_t bits = db->keys_bits; uint32_t rec_index = key >> db->keys_bits; uint32_t key_index = key & ((1 << bits) - 1); // get record pointer keys_record_t * recptr = db->root[rec_index]; // compute value void * value = (recptr == NULL) ? NULL : recptr->tbl[key_index]; return value; } /* /////////////////////////////////// error_t keysdb_bind( keysdb_t * db, uint32_t key_start, uint32_t keys_nr, void * value ) { error_t err; uint32_t i; err = 0; for(i = 0; i < keys_nr; i++) { err = keysdb_insert(db, key_start + i, value); if(err != 0) break; } while((err != 0) && (i != 0)) { i--; keysdb_remove(db, key_start + i); } return err; } ///////////////////////////////////// error_t keysdb_unbind( keysdb_t * db, uint32_t key_start, uint32_t keys_nr ) { uint32_t i; for(i = 0; i < keys_nr; i++) (void)keysdb_remove(db , key_start + i); return 0; } */