// throws InvalidOperationException public void UpWrite() { lock (lockObj) { //se n tiver sido invocado por uma thread que invocou o DownWrite //lança excepção if (writerInside != Thread.CurrentThread.ManagedThreadId) { throw new InvalidOperationException(); } //Nenhum escritor a escrever isWriting = false; //Se houver leitores/escritores à espera if (rwq.Count > 0) { //Se houver leitores à espera if (rwq.First.Value.rw == READER) { //Notificar todos os leitores que estão no inicio da fila, antes de uma escrita NotifyAllReaders(); } //Se houver escritores à espera else { //Notifica o primeiro escritor da lista SyncUtils.Notify(lockObj, rwq.First); } } } }
public SoundcloudSync(SyncUtils syncUtil, bool mergePlaylists) { MergePlaylists = mergePlaylists; _syncUtil = syncUtil; JsonUtil = new JsonUtils(_syncUtil.ManifestUtil, _syncUtil.DownloadUtil.ClientIDsUtil.ClientIdCurrentValue); _syncUtil.ManifestUtil.ProgressUtil.ResetProgress(); }
public bool Enter() { // ainda há espaço if (!IsRegionFull()) { if (maxInside > 0) { this.maxInside--; return(true); // a entrada foi feita com sucesso } } /* não há espaço, vou ver se posso ficar em espera na waitingQueue * não podem estar mais do que maxWaiting threads à espera de entrar na * zona protegida pela mesma chave */ if (IsWaitingQueueFull()) { return(false); } else { LinkedListNode <bool> node = waitingQueue.AddLast(false); int timeout = waitTimeout; int lastTime = (timeout != Timeout.Infinite) ? Environment.TickCount : 0; do { try { Monitor.Wait(myLock, timeout); } // interrompido o bloqueio da thread catch (ThreadInterruptedException e) { waitingQueue.Remove(node); throw; } // verificar se já fui sinalizado if (node.Value) { waitingQueue.Remove(node); if (maxInside > 0) { this.maxInside--; return(true); } } /* verificar se ocorreu timeout, uma thread não poderá esperar mais * do que waitTimeout milésimos de segundo para entrar na zona * protegida */ if (SyncUtils.AdjustTimeout(ref lastTime, ref timeout) == 0) { waitingQueue.Remove(node); return(false); } } while (true); } }
//Acedido na posse do lock - lockObj private void NotifyAllReaders() { for (LinkedListNode <Rw> curr = rwq.First; ; curr = curr.Next) { if (curr.Value.rw == WRITER) { return; } SyncUtils.Notify(lockObj, curr); } }
public T Exchange(T mine, int timeout) // throws ThreadInterruptedException { lock (myLock) { if (someoneIsWaiting) { this.mail.secondMessage = mine; this.mail.completed = true; someoneIsWaiting = false; Monitor.PulseAll(myLock); return(this.mail.firstMessage); } if (timeout == 0) { throw new TimeoutException(); } int lastTime = (timeout != Timeout.Infinite) ? Environment.TickCount : 0; mail = new Mail <T>(); mail.firstMessage = mine; mail.secondMessage = default(T); someoneIsWaiting = true; do { try { Monitor.Wait(myLock, timeout); } /* (c) a espera seja interrompida, terminado o método com o lançamento de ThreadInterruptedException. */ catch (ThreadInterruptedException) { if (mail.completed) { return(mail.secondMessage); } else { someoneIsWaiting = false; // vale a pena retiro a minha mensagem? visto q a proxima a entrar vai fazer default throw; } } /* (a) outra thread invoque o método Exchange , devolvendo o método a mensagem oferecida pela outra thread; */ if (mail.completed) { return(mail.secondMessage); } /* (b) expire o limite do tempo de espera especificado, situação em que o método devolve null , ou; */ if (SyncUtils.AdjustTimeout(ref lastTime, ref timeout) == 0) { someoneIsWaiting = false; throw new TimeoutException(); } } while (true); } }
public void TestSync() { var oldItems = new List <Item> { new Item { Id = "1", Title = "Title 1" }, new Item { Id = "2", Title = "Title 2" }, new Item { Id = "3", Title = "Title 3" } }; // item id 1 removed // item 2 updated // item 3 not updated // item 4 added var newItems = new List <Item> { new Item { Id = "2", Title = "Title 2!!!!!!" }, new Item { Id = "3", Title = "Title 3" }, new Item { Id = "4", Title = "Title 4" } }; SyncUtils.Sync(oldItems, newItems); var service = new ItemService(); Assert.IsFalse(service.Has(oldItems, "1")); var item2 = service.Get(oldItems, "2"); Assert.AreEqual("Title 2!!!!!!", item2.Title); var item3 = service.Get(oldItems, "3"); Assert.AreEqual("Title 3", item3.Title); Assert.IsTrue(service.Has(oldItems, "4")); }
public async Task Sync(ExplorerDbContext context) { SyncAdditionalDataCounter++; foreach (var chain in context.Chains) { while (await _phantasmaRpcService.GetBlockHeight.SendRequestAsync(chain.Address) > chain.Height) { if (ContinueSync) { Console.WriteLine($"NEW BLOCK: Chain: {chain.Name}, block: {chain.Height + 1}"); var block = await _phantasmaRpcService.GetBlockByHeight.SendRequestAsync(chain.Address, (int)(chain.Height + 1)); await SyncBlock(context, chain, block); } else { Console.WriteLine("Sync has stopped"); return; } } } //todo find smarter way to do this await UpdateAccountBalances(context, _addressChanged); _addressChanged.Clear(); if (SyncAdditionalDataCounter >= 5) { Console.WriteLine("Sync new chains?"); await SyncChains(context); Console.WriteLine("Sync new apps?"); var appList = await _phantasmaRpcService.GetApplications.SendRequestAsync(); await SyncUtils.SyncApps(context, appList); Console.WriteLine("Sync new tokens?"); var tokenList = await _phantasmaRpcService.GetTokens.SendRequestAsync(); await SyncUtils.SyncToken(context, tokenList); SyncAdditionalDataCounter = 0; } }
public async Task SeedEverythingAsync(ExplorerDbContext context) { try { var sw = new Stopwatch(); sw.Start(); context.Database.EnsureCreated(); _phantasmaRpcService = (IPhantasmaRpcService)Explorer.AppServices.GetService(typeof(IPhantasmaRpcService)); if (!context.Apps.Any()) { var appList = await _phantasmaRpcService.GetApplications.SendRequestAsync(); await SyncUtils.SyncApps(context, appList); } if (!context.Tokens.Any()) { var tokenList = await _phantasmaRpcService.GetTokens.SendRequestAsync(); await SyncUtils.SyncToken(context, tokenList); } if (!context.Chains.Any()) { await SeedChains(context); } if (!context.Blocks.Any()) { await SeedBlocks(context); } sw.Stop(); Console.WriteLine("Elapsed time to initializing db = {0}", sw.Elapsed); } catch (Exception e) { Console.WriteLine(e); Console.WriteLine("Exception occurred during DB initialization, explorer cannot start"); } }
// throws ThreadInterruptedException public void DownWrite() { lock (lockObj) { //Se não houver leitores/escritores à espera e não houver nenhum escritor a escrever e leitores a ler if (rwq.Count == 0 && !isWriting && readersReading == 0) { //Um escritor a escrever isWriting = true; writerInside = Thread.CurrentThread.ManagedThreadId; return; } //Adicionar um novo escritor à lista de espera LinkedListNode <Rw> wr = rwq.AddLast(new Rw(WRITER)); do { try { //Espera SyncUtils.Wait(lockObj, wr); } catch (ThreadInterruptedException) { //Remover da lista de espera rwq.Remove(wr); //Lançar excepção throw; } //Se for o primeiro da lista e não houver ninguém a escrever nem a ler if (rwq.First == wr && !isWriting && readersReading == 0) { //Remover da lista de espera rwq.Remove(wr); //Escritor a escrever isWriting = true; writerInside = Thread.CurrentThread.ManagedThreadId; return; } } while (true); } }
public void Leave(int key) { lock (map) { //Se não existe a key, retorna e não faz nada if (!map.ContainsKey(key)) { return; } //Região associada à key Region r = map[key]; //menos uma thread dentro da região r.inside--; //se houver threads à espera para entrar na região if (r.waiting.Count > 0) { //É notificada a primeira que entrou para cumprir a disciplina FIFO SyncUtils.Notify(map, r.waiting.First); } } }
// throws ThreadInterruptedException public void DownRead() { lock (lockObj){ //Se não houver escritores à espera, nem estiver nenhum escritor a escrever if (!isWriting && rwq.First.Value.rw != WRITER) { //mais um leitor a ler readersReading++; readersInside.AddLast(Thread.CurrentThread.ManagedThreadId); return; } //Adicionar um novo leitor à lista de espera LinkedListNode <Rw> rd = rwq.AddLast(new Rw(READER)); do { try { //Esperar SyncUtils.Wait(lockObj, rd); } catch (ThreadInterruptedException) { //Remover da lista de espera rwq.Remove(rd); //Lançar excepção throw; } //Pode ler se ninguem estiver a escrever e se for o primeiro da lista de espera if (!isWriting && rwq.First == rd) { //Remover da lista de espera rwq.Remove(rd); //Mais um leitor a ler readersReading++; readersInside.AddLast(Thread.CurrentThread.ManagedThreadId); return; } } while (true); } }
// throws InvalidOperationException public void UpRead() { lock (lockObj) { if (!readersInside.Contains(Thread.CurrentThread.ManagedThreadId)) { throw new InvalidOperationException(); } //Menos um leitor a ler readersReading--; readersInside.Remove(Thread.CurrentThread.ManagedThreadId); //Se não esta nenhum leitor a ler e houver escritores à espera //Não pode haver leitores à espera no inicio da fila neste momento!! if (readersReading == 0 && rwq.Count > 0) { //Notifica o primeiro escritor da lista SyncUtils.Notify(lockObj, rwq.First); } } }
private void syncButton_Click(object sender, EventArgs e) { SaveSettingsToConfig(ConfigStateCurrentIndex); _dlMode = playlistRadio.Checked ? EnumUtil.DownloadMode.Playlist : userPlaylists.Checked ? EnumUtil.DownloadMode.UserPlaylists : favoritesRadio.Checked ? EnumUtil.DownloadMode.Favorites : artistRadio.Checked ? EnumUtil.DownloadMode.Artist : EnumUtil.DownloadMode.Track; if (!string.IsNullOrWhiteSpace(url.Text?.ToLower()) && !string.IsNullOrWhiteSpace(directoryPath.Text?.ToLower()) && !IsSyncButtonClicked) { IsSyncButtonClicked = true; syncButton.Tag = "STR_ABORT"; syncButton.Text = LanguageManager.Language[syncButton.Tag.ToString()]; status.Tag = "STR_MAIN_STATUS_CHECK"; status.Text = LanguageManager.Language[status.Tag.ToString()]; progressUtil.Completed = false; progressBar.Value = 0; progressBar.Maximum = 0; progressBar.Minimum = 0; TaskbarManager.Instance.SetProgressState(TaskbarProgressBarState.Normal); Highqualitysong = chk_highquality.Checked; ConvertToMp3 = chk_convertToMp3.Checked; SyncMethod = rbttn_oneWay.Checked ? 1 : 2; FoldersPerArtist = chk_folderByArtist.Checked; ReplaceIllegalCharacters = chk_replaceIllegalCharacters.Checked; ExcludeAac = chk_excl_m4a.Checked; ExcludeM4A = chk_excl_m4a.Checked; CreatePlaylists = chk_CreatePlaylists.Checked; ConcurrentDownloads = (int)nudConcurrency.Value; MergePlaylists = chk_MergePlaylists.Checked; Uri soundCloudUri; try { soundCloudUri = new Uri(url?.Text?.ToLower()); } catch (Exception) { status.Tag = "STR_MAIN_STATUS_INVALIDURL"; status.Text = LanguageManager.Language[status.Tag.ToString()]; progressUtil.Completed = true; InvokeSyncComplete(); return; } var filesystemUtil = new FilesystemUtils(new DirectoryInfo(directoryPath?.Text?.ToLower()), trackRadio.Checked ? FormatForTag : FormatForName, FoldersPerArtist, ReplaceIllegalCharacters); var manifestUtil = new ManifestUtils(progressUtil, filesystemUtil, soundCloudUri, _dlMode, SyncMethod); var playlistUtil = new PlaylistUtils(manifestUtil); DownloadUtils downloadUtil = new DownloadUtils(clientIdUtil, ExcludeM4A, ExcludeAac, ConvertToMp3, manifestUtil, Highqualitysong, ConcurrentDownloads); var syncUtil = new SyncUtils(CreatePlaylists, manifestUtil, downloadUtil, playlistUtil); if (_dlMode != EnumUtil.DownloadMode.Track) { bool differentmanifest; if (!manifestUtil.FindManifestAndBackup(out differentmanifest)) { if (differentmanifest) { status.Tag = "STR_MAIN_STATUS_DIFFMANY"; status.Text = LanguageManager.Language[status.Tag.ToString()]; progressUtil.Completed = true; InvokeSyncComplete(); return; } } } new Thread(() => { // perform progress updates while (!progressUtil.Completed && !progressUtil.Exiting) { Thread.Sleep(500); InvokeUpdateStatus(); this.Invoke((MethodInvoker)(() => lb_progressOfTracks.DataSource = progressUtil.GetTrackProgressValues())); this.Invoke((MethodInvoker)(() => lb_progressOfTracks.Refresh())); InvokeUpdateProgressBar(); } if (!progressUtil.Exiting) { InvokeUpdateStatus(); } }).Start(); new Thread(() => { try { var sync = new SoundcloudSync(syncUtil, MergePlaylists); sync.Synchronize(url?.Text?.ToLower()); } catch (Exception ex) { MessageBox.Show($"{ex.Message} { ExceptionHandlerUtils.GetInnerExceptionMessages(ex)}", LanguageManager.Language["STR_ERR"]); } finally { progressUtil.Completed = true; InvokeSyncComplete(); } }).Start(); } else if (progressUtil.IsActive && IsSyncButtonClicked) { progressUtil.IsActive = false; syncButton.Enabled = false; } else if (!IsSyncButtonClicked && string.IsNullOrWhiteSpace(url.Text)) { status.Tag = "STR_MAIN_STATUS_NULLURL"; status.Text = LanguageManager.Language[status.Tag.ToString()]; } else if (!IsSyncButtonClicked && string.IsNullOrWhiteSpace(directoryPath.Text)) { status.Tag = "STR_MAIN_STATUS_NULLDIR"; status.Text = LanguageManager.Language[status.Tag.ToString()]; } }
// throws ThreadInterruptedException public bool TryEnter(int key) { lock (map) { //Se não existir a key, adiciona-se essa key com uma nova região if (!map.ContainsKey(key)) { map.Add(key, new Region()); } //região associada à key Region r = map[key]; //se a região não estiver cheia a thread pode entrar if (r.inside < maxInside) { //mais uma thread dentro da região r.inside++; //conseguiu entrar logo retorna true return(true); } //se a lista de espera para entrar na região não estiver cheia a thread pode ficar à espera if (r.waiting.Count < maxWaiting) { //Momento inicial da espera int lastTime = (waitTimeout != Timeout.Infinite) ? Environment.TickCount : 0; //Nova thread à espera - adiciona-se ao fim para cumprir a disciplina FIFO LinkedListNode <object> myRequest = r.waiting.AddLast(new object()); do { try { //Espera por waitTimeout ms SyncUtils.Wait(map, myRequest, waitTimeout); } catch (ThreadInterruptedException) { //Se saiu por excepção então removo a thread da lista de espera r.waiting.Remove(myRequest); //A expecção é relançada throw; } //Se a thread saiu por timeOut mas há espaço para entrar então entra na mesma if (r.inside < maxInside) { //Removo a thread da lista de espera r.waiting.Remove(myRequest); //Thread entra na região r.inside++; //Conseguiu entrar logo retorna true return(true); } //enquanto não tiver passado timeOut. Isto porque podem ocorrer saidas espurias } while (SyncUtils.AdjustTimeout(ref lastTime, ref waitTimeout) != 0); //Se a thread saiu por timeOut e não houve espaço para entrar na região então removo da lista de espera r.waiting.Remove(myRequest); //Lanço timeOut exception throw new TimeoutException(); } //Não conseguiu entrar na região nem na lista de espera então retorna false return(false); } }
private async Task SeedBlocksByChain(ExplorerDbContext context, Chain chain) { try { var height = await _phantasmaRpcService.GetBlockHeight.SendRequestAsync(chain.Address); using (var progress = new ProgressBar()) { for (int i = 1; i <= height; i++) { progress.Report((double)i / height); var blockDto = await _phantasmaRpcService.GetBlockByHeight.SendRequestAsync(chain.Address, i); var block = new Block { Chain = chain, ChainName = chain.Name, Hash = blockDto.Hash, PreviousHash = blockDto.PreviousHash, Timestamp = blockDto.Timestamp, Height = blockDto.Height, Payload = blockDto.Payload, Reward = blockDto.Reward, ValidatorAddress = blockDto.ValidatorAddress }; //Transactions foreach (var transactionDto in blockDto.Txs) { var transaction = new Transaction { Block = block, Hash = transactionDto.Txid, Timestamp = transactionDto.Timestamp, Script = transactionDto.Script, Result = transactionDto.Result }; bool addedToTokenList = false; //Events foreach (var eventDto in transactionDto.Events) { var domainEvent = new Domain.ValueObjects.Event { Data = eventDto.Data, EventAddress = eventDto.EventAddress, EventKind = eventDto.EventKind, Contract = eventDto.Contract }; transaction.Events.Add(domainEvent); if (!addedToTokenList) { if (domainEvent.EventKind == EventKind.TokenBurn || domainEvent.EventKind == EventKind.TokenSend || domainEvent.EventKind == EventKind.TokenStake || domainEvent.EventKind == EventKind.TokenUnstake || domainEvent.EventKind == EventKind.TokenReceive || domainEvent.EventKind == EventKind.TokenClaim || domainEvent.EventKind == EventKind.TokenMint ) { var data = Serialization.Unserialize <TokenEventData>(eventDto.Data.Decode()); var token = context.Tokens.SingleOrDefault(p => p.Symbol == data.Symbol); if (token != null) { token.Transactions.Add(transaction); addedToTokenList = true; await context.SaveChangesAsync(); } } } await SyncUtils.UpdateAccount(context, transaction, eventDto.EventAddress); } block.Transactions.Add(transaction); } chain.Height = block.Height; chain.Blocks.Add(block); } } await context.SaveChangesAsync(); } catch (Exception ex) { Debug.WriteLine(ex.ToString()); } }
public T Exchange(T mine, int timeout) { lock (lockObj) { //Se já existir um request então este request pode emparelhar com ele if (request != null) { //dois requests estão a emparelhar request.isExchanging = true; //Trocar mensagens T myMessage = request.message; request.message = mine; //Acorda a thread à espera de emparelhamento Monitor.Pulse(lockObj); //Retorna a mensagem return(myMessage); } //Ainda não existe nenhum request em espera de emparelhamento, logo tem de esperar por outro ThreadRequest req = new ThreadRequest(mine); request = req; //Momento inicial da espera int lastTime = (timeout != Timeout.Infinite) ? Environment.TickCount : 0; do { try { //Esperar por outro emparelhamento Monitor.Wait(lockObj, timeout); } catch (ThreadInterruptedException) { //Se sair por excepção e estiver a emparelhar: if (req.isExchanging) { //sinalizar esta thread como interrompida Thread.CurrentThread.Interrupt(); //retornar a mensagem return(req.message); } //Se sair por excepção e não estiver a emparelhar elimina o request e lança excepção request = null; throw; } //Se a thread acordou e estiver a emparelhar: if (req.isExchanging) { //Apagar o request request = null; //Retornar a mensagem return(req.message); } //enquanto não tiver passado timeOut. Isto porque podem ocorrer saidas espurias } while (SyncUtils.AdjustTimeout(ref lastTime, ref timeout) != 0); //Se a thread saiu por timeOut e está a emparelhar então continua e retorna if (req.isExchanging) { //Apagar o request request = null; //Retornar a mensagem return(req.message); } //Se a thread saiu por timeOut e não está a emparelhar então apaga o request e lança excepção request = null; throw new TimeoutException(); } }
private async Task SyncChains(ExplorerDbContext context) { var chainsDto = await _phantasmaRpcService.GetChains.SendRequestAsync(); await SyncUtils.SyncChains(chainsDto, context); }
public SoundcloudSync(SyncUtils syncUtil, bool mergePlaylists) { MergePlaylists = mergePlaylists; _syncUtil = syncUtil; JsonUtil = new JsonUtils(_syncUtil.ManifestUtil, _syncUtil.DownloadUtil.ClientIDsUtil); }
private async Task SyncBlock(ExplorerDbContext context, Chain chain, BlockDto blockDto) { if (context.Blocks.FirstOrDefault(p => p.Hash.Equals(blockDto.Hash)) != null) { return; } Console.WriteLine($"Seeding block {blockDto.Height}"); var block = new Block { Chain = chain, ChainName = chain.Name, Hash = blockDto.Hash, PreviousHash = blockDto.PreviousHash, Timestamp = blockDto.Timestamp, Height = blockDto.Height, Payload = blockDto.Payload, Reward = blockDto.Reward, ValidatorAddress = blockDto.ValidatorAddress }; //Transactions foreach (var transactionDto in blockDto.Txs) { var transaction = new Transaction { Block = block, Hash = transactionDto.Txid, Timestamp = transactionDto.Timestamp, Script = transactionDto.Script, Result = transactionDto.Result }; //Events foreach (var eventDto in transactionDto.Events) { var domainEvent = new Event { Data = eventDto.Data, EventAddress = eventDto.EventAddress, EventKind = eventDto.EventKind, Contract = eventDto.Contract }; transaction.Events.Add(domainEvent); AddToUpdateList(eventDto.EventAddress); await SyncUtils.UpdateAccount(context, transaction, eventDto.EventAddress); } } chain.Height = block.Height; context.Update(chain); await context.SaveChangesAsync(); Console.WriteLine($"Finished syncing block {blockDto.Height}"); Console.WriteLine("****************************************"); Console.WriteLine(); }
private async Task SeedBlocksByChain(ExplorerDbContext context, Chain chain) { try { var height = await _phantasmaRpcService.GetBlockHeight.SendRequestAsync(chain.Address); using (var progress = new ProgressBar()) { for (int i = 1; i <= height; i++) { progress.Report((double)i / height); var blockDto = await _phantasmaRpcService.GetBlockByHeight.SendRequestAsync(chain.Address, i); var block = new Block { Chain = chain, ChainName = chain.Name, Hash = blockDto.Hash, PreviousHash = blockDto.PreviousHash, Timestamp = blockDto.Timestamp, Height = blockDto.Height, Payload = blockDto.Payload, Reward = blockDto.Reward, ValidatorAddress = blockDto.ValidatorAddress }; //Transactions foreach (var transactionDto in blockDto.Txs) { var transaction = new Transaction { Block = block, Hash = transactionDto.Txid, Timestamp = transactionDto.Timestamp, Script = transactionDto.Script, Result = transactionDto.Result }; bool counterIncremented = false; //Events foreach (var eventDto in transactionDto.Events) { var domainEvent = new Event { Data = eventDto.Data, EventAddress = eventDto.EventAddress, EventKind = eventDto.EventKind, }; transaction.Events.Add(domainEvent); await SyncUtils.UpdateAccount(context, transaction, eventDto.EventAddress); if (!counterIncremented) { if (TransactionUtils.IsTransferEvent(domainEvent)) { var tokenSymbol = TransactionUtils.GetTokenSymbolFromTokenEventData(domainEvent); SyncUtils.AddToTokenTxCounter(context, tokenSymbol); counterIncremented = true; } } } block.Transactions.Add(transaction); } chain.Height = block.Height; chain.Blocks.Add(block); } } await context.SaveChangesAsync(); } catch (Exception ex) { } }