예제 #1
0
        internal override void Visit(InsertTxIdRequest req)
        {
            string hashId = req.TxId.ToString();

            if (this.redisVersionDbMode == RedisVersionDbMode.Cluster)
            {
                hashId = RedisVersionDb.PACK_KEY(RedisVersionDb.TX_KEY_PREFIX, hashId);
            }

            byte[][] keysBytes =
            {
                Encoding.ASCII.GetBytes(TxTableEntry.STATUS_STRING),
                Encoding.ASCII.GetBytes(TxTableEntry.COMMIT_TIME_STRING),
                Encoding.ASCII.GetBytes(TxTableEntry.COMMIT_LOWER_BOUND_STRING)
            };
            byte[][] valuesBytes =
            {
                BitConverter.GetBytes((int)TxStatus.Ongoing),
                BitConverter.GetBytes(TxTableEntry.DEFAULT_COMMIT_TIME),
                BitConverter.GetBytes(TxTableEntry.DEFAULT_LOWER_BOUND)
            };

            RedisRequest redisReq = this.NextRedisRequest();

            redisReq.Set(hashId, keysBytes, valuesBytes, RedisRequestType.HMSet);
            redisReq.ParentRequest = req;
        }
        internal override void Visit(ReplaceVersionRequest req)
        {
            string sha1   = this.redisLuaManager.GetLuaScriptSha1(LuaScriptName.REPLACE_VERSION_ENTRY);
            string hashId = req.RecordKey.ToString();

            if (this.redisVersionDbMode == RedisVersionDbMode.Cluster)
            {
                hashId = RedisVersionDb.PACK_KEY(RedisVersionDb.VER_KEY_PREFIX, hashId);
            }

            byte[][] keysAndArgs =
            {
                Encoding.ASCII.GetBytes(hashId),
                BitConverter.GetBytes(req.VersionKey),
                BitConverter.GetBytes(req.BeginTs),
                BitConverter.GetBytes(req.EndTs),
                BitConverter.GetBytes(req.TxId),
                BitConverter.GetBytes(req.SenderId),
                BitConverter.GetBytes(req.ExpectedEndTs),
                RedisVersionDb.NEGATIVE_ONE_BYTES,
            };

            RedisRequest redisReq = this.NextRedisRequest();

            redisReq.Set(keysAndArgs, sha1, 1, RedisRequestType.EvalSha);
            redisReq.ParentRequest = req;
        }
예제 #3
0
        internal override void AddPartition(int partitionCount)
        {
            int prePartitionCount = this.PartitionCount;

            RedisConnectionPool clientPool = null;

            if (this.redisVersionDbMode == RedisVersionDbMode.Cluster)
            {
                clientPool = this.singletonConnPool;
            }

            Array.Resize(ref this.tableVisitors, partitionCount);
            Array.Resize(ref this.requestQueues, partitionCount);
            Array.Resize(ref this.flushQueues, partitionCount);
            Array.Resize(ref this.queueLatches, partitionCount);

            for (int pk = prePartitionCount; pk < partitionCount; pk++)
            {
                if (clientPool == null)
                {
                    clientPool = this.RedisManager.GetClientPool(
                        this.redisDbIndex, RedisVersionDb.GetRedisInstanceIndex(pk));
                }
                this.tableVisitors[pk] = new RedisVersionTableVisitor(
                    clientPool, this.LuaManager, this.responseVisitor, this.redisVersionDbMode);

                this.requestQueues[pk] = new Queue <VersionEntryRequest>(VersionDb.REQUEST_QUEUE_CAPACITY);
                this.flushQueues[pk]   = new Queue <VersionEntryRequest>(VersionDb.REQUEST_QUEUE_CAPACITY);
                this.queueLatches[pk]  = 0;
            }

            base.AddPartition(partitionCount);
        }
예제 #4
0
 public static RedisVersionDb Instance(
     int partitionCount      = 1,
     string[] readWriteHosts = null,
     RedisVersionDbMode mode = RedisVersionDbMode.Cluster)
 {
     if (RedisVersionDb.instance == null)
     {
         lock (RedisVersionDb.initLock)
         {
             if (RedisVersionDb.instance == null)
             {
                 if (readWriteHosts == null || readWriteHosts.Length == 0)
                 {
                     RedisVersionDb.instance = new RedisVersionDb(
                         1, new string[] { RedisVersionDb.DEFAULT_REDIS_HOST });
                 }
                 else
                 {
                     RedisVersionDb.instance = new RedisVersionDb(partitionCount, readWriteHosts, mode);
                 }
             }
         }
     }
     return(RedisVersionDb.instance);
 }
        private string GetHashKey(VersionEntryRequest request)
        {
            string hashId = request.RecordKey.ToString();

            return(redisVersionDbMode == RedisVersionDbMode.Cluster
                ? RedisVersionDb.PACK_KEY(RedisVersionDb.VER_KEY_PREFIX, hashId)
                : hashId);
        }
예제 #6
0
        internal override void Clear()
        {
            if (this.redisVersionDbMode == RedisVersionDbMode.Cluster)
            {
                // IMPORTMENT: Since the Redis Cluster doesn't allow multi-key commands across multiple hash slots
                // So we couldn't clear keys in batch
                //using (RedisClient redisClient = this.singletonConnPool.GetRedisClient())
                //{
                //    byte[][] keysAndArgs =
                //    {
                //        Encoding.ASCII.GetBytes(RedisVersionDb.VER_KEY_PREFIX),
                //    };
                //    string sha1 = this.LuaManager.GetLuaScriptSha1(LuaScriptName.REMOVE_KEYS_WITH_PREFIX);
                //    redisClient.EvalSha(sha1, 0, keysAndArgs);
                //}

                int batchSize = 100;
                using (RedisClient redisClient = this.singletonConnPool.GetRedisClient())
                {
                    byte[][] keys = redisClient.Keys(RedisVersionDb.VER_KEY_PREFIX + "*");
                    if (keys != null)
                    {
                        for (int i = 0; i < keys.Length; i += batchSize)
                        {
                            int upperBound = Math.Min(keys.Length, i + batchSize);
                            using (IRedisPipeline pipe = redisClient.CreatePipeline())
                            {
                                for (int j = i; j < upperBound; j++)
                                {
                                    string keyStr = Encoding.ASCII.GetString(keys[j]);
                                    pipe.QueueCommand(r => ((RedisNativeClient)r).Del(keyStr));
                                }
                                pipe.Flush();
                            }
                        }
                    }
                }
            }
            else
            {
                for (int pid = 0; pid < this.PartitionCount; pid++)
                {
                    using (RedisClient redisClient = this.RedisManager.GetClient(
                               this.redisDbIndex, RedisVersionDb.GetRedisInstanceIndex(pid)))
                    {
                        redisClient.FlushDb();
                    }
                }
            }
        }
        internal override void Visit(ReadVersionRequest req)
        {
            string hashId = req.RecordKey.ToString();

            if (this.redisVersionDbMode == RedisVersionDbMode.Cluster)
            {
                hashId = RedisVersionDb.PACK_KEY(RedisVersionDb.VER_KEY_PREFIX, hashId);
            }

            byte[] keyBytes = BitConverter.GetBytes(req.VersionKey);

            RedisRequest redisReq = this.NextRedisRequest();

            redisReq.Set(hashId, keyBytes, RedisRequestType.HGet);
            redisReq.ParentRequest = req;
        }
예제 #8
0
        internal override void Visit(UpdateTxStatusRequest req)
        {
            string hashId = req.TxId.ToString();

            if (this.redisVersionDbMode == RedisVersionDbMode.Cluster)
            {
                hashId = RedisVersionDb.PACK_KEY(RedisVersionDb.TX_KEY_PREFIX, hashId);
            }

            byte[] keyBytes   = Encoding.ASCII.GetBytes(TxTableEntry.STATUS_STRING);
            byte[] valueBytes = BitConverter.GetBytes((int)req.TxStatus);

            RedisRequest redisReq = this.NextRedisRequest();

            redisReq.Set(hashId, keyBytes, valueBytes, RedisRequestType.HSet);
            redisReq.ParentRequest = req;
        }
예제 #9
0
        private RedisVersionDb(int partitionCount, string[] readWriteHosts, RedisVersionDbMode mode = RedisVersionDbMode.Cluster)
            : base(partitionCount)
        {
            this.PartitionCount = partitionCount;

            if (readWriteHosts == null)
            {
                throw new ArgumentException("readWriteHosts must be a null array");
            }
            this.readWriteHosts = readWriteHosts;
            this.Mode           = mode;

            this.tableLock       = new object();
            this.responseVisitor = new RedisResponseVisitor();

            this.Setup();

            this.txEntryRequestQueues = new Queue <TxEntryRequest> [partitionCount];
            this.flushQueues          = new Queue <TxEntryRequest> [partitionCount];
            this.queueLatches         = new int[partitionCount];

            for (int pid = 0; pid < this.PartitionCount; pid++)
            {
                RedisConnectionPool clientPool = null;
                if (this.Mode == RedisVersionDbMode.Cluster)
                {
                    clientPool = SingletonConnPool;
                }
                else
                {
                    clientPool = this.RedisManager.GetClientPool(
                        RedisVersionDb.TX_DB_INDEX, RedisVersionDb.GetRedisInstanceIndex(pid));
                }
                this.dbVisitors[pid] = new RedisVersionDbVisitor(
                    clientPool, this.RedisLuaManager, this.responseVisitor, this.Mode);

                this.txEntryRequestQueues[pid] = new Queue <TxEntryRequest>(VersionDb.REQUEST_QUEUE_CAPACITY);
                this.flushQueues[pid]          = new Queue <TxEntryRequest>(VersionDb.REQUEST_QUEUE_CAPACITY);
                this.queueLatches[pid]         = 0;
            }
        }
예제 #10
0
        internal override void Visit(GetTxEntryRequest req)
        {
            string hashId = req.TxId.ToString();

            if (this.redisVersionDbMode == RedisVersionDbMode.Cluster)
            {
                hashId = RedisVersionDb.PACK_KEY(RedisVersionDb.TX_KEY_PREFIX, hashId);
            }

            byte[][] keyBytes =
            {
                Encoding.ASCII.GetBytes(TxTableEntry.STATUS_STRING),
                Encoding.ASCII.GetBytes(TxTableEntry.COMMIT_TIME_STRING),
                Encoding.ASCII.GetBytes(TxTableEntry.COMMIT_LOWER_BOUND_STRING)
            };

            RedisRequest redisReq = this.NextRedisRequest();

            redisReq.Set(hashId, keyBytes, RedisRequestType.HMGet);
            redisReq.ParentRequest = req;
        }
예제 #11
0
        internal override void Visit(SetCommitTsRequest req)
        {
            string hashId = req.TxId.ToString();

            if (this.redisVersionDbMode == RedisVersionDbMode.Cluster)
            {
                hashId = RedisVersionDb.PACK_KEY(RedisVersionDb.TX_KEY_PREFIX, hashId);
            }

            string sha1 = this.redisLuaScriptManager.GetLuaScriptSha1(LuaScriptName.SET_AND_GET_COMMIT_TIME);

            byte[][] keys =
            {
                Encoding.ASCII.GetBytes(hashId),
                BitConverter.GetBytes(req.ProposedCommitTs),
                RedisVersionDb.NEGATIVE_ONE_BYTES,
            };

            RedisRequest redisReq = this.NextRedisRequest();

            redisReq.Set(keys, sha1, 1, RedisRequestType.EvalSha);
            redisReq.ParentRequest = req;
        }
        internal override void Visit(UpdateVersionMaxCommitTsRequest req)
        {
            string sha1   = this.redisLuaManager.GetLuaScriptSha1(LuaScriptName.UPDATE_VERSION_MAX_COMMIT_TS);
            string hashId = req.RecordKey.ToString();

            if (this.redisVersionDbMode == RedisVersionDbMode.Cluster)
            {
                hashId = RedisVersionDb.PACK_KEY(RedisVersionDb.VER_KEY_PREFIX, hashId);
            }

            byte[][] keysAndArgs =
            {
                Encoding.ASCII.GetBytes(hashId),
                BitConverter.GetBytes(req.VersionKey),
                BitConverter.GetBytes(req.MaxCommitTs),
                RedisVersionDb.NEGATIVE_ONE_BYTES,
            };

            RedisRequest redisReq = this.NextRedisRequest();

            redisReq.Set(keysAndArgs, sha1, 1, RedisRequestType.EvalSha);
            redisReq.ParentRequest = req;
        }
예제 #13
0
        internal override void Visit(UpdateCommitLowerBoundRequest req)
        {
            string hashId = req.TxId.ToString();

            if (this.redisVersionDbMode == RedisVersionDbMode.Cluster)
            {
                hashId = RedisVersionDb.PACK_KEY(RedisVersionDb.TX_KEY_PREFIX, hashId);
            }

            string sha1 = this.redisLuaScriptManager.GetLuaScriptSha1(LuaScriptName.UPDATE_COMMIT_LOWER_BOUND);

            byte[][] keys =
            {
                Encoding.ASCII.GetBytes(hashId),
                BitConverter.GetBytes(req.CommitTsLowerBound),
                RedisVersionDb.NEGATIVE_ONE_BYTES,
                RedisVersionDb.NEGATIVE_TWO_BYTES,
            };

            RedisRequest redisReq = this.NextRedisRequest();

            redisReq.Set(keys, sha1, 1, RedisRequestType.EvalSha);
            redisReq.ParentRequest = req;
        }
예제 #14
0
        public RedisVersionTable(VersionDb versionDb, string tableId, long redisDbIndex)
            : base(versionDb, tableId, versionDb.PartitionCount)
        {
            this.redisDbIndex       = redisDbIndex;
            this.responseVisitor    = new RedisResponseVisitor();
            this.redisVersionDb     = ((RedisVersionDb)this.VersionDb);
            this.RedisManager       = redisVersionDb.RedisManager;
            this.LuaManager         = redisVersionDb.RedisLuaManager;
            this.singletonConnPool  = redisVersionDb.SingletonConnPool;
            this.redisVersionDbMode = redisVersionDb.Mode;

            this.requestQueues = new Queue <VersionEntryRequest> [this.PartitionCount];
            this.flushQueues   = new Queue <VersionEntryRequest> [this.PartitionCount];
            this.queueLatches  = new int[this.PartitionCount];

            RedisConnectionPool clientPool = null;

            for (int pid = 0; pid < this.PartitionCount; pid++)
            {
                if (this.redisVersionDbMode == RedisVersionDbMode.Cluster)
                {
                    clientPool = this.singletonConnPool;
                }
                else
                {
                    clientPool = this.RedisManager.GetClientPool(
                        this.redisDbIndex, RedisVersionDb.GetRedisInstanceIndex(pid));
                }
                this.tableVisitors[pid] = new RedisVersionTableVisitor(
                    clientPool, this.LuaManager, this.responseVisitor, this.redisVersionDbMode);

                this.requestQueues[pid] = new Queue <VersionEntryRequest>(VersionDb.REQUEST_QUEUE_CAPACITY);
                this.flushQueues[pid]   = new Queue <VersionEntryRequest>(VersionDb.REQUEST_QUEUE_CAPACITY);
                this.queueLatches[pid]  = 0;
            }
        }
예제 #15
0
        /// <summary>
        /// Reshuffle records in the version db, which will recalculate the partition of record keys,
        /// and put them to right partitions under the new number of partition
        /// </summary>
        /// <param name="perPartitionCount">The number of partitions before adding partitions</param>
        /// <param name="partitionCount">The current number of partitions</param>
        private void ReshuffleRecords(int prePartitionCount, int partitionCount)
        {
            List <Tuple <byte[], byte[][]> >[] reshuffledRecords = new List <Tuple <byte[], byte[][]> > [partitionCount];
            for (int npk = 0; npk < partitionCount; npk++)
            {
                reshuffledRecords[npk] = new List <Tuple <byte[], byte[][]> >();
            }

            RedisConnectionPool connPool = null;

            if (this.redisVersionDbMode == RedisVersionDbMode.Cluster)
            {
                connPool = this.singletonConnPool;
            }

            for (int pk = 0; pk < prePartitionCount; pk++)
            {
                if (connPool == null)
                {
                    connPool = this.RedisManager.GetClientPool(this.redisDbIndex, RedisVersionDb.GetRedisInstanceIndex(pk));
                }
                using (RedisClient redisClient = connPool.GetRedisClient())
                {
                    byte[][] keys = redisClient.Keys("*");
                    foreach (byte[] key in keys)
                    {
                        byte[][] values = redisClient.HGetAll(Encoding.ASCII.GetString(key));

                        string recordKey = Encoding.ASCII.GetString(key);
                        // TODO: Only For Benchmark Test as the recordKey is an integer
                        int intRecordKey = int.Parse(recordKey);

                        int npk = this.VersionDb.PhysicalPartitionByKey(intRecordKey);
                        reshuffledRecords[npk].Add(Tuple.Create(key, values));
                    }

                    redisClient.FlushDb();
                }
            }

            // flush the redis db
            for (int pk = 0; pk < partitionCount; pk++)
            {
                using (RedisClient redisClient = this.RedisManager.GetClient(
                           this.redisDbIndex, RedisVersionDb.GetRedisInstanceIndex(pk)))
                {
                    redisClient.FlushDb();
                }
            }
            Console.WriteLine("Reshuffled Records into Memory");

            for (int pk = 0; pk < partitionCount; pk++)
            {
                Console.WriteLine("Reshuffled Partition {0}", pk);
                List <Tuple <byte[], byte[][]> > records = reshuffledRecords[pk];
                using (RedisClient redisClient = this.RedisManager.GetClient(
                           this.redisDbIndex, RedisVersionDb.GetRedisInstanceIndex(pk)))
                {
                    foreach (Tuple <byte[], byte[][]> versions in records)
                    {
                        string   hashId = Encoding.ASCII.GetString(versions.Item1);
                        byte[][] keys   = new byte[versions.Item2.Length / 2][];
                        byte[][] values = new byte[versions.Item2.Length / 2][];

                        for (int i = 0; 2 * i < versions.Item2.Length; i++)
                        {
                            keys[i]   = versions.Item2[2 * i];
                            values[i] = versions.Item2[2 * i + 1];
                        }

                        redisClient.HMSet(hashId, keys, values);
                    }
                }
            }
        }
예제 #16
0
        internal override void MockLoadData(int recordCount)
        {
            int pk = 0;
            RedisConnectionPool connPool = null;

            if (this.redisVersionDbMode == RedisVersionDbMode.Cluster)
            {
                connPool = this.singletonConnPool;
            }

            int loaded = 0;

            while (pk < this.PartitionCount)
            {
                Console.WriteLine("Loading Partition {0}", pk);
                if (connPool == null)
                {
                    connPool = this.RedisManager.GetClientPool(this.redisDbIndex, RedisVersionDb.GetRedisInstanceIndex(pk));
                }

                using (RedisClient redisClient = connPool.GetRedisClient())
                {
                    int batchSize  = 100;
                    int partitions = this.PartitionCount;

                    for (int i = pk; i < recordCount; i += partitions * batchSize)
                    {
                        int upperBound = Math.Min(recordCount, i + partitions * batchSize);
                        using (IRedisPipeline pipe = redisClient.CreatePipeline())
                        {
                            for (int j = i; j < upperBound; j += partitions)
                            {
                                object recordKey = j;
                                string hashId    = recordKey.ToString();
                                if (this.redisVersionDbMode == RedisVersionDbMode.Cluster)
                                {
                                    hashId = RedisVersionDb.PACK_KEY(RedisVersionDb.VER_KEY_PREFIX, hashId);
                                }

                                VersionEntry versionEntry = new VersionEntry();
                                VersionEntry.InitFirstVersionEntry(new String('a', 100), versionEntry);

                                byte[] key   = BitConverter.GetBytes(VersionEntry.VERSION_KEY_START_INDEX + 1);
                                byte[] value = VersionEntry.Serialize(versionEntry);

                                pipe.QueueCommand(r => ((RedisNativeClient)r).HSet(hashId, key, value));
                                pipe.QueueCommand(r => ((RedisNativeClient)r).HSet(hashId, RedisVersionDb.LATEST_VERSION_PTR_FIELD, key));

                                loaded++;
                            }
                            pipe.Flush();
                        }
                    }
                }
                pk++;

                if (this.redisVersionDbMode != RedisVersionDbMode.Cluster)
                {
                    connPool = null;
                }
            }

            Console.WriteLine("Loaded {0} records Successfully", loaded);
        }