Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(553)

Unified Diff: logdog/appengine/coordinator/hierarchy/hierarchy.go

Issue 2991253004: [logdog] Remove list functionality. (Closed)
Patch Set: fix test Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: logdog/appengine/coordinator/hierarchy/hierarchy.go
diff --git a/logdog/appengine/coordinator/hierarchy/hierarchy.go b/logdog/appengine/coordinator/hierarchy/hierarchy.go
deleted file mode 100644
index c42ae8f75dc77b4df9ae2a0dd11eb4fcdf87b629..0000000000000000000000000000000000000000
--- a/logdog/appengine/coordinator/hierarchy/hierarchy.go
+++ /dev/null
@@ -1,291 +0,0 @@
-// Copyright 2015 The LUCI Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package hierarchy
-
-import (
- "crypto/sha256"
- "encoding/base64"
- "encoding/hex"
-
- log "github.com/luci/luci-go/common/logging"
- "github.com/luci/luci-go/grpc/grpcutil"
- "github.com/luci/luci-go/logdog/appengine/coordinator"
- "github.com/luci/luci-go/logdog/common/types"
- "github.com/luci/luci-go/luci_config/common/cfgtypes"
-
- ds "github.com/luci/gae/service/datastore"
-
- "golang.org/x/net/context"
- "google.golang.org/grpc/codes"
-)
-
-// componentEntity is a hierarchial component that stores a specific log path
-// component. A given stream path is broken into components, each of which is
-// represented by a single componentEntity.
-//
-// A componentEntity is keyed based on its path component name and the hash of
-// its parent component's path. This ensures that the set of child components
-// can be obtained for any parent component path.
-//
-// The child component's key is chosen to be sortable with the following
-// preferences:
-// - Stream components sort before path components.
-// - Stream components sort alphanumerically. Elements that are entirely
-// numeric will be constructed to sort numerically.
-//
-// Storing the component's name in its key ensures that a keys query will pull
-// the set of elements in the correct order, requiring no non-default indexes.
-//
-// Writing path components is inherently idempotent, since each one is defined
-// solely by its identity. Consequently, transactions are not necessary when
-// writing path components.
-//
-// All componentEntity share a common implicit ancestor, "/".
-//
-// This entity is created at stream and prefix registration, and is entirely
-// centered around being queried for log stream "directory" listings. For
-// example:
-//
-// foo/bar/+/baz/qux
-//
-// This stream would add the following name components to the datastore, keyed
-// (parent-key, id) as:
-// ("/", "foo")
-// ("/foo", "bar")
-// ("/foo/bar", "+")
-// ("/foo/bar/+", "baz")
-// ("/foo/bar/+/baz", "qux")
-//
-// A generated property, "s", is stored to indicate whether this entry is a
-// stream or path component.
-type componentEntity struct {
- // _kind is the entity's kind. This is intentionally short to mitigate index
- // bloat since this will be repeated in a lot of keys.
- _kind string `gae:"$kind,_StreamNameComponent"`
-
- // ID is the name component of this specific stream.
- ID componentID `gae:"$id"`
-}
-
-var _ ds.PropertyLoadSaver = (*componentEntity)(nil)
-
-func (c *componentEntity) Load(pmap ds.PropertyMap) error {
- // Delete custom elements (added in Save).
- delete(pmap, "s")
- delete(pmap, "p")
-
- return ds.GetPLS(c).Load(pmap)
-}
-
-func (c *componentEntity) Save(withMeta bool) (ds.PropertyMap, error) {
- pmap, err := ds.GetPLS(c).Save(withMeta)
- if err != nil {
- return nil, err
- }
- pmap["s"] = ds.MkProperty(c.ID.stream)
- pmap["p"] = ds.MkProperty(c.ID.parent)
- return pmap, nil
-}
-
-// streamPath returns the StreamPath of this component, given its parent path.
-//
-// This is only valid if the component is a stream component.
-func (c *componentEntity) streamPath(parent types.StreamPath) types.StreamPath {
- return parent.Append(c.ID.name)
-}
-
-func componentEntityParent(parent types.StreamPath) string {
- hash := sha256.Sum256([]byte(parent))
- return hex.EncodeToString(hash[:])
-}
-
-func mkComponentEntity(parent types.StreamPath, name string, stream bool) *componentEntity {
- return &componentEntity{
- ID: componentID{
- parent: componentEntityParent(parent),
- name: name,
- stream: stream,
- },
- }
-}
-
-// Request is a listing request to execute.
-//
-// It describes a hierarchy listing request. For example, given the following
-// streams in project "qux":
-// qux/foo/+/bar
-// qux/foo/+/bar/baz
-// qux/foo/bar/+/baz
-//
-// The following queries would return values ("$" denotes streams vs. paths):
-// Project="", Path="": ["qux"]
-// Project="qux", Path="": ["foo"]
-// Project="qux", Path="foo": ["+", "bar"]
-// Project="qux", Path="foo/+": ["bar$", "bar"]
-// Project="qux", Path="foo/bar": ["+"]
-// Project="qux", Path="foo/bar/+": ["baz$"]
-//
-// If Limit is >0, it will be used to constrain the results. Otherwise, all
-// results will be returned.
-//
-// If Next is not empty, it is a datastore cursor for a continued query. If
-// supplied, it must use the same parameters as the previous queries in the
-// sequence.
-type Request struct {
- // Project is the project to list. If empty, Request will perform a
- // project-level listing.
- Project string
- // PathBase is the base path within Project to list.
- PathBase string
- // StreamOnly, if true, only returns stream path components.
- StreamOnly bool
-
- // Limit, if >0, is the maximum number of results to return. If more results
- // are available, the returned List will have its Next field set to a cursor
- // that can be used to issue iterative requests.
- Limit int
- // Next, if not empty, is the start cursor for this stream.
- Next string
- // Skip, if >0, skips past the first Skip query results.
- Skip int
-}
-
-// ListComponent is a single component element in the stream path hierarchy.
-//
-// This can represent a path component "path" in (path/component/+/stream)
-// or a stream component ("stream").
-type ListComponent struct {
- // Name is the name of this hierarchy element.
- Name string
- // Stream, if true, indicates that this is a stream component.
- Stream bool
-}
-
-// List is a branch of the stream path tree.
-//
-// It may represent either the top-level project hierarchy, or the sub-project
-// stream space hierarchy, depending on the query base.
-type List struct {
- // Project is the listed project name. If empty, the list refers to the
- // project namespace.
- Project cfgtypes.ProjectName
- // PathBase is the stream path base.
- PathBase types.StreamPath
- // Comp is the set of elements in this hierarchy result.
- Comp []*ListComponent
-
- // Next, if not empty, is the iterative query cursor.
- Next string
-}
-
-// Path returns the StreamPath of the supplied Component.
-func (l *List) Path(c *ListComponent) types.StreamPath {
- return l.PathBase.Append(c.Name)
-}
-
-// Get performs a hierarchy query based on parameters in the supplied Request
-// and returns the resulting List.
-//
-// This method will set the namespace based on the request after asserting user
-// membership.
-//
-// The supplied Context should not be bound to a namespace (i.e., default
-// namespace).
-//
-// If a failure is encountered, a wrapped gRPC error will be returned.
-func Get(c context.Context, r Request) (*List, error) {
- // If our project is empty, this is a project-level query.
- if r.Project == "" {
- return getProjects(c, &r)
- }
-
- // Build our List result.
- //
- // We will validate our Project and PathBase types immediately afterwards.
- l := List{
- Project: cfgtypes.ProjectName(r.Project),
- PathBase: types.StreamPath(r.PathBase),
- }
-
- // Validate our PathBase component.
- if err := l.PathBase.ValidatePartial(); err != nil {
- return nil, grpcutil.Errf(codes.InvalidArgument, "invalid stream path base %q: %v", l.PathBase, err)
- }
-
- // Enter the supplied Project namespace. This will assert the the user has
- // access to the project.
- if err := coordinator.WithProjectNamespace(&c, l.Project, coordinator.NamespaceAccessREAD); err != nil {
- return nil, err
- }
-
- // Determine our ancestor component.
- q := ds.NewQuery("_StreamNameComponent")
- q = q.Eq("p", componentEntityParent(l.PathBase))
- if r.StreamOnly {
- q = q.Eq("s", true)
- }
- if r.Next != "" {
- k, err := keyForCursor(c, r.Next)
- if err != nil {
- return nil, grpcutil.Errf(codes.InvalidArgument, "invalid cursor: %s", err)
- }
- q = q.Gt("__key__", k)
- }
- if r.Skip > 0 {
- q = q.Offset(int32(r.Skip))
- }
-
- limit := r.Limit
- if limit > 0 {
- q = q.Limit(int32(limit))
- }
-
- err := ds.Run(c, q, func(e *componentEntity) error {
- l.Comp = append(l.Comp, &ListComponent{
- Name: e.ID.name,
- Stream: e.ID.stream,
- })
-
- if limit > 0 && len(l.Comp) >= limit {
- l.Next = cursorForKey(c, e)
- return ds.Stop
- }
- return nil
- })
- if err != nil {
- log.WithError(err).Errorf(c, "Failed to execute hierarhcy query.")
- return nil, grpcutil.Internal
- }
- return &l, nil
-}
-
-// keyForCursor returns the component key for the supplied cursor.
-//
-// If the cursor string is not valid, an error will be returned.
-func keyForCursor(c context.Context, curs string) (*ds.Key, error) {
- d, err := base64.URLEncoding.DecodeString(curs)
- if err != nil {
- return nil, err
- }
-
- return ds.NewKey(c, "_StreamNameComponent", string(d), 0, nil), nil
-}
-
-// cursorForKey returns a cursor for the supplied componentID. This cursor will
-// start new queries at the component immediately following this ID.
-func cursorForKey(c context.Context, e *componentEntity) string {
- key := ds.KeyForObj(c, e)
- return base64.URLEncoding.EncodeToString([]byte(key.StringID()))
-}
« no previous file with comments | « logdog/appengine/coordinator/hierarchy/component_test.go ('k') | logdog/appengine/coordinator/hierarchy/hierarchy_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698