// Lock a segment, or block until a segment can be locked // Returns a Segment struct // Implicit unchecked assumption: you cannot lock more than one segment // for a given uuid (without unlocking them in between). It will break // segcache func (sp *CephStorageProvider) LockSegment(uuid []byte) bprovider.Segment { rv := new(CephSegment) rv.sp = sp h, err := C.handle_create() if err != nil { log.Panic("CGO ERROR: %v", err) } rv.h = h rv.ptr = <-sp.alloc rv.uid = UUIDSliceToArr(uuid) rv.wcache = make([]byte, 0, WCACHE_SIZE) sp.segcachelock.Lock() cached_ptr, ok := sp.segaddrcache[rv.uid] if ok { delete(sp.segaddrcache, rv.uid) } sp.segcachelock.Unlock() //ok = false if ok { rv.base = cached_ptr rv.naddr = rv.base } else { rv.base = rv.ptr rv.naddr = rv.base } rv.wcache_base = rv.naddr //Although I don't know this for sure, I am concerned that when we pass the write array pointer to C //the Go GC may free it before C is done. I prevent this by pinning all the written arrays, which get //deref'd after the segment is unlocked rv.warrs = make([][]byte, 0, 64) return rv }
func (sp *CephStorageProvider) obtainBaseAddress() uint64 { h, err := C.handle_create() if err != nil { log.Panic("CGO ERROR: %v", err) } addr, err := C.handle_obtainrange(h) if err != nil { log.Panic("CGO ERROR: %v", err) } return uint64(addr) }
//Called at startup of a normal run func (sp *CephStorageProvider) Initialize(opts map[string]string) { //Allocate caches sp.rcache = &CephCache{} cachesz, _ := strconv.Atoi(opts["cephrcache"]) if cachesz < 40 { cachesz = 40 //one per read handle: 40MB } sp.rcache.initCache(uint64(cachesz)) cephconf := C.CString(opts["cephconf"]) cephpool := C.CString(opts["cephpool"]) _, err := C.initialize_provider(cephconf, cephpool) if err != nil { log.Panic("CGO ERROR: %v", err) } C.free(unsafe.Pointer(cephconf)) C.free(unsafe.Pointer(cephpool)) sp.rh = make([]C.phandle_t, NUM_RHANDLES) sp.rh_avail = make([]bool, NUM_RHANDLES) sp.rhidx = make(chan int, NUM_RHANDLES+1) sp.rhidx_ret = make(chan int, NUM_RHANDLES+1) sp.alloc = make(chan uint64, 128) sp.segaddrcache = make(map[[16]byte]uint64, SEGCACHE_SIZE) sp.chunkgate = make(map[chunkreqindex][]chan []byte) for i := 0; i < NUM_RHANDLES; i++ { sp.rh_avail[i] = true h, err := C.handle_create() if err != nil { log.Panic("CGO ERROR: %v", err) } sp.rh[i] = h } //Obtain base address sp.ptr = sp.obtainBaseAddress() if sp.ptr == 0 { log.Panic("Could not read allocator! DB not created properly?") } log.Info("Base address obtained as 0x%016x", sp.ptr) //Start serving read handles go sp.provideReadHandles() //Start providing address allocations go sp.provideAllocs() }
//Called to create the database for the first time func (sp *CephStorageProvider) CreateDatabase(opts map[string]string) error { cephconf := C.CString(opts["cephconf"]) cephpool := C.CString(opts["cephpool"]) _, err := C.initialize_provider(cephconf, cephpool) if err != nil { log.Panic("CGO ERROR: %v", err) } C.free(unsafe.Pointer(cephconf)) C.free(unsafe.Pointer(cephpool)) h, err := C.handle_create() if err != nil { log.Panic("CGO ERROR: %v", err) } C.handle_init_allocator(h) _, err = C.handle_close(h) if err != nil { log.Panic("CGO ERROR: %v", err) } return nil }