1e9b52b79SMike Goldsmithusing System;
208fea4a2SBrant Burnettusing System.Buffers;
3502afd31SJeff Morrisusing System.Collections.Generic;
494f26dbcSJeff Morrisusing System.Diagnostics;
52f9745bfSJeff Morrisusing System.Globalization;
6f0de3118SBrant Burnettusing System.Runtime.CompilerServices;
70ba3f4aaSjeffrymorrisusing System.Text;
878a9d823SJeff Morrisusing System.Threading;
90ba3f4aaSjeffrymorrisusing System.Threading.Tasks;
1057844b28SBrant Burnettusing System.Threading.Tasks.Sources;
1143cf091cSMike Goldsmithusing Couchbase.Core.Configuration.Server;
129795828fSJeff Morrisusing Couchbase.Core.Diagnostics.Metrics;
13c7f4f8f4SRiPontusing Couchbase.Core.Diagnostics.Tracing;
14d6a3e38fSJeff Morrisusing Couchbase.Core.Diagnostics.Tracing.OrphanResponseReporting;
155c51a3daSJeff Morrisusing Couchbase.Core.Diagnostics.Tracing.ThresholdTracing;
169670b373SBrant Burnettusing Couchbase.Core.IO.Compression;
17d075be7dSBrant Burnettusing Couchbase.Core.IO.Connections;
1843cf091cSMike Goldsmithusing Couchbase.Core.IO.Converters;
1943cf091cSMike Goldsmithusing Couchbase.Core.IO.Transcoders;
20502afd31SJeff Morrisusing Couchbase.Core.Retry;
2143cf091cSMike Goldsmithusing Couchbase.Core.Utils;
2208fea4a2SBrant Burnettusing Couchbase.Utils;
231663c0ccSBrant Burnettusing Microsoft.Extensions.ObjectPool;
241a28374eSBrant Burnett
251a28374eSBrant Burnett#nullable enable
260ba3f4aaSjeffrymorris
27e308481bSJeff Morrisnamespace Couchbase.Core.IO.Operations
280ba3f4aaSjeffrymorris{
29eb1c124fSBrant Burnett    /// <remarks>
30eb1c124fSBrant Burnett    /// It is important for this object to be disposed. Failure to properly dispose this object may result
31eb1c124fSBrant Burnett    /// in memory not being returned to the ArrayPool, which will increase GC impact across various parts of the framework.
32eb1c124fSBrant Burnett    /// </remarks>
3357844b28SBrant Burnett    internal abstract class OperationBase : IOperation, IValueTaskSource<ResponseStatus>
340ba3f4aaSjeffrymorris    {
35d9a085c6SBrant Burnett        private SlicedMemoryOwner<byte> _data;
365c51a3daSJeff Morris        private IRequestSpan? _span;
371a28374eSBrant Burnett        private List<RetryReason>? _retryReasons;
381a28374eSBrant Burnett        private IRetryStrategy? _retryStrategy;
391a28374eSBrant Burnett        private volatile bool _isSent;
409795828fSJeff Morris        private IValueRecorder? _recorder;
4194f26dbcSJeff Morris        private readonly Stopwatch _stopwatch;
42690bf3f2SJeff Morris        private IRequestSpan? _dispatchSpan;
43d6a3e38fSJeff Morris        private bool _isOrphaned;
440ba3f4aaSjeffrymorris
4543cf091cSMike Goldsmith        protected OperationBase()
460ba3f4aaSjeffrymorris        {
4743cf091cSMike Goldsmith            Opaque = SequenceGenerator.GetNext();
4837583118STommyJa            Header = new OperationHeader { Status = ResponseStatus.None };
4943cf091cSMike Goldsmith            Key = string.Empty;
5094f26dbcSJeff Morris            _stopwatch = Stopwatch.StartNew();
510ba3f4aaSjeffrymorris        }
520ba3f4aaSjeffrymorris
531a28374eSBrant Burnett        #region IOperation Properties
541a28374eSBrant Burnett
558cb06c5aSJeff Morris        public virtual bool PreserveTtl { get; set; } = false;
568cb06c5aSJeff Morris
571a28374eSBrant Burnett        /// <inheritdoc />
5843cf091cSMike Goldsmith        public abstract OpCode OpCode { get; }
591a28374eSBrant Burnett
601a28374eSBrant Burnett        /// <inheritdoc />
611a28374eSBrant Burnett        public string? BucketName { get; set; }
621a28374eSBrant Burnett
631a28374eSBrant Burnett        /// <inheritdoc />
641a28374eSBrant Burnett        public string? SName { get; set; }
651a28374eSBrant Burnett
661a28374eSBrant Burnett        /// <inheritdoc />
671a28374eSBrant Burnett        public string? CName { get; set; }
681a28374eSBrant Burnett
691a28374eSBrant Burnett        /// <inheritdoc />
7043cf091cSMike Goldsmith        public uint? Cid { get; set; }
711a28374eSBrant Burnett
721a28374eSBrant Burnett        /// <inheritdoc />
731a28374eSBrant Burnett        public string Key { get; set; }
741a28374eSBrant Burnett
751a28374eSBrant Burnett        /// <inheritdoc />
7643cf091cSMike Goldsmith        public uint Opaque { get; set; }
771a28374eSBrant Burnett
781a28374eSBrant Burnett        /// <inheritdoc />
791a28374eSBrant Burnett        public ulong Cas { get; set; }
801a28374eSBrant Burnett
811a28374eSBrant Burnett        /// <inheritdoc />
8243cf091cSMike Goldsmith        public short? VBucketId { get; set; }
83502afd31SJeff Morris
841a28374eSBrant Burnett        /// <inheritdoc />
851a28374eSBrant Burnett        public short? ReplicaIdx { get; protected set; }
861a28374eSBrant Burnett
871a28374eSBrant Burnett        /// <inheritdoc />
881a28374eSBrant Burnett        public OperationHeader Header { get; set; }
891a28374eSBrant Burnett
901a28374eSBrant Burnett        /// <inheritdoc />
915c51a3daSJeff Morris        public IRequestSpan Span
92c7f4f8f4SRiPont        {
935c51a3daSJeff Morris            get => _span ?? NoopRequestSpan.Instance;
94c7f4f8f4SRiPont            internal set
95c7f4f8f4SRiPont            {
96c7f4f8f4SRiPont                _span = value;
975c51a3daSJeff Morris                _span.WithOperationId(this);
98c7f4f8f4SRiPont            }
99c7f4f8f4SRiPont        }
100c7f4f8f4SRiPont
1019795828fSJeff Morris        /// <inheritdoc />
1029795828fSJeff Morris        public IValueRecorder Recorder
1039795828fSJeff Morris        {
1049795828fSJeff Morris            get => _recorder ?? NoopValueRecorder.Instance;
1059795828fSJeff Morris            set => _recorder = value;
1069795828fSJeff Morris        }
1079795828fSJeff Morris
108fc440704SBrant Burnett        /// <inheritdoc />
1091a28374eSBrant Burnett        public virtual bool HasDurability => false;
110fc440704SBrant Burnett
1111a28374eSBrant Burnett        /// <inheritdoc />
1121a28374eSBrant Burnett        public virtual bool IsReadOnly => true;
113fc440704SBrant Burnett
114fc440704SBrant Burnett        /// <inheritdoc />
115fc440704SBrant Burnett        public bool IsSent
116fc440704SBrant Burnett        {
117fc440704SBrant Burnett            get => _isSent;
118fc440704SBrant Burnett            internal set => _isSent = value; // For unit tests
119fc440704SBrant Burnett        }
120fc440704SBrant Burnett
1211a28374eSBrant Burnett        /// <inheritdoc />
1221a28374eSBrant Burnett        public ValueTask<ResponseStatus> Completed => new(this, _valueTaskSource.Version);
1231a28374eSBrant Burnett
124bc287781SJeff Morris        /// <inheritdoc />
125bc287781SJeff Morris        public virtual bool RequiresVBucketId => true;
126bc287781SJeff Morris
1271a28374eSBrant Burnett        #endregion
1281a28374eSBrant Burnett
1291a28374eSBrant Burnett        #region IRequest Properties (RetryAsync SDK-3)
130502afd31SJeff Morris
131502afd31SJeff Morris        public uint Attempts { get; set; }
1321a28374eSBrant Burnett        bool IRequest.Idempotent => IsReadOnly;
133f0301486SJeff Morris
134f0301486SJeff Morris        public List<RetryReason> RetryReasons
135f0301486SJeff Morris        {
136f0301486SJeff Morris            get => _retryReasons ??= new List<RetryReason>();
137f0301486SJeff Morris            set => _retryReasons = value;
138f0301486SJeff Morris        }
139f0301486SJeff Morris
140f0301486SJeff Morris        public IRetryStrategy RetryStrategy
141f0301486SJeff Morris        {
142f0301486SJeff Morris            get => _retryStrategy ??= new BestEffortRetryStrategy(new ControlledBackoff());
143f0301486SJeff Morris            set => _retryStrategy = value;
144f0301486SJeff Morris        }
145f0301486SJeff Morris
14678a9d823SJeff Morris        public TimeSpan Timeout { get; set; }
14778a9d823SJeff Morris        public CancellationToken Token { get; set; }
1481a28374eSBrant Burnett
1491a28374eSBrant Burnett        // Not necessary for operations, just throw NotImplementedException and avoid an unnecessary backing field
1501a28374eSBrant Burnett        public string? ClientContextId
1511a28374eSBrant Burnett        {
1521a28374eSBrant Burnett            get => null;
1531a28374eSBrant Burnett            set => throw new NotImplementedException();
1541a28374eSBrant Burnett        }
1551a28374eSBrant Burnett
1561a28374eSBrant Burnett        // Not necessary for operations, just throw NotImplementedException and avoid an unnecessary backing field
1571a28374eSBrant Burnett        public string? Statement
1581a28374eSBrant Burnett        {
1591a28374eSBrant Burnett            get => null;
1601a28374eSBrant Burnett            set => throw new NotImplementedException();
1611a28374eSBrant Burnett        }
1621a28374eSBrant Burnett
1631a28374eSBrant Burnett        #endregion
1641a28374eSBrant Burnett
1651a28374eSBrant Burnett        #region Public Properties
1661a28374eSBrant Burnett
1671a28374eSBrant Burnett        /// <summary>
1681a28374eSBrant Burnett        /// Expiration to apply for mutation operations, and returns the expiration after the operation is completed.
1691a28374eSBrant Burnett        /// </summary>
1701a28374eSBrant Burnett        public uint Expires { get; set; }
1711a28374eSBrant Burnett
1721a28374eSBrant Burnett        /// <summary>
1731a28374eSBrant Burnett        /// Flags returned in the operation response.
1741a28374eSBrant Burnett        /// </summary>
1751a28374eSBrant Burnett        public Flags Flags { get; protected set; }
1761a28374eSBrant Burnett
1771a28374eSBrant Burnett        /// <summary>
1781a28374eSBrant Burnett        /// Mutation token returned by mutation operations, if any.
1791a28374eSBrant Burnett        /// </summary>
1801a28374eSBrant Burnett        public MutationToken? MutationToken { get; private set; }
1811a28374eSBrant Burnett
1821a28374eSBrant Burnett        /// <summary>
1831a28374eSBrant Burnett        /// Transcoder used for reading and writing the body of the operation.
1841a28374eSBrant Burnett        /// </summary>
1851a28374eSBrant Burnett        public ITypeTranscoder Transcoder { get; set; } = null!; // Assumes we always initialize with OperationConfigurator
1861a28374eSBrant Burnett
1871a28374eSBrant Burnett        /// <summary>
1881a28374eSBrant Burnett        /// Service for compressing and decompressing operation bodies. Typically set by the <see cref="IOperationConfigurator"/>.
1891a28374eSBrant Burnett        /// </summary>
1901a28374eSBrant Burnett        public IOperationCompressor OperationCompressor { get; set; } = null!; // Assumes we always initialize with OperationConfigurator
1911a28374eSBrant Burnett
1921a28374eSBrant Burnett        /// <summary>
1931a28374eSBrant Burnett        /// Service which providers <see cref="OperationBuilder"/> instances as needed.
1941a28374eSBrant Burnett        /// </summary>
1951a28374eSBrant Burnett        public ObjectPool<OperationBuilder> OperationBuilderPool { get; set; } = null!;  // Assumes we always initialize with OperationConfigurator
196502afd31SJeff Morris
197502afd31SJeff Morris        #endregion
198502afd31SJeff Morris
1991a28374eSBrant Burnett        #region Protected Properties
2001a28374eSBrant Burnett
2011a28374eSBrant Burnett        /// <summary>
2021a28374eSBrant Burnett        /// Exception encountered when parsing data, if any.
2031a28374eSBrant Burnett        /// </summary>
2041a28374eSBrant Burnett        protected Exception? Exception { get; set; }
2051a28374eSBrant Burnett
2061a28374eSBrant Burnett        /// <summary>
2071a28374eSBrant Burnett        /// Response data.
2081a28374eSBrant Burnett        /// </summary>
2091a28374eSBrant Burnett        protected ReadOnlyMemory<byte> Data => _data.Memory;
2101a28374eSBrant Burnett
211