| Index: go/src/infra/gae/libs/wrapper/memory/README.md
 | 
| diff --git a/go/src/infra/gae/libs/wrapper/memory/README.md b/go/src/infra/gae/libs/wrapper/memory/README.md
 | 
| deleted file mode 100644
 | 
| index 719edc947d7145b5ee346f68f1fd95de566bc9f3..0000000000000000000000000000000000000000
 | 
| --- a/go/src/infra/gae/libs/wrapper/memory/README.md
 | 
| +++ /dev/null
 | 
| @@ -1,114 +0,0 @@
 | 
| -In-memory appengine wrapper
 | 
| -===========================
 | 
| -
 | 
| -
 | 
| -Notes on the internal encodings
 | 
| --------------------------------
 | 
| -
 | 
| -All datatypes inside of the index Collections of the gkvlite Store are stored
 | 
| -in a manner which allows them to be compared entirely via bytes.Compare. All
 | 
| -types are prefixed by a sortable type byte which encodes the sort-order of types
 | 
| -according to the appengine SDK. Additionally, types have the following data
 | 
| -encoding:
 | 
| -  * ints
 | 
| -    * stored with the `funnybase` varint encoding
 | 
| -  * floats
 | 
| -    * http://stereopsis.com/radix.html
 | 
| -    * toBytes:
 | 
| -        ```
 | 
| -        b := math.Float64bits(f)
 | 
| -        return b ^ (-(b >> 63) | 0x8000000000000000)
 | 
| -        ```
 | 
| -    * fromBytes:
 | 
| -        ```
 | 
| -        return math.Float64frombits(b ^ ((b >> 63) - 1) | 0x8000000000000000)
 | 
| -        ```
 | 
| -  * string, []byte, BlobKey, ByteString
 | 
| -    * funnybase byte count
 | 
| -    * raw bytes
 | 
| -  * \*Key, GeoPoint
 | 
| -    * composite of above types
 | 
| -  * time.Time
 | 
| -    * composite of above types, stored with microsecond accuracy.
 | 
| -      * rounding to microseconds is a limitation of the real appengine.
 | 
| -		* toMicro: `return t.Unix()*1e6 + int64(t.Nanosecond()/1e3)`
 | 
| -		* fromMicro: `return time.Unix(t/1e6, (t%1e6)*1e3)`
 | 
| -  * nil, true, false
 | 
| -    * value is encoded directly in the type byte
 | 
| -
 | 
| -
 | 
| -Gkvlite Collection schema
 | 
| --------------------------
 | 
| -
 | 
| -In order to provide efficient result deduplication, the value of an index row
 | 
| -which indexes 1 or more properties is a concatenation of the previous values
 | 
| -which would show up in the same index. For example, if you have the property
 | 
| -list for the key K:
 | 
| -
 | 
| -    bob: 1
 | 
| -    bob: 4
 | 
| -    bob: 7
 | 
| -    cat: "hello"
 | 
| -    cat: "world"
 | 
| -
 | 
| -And the regular (non-ancestor) composite index was {bob, -cat}, you'd have the
 | 
| -rows in the index `idx:ns:kind|R|bob|-cat` (| in the row indicates
 | 
| -concatenation, each value has an implied type byte. `...` indicates that other
 | 
| -rows may be present):
 | 
| -
 | 
| -    ...
 | 
| -    1|"world"|K = nil|nil
 | 
| -    ...
 | 
| -    1|"hello"|K = nil|"world"
 | 
| -    ...
 | 
| -    4|"world"|K = 1|nil
 | 
| -    ...
 | 
| -    4|"hello"|K = 1|"world"
 | 
| -    ...
 | 
| -    7|"world"|K = 4|nil
 | 
| -    ...
 | 
| -    7|"hello"|K = 4|"world"
 | 
| -    ...
 | 
| -
 | 
| -This allows us to, start scanning at any point and be able to determine if we've
 | 
| -returned a given key already (without storing all of the keys in memory
 | 
| -for the duration of the Query run). We can do this because we can see if the
 | 
| -value of an index row falls within the original query filter parameters. If it
 | 
| -does, then we must already have returned they Key, and can safely skip the index
 | 
| -row.  AFAIK, real-datastore provides deduplication by keeping all the returned
 | 
| -keys in memory as it runs the query, and doing a set-check.
 | 
| -
 | 
| -The end-result is semantically equivalent, with the exception that Query Cursors
 | 
| -on the real datastore will potentially return the same Key in the first Cursor
 | 
| -use as well as on the 2nd (or Nth) cursor use, where this method will not.
 | 
| -
 | 
| -    collections
 | 
| -      ents:ns                    -> key -> value
 | 
| -                                    (rootkind, rootid, __entity_group__,1) -> {__version__: int}
 | 
| -                                    (rootkind, rootid, __entity_group_ids__,1) -> {__version__: int}
 | 
| -                                    (__entity_group_ids__,1) -> {__version__: int}
 | 
| -      // TODO(iannucci): Journal every entity write in a log with a globally
 | 
| -      // increasing version number (aka "timestamp").
 | 
| -      //
 | 
| -      // TODO(iannucci): Use the value in idx collection to indicate the last
 | 
| -      // global log version reflected in this index. Then index updates can happen
 | 
| -      // in parallel, in a truly eventually-consistent fashion (and completely
 | 
| -      // avoid holding the DB writelock while calculating index entries).
 | 
| -      // Unfortunately, copying new records (and removing old ones) into the DB
 | 
| -      // would still require holding global writelock.
 | 
| -      //
 | 
| -      // TODO(iannucci): how do we garbage-collect the journal?
 | 
| -      //
 | 
| -      // TODO(iannucci): add the ability in gkvlite to 'swap' a collection with
 | 
| -      // another one, transactionally? Not sure if this is possible to do easily.
 | 
| -      // If we had this, then we could do all the index writes for a given index
 | 
| -      // on the side, and then do a quick swap into place with a writelock. As
 | 
| -      // long as every index only has a single goroutine writing it, then this
 | 
| -      // would enable maximum concurrency, since all indexes could update in
 | 
| -      // parallel and only synchronize for the duration of a single pointer swap.
 | 
| -      idx                        -> kind|A?|[-?prop]* = nil
 | 
| -      idx:ns:kind                -> key = nil
 | 
| -      idx:ns:kind|prop           -> propval|key = [prev val]
 | 
| -      idx:ns:kind|-prop          -> -propval|key = [next val]
 | 
| -      idx:ns:kind|A|?prop|?prop  -> A|propval|propval|key = [prev/next val]|[prev/next val]
 | 
| -      idx:ns:kind|?prop|?prop    -> propval|propval|key = [prev/next val]|[prev/next val]
 | 
| 
 |