internal PadIntCommitted CreatePadInt(ulong tid, int uid, bool isReplicating) { Console.WriteLine("Create padInt " + uid); if (objectsInServer.ContainsKey(uid)) { return(null); } PadIntTransaction obj = new PadIntTransaction(uid); PadIntCommitted committed = new PadIntCommitted(uid); obj.setCommited(committed); objectsInServer[uid] = obj; //wait handle não notificado e com manual reset pois deve ser o write a fechar a passagem às threads. objectWaitHandle[uid] = new EventWaitHandle(false, EventResetMode.ManualReset);//esta errado? se for criado, todas as threads devem puder passar por handle certo? pendingTransactions[uid] = new EventWaitHandle(false, EventResetMode.ManualReset); if (!isReplicating) { Write(tid, uid, 0); } return(committed); }
//o doCommit deveria ser atomico. pode dar problema? internal bool doCommit(ulong tid) { PadIntTransaction objectTransaction = null; PadIntTentative tentative = null; PadIntCommitted commited = null; List <PadIntRemote> toReplicate = new List <PadIntRemote>(); //desbloquear threads em espera no read com Console.WriteLine("Em do commit Tid: " + tid); foreach (int modifiedObject in transactions[tid].getModifiedObjectIds()) { //Console.WriteLine("Em do commit no for Tid: " + tid + "modificou" + modifiedObject); //por commited //remover objecto transaccao //remover objecto tentativa //por tentativa como commited se vamos remover vale a pena? ter em atenção que no read ele ve se o anterior esta commited. nao sei se deviamos eliminar. //actualizar o valor do commited objectTransaction = objectsInServer[modifiedObject]; SortedList <ulong, PadIntTentative> tentatives = objectTransaction.getTentatives(); tentative = tentatives[tid]; commited = objectTransaction.getCommitted(); commited.WriteTimestamp = tid; commited.Value = tentative.Value; toReplicate.Add(commited); tentative.SetCommited(); tentatives.Remove(tid); objectWaitHandle[modifiedObject].Set();//fez commit.temos de notificar threads para avancarem. pendingTransactions[modifiedObject].Set(); } transactions[tid].setCommited(); //Transacção efectuda e agora removida transactions.Remove(tid); if (replica != null) { replica.SendPadInt(toReplicate); } foreach (var p in toReplicate) { Console.WriteLine("replicado = " + p.uid + " " + p.Value); } checkTableOfPendingTransactions(tid); return(true); //sempre verdade? }
internal bool doAbort(ulong tid) { Console.WriteLine("doAbort"); PadIntTransaction objectTransaction = null; PadIntTentative tentative = null; //desbloquear threads em espera no read com foreach (int modifiedObject in transactions[tid].getModifiedObjectIds()) { Console.WriteLine("Abort: " + modifiedObject); //por abort //remover objecto transaccao check //remover objecto tentativa check //por tentativa como commited se vamos remover vale a pena? ter em atenção que no read ele ve se o anterior esta commited. nao sei se deviamos eliminar. //actualizar o valor do commited objectTransaction = objectsInServer[modifiedObject]; SortedList <ulong, PadIntTentative> tentatives = objectTransaction.getTentatives(); tentative = tentatives[tid]; tentative.SetAborted(); tentatives.Remove(tid); PadIntCommitted com = objectTransaction.getCommitted(); //Remove creates if (com.WriteTimestamp == 0) { objectsInServer.Remove(modifiedObject); objectWaitHandle[modifiedObject].Set();//fez commit.temos de notificar threads para avancarem. pendingTransactions[modifiedObject].Set(); objectWaitHandle.Remove(modifiedObject);//fez commit.temos de notificar threads para avancarem. pendingTransactions.Remove(modifiedObject); } else { objectWaitHandle[modifiedObject].Set();//fez commit.temos de notificar threads para avancarem. pendingTransactions[modifiedObject].Set(); } } transactions[tid].setAborted(); //Transacção efectuda e agora removida transactions.Remove(tid); return(true); //sempre verdade? }
internal PadIntCommitted AccessPadInt(int uid) { //Nao foi encontrado o PadInt procurado //Se calhar devia lançar excepção if (!objectsInServer.ContainsKey(uid)) { Console.WriteLine("Nao foi encontrado " + uid); return(null); } PadIntTransaction obj = objectsInServer[uid]; //O PadInt foi encontrado mas é null if (obj == null) { return(null); } return(obj.getCommitted()); }
internal PadIntCommitted CreatePadInt(ulong tid, int uid, bool isReplicating) { Console.WriteLine("Create padInt " + uid); if (objectsInServer.ContainsKey(uid)) return null; PadIntTransaction obj = new PadIntTransaction(uid); PadIntCommitted committed = new PadIntCommitted(uid); obj.setCommited(committed); objectsInServer[uid] = obj; //wait handle não notificado e com manual reset pois deve ser o write a fechar a passagem às threads. objectWaitHandle[uid] = new EventWaitHandle(false, EventResetMode.ManualReset);//esta errado? se for criado, todas as threads devem puder passar por handle certo? pendingTransactions[uid] = new EventWaitHandle(false, EventResetMode.ManualReset); if (!isReplicating) Write(tid, uid, 0); return committed; }
internal void Write(ulong tid, int uid, int value) { //addicionar objecto modificado //ServerApp.debug = "Write called!"; //fica a espera que sejam transferidos dados de um servidor que sofreu divisao do seeu range pela entrada deste novo server if (tid > maxTID) { waitForPadIntTransfer.Reset(); } if (!objectsInServer.ContainsKey(uid)) { //O objecto nao foi criado no servidor throw new PadIntNotExists(tid, uid); } PadIntTransaction obj = objectsInServer[uid]; PadIntCommitted committed = obj.getCommitted(); ulong tc = committed.WriteTimestamp; //Verificacao 1: Ja existem escritas committed com timestamp superior ao desta transaccao if (tid <= tc) { throw new PadIntWriteTooLate(tid, uid); } //Debug.WriteLine(); SortedList <ulong, PadIntTentative> tentatives = obj.getTentatives(); PadIntTentative t; //Não existem transações a mexer no objecto com identificador uid if (tentatives.Count == 0) { t = new PadIntTentative(uid, tid, value); obj.addTentative(tid, t); transactions[tid].addModifiedObjectId(uid); ////depois de modificar o object, adiciona-lo à transaccao para sabermos o que mudamos no fim. objectWaitHandle[uid].Reset(); //escreveu, bloqueia as threads. O que acontece se não fôr a tempo de bloquear as threads??????? pendingTransactions[uid].Reset(); // dado que escrevemos, as que forem fazer commit teem de esperar //evitar que venha a esperar por si mesma espera por si mesma? return; } //Max de timestamp de leitura das versoes //Func<PadIntTentative, decimal> lam = tent => (decimal) tent.ReadTimestamp; // ulong tMax = tentatives.Max<PadIntTentative,ulong>(x => x.ReadTimestamp); //metodos extendidos. porque nao da? Não apagar. Ainda tenho de //perceber isto Ass:Braga :) ulong tMax = (ulong)tentatives.Max(x => x.Value.ReadTimestamp); //Console.WriteLine("Tid: " + tid + "Tmax: " + tMax); //Verificacao 2: Ja existem leituras de transaccoes a serem processadas if (tid < tMax) { throw new PadIntWriteTooLate(tid, uid); } if (tentatives.ContainsKey(tid)) { PadIntTentative transactionTentative = tentatives[tid]; // transactionTentative.Write(value);--> ja existe uma property //se tem tentativa é porque já escreveu antes. Não é preciso resetar o handle? Ou é???????? transactionTentative.Value = value; } else//primeira tentativa da transacçao tid { t = new PadIntTentative(uid, tid, value); obj.addTentative(tid, t); transactions[tid].addModifiedObjectId(uid); ////depois de modificar o object, adiciona-lo à transaccao para sabermos o que mudamos no fim. objectWaitHandle[uid].Reset(); ///primeira tentativa de escrita. Reseta handle para bloquear threads. pendingTransactions[uid].Reset(); // dado que escrevemos, as que forem fazer commit teem de esperar } }
internal int Read(ulong tid, int uid) { //ServerApp.debug = "Read called!"; //fica a espera que sejam transferidos dados de um servidor que sofreu divisao do seeu range pela entrada deste novo server if (tid > maxTID) { //Console.WriteLine("read: tid>mazxTID"); waitForPadIntTransfer.Reset(); } if (!objectsInServer.ContainsKey(uid)) { //O objecto nao foi criado no servidor throw new PadIntNotExists(tid, uid); } PadIntTransaction obj = objectsInServer[uid]; PadIntCommitted committed = obj.getCommitted(); // return committed.Read(); ulong tc = committed.WriteTimestamp; //ServerApp.debug = "Object commited with value: " + committed.Value; //Console.WriteLine(String.Format("on read:Tid:{0} Tc:{1}", tid, tc)); if (tid <= tc) { throw new PadIntReadTooLate(tid, uid); } SortedList <ulong, PadIntTentative> tentatives = obj.getTentatives(); //se não existirem versões tentativa, ele não/ninguém escreveu. pode ler do commited. if (tentatives.Count == 0) { objectsInServer[uid].addTentative(tid, new PadIntTentative(uid, tid, tid, committed.Value)); ////////////////////////////////////////////////////////////////////// transactions[tid].addModifiedObjectId(uid); ////depois de modificar o object, adiciona-lo à transaccao para sabermos o que mudamos no fim. pendingTransactions[uid].Reset(); // dado que temos uma tentativa, as que forem fazer commit teem de esperar return(committed.Value); } //se ja foi escrita uma versao, entao le-se dessa versão. if (tentatives.ContainsKey(tid)) { PadIntTentative ownTentative = tentatives[tid]; ownTentative.ReadTimestamp = tid; return(ownTentative.Value); } //versao de tentativa que tem um timestamp de escrita superior a todos os inferiores ao da transaccao que quer ler. PadIntTentative mostUpdated = tentatives.Values.Where(x => ((x.WriteTimestamp < tid) ? true : false)).Max(x => x.WriteTimestamp < tid ? x : null); //se nao existe nenhum que tenha escrito e que tenha timestamp inferior, significa que a transaccao actual pode ler o valor do commited. if (mostUpdated == null) { objectsInServer[uid].addTentative(tid, new PadIntTentative(uid, tid, tid, committed.Value)); ////////////////////////////////////////////////////////////////////// transactions[tid].addModifiedObjectId(uid); ////depois de modificar o object, adiciona-lo à transaccao para sabermos o que mudamos no fim. pendingTransactions[uid].Reset(); // dado que temos uma tentativa, as que forem fazer commit teem de esperar return(committed.Value); } ulong tMax = mostUpdated.WriteTimestamp;// este e o valor do maior timestamp de escrita menor que o da transaccao //verificar se a versao commited tem um timestamp igual ao de tmax. se tiver, significa que o tmax está commited. pode então ler if (tc == tMax)//pode ler { mostUpdated.ReadTimestamp = tid; return(mostUpdated.Value); } else //espera que a transaccao faca commit e volta a repetir todos os passos até aqui.É criada uma thred para cada chamada a esta função. { objectWaitHandle[uid].WaitOne(); //bloqueia e quando fôr desbloqueada, volta a tentar. return(Read(tid, uid)); } }