Repository: microsoft/garnet
File: libs/server/Storage/Session/ObjectStore/SortedSetOps.cs (C#)

Code before:
        /// <param name="count"></param>
        /// <returns></returns>
        public unsafe GarnetStatus SortedSetDifferenceStore(ReadOnlySpan<ArgSlice> keys, ArgSlice destinationKey, out int count)
        {
            count = default;

            if (keys.Length == 0)
                return GarnetStatus.OK;

            var createTransaction = false;

            if (txnManager.state != TxnState.Running)
            {
                Debug.Assert(txnManager.state == TxnState.None);
                createTransaction = true;
                txnManager.SaveKeyEntryToLock(destinationKey, true, LockType.Exclusive);
                foreach (var item in keys)
                    txnManager.SaveKeyEntryToLock(item, true, LockType.Shared);
                _ = txnManager.Run(true);
            }

            var setObjectStoreLockableContext = txnManager.ObjectStoreLockableContext;

            try
            {
                var status = SortedSetDifference(keys, out var result);

                if (status != GarnetStatus.OK)
                {
                    return GarnetStatus.WRONGTYPE;
                }

                count = result is null ? 0 : result.Count;

                if (count > 0)
                {
                    SortedSetObject newSetObject = new();
                    foreach (var (element, score) in result)
                    {
                        newSetObject.Add(element, score);
                    }
                    _ = SET(destinationKey.ToArray(), newSetObject, ref setObjectStoreLockableContext);
                }
                else
                {
                    _ = EXPIRE(destinationKey, TimeSpan.Zero, out _, StoreType.Object, ExpireOption.None,
                        ref lockableContext, ref setObjectStoreLockableContext);
                }

                return status;
            }

Review comment (refactor):
Note that SortedSetDifference is also doing locking (that you don't need at that point), there should be a common method that extracts only the common logic that both SSD & SSDS call. See SetDiff & SetDiffStore for reference.

Code after:
                if (count > 0)
                {
                    SortedSetObject newSetObject = new();
                    foreach (var (element, score) in pairs)
                    {
                        newSetObject.Add(element, score);
                    }
                    _ = SET(destinationKey.ToArray(), newSetObject, ref objectContext);
                }
                else
                {
                    _ = EXPIRE(destinationKey, TimeSpan.Zero, out _, StoreType.Object, ExpireOption.None,
                        ref lockableContext, ref objectContext);
                }

                return status;
            }
            finally
            {
                if (createTransaction)
                    txnManager.Commit(true);
            }
        }

        /// <summary>
        /// Returns the rank of member in the sorted set, the scores in the sorted set are ordered from high to low
        /// <param name="key">The key of the sorted set</param>
        /// <param name="member">The member to get the rank</param>
        /// <param name="reverse">If true, the rank is calculated from low to high</param>
        /// <param name="rank">The rank of the member (null if the member does not exist)</param>
        /// <param name="objectStoreContext"></param>
        /// </summary>
        public unsafe GarnetStatus SortedSetRank<TObjectContext>(ArgSlice key, ArgSlice member, bool reverse, out long? rank, ref TObjectContext objectStoreContext)
            where TObjectContext : ITsavoriteContext<byte[], IGarnetObject, ObjectInput, GarnetObjectStoreOutput, long, ObjectSessionFunctions, ObjectStoreFunctions, ObjectStoreAllocator>
        {
            rank = null;
            if (key.Length == 0)
                return GarnetStatus.OK;

            // Prepare the parse state
            parseState.InitializeWithArgument(member);

            // Prepare the input
            var op = reverse ? SortedSetOperation.ZREVRANK : SortedSetOperation.ZRANK;
            var header = new RespInputHeader(GarnetObjectType.SortedSet) { SortedSetOp = op };
            var input = new ObjectInput(header, ref parseState);

            const int outputContainerSize = 32; // 3 for HEADER + CRLF + 20 for ascii long
            var outputContainer = stackalloc byte[outputContainerSize];
            var outputFooter = new GarnetObjectStoreOutput { spanByteAndMemory = new SpanByteAndMemory(outputContainer, outputContainerSize) };