func (pi *primaryIndex) Scan(span *datastore.Span, distinct bool, limit int64, cons datastore.ScanConsistency, vector timestamp.Vector, conn *datastore.IndexConnection) { defer close(conn.EntryChannel()) // For primary indexes, bounds must always be strings, so we // can just enforce that directly low, high := "", "" // Ensure that lower bound is a string, if any if len(span.Range.Low) > 0 { a := span.Range.Low[0].Actual() switch a := a.(type) { case string: low = a default: conn.Error(errors.NewOtherDatastoreError(nil, fmt.Sprintf("Invalid lower bound %v of type %T.", a, a))) return } } // Ensure that upper bound is a string, if any if len(span.Range.High) > 0 { a := span.Range.High[0].Actual() switch a := a.(type) { case string: high = a default: conn.Error(errors.NewOtherDatastoreError(nil, fmt.Sprintf("Invalid upper bound %v of type %T.", a, a))) return } } if limit == 0 { limit = int64(pi.keyspace.nitems) } for i := 0; i < pi.keyspace.nitems && int64(i) < limit; i++ { id := strconv.Itoa(i) if low != "" && (id < low || (id == low && (span.Range.Inclusion&datastore.LOW == 0))) { continue } low = "" if high != "" && (id > high || (id == high && (span.Range.Inclusion&datastore.HIGH == 0))) { break } entry := datastore.IndexEntry{PrimaryKey: id} conn.EntryChannel() <- &entry } }
// generate a mock document - used by fetchOne to mock a document in the keyspace func genItem(i int, nitems int) (value.AnnotatedValue, errors.Error) { if i < 0 || i >= nitems { return nil, errors.NewOtherDatastoreError(nil, fmt.Sprintf("item out of mock range: %v [0,%v)", i, nitems)) } id := strconv.Itoa(i) doc := value.NewAnnotatedValue(map[string]interface{}{"id": id, "i": float64(i)}) doc.SetAttachment("meta", map[string]interface{}{"id": id}) return doc, nil }
// NewDatastore creates a new mock store for the given "path". The // path has prefix "mock:", with the rest of the path treated as a // comma-separated key=value params. For example: // mock:namespaces=2,keyspaces=5,items=50000 The above means 2 // namespaces. And, each namespace has 5 keyspaces. And, each // keyspace with 50000 items. By default, you get... // mock:namespaces=1,keyspaces=1,items=100000 Which is what you'd get // by specifying a path of just... mock: func NewDatastore(path string) (datastore.Datastore, errors.Error) { if strings.HasPrefix(path, "mock:") { path = path[5:] } params := map[string]int{} for _, kv := range strings.Split(path, ",") { if kv == "" { continue } pair := strings.Split(kv, "=") v, e := strconv.Atoi(pair[1]) if e != nil { return nil, errors.NewOtherDatastoreError(e, fmt.Sprintf("could not parse mock param key: %s, val: %s", pair[0], pair[1])) } params[pair[0]] = v } nnamespaces := paramVal(params, "namespaces", DEFAULT_NUM_NAMESPACES) nkeyspaces := paramVal(params, "keyspaces", DEFAULT_NUM_KEYSPACES) nitems := paramVal(params, "items", DEFAULT_NUM_ITEMS) s := &store{path: path, params: params, namespaces: map[string]*namespace{}, namespaceNames: []string{}} for i := 0; i < nnamespaces; i++ { p := &namespace{store: s, name: "p" + strconv.Itoa(i), keyspaces: map[string]*keyspace{}, keyspaceNames: []string{}} for j := 0; j < nkeyspaces; j++ { b := &keyspace{namespace: p, name: "b" + strconv.Itoa(j), nitems: nitems} b.mi = newMockIndexer(b) b.mi.CreatePrimaryIndex("#primary", nil) p.keyspaces[b.name] = b p.keyspaceNames = append(p.keyspaceNames, b.name) } s.namespaces[p.name] = p s.namespaceNames = append(s.namespaceNames, p.name) } return s, nil }