Beispiel #1
0
        private static PrepareWriteResult ParsePrepareResult(INativeData data)
        {
            PrepareWriteResult res = new PrepareWriteResult();

            unsafe
            {
                byte * dataPtr        = (byte *)data.DataPtr.ToPointer();
                ulong *raftGroupIdPtr = (ulong *)dataPtr;
                res.ChunkRaftGroupId = *raftGroupIdPtr;
                Guid *pathIdPtr = (Guid *)(dataPtr + 8);
                res.ParentPathId = *pathIdPtr;
            }
            return(res);
        }
Beispiel #2
0
        public static async ValueTask UploadAsync(byte appId, Stream stream, string toPath)
        {
            //TODO:判断长度超过限制
            if (!toPath.StartsWith('/'))
            {
                throw new ArgumentException("Path must start with '/'", nameof(toPath));
            }
            if (string.IsNullOrEmpty(Path.GetFileName(toPath)))
            {
                throw new ArgumentException("Path must has file name", nameof(toPath));
            }

            var needSize = (uint)stream.Length;

            //1. 先生成写事务标识
            Guid txnId = GenWriteTxnId();

            //2. 提议至BlobMetaRaftGroup准备写
            var res = await PrepareWriteAsync(appId, txnId, toPath, needSize);

            if (res == null)
            {
                throw new Exception("准备写结果为空");
            }

            PrepareWriteResult result = ParsePrepareResult(res);

            res.Dispose();
            if (result.ChunkRaftGroupId == 0) //上级目录没有可用的Chunk,则提议创建新的
            {
                res = await TryCreateChunkAsync(appId, Path.GetDirectoryName(toPath), needSize);

                result = ParsePrepareResult(res);
                res.Dispose();
            }

            //Log.Debug($"ChunkRaftGroupId = {result.ChunkRaftGroupId}  8864812498945");

            //3. 循环写入块,最后一块带结束标记(引擎计算新旧文件大小差异)
            //TODO:优化内存复制
            string fileName = Path.GetFileName(toPath);

            byte[] fileNameData = System.Text.Encoding.UTF8.GetBytes(fileName);
            int    pathSize     = 32 + fileNameData.Length;
            IntPtr pathPtr      = Marshal.AllocHGlobal(pathSize);

            unsafe
            {
                var idPtr = (Guid *)pathPtr.ToPointer();
                idPtr[0] = result.ParentPathId;
                idPtr[1] = txnId;

                var namePtr = pathPtr + 32;
                Marshal.Copy(fileNameData, 0, namePtr, fileNameData.Length);
            }

            var    buffer    = new byte[SegmentSize];
            int    bytesRead = 0;
            int    totalRead = 0;
            uint   option    = 0;
            IntPtr nativeDataPtr;

            do
            {
                bytesRead = stream.Read(buffer);
                if (bytesRead <= 0)
                {
                    break;
                }
                totalRead += bytesRead;
                if (totalRead >= stream.Length)
                {
                    option = 2;
                }
                unsafe
                {
                    nativeDataPtr = NativeApi.NewNativeString(bytesRead, out byte *dataPtr);
                    Marshal.Copy(buffer, 0, new IntPtr(dataPtr), bytesRead);
                }
                await StoreApi.Api.BlobWriteChunkAsync(result.ChunkRaftGroupId, pathPtr, (uint)pathSize, option, nativeDataPtr);

                if (option == 2)
                {
                    break;
                }
                option = 1;
            } while (true);

            //释放分配的pathPtr
            buffer = null;
            Marshal.FreeHGlobal(pathPtr);
        }