github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/go.mongodb.org/mongo-driver/mongo/writeconcern/writeconcern.go (about)

     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  
     7  // Package writeconcern defines write concerns for MongoDB operations.
     8  //
     9  // For more information about MongoDB write concerns, see
    10  // https://www.mongodb.com/docs/manual/reference/write-concern/
    11  package writeconcern // import "go.mongodb.org/mongo-driver/mongo/writeconcern"
    12  
    13  import (
    14  	"errors"
    15  	"fmt"
    16  	"time"
    17  
    18  	"go.mongodb.org/mongo-driver/bson"
    19  	"go.mongodb.org/mongo-driver/bson/bsontype"
    20  	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
    21  )
    22  
    23  const majority = "majority"
    24  
    25  // ErrInconsistent indicates that an inconsistent write concern was specified.
    26  //
    27  // Deprecated: ErrInconsistent will be removed in Go Driver 2.0.
    28  var ErrInconsistent = errors.New("a write concern cannot have both w=0 and j=true")
    29  
    30  // ErrEmptyWriteConcern indicates that a write concern has no fields set.
    31  //
    32  // Deprecated: ErrEmptyWriteConcern will be removed in Go Driver 2.0.
    33  var ErrEmptyWriteConcern = errors.New("a write concern must have at least one field set")
    34  
    35  // ErrNegativeW indicates that a negative integer `w` field was specified.
    36  //
    37  // Deprecated: ErrNegativeW will be removed in Go Driver 2.0.
    38  var ErrNegativeW = errors.New("write concern `w` field cannot be a negative number")
    39  
    40  // ErrNegativeWTimeout indicates that a negative WTimeout was specified.
    41  //
    42  // Deprecated: ErrNegativeWTimeout will be removed in Go Driver 2.0.
    43  var ErrNegativeWTimeout = errors.New("write concern `wtimeout` field cannot be negative")
    44  
    45  // A WriteConcern defines a MongoDB read concern, which describes the level of acknowledgment
    46  // requested from MongoDB for write operations to a standalone mongod, to replica sets, or to
    47  // sharded clusters.
    48  //
    49  // For more information about MongoDB write concerns, see
    50  // https://www.mongodb.com/docs/manual/reference/write-concern/
    51  type WriteConcern struct {
    52  	// W requests acknowledgment that the write operation has propagated to a
    53  	// specified number of mongod instances or to mongod instances with
    54  	// specified tags. It sets the the "w" option in a MongoDB write concern.
    55  	//
    56  	// W values must be a string or an int.
    57  	//
    58  	// Common values are:
    59  	//   - "majority": requests acknowledgment that write operations have been
    60  	//     durably committed to the calculated majority of the data-bearing
    61  	//     voting members.
    62  	//   - 1: requests acknowledgment that write operations have been written
    63  	//     to 1 node.
    64  	//   - 0: requests no acknowledgment of write operations
    65  	//
    66  	// For more information about the "w" option, see
    67  	// https://www.mongodb.com/docs/manual/reference/write-concern/#w-option
    68  	W interface{}
    69  
    70  	// Journal requests acknowledgment from MongoDB that the write operation has
    71  	// been written to the on-disk journal. It sets the "j" option in a MongoDB
    72  	// write concern.
    73  	//
    74  	// For more information about the "j" option, see
    75  	// https://www.mongodb.com/docs/manual/reference/write-concern/#j-option
    76  	Journal *bool
    77  
    78  	// WTimeout specifies a time limit for the write concern. It sets the
    79  	// "wtimeout" option in a MongoDB write concern.
    80  	//
    81  	// It is only applicable for "w" values greater than 1. Using a WTimeout and
    82  	// setting Timeout on the Client at the same time will result in undefined
    83  	// behavior.
    84  	//
    85  	// For more information about the "wtimeout" option, see
    86  	// https://www.mongodb.com/docs/manual/reference/write-concern/#wtimeout
    87  	WTimeout time.Duration
    88  }
    89  
    90  // Unacknowledged returns a WriteConcern that requests no acknowledgment of
    91  // write operations.
    92  //
    93  // For more information about write concern "w: 0", see
    94  // https://www.mongodb.com/docs/manual/reference/write-concern/#mongodb-writeconcern-writeconcern.-number-
    95  func Unacknowledged() *WriteConcern {
    96  	return &WriteConcern{W: 0}
    97  }
    98  
    99  // W1 returns a WriteConcern that requests acknowledgment that write operations
   100  // have been written to memory on one node (e.g. the standalone mongod or the
   101  // primary in a replica set).
   102  //
   103  // For more information about write concern "w: 1", see
   104  // https://www.mongodb.com/docs/manual/reference/write-concern/#mongodb-writeconcern-writeconcern.-number-
   105  func W1() *WriteConcern {
   106  	return &WriteConcern{W: 1}
   107  }
   108  
   109  // Journaled returns a WriteConcern that requests acknowledgment that write
   110  // operations have been written to the on-disk journal on MongoDB.
   111  //
   112  // The database's default value for "w" determines how many nodes must write to
   113  // their on-disk journal before the write operation is acknowledged.
   114  //
   115  // For more information about write concern "j: true", see
   116  // https://www.mongodb.com/docs/manual/reference/write-concern/#mongodb-writeconcern-ournal
   117  func Journaled() *WriteConcern {
   118  	journal := true
   119  	return &WriteConcern{Journal: &journal}
   120  }
   121  
   122  // Majority returns a WriteConcern that requests acknowledgment that write
   123  // operations have been durably committed to the calculated majority of the
   124  // data-bearing voting members.
   125  //
   126  // Write concern "w: majority" typically requires write operations to be written
   127  // to the on-disk journal before they are acknowledged, unless journaling is
   128  // disabled on MongoDB or the "writeConcernMajorityJournalDefault" replica set
   129  // configuration is set to false.
   130  //
   131  // For more information about write concern "w: majority", see
   132  // https://www.mongodb.com/docs/manual/reference/write-concern/#mongodb-writeconcern-writeconcern.-majority-
   133  func Majority() *WriteConcern {
   134  	return &WriteConcern{W: majority}
   135  }
   136  
   137  // Custom returns a WriteConcern that requests acknowledgment that write
   138  // operations have propagated to tagged members that satisfy the custom write
   139  // concern defined in "settings.getLastErrorModes".
   140  //
   141  // For more information about custom write concern names, see
   142  // https://www.mongodb.com/docs/manual/reference/write-concern/#mongodb-writeconcern-writeconcern.-custom-write-concern-name-
   143  func Custom(tag string) *WriteConcern {
   144  	return &WriteConcern{W: tag}
   145  }
   146  
   147  // Option is an option to provide when creating a WriteConcern.
   148  //
   149  // Deprecated: Use the WriteConcern convenience functions or define a struct literal instead.
   150  // For example:
   151  //
   152  //	writeconcern.Majority()
   153  //
   154  // or
   155  //
   156  //	journal := true
   157  //	&writeconcern.WriteConcern{
   158  //		W:       2,
   159  //		Journal: &journal,
   160  //	}
   161  type Option func(concern *WriteConcern)
   162  
   163  // New constructs a new WriteConcern.
   164  //
   165  // Deprecated: Use the WriteConcern convenience functions or define a struct literal instead.
   166  // For example:
   167  //
   168  //	writeconcern.Majority()
   169  //
   170  // or
   171  //
   172  //	journal := true
   173  //	&writeconcern.WriteConcern{
   174  //		W:       2,
   175  //		Journal: &journal,
   176  //	}
   177  func New(options ...Option) *WriteConcern {
   178  	concern := &WriteConcern{}
   179  
   180  	for _, option := range options {
   181  		option(concern)
   182  	}
   183  
   184  	return concern
   185  }
   186  
   187  // W requests acknowledgement that write operations propagate to the specified number of mongod
   188  // instances.
   189  //
   190  // Deprecated: Use the Unacknowledged or W1 functions or define a struct literal instead.
   191  // For example:
   192  //
   193  //	writeconcern.Unacknowledged()
   194  //
   195  // or
   196  //
   197  //	journal := true
   198  //	&writeconcern.WriteConcern{
   199  //		W:       2,
   200  //		Journal: &journal,
   201  //	}
   202  func W(w int) Option {
   203  	return func(concern *WriteConcern) {
   204  		concern.W = w
   205  	}
   206  }
   207  
   208  // WMajority requests acknowledgement that write operations propagate to the majority of mongod
   209  // instances.
   210  //
   211  // Deprecated: Use [Majority] instead.
   212  func WMajority() Option {
   213  	return func(concern *WriteConcern) {
   214  		concern.W = majority
   215  	}
   216  }
   217  
   218  // WTagSet requests acknowledgement that write operations propagate to the specified mongod
   219  // instance.
   220  //
   221  // Deprecated: Use [Custom] instead.
   222  func WTagSet(tag string) Option {
   223  	return func(concern *WriteConcern) {
   224  		concern.W = tag
   225  	}
   226  }
   227  
   228  // J requests acknowledgement from MongoDB that write operations are written to
   229  // the journal.
   230  //
   231  // Deprecated: Use the Journaled function or define a struct literal instead.
   232  // For example:
   233  //
   234  //	writeconcern.Journaled()
   235  //
   236  // or
   237  //
   238  //	journal := true
   239  //	&writeconcern.WriteConcern{
   240  //		W:       2,
   241  //		Journal: &journal,
   242  //	}
   243  func J(j bool) Option {
   244  	return func(concern *WriteConcern) {
   245  		// To maintain backward compatible behavior (now that the J field is a
   246  		// bool pointer), only set a value for J if the input is true. If the
   247  		// input is false, do not set a value, which omits "j" from the
   248  		// marshaled write concern.
   249  		if j {
   250  			concern.Journal = &j
   251  		}
   252  	}
   253  }
   254  
   255  // WTimeout specifies a time limit for the write concern.
   256  //
   257  // It is only applicable for "w" values greater than 1. Using a WTimeout and setting Timeout on the
   258  // Client at the same time will result in undefined behavior.
   259  //
   260  // Deprecated: Use the WriteConcern convenience functions or define a struct literal instead.
   261  // For example:
   262  //
   263  //	wc := writeconcern.W1()
   264  //	wc.WTimeout = 30 * time.Second
   265  //
   266  // or
   267  //
   268  //	journal := true
   269  //	&writeconcern.WriteConcern{
   270  //		W:        "majority",
   271  //		WTimeout: 30 * time.Second,
   272  //	}
   273  func WTimeout(d time.Duration) Option {
   274  	return func(concern *WriteConcern) {
   275  		concern.WTimeout = d
   276  	}
   277  }
   278  
   279  // MarshalBSONValue implements the bson.ValueMarshaler interface.
   280  //
   281  // Deprecated: Marshaling a WriteConcern to BSON will not be supported in Go
   282  // Driver 2.0.
   283  func (wc *WriteConcern) MarshalBSONValue() (bsontype.Type, []byte, error) {
   284  	if wc == nil {
   285  		return 0, nil, ErrEmptyWriteConcern
   286  	}
   287  
   288  	var elems []byte
   289  	if wc.W != nil {
   290  		// Only support string or int values for W. That aligns with the
   291  		// documentation and the behavior of other functions, like Acknowledged.
   292  		switch w := wc.W.(type) {
   293  		case int:
   294  			if w < 0 {
   295  				return 0, nil, ErrNegativeW
   296  			}
   297  
   298  			// If Journal=true and W=0, return an error because that write
   299  			// concern is ambiguous.
   300  			if wc.Journal != nil && *wc.Journal && w == 0 {
   301  				return 0, nil, ErrInconsistent
   302  			}
   303  
   304  			elems = bsoncore.AppendInt32Element(elems, "w", int32(w))
   305  		case string:
   306  			elems = bsoncore.AppendStringElement(elems, "w", w)
   307  		default:
   308  			return 0,
   309  				nil,
   310  				fmt.Errorf("WriteConcern.W must be a string or int, but is a %T", wc.W)
   311  		}
   312  	}
   313  
   314  	if wc.Journal != nil {
   315  		elems = bsoncore.AppendBooleanElement(elems, "j", *wc.Journal)
   316  	}
   317  
   318  	if wc.WTimeout < 0 {
   319  		return 0, nil, ErrNegativeWTimeout
   320  	}
   321  
   322  	if wc.WTimeout != 0 {
   323  		elems = bsoncore.AppendInt64Element(elems, "wtimeout", int64(wc.WTimeout/time.Millisecond))
   324  	}
   325  
   326  	if len(elems) == 0 {
   327  		return 0, nil, ErrEmptyWriteConcern
   328  	}
   329  	return bson.TypeEmbeddedDocument, bsoncore.BuildDocument(nil, elems), nil
   330  }
   331  
   332  // AcknowledgedValue returns true if a BSON RawValue for a write concern represents an acknowledged write concern.
   333  // The element's value must be a document representing a write concern.
   334  //
   335  // Deprecated: AcknowledgedValue will not be supported in Go Driver 2.0.
   336  func AcknowledgedValue(rawv bson.RawValue) bool {
   337  	doc, ok := bsoncore.Value{Type: rawv.Type, Data: rawv.Value}.DocumentOK()
   338  	if !ok {
   339  		return false
   340  	}
   341  
   342  	val, err := doc.LookupErr("w")
   343  	if err != nil {
   344  		// key w not found --> acknowledged
   345  		return true
   346  	}
   347  
   348  	i32, ok := val.Int32OK()
   349  	if !ok {
   350  		return false
   351  	}
   352  	return i32 != 0
   353  }
   354  
   355  // Acknowledged indicates whether or not a write with the given write concern will be acknowledged.
   356  func (wc *WriteConcern) Acknowledged() bool {
   357  	// Only {w: 0} or {w: 0, j: false} are an unacknowledged write concerns. All other values are
   358  	// acknowledged.
   359  	return wc == nil || wc.W != 0 || (wc.Journal != nil && *wc.Journal)
   360  }
   361  
   362  // IsValid returns true if the WriteConcern is valid.
   363  func (wc *WriteConcern) IsValid() bool {
   364  	if wc == nil {
   365  		return true
   366  	}
   367  
   368  	switch w := wc.W.(type) {
   369  	case int:
   370  		// A write concern with {w: int} must have a non-negative value and
   371  		// cannot have the combination {w: 0, j: true}.
   372  		return w >= 0 && (w > 0 || wc.Journal == nil || !*wc.Journal)
   373  	case string, nil:
   374  		// A write concern with {w: string} or no w specified is always valid.
   375  		return true
   376  	default:
   377  		// A write concern with an unsupported w type is not valid.
   378  		return false
   379  	}
   380  }
   381  
   382  // GetW returns the write concern w level.
   383  //
   384  // Deprecated: Use the WriteConcern.W field instead.
   385  func (wc *WriteConcern) GetW() interface{} {
   386  	return wc.W
   387  }
   388  
   389  // GetJ returns the write concern journaling level.
   390  //
   391  // Deprecated: Use the WriteConcern.Journal field instead.
   392  func (wc *WriteConcern) GetJ() bool {
   393  	// Treat a nil Journal as false. That maintains backward compatibility with the existing
   394  	// behavior of GetJ where unset is false. If users want the real value of Journal, they can
   395  	// access the Journal field.
   396  	return wc.Journal != nil && *wc.Journal
   397  }
   398  
   399  // GetWTimeout returns the write concern timeout.
   400  //
   401  // Deprecated: Use the WriteConcern.WTimeout field instead.
   402  func (wc *WriteConcern) GetWTimeout() time.Duration {
   403  	return wc.WTimeout
   404  }
   405  
   406  // WithOptions returns a copy of this WriteConcern with the options set.
   407  //
   408  // Deprecated: Use the WriteConcern convenience functions or define a struct literal instead.
   409  // For example:
   410  //
   411  //	writeconcern.Majority()
   412  //
   413  // or
   414  //
   415  //	journal := true
   416  //	&writeconcern.WriteConcern{
   417  //		W:       2,
   418  //		Journal: &journal,
   419  //	}
   420  func (wc *WriteConcern) WithOptions(options ...Option) *WriteConcern {
   421  	if wc == nil {
   422  		return New(options...)
   423  	}
   424  	newWC := &WriteConcern{}
   425  	*newWC = *wc
   426  
   427  	for _, option := range options {
   428  		option(newWC)
   429  	}
   430  
   431  	return newWC
   432  }
   433  
   434  // AckWrite returns true if a write concern represents an acknowledged write
   435  //
   436  // Deprecated: Use [WriteConcern.Acknowledged] instead.
   437  func AckWrite(wc *WriteConcern) bool {
   438  	return wc == nil || wc.Acknowledged()
   439  }