Inheritance: System.ApplicationException
        // actual get object requests with concurrency control
        private void GetObject(string crc64ecma)
        {
            lock (syncExit)
            {
                if (isExit)
                {
                    return;
                }
            }
            // create dir if not exist
            DirectoryInfo dirInfo = new DirectoryInfo(localDir);

            if (!dirInfo.Exists)
            {
                dirInfo.Create();
            }
            // concurrency control
            AutoResetEvent resetEvent = new AutoResetEvent(false);
            int            retries    = 0;
            // return last response
            GetObjectResult downloadResult = null;

            if (sliceToRemove == null)
            {
                sliceToRemove = new HashSet <int>();
            }
            while (sliceList.Count != 0 && retries < maxRetries)
            {
                retries += 1;
                foreach (int partNumber in sliceList.Keys)
                {
                    if (sliceToRemove.Contains(partNumber))
                    {
                        continue;
                    }
                    DownloadSliceStruct slice;
                    bool get_state = sliceList.TryGetValue(partNumber, out slice);
                    if (activeTasks >= maxTasks)
                    {
                        resetEvent.WaitOne();
                    }
                    lock (syncExit)
                    {
                        if (isExit)
                        {
                            return;
                        }
                    }
                    string tmpFileName = "." + localFileName + ".cosresumable." + slice.partNumber;
                    // clear remainance
                    FileInfo tmpFileInfo = new FileInfo(localDir + tmpFileName);
                    if (tmpFileInfo.Exists &&
                        tmpFileInfo.Length != (slice.sliceEnd - slice.sliceStart + 1) &&
                        localFileOffset != 0)
                    {
                        System.IO.File.Delete(localDir + tmpFileName);
                    }
                    getObjectRequest = new GetObjectRequest(bucket, key, localDir, tmpFileName);
                    tmpFilePaths.Add(localDir + tmpFileName);
                    getObjectRequest.SetRange(slice.sliceStart, slice.sliceEnd);
                    if (progressCallback != null && this.sliceList.Count == 1)
                    {
                        getObjectRequest.SetCosProgressCallback(delegate(long completed, long total)
                        {
                            progressCallback(completed, total);
                        }
                                                                );
                    }
                    Interlocked.Increment(ref activeTasks);
                    cosXmlServer.GetObject(getObjectRequest,
                                           delegate(CosResult result)
                    {
                        Interlocked.Decrement(ref activeTasks);
                        lock (syncExit)
                        {
                            if (isExit)
                            {
                                return;
                            }
                        }
                        sliceToRemove.Add(partNumber);
                        if (progressCallback != null && this.sliceList.Count > 1)
                        {
                            long completed = sliceToRemove.Count * this.sliceSize;
                            long total     = rangeEnd - rangeStart;
                            if (completed > total)
                            {
                                completed = total;
                            }
                            progressCallback(completed, total);
                        }
                        downloadResult = result as GetObjectResult;
                        resetEvent.Set();
                        if (resumable)
                        {
                            // flush done parts
                            this.resumableInfo.slicesDownloaded.Add(slice);
                            this.resumableInfo.Persist(resumableTaskFile);
                        }
                    },
                                           delegate(CosClientException clientEx, CosServerException serverEx)
                    {
                        Interlocked.Decrement(ref activeTasks);
                        lock (syncExit)
                        {
                            if (isExit)
                            {
                                return;
                            }
                        }
                        // server 4xx throw and stop
                        if (serverEx != null && serverEx.statusCode < 500)
                        {
                            throw serverEx;
                            if (failCallback != null)
                            {
                                failCallback(null, serverEx);
                            }
                            return;
                        }
                        // client cannot connect, just retry
                        if (clientEx != null)
                        {
                            gClientExp = clientEx;
                        }
                        resetEvent.Set();
                    }
                                           );
                }
                while (activeTasks != 0)
                {
                    Thread.Sleep(100);
                }
                // remove success parts
                foreach (int partNumber in sliceToRemove)
                {
                    sliceList.Remove(partNumber);
                }
            }
            if (this.sliceList.Count != 0)
            {
                if (gClientExp != null)
                {
                    throw gClientExp;
                }
                COSXML.CosException.CosClientException clientEx = new COSXML.CosException.CosClientException
                                                                      ((int)CosClientError.InternalError, "max retries " + retries + " excceed, download fail");
                throw clientEx;
                if (UpdateTaskState(TaskState.Failed))
                {
                    if (failCallback != null)
                    {
                        failCallback(clientEx, null);
                    }
                }
                return;
            }
            // file merge
            FileMode fileMode      = FileMode.OpenOrCreate;
            FileInfo localFileInfo = new FileInfo(localDir + localFileName);

            if (localFileInfo.Exists && localFileOffset == 0 && localFileInfo.Length != rangeEnd - rangeStart + 1)
            {
                fileMode = FileMode.Truncate;
            }
            using (var outputStream = File.Open(localDir + localFileName, fileMode))
            {
                outputStream.Seek(localFileOffset, 0);
                // sort
                List <string> tmpFileList = new List <string>(this.tmpFilePaths);
                tmpFileList.Sort(delegate(string x, string y){
                    int partNumber1 = int.Parse(x.Split(new string[] { "cosresumable." }, StringSplitOptions.None)[1]);
                    int partNumber2 = int.Parse(y.Split(new string[] { "cosresumable." }, StringSplitOptions.None)[1]);
                    return(partNumber1 - partNumber2);
                });
                foreach (var inputFilePath in tmpFileList)
                {
                    // tmp not exist, clear everything and ask for retry
                    if (!File.Exists(inputFilePath))
                    {
                        // check if download already completed
                        if (File.Exists(localDir + localFileName))
                        {
                            FileInfo fileInfo = new FileInfo(localDir + localFileName);
                            if (fileInfo.Length == rangeEnd - rangeStart + 1)
                            {
                                foreach (var tmpFile in tmpFileList)
                                {
                                    System.IO.File.Delete(tmpFile);
                                }
                                if (resumableTaskFile != null)
                                {
                                    System.IO.File.Delete(resumableTaskFile);
                                }
                                break;
                            }
                        }
                        // not completed, report fatal error
                        foreach (var tmpFile in tmpFileList)
                        {
                            System.IO.File.Delete(tmpFile);
                        }
                        if (resumableTaskFile != null)
                        {
                            System.IO.File.Delete(resumableTaskFile);
                        }
                        if (File.Exists(localDir + localFileName))
                        {
                            System.IO.File.Delete(localDir + localFileName);
                        }
                        COSXML.CosException.CosClientException clientEx = new COSXML.CosException.CosClientException
                                                                              ((int)CosClientError.InternalError, "local tmp file not exist, could be concurrent writing same file"
                                                                              + inputFilePath + " download again");
                        throw clientEx;
                        if (failCallback != null)
                        {
                            failCallback(clientEx, null);
                        }
                        break;
                    }
                    using (var inputStream = File.OpenRead(inputFilePath))
                    {
                        FileInfo info = new FileInfo(inputFilePath);
                        inputStream.CopyTo(outputStream);
                    }
                }
                tmpFileList.Clear();
                tmpFilePaths.Clear();
                if (UpdateTaskState(TaskState.Completed))
                {
                    var dir = new DirectoryInfo(localDir);
                    foreach (var file in dir.EnumerateFiles("." + localFileName + ".cosresumable.*"))
                    {
                        file.Delete();
                    }
                    if (resumableTaskFile != null)
                    {
                        FileInfo info = new FileInfo(resumableTaskFile);
                        if (info.Exists)
                        {
                            info.Delete();
                        }
                    }
                    DownloadTaskResult downloadTaskResult = new DownloadTaskResult();
                    downloadTaskResult.SetResult(downloadResult);
                    outputStream.Close();
                    if (successCallback != null)
                    {
                        successCallback(downloadTaskResult);
                    }
                    return;
                }
                else
                {
                    // 容灾 return
                    DownloadTaskResult downloadTaskResult = new DownloadTaskResult();
                    downloadTaskResult.SetResult(downloadResult);
                    outputStream.Close();
                    if (successCallback != null)
                    {
                        successCallback(downloadTaskResult);
                    }
                }
            }
            return;
        }