func handleRootPost(w http.ResponseWriter, req *http.Request, ps URLParams, cs chunks.ChunkStore) { d.PanicIfTrue(req.Method != "POST", "Expected post method.") params := req.URL.Query() tokens := params["last"] d.PanicIfTrue(len(tokens) != 1, `Expected "last" query param value`) last := hash.Parse(tokens[0]) tokens = params["current"] d.PanicIfTrue(len(tokens) != 1, `Expected "current" query param value`) current := hash.Parse(tokens[0]) // Ensure that proposed new Root is present in cs c := cs.Get(current) d.PanicIfTrue(c.IsEmpty(), "Can't set Root to a non-present Chunk") // Ensure that proposed new Root is a Map and, if it has anything in it, that it's <String, <RefCommit>> v := types.DecodeValue(c, nil) d.PanicIfTrue(v.Type().Kind() != types.MapKind, "Root of a Database must be a Map") m := v.(types.Map) if !m.Empty() && !isMapOfStringToRefOfCommit(m) { panic(d.Wrap(fmt.Errorf("Root of a Database must be a Map<String, Ref<Commit>>, not %s", m.Type().Describe()))) } if !cs.UpdateRoot(current, last) { w.WriteHeader(http.StatusConflict) return } }
func TestWriteValue(t *testing.T) { assert := assert.New(t) factory := chunks.NewMemoryStoreFactory() defer factory.Shutter() router = setupWebServer(factory) defer func() { router = nil }() testString := "Now, what?" authKey = "anauthkeyvalue" w := httptest.NewRecorder() r, err := newRequest("GET", dbName+constants.RootPath, nil) assert.NoError(err) router.ServeHTTP(w, r) lastRoot := w.Body assert.Equal(http.StatusOK, w.Code) tval := types.Bool(true) wval := types.String(testString) chunk1 := types.EncodeValue(tval, nil) chunk2 := types.EncodeValue(wval, nil) refList := types.NewList(types.NewRef(tval), types.NewRef(wval)) chunk3 := types.EncodeValue(refList, nil) body := &bytes.Buffer{} // we would use this func, but it's private so use next line instead: serializeHints(body, map[ref.Ref]struct{}{hint: struct{}{}}) err = binary.Write(body, binary.BigEndian, uint32(0)) assert.NoError(err) chunks.Serialize(chunk1, body) chunks.Serialize(chunk2, body) chunks.Serialize(chunk3, body) w = httptest.NewRecorder() r, err = newRequest("POST", dbName+constants.WriteValuePath+"?access_token="+authKey, ioutil.NopCloser(body)) assert.NoError(err) router.ServeHTTP(w, r) assert.Equal(http.StatusCreated, w.Code) w = httptest.NewRecorder() args := fmt.Sprintf("&last=%s¤t=%s", lastRoot, types.NewRef(refList).TargetHash()) r, _ = newRequest("POST", dbName+constants.RootPath+"?access_token="+authKey+args, ioutil.NopCloser(body)) router.ServeHTTP(w, r) assert.Equal(http.StatusOK, w.Code) whash := wval.Hash() hints := map[hash.Hash]struct{}{whash: struct{}{}} rdr := buildGetRefsRequestBody(hints) r, _ = newRequest("POST", dbName+constants.GetRefsPath, rdr) r.Header.Add("Content-Type", "application/x-www-form-urlencoded") router.ServeHTTP(w, r) assert.Equal(http.StatusOK, w.Code) ms := chunks.NewMemoryStore() chunks.Deserialize(w.Body, ms, nil) v := types.DecodeValue(ms.Get(whash), datas.NewDatabase(ms)) assert.Equal(testString, string(v.(types.String))) }
// SomeChunksP invokes callbacks on every unique chunk reachable from |r| in top-down order. Callbacks are invoked only once for each chunk regardless of how many times the chunk appears. // // |stopCb| is invoked for the types.Ref of every chunk. It can return true to stop SomeChunksP from descending any further. // |chunkCb| is optional, invoked with the chunks.Chunk referenced by |stopCb| if it didn't return true. func SomeChunksP(r types.Ref, bs types.BatchStore, stopCb SomeChunksStopCallback, chunkCb SomeChunksChunkCallback, concurrency int) { rq := newRefQueue() wg := sync.WaitGroup{} mu := sync.Mutex{} visitedRefs := map[hash.Hash]bool{} walkChunk := func(r types.Ref) { defer wg.Done() tr := r.TargetHash() mu.Lock() visited := visitedRefs[tr] visitedRefs[tr] = true mu.Unlock() if visited || stopCb(r) { return } // Try to avoid the cost of reading |c|. It's only necessary if the caller wants to know about every chunk, or if we need to descend below |c| (ref height > 1). var c chunks.Chunk if chunkCb != nil || r.Height() > 1 { c = bs.Get(tr) d.Chk.False(c.IsEmpty()) if chunkCb != nil { chunkCb(r, c) } } if r.Height() == 1 { return } v := types.DecodeValue(c, nil) for _, r1 := range v.Chunks() { wg.Add(1) rq.tail() <- r1 } } iter := func() { for r := range rq.head() { walkChunk(r) } } for i := 0; i < concurrency; i++ { go iter() } wg.Add(1) rq.tail() <- r wg.Wait() rq.close() }
func traverseSource(srcRef types.Ref, srcDB, sinkDB Database) traverseResult { h := srcRef.TargetHash() if !sinkDB.has(h) { srcBS := srcDB.validatingBatchStore() c := srcBS.Get(h) v := types.DecodeValue(c, srcDB) d.Chk.True(v != nil, "Expected decoded chunk to be non-nil.") sinkDB.validatingBatchStore().SchedulePut(c, srcRef.Height(), types.Hints{}) return traverseResult{h, v.Chunks(), len(c.Data())} } return traverseResult{} }