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 }