github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/go-hbase/admin.go (about)

     1  package hbase
     2  
     3  import (
     4  	"sort"
     5  	"strconv"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/insionng/yougam/libraries/juju/errors"
    10  	"github.com/insionng/yougam/libraries/ngaut/log"
    11  	"github.com/insionng/yougam/libraries/pingcap/go-hbase/proto"
    12  )
    13  
    14  const defaultNS = "default"
    15  
    16  type TableName struct {
    17  	namespace string
    18  	name      string
    19  }
    20  
    21  func newTableNameWithDefaultNS(tblName string) TableName {
    22  	return TableName{
    23  		namespace: defaultNS,
    24  		name:      tblName,
    25  	}
    26  }
    27  
    28  type TableDescriptor struct {
    29  	name  TableName
    30  	attrs map[string][]byte
    31  	cfs   []*ColumnFamilyDescriptor
    32  }
    33  
    34  func NewTableDesciptor(tblName string) *TableDescriptor {
    35  	ret := &TableDescriptor{
    36  		name:  newTableNameWithDefaultNS(tblName),
    37  		attrs: map[string][]byte{},
    38  	}
    39  	ret.AddAddr("IS_META", "false")
    40  	return ret
    41  }
    42  
    43  func (c *TableDescriptor) AddAddr(attrName string, val string) {
    44  	c.attrs[attrName] = []byte(val)
    45  }
    46  
    47  func (t *TableDescriptor) AddColumnDesc(cf *ColumnFamilyDescriptor) {
    48  	for _, c := range t.cfs {
    49  		if c.name == cf.name {
    50  			return
    51  		}
    52  	}
    53  	t.cfs = append(t.cfs, cf)
    54  }
    55  
    56  type ColumnFamilyDescriptor struct {
    57  	name  string
    58  	attrs map[string][]byte
    59  }
    60  
    61  func (c *ColumnFamilyDescriptor) AddAttr(attrName string, val string) {
    62  	c.attrs[attrName] = []byte(val)
    63  }
    64  
    65  // Themis will use VERSIONS=1 for some hook.
    66  func NewColumnFamilyDescriptor(name string) *ColumnFamilyDescriptor {
    67  	return newColumnFamilyDescriptor(name, 1)
    68  }
    69  
    70  func newColumnFamilyDescriptor(name string, versionsNum int) *ColumnFamilyDescriptor {
    71  	versions := strconv.Itoa(versionsNum)
    72  
    73  	ret := &ColumnFamilyDescriptor{
    74  		name:  name,
    75  		attrs: make(map[string][]byte),
    76  	}
    77  
    78  	// add default attrs
    79  	ret.AddAttr("DATA_BLOCK_ENCODING", "NONE")
    80  	ret.AddAttr("BLOOMFILTER", "ROW")
    81  	ret.AddAttr("REPLICATION_SCOPE", "0")
    82  	ret.AddAttr("COMPRESSION", "NONE")
    83  	ret.AddAttr("VERSIONS", versions)
    84  	ret.AddAttr("TTL", "2147483647") // 1 << 31
    85  	ret.AddAttr("MIN_VERSIONS", "0")
    86  	ret.AddAttr("KEEP_DELETED_CELLS", "false")
    87  	ret.AddAttr("BLOCKSIZE", "65536")
    88  	ret.AddAttr("IN_MEMORY", "false")
    89  	ret.AddAttr("BLOCKCACHE", "true")
    90  	return ret
    91  }
    92  
    93  func getPauseTime(retry int) int64 {
    94  	if retry >= len(retryPauseTime) {
    95  		retry = len(retryPauseTime) - 1
    96  	}
    97  	if retry < 0 {
    98  		retry = 0
    99  	}
   100  	return retryPauseTime[retry] * defaultRetryWaitMs
   101  }
   102  
   103  func (c *client) CreateTable(t *TableDescriptor, splits [][]byte) error {
   104  	req := &proto.CreateTableRequest{}
   105  	schema := &proto.TableSchema{}
   106  
   107  	sort.Sort(BytesSlice(splits))
   108  
   109  	schema.TableName = &proto.TableName{
   110  		Qualifier: []byte(t.name.name),
   111  		Namespace: []byte(t.name.namespace),
   112  	}
   113  
   114  	for k, v := range t.attrs {
   115  		schema.Attributes = append(schema.Attributes, &proto.BytesBytesPair{
   116  			First:  []byte(k),
   117  			Second: []byte(v),
   118  		})
   119  	}
   120  
   121  	for _, c := range t.cfs {
   122  		cf := &proto.ColumnFamilySchema{
   123  			Name: []byte(c.name),
   124  		}
   125  		for k, v := range c.attrs {
   126  			cf.Attributes = append(cf.Attributes, &proto.BytesBytesPair{
   127  				First:  []byte(k),
   128  				Second: []byte(v),
   129  			})
   130  		}
   131  		schema.ColumnFamilies = append(schema.ColumnFamilies, cf)
   132  	}
   133  
   134  	req.TableSchema = schema
   135  	req.SplitKeys = splits
   136  
   137  	ch, err := c.adminAction(req)
   138  	if err != nil {
   139  		return errors.Trace(err)
   140  	}
   141  
   142  	resp := <-ch
   143  	switch r := resp.(type) {
   144  	case *exception:
   145  		return errors.New(r.msg)
   146  	}
   147  
   148  	// wait and check
   149  	for retry := 0; retry < defaultMaxActionRetries*retryLongerMultiplier; retry++ {
   150  		regCnt := 0
   151  		numRegs := len(splits) + 1
   152  		err = c.metaScan(t.name.name, func(r *RegionInfo) (bool, error) {
   153  			if !(r.Offline || r.Split) && len(r.Server) > 0 && r.TableName == t.name.name {
   154  				regCnt++
   155  			}
   156  			return true, nil
   157  		})
   158  		if err != nil {
   159  			return errors.Trace(err)
   160  		}
   161  
   162  		if regCnt == numRegs {
   163  			return nil
   164  		}
   165  		log.Warnf("Retrying create table for the %d time(s)", retry+1)
   166  		time.Sleep(time.Duration(getPauseTime(retry)) * time.Millisecond)
   167  	}
   168  	return errors.New("create table timeout")
   169  }
   170  
   171  func (c *client) DisableTable(tblName string) error {
   172  	req := &proto.DisableTableRequest{
   173  		TableName: &proto.TableName{
   174  			Qualifier: []byte(tblName),
   175  			Namespace: []byte(defaultNS),
   176  		},
   177  	}
   178  
   179  	ch, err := c.adminAction(req)
   180  	if err != nil {
   181  		return errors.Trace(err)
   182  	}
   183  
   184  	resp := <-ch
   185  	switch r := resp.(type) {
   186  	case *exception:
   187  		return errors.New(r.msg)
   188  	}
   189  
   190  	return nil
   191  }
   192  
   193  func (c *client) EnableTable(tblName string) error {
   194  	req := &proto.EnableTableRequest{
   195  		TableName: &proto.TableName{
   196  			Qualifier: []byte(tblName),
   197  			Namespace: []byte(defaultNS),
   198  		},
   199  	}
   200  
   201  	ch, err := c.adminAction(req)
   202  	if err != nil {
   203  		return errors.Trace(err)
   204  	}
   205  
   206  	resp := <-ch
   207  	switch r := resp.(type) {
   208  	case *exception:
   209  		return errors.New(r.msg)
   210  	}
   211  
   212  	return nil
   213  }
   214  
   215  func (c *client) DropTable(tblName string) error {
   216  	req := &proto.DeleteTableRequest{
   217  		TableName: &proto.TableName{
   218  			Qualifier: []byte(tblName),
   219  			Namespace: []byte(defaultNS),
   220  		},
   221  	}
   222  
   223  	ch, err := c.adminAction(req)
   224  	if err != nil {
   225  		return errors.Trace(err)
   226  	}
   227  
   228  	resp := <-ch
   229  	switch r := resp.(type) {
   230  	case *exception:
   231  		return errors.New(r.msg)
   232  	}
   233  
   234  	return nil
   235  }
   236  
   237  func (c *client) metaScan(tbl string, fn func(r *RegionInfo) (bool, error)) error {
   238  	scan := NewScan(metaTableName, 0, c)
   239  	defer scan.Close()
   240  
   241  	scan.StartRow = []byte(tbl)
   242  	scan.StopRow = nextKey([]byte(tbl))
   243  
   244  	for {
   245  		r := scan.Next()
   246  		if r == nil || scan.Closed() {
   247  			break
   248  		}
   249  
   250  		region, err := c.parseRegion(r)
   251  		if err != nil {
   252  			return errors.Trace(err)
   253  		}
   254  
   255  		if more, err := fn(region); !more || err != nil {
   256  			return errors.Trace(err)
   257  		}
   258  	}
   259  
   260  	return nil
   261  }
   262  
   263  func (c *client) TableExists(tbl string) (bool, error) {
   264  	found := false
   265  	err := c.metaScan(tbl, func(region *RegionInfo) (bool, error) {
   266  		if region.TableName == tbl {
   267  			found = true
   268  			return false, nil
   269  		}
   270  		return true, nil
   271  	})
   272  	if err != nil {
   273  		return false, errors.Trace(err)
   274  	}
   275  
   276  	return found, nil
   277  }
   278  
   279  // Split splits region.
   280  // tblOrRegion table name or region(<tbl>,<endKey>,<timestamp>.<md5>).
   281  // splitPoint which is a key, leave "" if want to split each region automatically.
   282  func (c *client) Split(tblOrRegion, splitPoint string) error {
   283  	// Extract table name from supposing regionName.
   284  	tbls := strings.SplitN(tblOrRegion, ",", 2)
   285  	tbl := tbls[0]
   286  	found := false
   287  	var foundRegion *RegionInfo
   288  	err := c.metaScan(tbl, func(region *RegionInfo) (bool, error) {
   289  		if region != nil && region.Name == tblOrRegion {
   290  			found = true
   291  			foundRegion = region
   292  			return false, nil
   293  		}
   294  		return true, nil
   295  	})
   296  	if err != nil {
   297  		return errors.Trace(err)
   298  	}
   299  
   300  	// This is a region name, split it directly.
   301  	if found {
   302  		return c.split(foundRegion, []byte(splitPoint))
   303  	}
   304  
   305  	// This is a table name.
   306  	tbl = tblOrRegion
   307  	regions, err := c.GetRegions([]byte(tbl), false)
   308  	if err != nil {
   309  		return errors.Trace(err)
   310  	}
   311  	// Split each region.
   312  	for _, region := range regions {
   313  		err := c.split(region, []byte(splitPoint))
   314  		if err != nil {
   315  			return errors.Trace(err)
   316  		}
   317  	}
   318  	return nil
   319  }
   320  
   321  func (c *client) split(region *RegionInfo, splitPoint []byte) error {
   322  	// Not in this region, skip it.
   323  	if len(splitPoint) > 0 && !findKey(region, splitPoint) {
   324  		return nil
   325  	}
   326  	c.CleanRegionCache([]byte(region.TableName))
   327  	rs := NewRegionSpecifier(region.Name)
   328  	req := &proto.SplitRegionRequest{
   329  		Region: rs,
   330  	}
   331  	if len(splitPoint) > 0 {
   332  		req.SplitPoint = splitPoint
   333  	}
   334  	// Empty response.
   335  	_, err := c.regionAction(region.Server, req)
   336  	if err != nil {
   337  		return errors.Trace(err)
   338  	}
   339  	return nil
   340  }