123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- // Copyright (C) 2016 The GoHBase Authors. All rights reserved.
- // This file is part of GoHBase.
- // Use of this source code is governed by the Apache License 2.0
- // that can be found in the COPYING file.
- package gohbase
- import (
- "context"
- "errors"
- "fmt"
- "time"
- log "github.com/sirupsen/logrus"
- "github.com/tsuna/gohbase/hrpc"
- "github.com/tsuna/gohbase/pb"
- "github.com/tsuna/gohbase/region"
- "github.com/tsuna/gohbase/zk"
- )
- const (
- // snapshotValidateInterval specifies the amount of time to wait before
- // polling the hbase server about the status of a snapshot operation.
- snaphotValidateInterval time.Duration = time.Second / 2
- )
- // AdminClient to perform admistrative operations with HMaster
- type AdminClient interface {
- CreateTable(t *hrpc.CreateTable) error
- DeleteTable(t *hrpc.DeleteTable) error
- EnableTable(t *hrpc.EnableTable) error
- DisableTable(t *hrpc.DisableTable) error
- CreateSnapshot(t *hrpc.Snapshot) error
- DeleteSnapshot(t *hrpc.Snapshot) error
- ListSnapshots(t *hrpc.ListSnapshots) ([]*pb.SnapshotDescription, error)
- RestoreSnapshot(t *hrpc.Snapshot) error
- ClusterStatus() (*pb.ClusterStatus, error)
- ListTableNames(t *hrpc.ListTableNames) ([]*pb.TableName, error)
- }
- // NewAdminClient creates an admin HBase client.
- func NewAdminClient(zkquorum string, options ...Option) AdminClient {
- return newAdminClient(zkquorum, options...)
- }
- func newAdminClient(zkquorum string, options ...Option) AdminClient {
- log.WithFields(log.Fields{
- "Host": zkquorum,
- }).Debug("Creating new admin client.")
- c := &client{
- clientType: region.MasterClient,
- rpcQueueSize: defaultRPCQueueSize,
- flushInterval: defaultFlushInterval,
- // empty region in order to be able to set client to it
- adminRegionInfo: region.NewInfo(0, nil, nil, nil, nil, nil),
- zkTimeout: defaultZkTimeout,
- zkRoot: defaultZkRoot,
- effectiveUser: defaultEffectiveUser,
- regionLookupTimeout: region.DefaultLookupTimeout,
- regionReadTimeout: region.DefaultReadTimeout,
- newRegionClientFn: region.NewClient,
- }
- for _, option := range options {
- option(c)
- }
- c.zkClient = zk.NewClient(zkquorum, c.zkTimeout)
- return c
- }
- //Get the status of the cluster
- func (c *client) ClusterStatus() (*pb.ClusterStatus, error) {
- pbmsg, err := c.SendRPC(hrpc.NewClusterStatus())
- if err != nil {
- return nil, err
- }
- r, ok := pbmsg.(*pb.GetClusterStatusResponse)
- if !ok {
- return nil, fmt.Errorf("sendRPC returned not a ClusterStatusResponse")
- }
- return r.GetClusterStatus(), nil
- }
- func (c *client) CreateTable(t *hrpc.CreateTable) error {
- pbmsg, err := c.SendRPC(t)
- if err != nil {
- return err
- }
- r, ok := pbmsg.(*pb.CreateTableResponse)
- if !ok {
- return fmt.Errorf("sendRPC returned not a CreateTableResponse")
- }
- return c.checkProcedureWithBackoff(t.Context(), r.GetProcId())
- }
- func (c *client) DeleteTable(t *hrpc.DeleteTable) error {
- pbmsg, err := c.SendRPC(t)
- if err != nil {
- return err
- }
- r, ok := pbmsg.(*pb.DeleteTableResponse)
- if !ok {
- return fmt.Errorf("sendRPC returned not a DeleteTableResponse")
- }
- return c.checkProcedureWithBackoff(t.Context(), r.GetProcId())
- }
- func (c *client) EnableTable(t *hrpc.EnableTable) error {
- pbmsg, err := c.SendRPC(t)
- if err != nil {
- return err
- }
- r, ok := pbmsg.(*pb.EnableTableResponse)
- if !ok {
- return fmt.Errorf("sendRPC returned not a EnableTableResponse")
- }
- return c.checkProcedureWithBackoff(t.Context(), r.GetProcId())
- }
- func (c *client) DisableTable(t *hrpc.DisableTable) error {
- pbmsg, err := c.SendRPC(t)
- if err != nil {
- return err
- }
- r, ok := pbmsg.(*pb.DisableTableResponse)
- if !ok {
- return fmt.Errorf("sendRPC returned not a DisableTableResponse")
- }
- return c.checkProcedureWithBackoff(t.Context(), r.GetProcId())
- }
- func (c *client) checkProcedureWithBackoff(ctx context.Context, procID uint64) error {
- backoff := backoffStart
- for {
- pbmsg, err := c.SendRPC(hrpc.NewGetProcedureState(ctx, procID))
- if err != nil {
- return err
- }
- res := pbmsg.(*pb.GetProcedureResultResponse)
- switch res.GetState() {
- case pb.GetProcedureResultResponse_NOT_FOUND:
- return fmt.Errorf("procedure not found")
- case pb.GetProcedureResultResponse_FINISHED:
- if fe := res.Exception; fe != nil {
- ge := fe.GenericException
- if ge == nil {
- return errors.New("got unexpected empty exception")
- }
- return fmt.Errorf("procedure exception: %s: %s", ge.GetClassName(), ge.GetMessage())
- }
- return nil
- default:
- backoff, err = sleepAndIncreaseBackoff(ctx, backoff)
- if err != nil {
- return err
- }
- }
- }
- }
- // CreateSnapshot creates a snapshot in HBase.
- //
- // If a context happens during creation, no cleanup is done.
- func (c *client) CreateSnapshot(t *hrpc.Snapshot) error {
- pbmsg, err := c.SendRPC(t)
- if err != nil {
- return err
- }
- _, ok := pbmsg.(*pb.SnapshotResponse)
- if !ok {
- return errors.New("sendPRC returned not a SnapshotResponse")
- }
- ticker := time.NewTicker(snaphotValidateInterval)
- defer ticker.Stop()
- check := hrpc.NewSnapshotDone(t)
- ctx := t.Context()
- for {
- select {
- case <-ticker.C:
- pbmsgs, err := c.SendRPC(check)
- if err != nil {
- return err
- }
- r, ok := pbmsgs.(*pb.IsSnapshotDoneResponse)
- if !ok {
- return errors.New("sendPRC returned not a IsSnapshotDoneResponse")
- }
- if r.GetDone() {
- return nil
- }
- case <-ctx.Done():
- return ctx.Err()
- }
- }
- }
- // DeleteSnapshot deletes a snapshot in HBase.
- func (c *client) DeleteSnapshot(t *hrpc.Snapshot) error {
- rt := hrpc.NewDeleteSnapshot(t)
- pbmsg, err := c.SendRPC(rt)
- if err != nil {
- return err
- }
- _, ok := pbmsg.(*pb.DeleteSnapshotResponse)
- if !ok {
- return errors.New("sendPRC returned not a DeleteSnapshotResponse")
- }
- return nil
- }
- func (c *client) ListSnapshots(t *hrpc.ListSnapshots) ([]*pb.SnapshotDescription, error) {
- pbmsg, err := c.SendRPC(t)
- if err != nil {
- return nil, err
- }
- r, ok := pbmsg.(*pb.GetCompletedSnapshotsResponse)
- if !ok {
- return nil, errors.New("sendPRC returned not a GetCompletedSnapshotsResponse")
- }
- return r.GetSnapshots(), nil
- }
- func (c *client) RestoreSnapshot(t *hrpc.Snapshot) error {
- rt := hrpc.NewRestoreSnapshot(t)
- pbmsg, err := c.SendRPC(rt)
- if err != nil {
- return err
- }
- _, ok := pbmsg.(*pb.RestoreSnapshotResponse)
- if !ok {
- return errors.New("sendPRC returned not a RestoreSnapshotResponse")
- }
- return nil
- }
- func (c *client) ListTableNames(t *hrpc.ListTableNames) ([]*pb.TableName, error) {
- pbmsg, err := c.SendRPC(t)
- if err != nil {
- return nil, err
- }
- res, ok := pbmsg.(*pb.GetTableNamesResponse)
- if !ok {
- return nil, errors.New("sendPRC returned not a GetTableNamesResponse")
- }
- return res.GetTableNames(), nil
- }
|