private async Task <bool> TraverseTree(string root, int maxTasks)
        {
            string currentDir = root;

            using (var throttler = new SemaphoreSlim(maxTasks))
            {
                var postTaskTasks = new List <PFTask>();

                while (currentDir != null)
                {
                    if (currentDir == root)
                    {
                        // First time get the directories syncroniously to populate the DB with directories to run on
                        IEnumerable <string> directories = Directory.EnumerateDirectories(currentDir);
                        List <string>        lst         = new List <string>();

                        foreach (string dir in directories)
                        {
                            try
                            {
                                DirectoryInfo di = new DirectoryInfo(dir);
                                lst.Add(di.FullName);
                                Log.Trace("Added folder: " + di.FullName + ", Thread Id: " + Thread.CurrentThread.ManagedThreadId);
                            }
                            catch (Exception ex)
                            {
                                Log.Info(ex, "User doesn't have permissions to folder: " + dir);
                            }
                        }
                        //await SMBDal.BulkAddFolders(directories.ToList());
                        await SMBDal.BulkAddFolders(lst);
                    }
                    else
                    {
                        Log.Trace("Before wait: " + currentDir + ", wait: " + throttler.CurrentCount + ", Thread Id: " + Thread.CurrentThread.ManagedThreadId);
                        await throttler.WaitAsync();

                        Log.Trace("After wait: " + currentDir + ", wait: " + throttler.CurrentCount + ", Thread Id: " + Thread.CurrentThread.ManagedThreadId);
                        string value = currentDir.ToString();
                        PFTask t     = new PFTask();
                        t.Task = Task.Run(() => ProcessDir(value), t.CancellationToken).ContinueWith(tsk => release(throttler));
                        postTaskTasks.Add(t);
                        Log.Trace("After add task: " + currentDir + ", Thread Id: " + Thread.CurrentThread.ManagedThreadId);
                    }

                    // Fetch the next directory to traverse and do it again
                    currentDir = await SMBIterator.GetNextFolderForTraverse();

                    Log.Trace("GetNextFolderForTraverse returned: " + currentDir + ", Thread Id: " + Thread.CurrentThread.ManagedThreadId);

                    // Clean the completed tasks from the array
                    foreach (PFTask t in postTaskTasks)
                    {
                        if (t.Task.IsCompleted || t.Task.IsCanceled || t.Task.IsFaulted)
                        {
                            _tasksToRemove.Add(t);
                        }
                    }
                    foreach (PFTask t in _tasksToRemove)
                    {
                        postTaskTasks.Remove(t);
                    }
                    _tasksToRemove = new List <PFTask>();

                    if (currentDir == null)
                    {
                        Log.Trace("WaitAll" + ", Thread Id: " + Thread.CurrentThread.ManagedThreadId);
                        Task.WaitAll(postTaskTasks.Select(t => t.Task).ToArray());
                        currentDir = await SMBIterator.GetNextFolderForTraverse();

                        Log.Trace("Got directory after wait all: " + currentDir + ", Thread Id: " + Thread.CurrentThread.ManagedThreadId);
                    }
                }
            }

            return(true);
        }
        public async Task <ScanResult> ScanNext(Repository repo)
        {
            IteratorItem item = await SMBIterator.NextItemAsync();

            return(await ScanNext(repo, item));
        }
        public async Task <bool> Scan(Repository repo)
        {
            bool   scanDone      = false;
            var    postTaskTasks = new List <PFTask>();
            object SpinLock      = new object();

            PrepCredentials(repo);
            using (var throttler = new SemaphoreSlim(_maxFilesScanCocur))
            {
                // Scan files
                while (!scanDone)
                {
                    bool semValue = await throttler.WaitAsync(_taskTimeout);

                    if (!semValue)
                    {
                        // See what tasks are hanging for more than 30 seconds and kill them
                        foreach (PFTask t in postTaskTasks)
                        {
                            if (t.StartTime.Subtract(DateTime.UtcNow).Seconds > _taskTimeout)
                            {
                                t.TokenSource.Cancel();
                            }
                        }
                    }

                    IteratorItem item = null;
                    lock (SpinLock)
                    {
                        // Get next item for iteration
                        item = SMBIterator.NextItem();
                    }

                    if (item != null)
                    {
                        // process the next item
                        PFTask tsk = new PFTask();
                        tsk.Task = Task.Run <ScanResult>(() => ScanNext(repo, item), tsk.CancellationToken).ContinueWith(t => release(throttler));
                        postTaskTasks.Add(tsk);
                    }
                    else
                    {
                        scanDone = true;
                    }

                    // Clean the completed tasks from the wait array
                    foreach (PFTask t in postTaskTasks)
                    {
                        if (t.Task.IsCompleted || t.Task.IsCanceled || t.Task.IsFaulted)
                        {
                            _tasksToRemove.Add(t);
                        }
                    }
                    foreach (PFTask t in _tasksToRemove)
                    {
                        postTaskTasks.Remove(t);
                        t.Task.Dispose();
                    }
                    _tasksToRemove = new List <PFTask>();

                    if (scanDone)
                    {
                        // Wait for all the tasks to finish before exiting
                        Task.WaitAll(postTaskTasks.Select(i => i.Task).ToArray(), 30000);
                    }
                }
            }
            Counter.PrintAll();
            return(true);
        }