github.com/zhiqiangxu/util@v0.0.0-20230112053021-0a7aee056cd5/osc/osc.go (about)

     1  package osc
     2  
     3  import "fmt"
     4  
     5  // this package implements a generic online schema change process
     6  
     7  // SchemaState is the state for schema elements.
     8  type SchemaState byte
     9  
    10  const (
    11  	// StateAbsent means this schema element is absent and can't be used.
    12  	StateAbsent SchemaState = iota
    13  	// StateDeleteOnly means we can only delete items for this schema element.
    14  	StateDeleteOnly
    15  	// StateWriteOnly means we can use any write operation on this schema element,
    16  	// but outer can't read the changed data.
    17  	StateWriteOnly
    18  	// StateWriteReorganization means we are re-organizing whole data after write only state.
    19  	StateWriteReorganization
    20  	// StateDeleteReorganization means we are re-organizing whole data after delete only state.
    21  	StateDeleteReorganization
    22  	// StatePublic means this schema element is ok for all write and read operations.
    23  	StatePublic
    24  )
    25  
    26  // AddSchemaChange for add schema change
    27  // each method should block until the state has been synced, or error
    28  type AddSchemaChange interface {
    29  	GetState() SchemaState
    30  	EnterDeleteOnly() error
    31  	EnterWriteOnly() error
    32  	EnterReorgAfterWriteOnly() error
    33  	EnterPublic() error
    34  }
    35  
    36  // DeleteSchemaChange for delete schema change
    37  // each method should block until the state has been synced, or error
    38  type DeleteSchemaChange interface {
    39  	GetState() SchemaState
    40  	EnterWriteOnly() error
    41  	EnterDeleteOnly() error
    42  	EnterReorgAfterDeleteOnly() error
    43  	EnterAbsent() error
    44  }
    45  
    46  const (
    47  	errInvalidState = "invalid state %d"
    48  )
    49  
    50  // StepAdd for a single add schema state transition
    51  func StepAdd(asc AddSchemaChange) (err error) {
    52  	state := asc.GetState()
    53  	switch state {
    54  	case StateAbsent:
    55  		err = asc.EnterDeleteOnly()
    56  		return
    57  	case StateDeleteOnly:
    58  		err = asc.EnterWriteOnly()
    59  		return
    60  	case StateWriteOnly:
    61  		err = asc.EnterReorgAfterWriteOnly()
    62  		return
    63  	case StateWriteReorganization:
    64  		err = asc.EnterPublic()
    65  		return
    66  	case StatePublic:
    67  		return
    68  	default:
    69  		err = fmt.Errorf(errInvalidState, state)
    70  		return
    71  	}
    72  }
    73  
    74  // StepDelete for a single delete schema state transition
    75  func StepDelete(dsc DeleteSchemaChange) (err error) {
    76  	state := dsc.GetState()
    77  	switch state {
    78  	case StatePublic:
    79  		err = dsc.EnterWriteOnly()
    80  		return
    81  	case StateWriteOnly:
    82  		err = dsc.EnterDeleteOnly()
    83  		return
    84  	case StateDeleteOnly:
    85  		err = dsc.EnterReorgAfterDeleteOnly()
    86  		return
    87  	case StateDeleteReorganization:
    88  		err = dsc.EnterAbsent()
    89  		return
    90  	case StateAbsent:
    91  		return
    92  	default:
    93  		err = fmt.Errorf(errInvalidState, state)
    94  		return
    95  	}
    96  }
    97  
    98  // StartAdd for start osc add process
    99  func StartAdd(asc AddSchemaChange) (err error) {
   100  	for asc.GetState() != StatePublic {
   101  		err = StepAdd(asc)
   102  		if err != nil {
   103  			return
   104  		}
   105  	}
   106  	return
   107  }
   108  
   109  // StartDelete for start osc delete process
   110  func StartDelete(dsc DeleteSchemaChange) (err error) {
   111  	for dsc.GetState() != StateAbsent {
   112  		err = StepDelete(dsc)
   113  		if err != nil {
   114  			return
   115  		}
   116  	}
   117  	return
   118  }
   119  
   120  // String implements fmt.Stringer interface.
   121  func (s SchemaState) String() string {
   122  	switch s {
   123  	case StateAbsent:
   124  		return "absent"
   125  	case StateDeleteOnly:
   126  		return "delete only"
   127  	case StateWriteOnly:
   128  		return "write only"
   129  	case StateWriteReorganization:
   130  		return "write reorganization"
   131  	case StateDeleteReorganization:
   132  		return "delete reorganization"
   133  	case StatePublic:
   134  		return "public"
   135  	default:
   136  		return fmt.Sprintf(errInvalidState, s)
   137  	}
   138  }