You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

writeconcern.go 5.4 kB

5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Copyright (C) MongoDB, Inc. 2017-present.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"); you may
  4. // not use this file except in compliance with the License. You may obtain
  5. // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
  6. package writeconcern // import "go.mongodb.org/mongo-driver/mongo/writeconcern"
  7. import (
  8. "errors"
  9. "time"
  10. "go.mongodb.org/mongo-driver/bson"
  11. "go.mongodb.org/mongo-driver/bson/bsontype"
  12. "go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
  13. )
  14. // ErrInconsistent indicates that an inconsistent write concern was specified.
  15. var ErrInconsistent = errors.New("a write concern cannot have both w=0 and j=true")
  16. // ErrEmptyWriteConcern indicates that a write concern has no fields set.
  17. var ErrEmptyWriteConcern = errors.New("a write concern must have at least one field set")
  18. // ErrNegativeW indicates that a negative integer `w` field was specified.
  19. var ErrNegativeW = errors.New("write concern `w` field cannot be a negative number")
  20. // ErrNegativeWTimeout indicates that a negative WTimeout was specified.
  21. var ErrNegativeWTimeout = errors.New("write concern `wtimeout` field cannot be negative")
  22. // WriteConcern describes the level of acknowledgement requested from MongoDB for write operations
  23. // to a standalone mongod or to replica sets or to sharded clusters.
  24. type WriteConcern struct {
  25. w interface{}
  26. j bool
  27. wTimeout time.Duration
  28. }
  29. // Option is an option to provide when creating a WriteConcern.
  30. type Option func(concern *WriteConcern)
  31. // New constructs a new WriteConcern.
  32. func New(options ...Option) *WriteConcern {
  33. concern := &WriteConcern{}
  34. for _, option := range options {
  35. option(concern)
  36. }
  37. return concern
  38. }
  39. // W requests acknowledgement that write operations propagate to the specified number of mongod
  40. // instances.
  41. func W(w int) Option {
  42. return func(concern *WriteConcern) {
  43. concern.w = w
  44. }
  45. }
  46. // WMajority requests acknowledgement that write operations propagate to the majority of mongod
  47. // instances.
  48. func WMajority() Option {
  49. return func(concern *WriteConcern) {
  50. concern.w = "majority"
  51. }
  52. }
  53. // WTagSet requests acknowledgement that write operations propagate to the specified mongod
  54. // instance.
  55. func WTagSet(tag string) Option {
  56. return func(concern *WriteConcern) {
  57. concern.w = tag
  58. }
  59. }
  60. // J requests acknowledgement from MongoDB that write operations are written to
  61. // the journal.
  62. func J(j bool) Option {
  63. return func(concern *WriteConcern) {
  64. concern.j = j
  65. }
  66. }
  67. // WTimeout specifies specifies a time limit for the write concern.
  68. func WTimeout(d time.Duration) Option {
  69. return func(concern *WriteConcern) {
  70. concern.wTimeout = d
  71. }
  72. }
  73. // MarshalBSONValue implements the bson.ValueMarshaler interface.
  74. func (wc *WriteConcern) MarshalBSONValue() (bsontype.Type, []byte, error) {
  75. if !wc.IsValid() {
  76. return bsontype.Type(0), nil, ErrInconsistent
  77. }
  78. var elems []byte
  79. if wc.w != nil {
  80. switch t := wc.w.(type) {
  81. case int:
  82. if t < 0 {
  83. return bsontype.Type(0), nil, ErrNegativeW
  84. }
  85. elems = bsoncore.AppendInt32Element(elems, "w", int32(t))
  86. case string:
  87. elems = bsoncore.AppendStringElement(elems, "w", string(t))
  88. }
  89. }
  90. if wc.j {
  91. elems = bsoncore.AppendBooleanElement(elems, "j", wc.j)
  92. }
  93. if wc.wTimeout < 0 {
  94. return bsontype.Type(0), nil, ErrNegativeWTimeout
  95. }
  96. if wc.wTimeout != 0 {
  97. elems = bsoncore.AppendInt64Element(elems, "wtimeout", int64(wc.wTimeout/time.Millisecond))
  98. }
  99. if len(elems) == 0 {
  100. return bsontype.Type(0), nil, ErrEmptyWriteConcern
  101. }
  102. return bsontype.EmbeddedDocument, bsoncore.BuildDocument(nil, elems), nil
  103. }
  104. // AcknowledgedValue returns true if a BSON RawValue for a write concern represents an acknowledged write concern.
  105. // The element's value must be a document representing a write concern.
  106. func AcknowledgedValue(rawv bson.RawValue) bool {
  107. doc, ok := bsoncore.Value{Type: rawv.Type, Data: rawv.Value}.DocumentOK()
  108. if !ok {
  109. return false
  110. }
  111. val, err := doc.LookupErr("w")
  112. if err != nil {
  113. // key w not found --> acknowledged
  114. return true
  115. }
  116. i32, ok := val.Int32OK()
  117. if !ok {
  118. return false
  119. }
  120. return i32 != 0
  121. }
  122. // Acknowledged indicates whether or not a write with the given write concern will be acknowledged.
  123. func (wc *WriteConcern) Acknowledged() bool {
  124. if wc == nil || wc.j {
  125. return true
  126. }
  127. switch v := wc.w.(type) {
  128. case int:
  129. if v == 0 {
  130. return false
  131. }
  132. }
  133. return true
  134. }
  135. // IsValid checks whether the write concern is invalid.
  136. func (wc *WriteConcern) IsValid() bool {
  137. if !wc.j {
  138. return true
  139. }
  140. switch v := wc.w.(type) {
  141. case int:
  142. if v == 0 {
  143. return false
  144. }
  145. }
  146. return true
  147. }
  148. // GetW returns the write concern w level.
  149. func (wc *WriteConcern) GetW() interface{} {
  150. return wc.w
  151. }
  152. // GetJ returns the write concern journaling level.
  153. func (wc *WriteConcern) GetJ() bool {
  154. return wc.j
  155. }
  156. // GetWTimeout returns the write concern timeout.
  157. func (wc *WriteConcern) GetWTimeout() time.Duration {
  158. return wc.wTimeout
  159. }
  160. // WithOptions returns a copy of this WriteConcern with the options set.
  161. func (wc *WriteConcern) WithOptions(options ...Option) *WriteConcern {
  162. if wc == nil {
  163. return New(options...)
  164. }
  165. newWC := &WriteConcern{}
  166. *newWC = *wc
  167. for _, option := range options {
  168. option(newWC)
  169. }
  170. return newWC
  171. }
  172. // AckWrite returns true if a write concern represents an acknowledged write
  173. func AckWrite(wc *WriteConcern) bool {
  174. return wc == nil || wc.Acknowledged()
  175. }