Hello list,

I'm just starting to learn  and code in Go (but I know well C, C++, Ocaml, 
Scheme and I am the main designer & implementor of GCC MELT 
<http://gcc-melt.org/>, a Lisp-y domain specific language to customize GCC). 

I'm using *Go 1.8*rc3 on Debian/Linux/Sid/amd64 (because the plugin 
facilities are essential to me). I don't care yet about other platforms, 
but I am interested in coding something which could be compilable both with 
Go 1.8 native compiler
and with future GCC GO 7.0.

I did read the following thread on *The feature I want most, weak* 
https://groups.google.com/forum/#!topic/golang-nuts/MMWXRANh0-g I am 
familiar with GC techniques, and I do know about the SetFinalizer routine 
<https://beta.golang.org/pkg/runtime/#SetFinalizer> of the standard runtime 
<https://beta.golang.org/pkg/runtime> package.

I want to code in Go something with would be similar to a dynamic data-like 
server a bit inspired by e.g. MongoDb. Nothing very extraordinary in 
principle!



*Context & motivations*

It would be a server (probably some JsonRpc one, but the exact protocol is 
not yet defined and is an unimportant implementation detail; I could switch 
to some HTTP or REST thing). 
Probably each connected client would be managed by one (or several) 
goroutines. I don't expect a lot of simultaneous clients (I'm thinking of a 
dozen at most).

It would manage persistent data organized in *data items*. So at shutdown 
time it would *persist* the set of alive items (and all the data and items 
reachable from it) into e.g. some Sqlite3 database, probably in JSON format.
I don't expect a lot of data. It would easily fit into RAM on a powerful 
desktop machine (so think of several gigabytes at most and a few million 
items at most, and probably a lot less: dozens of megabytes and a few 
thousand of items).

Each data item has a *fixed*  (globally) *unique* id (inspired by UUID 
<https://en.wikipedia.org/wiki/Universally_unique_identifier>-s) which is 
*randomly* generated.
That item id is a 126 bit number, represented by two 63 bits (of course 
represented as *uint64_t* in Go) serial numbers in base 62 notation 
starting with an underscore then a digit, so both _136vhwQ6Q5W & 
_3FirKslewA3 are serials, and their concatenation _136vhwQ6Q5W_3FirKslewA3 is 
the textual representation of some id; the underlying *uint64_t* number 
pair of that id is (881330831883687952,3076946490273043099) 

So data items are both hash-able (their hash code is some hash of their id) 
and comparable (to compare two items, e.g. for sorting purposes or for 
dichotomical access, we would compare their id).

There exist some root data items (whose ids are publicly known, without any 
interaction with the server) and which are always alive. 
Without loss of generality we might pretend that there is a single root 
item of id _123456789AB_987654321CD (so that particular root id is 
*publicly* known and is documented with the protocol) and
 that root data item is always alive.

Each data item contain *data values*, organized as *attributes* and 
*components* (both explained in more detail below) of that item, and these 
data values are always  *immutable*. So one can replace a data value by 
another one (e.g. in attributes or components), but cannot change the 
content of a given data value.

A data value is *one of*:

   - null (which also represent "absence" of value)
   - an integer
   - a string
   - a reference to a data item (represented by the id)
   - a tuple (finite sequence of data item references, represented by their 
   id; repetitions are possible) of components
   - a set (ascending ordered finite sequence of data item references, 
   represented by their id, without repetition) of elements, so membership (of 
   some data item in some given set) can be tested dichotomically 
   
The *attributes*  of a data item are conceptually a (finite) association 
from data items (keys) to non-nil data values (so fetching a missing 
attribute gives null).
The *components* of a data item are conceptually a (finite) vector of data 
values. That vector could be resized (with new slots having null by 
default).

A *request* to the data server would be an (atomicly processed) sequence 
(ordered) or composition of elementary operations including

   - accessing operations, notably
      - fetching a data item of given id (or null if none)
      - get the attribute in some data item with some given data item Id as 
      key
      - get the N-th component of some data item
      - get the I-th item inside a tuple or a set
      - test membership inside a set
      - get the component size of a data item
      - get the attribute size (cardinality of attribute association) in a 
      data item
      - etc...
   - creating operations, notably
      - make a fresh data item (giving its new id)
      - make an integer data value, or a string data value
      - make a tuple data value, from the ids of its tuple-compoents
      - make a set data value, from the sequence of ids of its set-elements
   - modifying operations, notably
      - adding (or removing) some attribute inside some data item, with a 
      given key data item (and added data value, if relevant)
      - putting some component inside some data item
      - resizing the component vector of some data item
   

And that request would be processed by the server which would return some 
serialization of the resulting data values (with data item references in 
results transmitted by their id)


* Q1: How to associate ids to data items?*


The id of data items is the only way to refer to data items on the protocol 
side. So I need a *weak association* between an id and the data item (if 
any) of that id. I do not want to keep (in some ordinary Go map, for 
example) the association between ids and their data items (otherwise, no 
data item would be garbage collected). I accept the fact that eventually 
(and perhaps quite later), a data item which is not reachable from the root 
data item would be garbage collected.

I was thinking of using unsafe.Pointer-s with runtime.SetFinalizer. A 
simplistic approach could be to use a Go map (module variable) from pairs 
of uint64_t to such unsafe pointers. At data item creation, I would 
register in that map, using the pair of uint64_t-s as key, the pointer of 
that data item suitably converted to an unsafe.Pointer. I would also pass 
to SetFinalizer some finalization routine which would unregister (delete) 
from that map. That scheme would work only if Go garbage collector does not 
move objects (i.e. struct-s). If Go's GC is a conservative GC à la Boehm GC 
<https://www.hboehm.info/gc/>, I'll probably even better "hide" the pointer 
(e.g. by keeping not a Pointer, but some uintptr suitably "hidden" e.g. by 
complementing all its bits à la GC_HIDE_POINTERS 
<https://github.com/ivmai/bdwgc/blob/master/include/gc.h#L1299> in Boehm 
GC). But that scheme would work only if Go's garbage collector is not 
moving values (e.g. struct-s).* Is Go's garbage collector guaranteed to be 
some marking *(not moving or generational copying, à la Ocaml) *one?* FWIW, 
I am familiar with the terminology of the GC handbook 
<http://gchandbook.org/>.

*This Q1 is my main question*. If you answer only to one question, please 
let that be Q1!


*Q2: How to represent attribute associations?*

I'm tempted to use a Go map with data item pointers as keys. But then I 
don't take advantage that ids are hashable. Maybe that is ok. Or should I 
find or implement my self some explicit manually coded hash table?
(I believe I could experiment both, so if you don't have time for Q2, 
please focus on Q1).


*Q3: How to represent data values?*

I'm sure to be able to find out how sum types should be represented in Go 
(a canonical example is of course the AST in the Go compiler itself). But 
if you have time, good hints are welcome. But I prefer answers to Q1 and 
perhaps to Q2 before that Q3.
I might have as additional wish the ability to dynamically load some plugin 
which would represent an additional kind of value (think of floating point, 
or bignums, etc...)

Thanks for reading.
Regards.

PS. Most important question is Q1.
-- 

Basile Starynkevitch http://starynkevitch.net/Basile/   - email is  basile 
at starynkevitch dot net

Bourg La Reine, France






-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to