Advertisement
jdefelice

tx-command-api.go

Jul 10th, 2012
295
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 2.83 KB | None | 0 0
  1. package tx
  2.  
  3. //
  4. // thoughts on container-managed transactions in google go
  5. //
  6.  
  7. //
  8. // approach 1: via tx-command pattern.  Downside to this (??) is that there is
  9. // no analog for thread-locals in go, so ctx must be passed around all the time
  10. // once you cross the first tx barrier
  11. //
  12.  
  13. // Error satisfies the error interface
  14. type Error string
  15. func (e Error) Error() string {
  16.   return string(e)
  17. }
  18.  
  19. type Mode int
  20. const (
  21.     Supports Mode = iota
  22.     Required
  23.     RequiresNew
  24.     Mandatory
  25.     Never
  26. )
  27.  
  28. type Context interface {
  29.   func SetRollback()
  30.   func IsRolledBack() bool
  31. }
  32.  
  33. type ContextSpi interface {
  34.   func exit()
  35.   Context
  36. }
  37.  
  38. // factory method for creating context service provider implementations.
  39. // implementation should function along the lines of get-or-create-context
  40. type ContextSpiFactory func(m Mode, parent *Context) (*ContextSpi)
  41.  
  42. // current, global context spi
  43. var spiFactory ContextSpiFactory
  44.  
  45. // client method to allow setting global context spi
  46. func() SetSpiFactory (f ContextSpiFactory) {
  47.   spiFactory = f
  48. }
  49.  
  50. type Command interface {
  51.  
  52.   // implementation of the command that does work in some tranactional context
  53.   func Run(ctx *Context, args ...interface{}) (results ...interface{})
  54.  
  55.   // transactional mode that this command should run in
  56.   func Mode() Mode
  57. }
  58.  
  59. // clients call this method to execute an instance of a Command.
  60. // if a client has not yet started a tx then ctx = nil is fine, otherwise the
  61. // client should pass in the current tx context.
  62. func (cmd Command*) Execute(parent *Context, args... interface{}) (err error, r ...interface{}) {
  63.  
  64.   defer func() {
  65.     if e = recover(); e != nil {
  66.       // XXX any cleanup should happen here...
  67.       err = e.(Error) // re-panic if not a tx error
  68.     }
  69.   }
  70.  
  71.   // establish new, or lookup current, tx context
  72.   ctx := spiFactory(cmd.Mode(), parent)
  73.  
  74.   defer func() {
  75.     ctx.exit()
  76.   }
  77.  
  78.   results = cmd.Run(ctx, args...)
  79.   return
  80. }
  81.  
  82. // basic, mock implementation of a context service provider
  83. type MockCtx struct {
  84.   ContextSpi
  85.   rolledBack bool
  86.   mode Mode
  87.   parent *MockCtx
  88. }
  89.  
  90. func (ctx *MockCtx) IsRolledBack() (bool) {
  91.   return ctx.rolledBack
  92. }
  93.  
  94. func (ctx *MockCtx) SetRollback() {
  95.   ctx.rolledBack = true
  96. }
  97.  
  98. // factory method for mock context.  obviously not implemented fully
  99. func NewMockCtx(m Mode, p *Context) (*ContextSpi) {
  100.   switch m {
  101.     case Supports:
  102.     case Required:
  103.     case RequiresNew:
  104.     case Mandatory:
  105.     case Never:
  106.     default:
  107.       panic(Error(fmt.Sprintf("tx: unsupported tx-mode ", m)))
  108.   }
  109.   return &MockCtx{mode: m, parent: p}
  110. }
  111.  
  112. // assume that commands are not allowed to throw their own errors across tx
  113. // boundaries
  114. func (ctx *MockCtx) exit() {
  115.   if err = recover(); err != nil || ctx.rolledBack {
  116.     // XXX rollback
  117.   }
  118.   else {
  119.     // XXX (2-phase) commit? (if necessary)
  120.   }
  121. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement