blob: 0433763b32904939e41564030d9552fe09cb00a4 [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Todd Wang1ea8f192015-04-03 17:31:51 -07005// Package statslib implements the Stats interface from
Todd Wang94c9d0b2015-04-01 14:27:00 -07006// v.io/v23/services/stats.
Todd Wang1ea8f192015-04-03 17:31:51 -07007package statslib
Robin Thellend7a442432014-08-22 09:05:08 -07008
9import (
Todd Wangb31da592015-02-20 12:50:39 -080010 "reflect"
Robin Thellend7a442432014-08-22 09:05:08 -070011 "time"
12
Jiri Simsaffceefa2015-02-28 11:03:34 -080013 libstats "v.io/x/ref/lib/stats"
Robin Thellend7a442432014-08-22 09:05:08 -070014
Jiri Simsa6ac95222015-02-23 16:11:49 -080015 "v.io/v23/naming"
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070016 "v.io/v23/rpc"
Todd Wang94c9d0b2015-04-01 14:27:00 -070017 "v.io/v23/services/stats"
Jiri Simsa6ac95222015-02-23 16:11:49 -080018 "v.io/v23/services/watch"
Jiri Simsa6ac95222015-02-23 16:11:49 -080019 "v.io/v23/vdl"
20 "v.io/v23/verror"
Jiri Simsa337af232015-02-27 14:36:46 -080021 "v.io/x/lib/vlog"
Robin Thellend7a442432014-08-22 09:05:08 -070022)
23
Robin Thellend8a0f04f2014-11-17 10:40:24 -080024type statsService struct {
Robin Thellend7a442432014-08-22 09:05:08 -070025 suffix string
26 watchFreq time.Duration
27}
28
Todd Wangfb939032015-04-08 16:42:44 -070029const pkgPath = "v.io/x/ref/services/internal/statslib"
Mike Burrowsd65df962014-12-17 10:01:19 -080030
Robin Thellend7a442432014-08-22 09:05:08 -070031var (
Mike Burrowsd65df962014-12-17 10:01:19 -080032 errOperationFailed = verror.Register(pkgPath+".errOperationFailed", verror.NoRetry, "{1:}{2:} operation failed{:_}")
Robin Thellend7a442432014-08-22 09:05:08 -070033)
34
Robin Thellend8a0f04f2014-11-17 10:40:24 -080035// NewStatsService returns a stats server implementation. The value of watchFreq
Robin Thellende34761d2014-11-13 13:11:25 -080036// is used to specify the time between WatchGlob updates.
Robin Thellend8a0f04f2014-11-17 10:40:24 -080037func NewStatsService(suffix string, watchFreq time.Duration) interface{} {
Robin Thellendbde278d2014-11-19 15:07:32 -080038 return stats.StatsServer(&statsService{suffix, watchFreq})
Robin Thellend7a442432014-08-22 09:05:08 -070039}
40
Robin Thellend39ac3232014-12-02 09:50:41 -080041// Glob__ returns the name of all objects that match pattern.
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070042func (i *statsService) Glob__(call rpc.ServerCall, pattern string) (<-chan naming.GlobReply, error) {
Robin Thellend39ac3232014-12-02 09:50:41 -080043 vlog.VI(1).Infof("%v.Glob__(%q)", i.suffix, pattern)
Robin Thellend7a442432014-08-22 09:05:08 -070044
Todd Wang2331dd02015-03-17 15:38:39 -070045 ch := make(chan naming.GlobReply)
Robin Thellend39ac3232014-12-02 09:50:41 -080046 go func() {
47 defer close(ch)
48 it := libstats.Glob(i.suffix, pattern, time.Time{}, false)
49 for it.Advance() {
Todd Wang2331dd02015-03-17 15:38:39 -070050 ch <- naming.GlobReplyEntry{naming.MountEntry{Name: it.Value().Key}}
Robin Thellend7a442432014-08-22 09:05:08 -070051 }
Robin Thellend39ac3232014-12-02 09:50:41 -080052 if err := it.Err(); err != nil {
53 vlog.VI(1).Infof("libstats.Glob(%q, %q) failed: %v", i.suffix, pattern, err)
54 }
55 }()
56 return ch, nil
Robin Thellend7a442432014-08-22 09:05:08 -070057}
58
59// WatchGlob returns the name and value of the objects that match the request,
60// followed by periodic updates when values change.
Todd Wang8c1e4c82015-03-25 16:40:43 -070061func (i *statsService) WatchGlob(call watch.GlobWatcherWatchGlobServerCall, req watch.GlobRequest) error {
Robin Thellend7a442432014-08-22 09:05:08 -070062 vlog.VI(1).Infof("%v.WatchGlob(%+v)", i.suffix, req)
63
64 var t time.Time
65Loop:
66 for {
67 prevTime := t
68 t = time.Now()
Robin Thellendbde278d2014-11-19 15:07:32 -080069 it := libstats.Glob(i.suffix, req.Pattern, prevTime, true)
Todd Wang8c1e4c82015-03-25 16:40:43 -070070 changes := []watch.Change{}
Robin Thellend7a442432014-08-22 09:05:08 -070071 for it.Advance() {
72 v := it.Value()
Todd Wang8c1e4c82015-03-25 16:40:43 -070073 c := watch.Change{
Robin Thellend7a442432014-08-22 09:05:08 -070074 Name: v.Key,
Todd Wang8c1e4c82015-03-25 16:40:43 -070075 State: watch.Exists,
Todd Wangb31da592015-02-20 12:50:39 -080076 Value: vdl.ValueOf(v.Value),
Robin Thellend7a442432014-08-22 09:05:08 -070077 }
78 changes = append(changes, c)
79 }
80 if err := it.Err(); err != nil {
Mike Burrows2c989372015-03-31 18:06:39 -070081 if verror.ErrorID(err) == verror.ErrNoExist.ID {
Suharsh Sivakumar31f49852015-03-03 16:13:20 -080082 return verror.New(verror.ErrNoExist, call.Context(), i.suffix)
Robin Thellend7a442432014-08-22 09:05:08 -070083 }
Suharsh Sivakumar31f49852015-03-03 16:13:20 -080084 return verror.New(errOperationFailed, call.Context(), i.suffix)
Robin Thellend7a442432014-08-22 09:05:08 -070085 }
Tilak Sharma8ef60262014-08-26 14:54:37 -070086 for _, change := range changes {
Suharsh Sivakumar31f49852015-03-03 16:13:20 -080087 if err := call.SendStream().Send(change); err != nil {
Tilak Sharma8ef60262014-08-26 14:54:37 -070088 return err
89 }
Robin Thellend7a442432014-08-22 09:05:08 -070090 }
91 select {
Suharsh Sivakumar31f49852015-03-03 16:13:20 -080092 case <-call.Context().Done():
Robin Thellend7a442432014-08-22 09:05:08 -070093 break Loop
94 case <-time.After(i.watchFreq):
95 }
96 }
97 return nil
98}
99
100// Value returns the value of the receiver object.
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700101func (i *statsService) Value(call rpc.ServerCall) (*vdl.Value, error) {
Robin Thellend7a442432014-08-22 09:05:08 -0700102 vlog.VI(1).Infof("%v.Value()", i.suffix)
103
Todd Wangb31da592015-02-20 12:50:39 -0800104 rv, err := libstats.Value(i.suffix)
105 switch {
Mike Burrows2c989372015-03-31 18:06:39 -0700106 case verror.ErrorID(err) == verror.ErrNoExist.ID:
Matt Rosencrantz9dce9b22015-03-02 10:48:37 -0800107 return nil, verror.New(verror.ErrNoExist, call.Context(), i.suffix)
Mike Burrows2c989372015-03-31 18:06:39 -0700108 case verror.ErrorID(err) == stats.ErrNoValue.ID:
Matt Rosencrantz9dce9b22015-03-02 10:48:37 -0800109 return nil, stats.NewErrNoValue(call.Context(), i.suffix)
Todd Wangb31da592015-02-20 12:50:39 -0800110 case err != nil:
Matt Rosencrantz9dce9b22015-03-02 10:48:37 -0800111 return nil, verror.New(errOperationFailed, call.Context(), i.suffix)
Robin Thellend7a442432014-08-22 09:05:08 -0700112 }
Todd Wangb31da592015-02-20 12:50:39 -0800113 vv, err := vdl.ValueFromReflect(reflect.ValueOf(rv))
114 if err != nil {
Matt Rosencrantz9dce9b22015-03-02 10:48:37 -0800115 return nil, verror.New(verror.ErrInternal, call.Context(), i.suffix, err)
Todd Wangb31da592015-02-20 12:50:39 -0800116 }
117 return vv, nil
Robin Thellend7a442432014-08-22 09:05:08 -0700118}