From 3911d7d66c9ada66c16115230a7935f77a6b2fb7 Mon Sep 17 00:00:00 2001 From: mappu Date: Sat, 20 May 2017 18:01:55 +1200 Subject: [PATCH] convert cgo function pointer call to repeated iteration --- main.go | 123 +++++++++++++++++++++++++++++++---------------- qbolt.h | 12 ++++- qbolt/boltdb.cpp | 45 +++++++++-------- 3 files changed, 118 insertions(+), 62 deletions(-) diff --git a/main.go b/main.go index 40ce3d0..6f68637 100644 --- a/main.go +++ b/main.go @@ -68,61 +68,102 @@ func withBoltDBReference(b ObjectReference, fn func(db *bolt.DB) error) error { return fn(ptrDB) } +type CallResponse struct { + s string + e error +} + +type NextCall struct { + content chan CallResponse +} + //export Bolt_ListBuckets -func Bolt_ListBuckets(b ObjectReference, browse []string, ctx uintptr, withEach func(uintptr, string)) string { - if len(browse) == 0 { - return Bolt_ListBucketsAtRoot(b, ctx, withEach) +func Bolt_ListBuckets(b ObjectReference, browse []string) ObjectReference { + pNC := &NextCall{ + content: make(chan CallResponse, 0), } - err := withBoltDBReference(b, func(db *bolt.DB) error { - return db.View(func(tx *bolt.Tx) error { + pNC_Ref := gms.Put(pNC) - bucket := tx.Bucket([]byte(browse[0])) - if bucket == nil { - return errors.New("Unknown bucket") - } + go func() { + err := withBoltDBReference(b, func(db *bolt.DB) error { + return db.View(func(tx *bolt.Tx) error { + + if len(browse) == 0 { + // Root-mode + return tx.ForEach(func(k []byte, _ *bolt.Bucket) error { + pNC.content <- CallResponse{s: string(k)} + return nil + }) + + } else { + // Nested-mode + bucket := tx.Bucket([]byte(browse[0])) + if bucket == nil { + return errors.New("Unknown bucket") + } + + for i := 1; i < len(browse); i += 1 { + bucket = bucket.Bucket([]byte(browse[i])) + if bucket == nil { + return errors.New("Unknown bucket") + } + } + + return bucket.ForEach(func(k, v []byte) error { + pNC.content <- CallResponse{s: string(k)} + return nil + }) - for i := 1; i < len(browse); i += 1 { - bucket = bucket.Bucket([]byte(browse[i])) - if bucket == nil { - return errors.New("Unknown bucket") } - } - - return bucket.ForEach(func(k, v []byte) error { - - withEach(ctx, string(k)) - return nil }) - }) - }) - if err != nil { - return err.Error() + if err != nil { + pNC.content <- CallResponse{e: err} + } + + close(pNC.content) + }() + + return pNC_Ref +} + +const ( + ERROR_AND_STOP_CALLING int = 100 + ERROR_AND_KEEP_CALLING = 101 + FINISHED_OK = 102 + REAL_MESSAGE = 103 +) + +//export GetNext +func GetNext(oRef ObjectReference) (int, string) { + pNC_Iface, ok := gms.Get(oRef) + if !ok { + return ERROR_AND_STOP_CALLING, NullObjectReference.Error() } - return "" + pNC, ok := pNC_Iface.(*NextCall) + if !ok { + return ERROR_AND_STOP_CALLING, NullObjectReference.Error() + } + + cr, ok := <-pNC.content + if !ok { + gms.Delete(oRef) + return FINISHED_OK, "" + } + + if cr.e != nil { + return ERROR_AND_KEEP_CALLING, cr.e.Error() + } + + return REAL_MESSAGE, cr.s } //export Bolt_ListBucketsAtRoot -func Bolt_ListBucketsAtRoot(b ObjectReference, ctx uintptr, withEach func(uintptr, string)) string { - err := withBoltDBReference(b, func(db *bolt.DB) error { - return db.View(func(tx *bolt.Tx) error { - - return tx.ForEach(func(n []byte, bucket *bolt.Bucket) error { - - withEach(ctx, string(n)) - return nil - }) - - }) - }) - - if err != nil { - return err.Error() - } - return "" +func Bolt_ListBucketsAtRoot(b ObjectReference) ObjectReference { + return Bolt_ListBuckets(b, nil) } //export Bolt_Close diff --git a/qbolt.h b/qbolt.h index 160e29a..64136a4 100644 --- a/qbolt.h +++ b/qbolt.h @@ -68,9 +68,17 @@ struct Bolt_Open_return { extern struct Bolt_Open_return Bolt_Open(GoString p0, GoUint32 p1, GoInt64 p2); -extern GoString Bolt_ListBuckets(GoInt64 p0, GoSlice p1, GoUintptr p2, void* p3); +extern GoInt64 Bolt_ListBuckets(GoInt64 p0, GoSlice p1); -extern GoString Bolt_ListBucketsAtRoot(GoInt64 p0, GoUintptr p1, void* p2); +/* Return type for GetNext */ +struct GetNext_return { + GoInt r0; + GoString r1; +}; + +extern struct GetNext_return GetNext(GoInt64 p0); + +extern GoInt64 Bolt_ListBucketsAtRoot(GoInt64 p0); extern GoString Bolt_Close(GoInt64 p0); diff --git a/qbolt/boltdb.cpp b/qbolt/boltdb.cpp index d4c12e5..92875ac 100644 --- a/qbolt/boltdb.cpp +++ b/qbolt/boltdb.cpp @@ -23,32 +23,39 @@ BoltDB* BoltDB::createFrom(QString filePath, QString &errorOut) return ret; } -template -struct Wrapper { - T t; -}; - -static void byteArrayCallback(void* ctx, GoString text) { - auto fn = static_cast*>(ctx); - fn->t(QByteArray::fromRawData(text.p, text.n)); -} +static const int ERROR_AND_STOP_CALLING = 100; +static const int ERROR_AND_KEEP_CALLING = 101; +static const int FINISHED_OK = 102; +static const int REAL_MESSAGE = 103; bool BoltDB::listBucketsAtRoot(QString& errorOut, NameReciever cb) { - auto containerVar = Wrapper{cb}; + auto listJob = ::Bolt_ListBucketsAtRoot(this->gmsDbRef); - GoString err = ::Bolt_ListBucketsAtRoot( - this->gmsDbRef, - (GoUintptr)(&containerVar), - byteArrayCallback // -fpermissive - ); + errorOut.clear(); - if (err.n > 0) { - errorOut = QString(err.p); - return false; + for(;;) { + auto gnr = ::GetNext(listJob); + + if (gnr.r0 == ERROR_AND_STOP_CALLING) { + errorOut.append(QString(gnr.r1.p)); // log error + break; // done + + } else if (gnr.r0 == ERROR_AND_KEEP_CALLING) { + errorOut.append(QString(gnr.r1.p)); // log error + continue; + + } else if (gnr.r0 == FINISHED_OK) { + // Once we hit this, the go-side will clean up the channel / associated goroutines + break; + + } else if (gnr.r0 == REAL_MESSAGE) { + cb(QByteArray(gnr.r1.p, gnr.r1.n)); + continue; + } } - return true; + return (errorOut.length() == 0); } BoltDB::~BoltDB()