forked from vitessio/vitess
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tablet.go
130 lines (114 loc) · 4.91 KB
/
tablet.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright 2014, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package topotools contains high level functions based on vt/topo and
vt/actionnode. It should not depend on anything else that's higher
level. In particular, it cannot depend on:
- vt/wrangler: much higher level, wrangler depends on topotools.
- vt/tabletmanager/initiator: we don't want the various remote
protocol dependencies here.
topotools is used by wrangler, so it ends up in all tools using
wrangler (vtctl, vtctld, ...). It is also included by vttablet, so it contains:
- most of the logic to rebuild a shard serving graph (helthcheck module)
- some of the logic to perform a TabletExternallyReparented (RPC call
to master vttablet to let it know it's the master).
*/
package topotools
// This file contains utility functions for tablets
import (
"errors"
"fmt"
"golang.org/x/net/context"
log "github.com/golang/glog"
"github.com/youtube/vitess/go/vt/hook"
"github.com/youtube/vitess/go/vt/topo"
"github.com/youtube/vitess/go/vt/topo/topoproto"
topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
)
// ConfigureTabletHook configures the right parameters for a hook
// running locally on a tablet.
func ConfigureTabletHook(hk *hook.Hook, tabletAlias *topodatapb.TabletAlias) {
if hk.ExtraEnv == nil {
hk.ExtraEnv = make(map[string]string, 1)
}
hk.ExtraEnv["TABLET_ALIAS"] = topoproto.TabletAliasString(tabletAlias)
}
// changeType is a single iteration of the update loop for ChangeType().
func changeType(tablet *topodatapb.Tablet, newType topodatapb.TabletType, health map[string]string) error {
tablet.Type = newType
if health != nil {
if len(health) == 0 {
tablet.HealthMap = nil
} else {
tablet.HealthMap = health
}
}
return nil
}
// ClearHealthMap is a sentinel value that tells ChangeType to clear the health
// map, as opposed to passing nil, which will leave the health map unchanged.
var ClearHealthMap = make(map[string]string)
// ChangeType changes the type of the tablet and possibly also updates
// the health information for it. Make this external, since these
// transitions need to be forced from time to time.
//
// - if health is nil, we don't touch the Tablet's Health record.
// - if health is an empty map, we clear the Tablet's Health record.
// - if health has values, we overwrite the Tablet's Health record.
//
// If successful, the updated tablet record is returned.
func ChangeType(ctx context.Context, ts topo.Server, tabletAlias *topodatapb.TabletAlias, newType topodatapb.TabletType, health map[string]string) (*topodatapb.Tablet, error) {
return ts.UpdateTabletFields(ctx, tabletAlias, func(tablet *topodatapb.Tablet) error {
return changeType(tablet, newType, health)
})
}
// ChangeOwnType is like ChangeType, except it fails if you no longer own the
// tablet record, as determined by CheckOwnership().
//
// Note that oldTablet is only used for its Alias, and to call CheckOwnership().
// Other fields in oldTablet have no effect on the update, which will read the
// latest tablet record before setting the type and health info (just like
// ChangeType() does).
//
// If successful, the updated tablet record is returned.
func ChangeOwnType(ctx context.Context, ts topo.Server, oldTablet *topodatapb.Tablet, newType topodatapb.TabletType, health map[string]string) (*topodatapb.Tablet, error) {
return ts.UpdateTabletFields(ctx, oldTablet.Alias, func(tablet *topodatapb.Tablet) error {
if err := CheckOwnership(oldTablet, tablet); err != nil {
return err
}
return changeType(tablet, newType, health)
})
}
// CheckOwnership returns nil iff the IP and port match on oldTablet and
// newTablet, which implies that no other tablet process has taken over the
// record.
func CheckOwnership(oldTablet, newTablet *topodatapb.Tablet) error {
if oldTablet == nil || newTablet == nil {
return errors.New("unable to verify ownership of tablet record")
}
if oldTablet.Ip != newTablet.Ip || oldTablet.PortMap["vt"] != newTablet.PortMap["vt"] {
return fmt.Errorf(
"tablet record was taken over by another process: "+
"my address is %v:%v, but record is owned by %v:%v",
oldTablet.Ip, oldTablet.PortMap["vt"], newTablet.Ip, newTablet.PortMap["vt"])
}
return nil
}
// DeleteTablet removes a tablet record from the topology:
// - the replication data record if any
// - the tablet record
func DeleteTablet(ctx context.Context, ts topo.Server, tablet *topodatapb.Tablet) error {
// try to remove replication data, no fatal if we fail
if err := topo.DeleteTabletReplicationData(ctx, ts, tablet); err != nil {
if err == topo.ErrNoNode {
log.V(6).Infof("no ShardReplication object for cell %v", tablet.Alias.Cell)
err = nil
}
if err != nil {
log.Warningf("remove replication data for %v failed: %v", topoproto.TabletAliasString(tablet.Alias), err)
}
}
// then delete the tablet record
return ts.DeleteTablet(ctx, tablet.Alias)
}