func Open(s string) (*TrailDB, error) { ok, er := exists(s) if er != nil { return nil, er } if !ok { return nil, errors.New(s + ": Path doesn't exist") } db := C.tdb_init() cs := C.CString(s) defer C.free(unsafe.Pointer(cs)) err := C.tdb_open(db, cs) if err != 0 { return nil, errors.New(s + ": Failed to open traildb: " + errToString(err)) } numFields := uint64(C.tdb_num_fields(db)) var fields []string fieldNameToId := make(map[string]uint64) // numFields contains timestamp too for i := uint64(0); i <= uint64(numFields)-1; i++ { fieldName := C.GoString(C.tdb_get_field_name(db, C.tdb_field(i))) fieldNameToId[fieldName] = uint64(i) fields = append(fields, fieldName) } return &TrailDB{ db: db, NumTrails: uint64(C.tdb_num_trails(db)), NumEvents: uint64(C.tdb_num_events(db)), NumFields: numFields, minTimestamp: uint64(C.tdb_min_timestamp(db)), maxTimestamp: uint64(C.tdb_max_timestamp(db)), fieldNames: fields, fieldNameToId: fieldNameToId, }, nil }
// Open is used by New with some reasonable default initial values apart from // path name. Following is a signature of libtdb's original C tdb_open() function // written in cgo convention: // // func tdb_open(name const *C.char, hash_size, tdb_flags, open_flags C.int, mode C.mode_t) *C.struct_tdb_context // // /* tdb_flags */ // DEFAULT /* just a readability place holder */ // CLEAR_IF_FIRST /* beats me... */ // INTERNAL /* don't store on disk */ // NOLOCK /* don't do any locking */ // NOMMAP /* don't use mmap */ // CONVERT /* convert endian (internal use) */ // BIGENDIAN /* header is big-endian (internal use) */ // NOSYNC /* don't use synchronous transactions */ // SEQNUM /* maintain a sequence number */ // VOLATILE /* Activate the per-hashchain freelist, default 5 */ // ALLOW_NESTING /* Allow transactions to nest */ // DISALLOW_NESTING /* Disallow transactions to nest */ // INCOMPATIBLE_HASH /* Better hashing: can't be opened by tdb < 1.2.6. */ // // /* open_flags */ // /* 'man 2 open' on *nix, but what of pkg/os? TOPONDER */ // O_RDONLY // /* O_WRONLY *//* is invalid */ // O_RDWR // O_CREAT, O_TRUNC, O_APPEND // /* well, Ay dunno... */ // O_CLOEXEC, O_EXCL // /* O_NOATIME *//* #define __USE_GNU */ // O_NOFOLLOW, O_NONBLOCK = O_NDELAY // // /* O_CREAT mode */ // USR_RW = (S_IWUSR | S_IRUSR) /* helpful shortcut */ // USR_RWX /* 00700 user (file owner) has read, write and execute permission */ // USR_R /* 00400 user has read permission */ // USR_W /* 00200 user has write permission */ // USR_X /* 00100 user has execute permission */ // GRP_RWX /* 00070 group has read, write and execute permission */ // GRP_R /* 00040 group has read permission */ // GRP_W /* 00020 group has write permission */ // GRP_X /* 00010 group has execute permission */ // OTH_RWX /* 00007 others have read, write and execute permission */ // OTH_R /* 00004 others have read permission */ // OTH_W /* 00002 others have write permission */ // OTH_X /* 00001 others have execute permission */ // func Open(path string, hash_size, tdb_flags, open_flags int, mode uint32) (DB, Error) { name := C.CString(path) defer C.free(unsafe.Pointer(name)) var ctx tdb_CTX if old := ns[path]; old != nil { // now, what do we do? // if db is still "here" in the ns but closed we if old.cld { ctx = C.tdb_open(name, C.int(hash_size), C.int(tdb_flags), C.int(open_flags), C.mode_t(mode)) if ctx == nil { return DB{old}, mkError(1, "tdb.Open() tdb_open old failed") } else { old.cld = false old.ctx = ctx return DB{old}, nil } // if it's not closed perhaps we should to something "more" // intelligent, like closing and reopening with new params // TODO: later? } else { return DB{old}, nil } } else { var fresh *db ctx = C.tdb_open(name, C.int(hash_size), C.int(tdb_flags), C.int(open_flags), C.mode_t(mode)) if ctx == nil { println("Open() new ctx == nil") fresh = &db{&path, false, true, ctx} ns[path] = fresh return DB{fresh}, mkError(1, "tdb.Open() tdb_open fresh failed") } else { fresh = &db{pth: &path, cld: false, dbg: false, ctx: ctx} ns[path] = fresh return DB{fresh}, nil } } panic("unreachable") // return &DB{path, false, ctx} }