private void EnviarAMemoriaBloqueVSiModificado(BloqueCacheDatos bloqueV) { if (bloqueV.Estado != EstadosB.Invalido) { Directorio directorioBloqueV = bloqueV.Directorio; // Bloqueo directorio de BloqueV directorioBloqueV.Bloquear(this.Nombre); bloqueados.Add(directorioBloqueV); // Se pregunta si el bloque a reemplazar en mi cache está modificado if (bloqueV.Estado == EstadosB.Modificado) { // Envio el bloque a memoria // Este método modifica tanto la cache como el directorio (U en directorio e I en Cache) bloqueV.EnviarAMemoria(); } else { bloqueV.Invalidar(); } // Desbloqueo el directorio del BloqueV directorioBloqueV.Desbloquear(this.Nombre); bloqueados.Remove(directorioBloqueV); } }
/// <summary> /// Trae un bloque de memoria o desde otra cache /// </summary> /// <param name="bloque">Bloque</param> /// <param name="controlador">Controlador</param> /// <param name="cache">Cache dueña del bloque</param> /// <param name="vieneDeMemoria">Indica si viene de memoria (true) o de otra cache (false)</param> public static BloqueCacheDatos TraerBloqueCacheDatos(Bloque bloque, Controlador controlador, CacheDatos cache, bool vieneDeMemoria) { // Se copian los datos del bloque BloqueCacheDatos bloqueCache = new BloqueCacheDatos(controlador, cache); bloqueCache.id = bloque.ID; bloqueCache.direccionInicial = bloque.Direccion; bloqueCache.indiceMemoriaPrincipal = bloque.IndiceMemoriaPrincipal; for (int i = 0; i < PalabrasPorBloque; ++i) { bloqueCache.palabras[i] = bloque[i]; } // Asigna el controlador y la cache bloqueCache.controlador = controlador; bloqueCache.cache = cache; Debug.Assert(cache.EstaBloqueado()); Debug.Assert(bloqueCache.Directorio.EstaBloqueado()); // Se espera que el bloque venga de memoria bloqueCache.EsperarTraida(vieneDeMemoria); // Se pone el bloque como compartido bloqueCache.estado = EstadosB.Compartido; // Me pongo en la cache cache[bloqueCache.IndiceCache] = bloqueCache; // Se refleja el cambio en el directorio // Se pone como compartido en el directorio bloqueCache.Directorio.AgregarUsuarioBloque(cache, bloqueCache); return(bloqueCache); }
public void ModificarBloque(CacheDatos solicitante, BloqueCacheDatos bloque) { Esperar(solicitante); Debug.Assert(EstaBloqueado()); Debug.Assert(usuarios[bloque.IndiceMemoriaPrincipal].Count == 1); Estados[bloque.IndiceMemoriaPrincipal] = EstadosD.Modificado; }
/// <summary> /// Se elimina cache de la lista respectiva /// </summary> /// <param name="solicitante">Cache de datos que ya no es usuaria del bloqueMemoria</param> /// <param name="bloqueMemoria">Bloque ya no utilizado</param> public void EliminarUsuarioBloque(CacheDatos solicitante, BloqueCacheDatos bloque) { Esperar(solicitante); Debug.Assert(EstaBloqueado()); Debug.Assert(usuarios[bloque.IndiceMemoriaPrincipal].Contains(solicitante.ID)); Debug.Assert(bloque.ID == this.id); usuarios[bloque.IndiceMemoriaPrincipal].Remove(solicitante.ID); if (usuarios[bloque.IndiceMemoriaPrincipal].Count == 0) { estados[bloque.IndiceMemoriaPrincipal] = EstadosD.Uncached; } }
/// <summary> /// Agrega una cache como usuaria de un bloque. Siempre se agregan los bloques en C. /// </summary> /// <param name="solicitante">Cache de datos usuaria del bloqueMemoria</param> /// <param name="bloqueMemoria">Bloque siendo utilizado</param> public void AgregarUsuarioBloque(CacheDatos solicitante, BloqueCacheDatos bloque) { Esperar(solicitante); // Debido a la implementación los bloques siempre se agregan como compartidos al directorio // Si la cache los modifica, luego llama al método de ModificarBloque del directorio Debug.Assert(EstaBloqueado()); Debug.Assert(estados[bloque.IndiceMemoriaPrincipal] != EstadosD.Modificado); Debug.Assert(bloque.Estado != EstadosB.Modificado); Debug.Assert(!usuarios[bloque.IndiceMemoriaPrincipal].Contains(solicitante.ID)); Debug.Assert(bloque.ID == this.id); Debug.Assert(solicitante[bloque.IndiceCache].Direccion == bloque.Direccion); usuarios[bloque.IndiceMemoriaPrincipal].Add(solicitante.ID); estados[bloque.IndiceMemoriaPrincipal] = EstadosD.Compartido; }
/// <summary> /// Se invalida el bloqueMemoria en todas las cachés que lo usen /// </summary> /// <param name="solicitante">Cache de Datos solicitante</param> /// <param name="bloqueMemoria">Bloque para obtener la dirección</param> public void InvalidarBloque(CacheDatos solicitante, Bloque bloque) { Esperar(solicitante); // Solo se puede invalidar un bloqueMemoria si alguien lo está compartiendo Debug.Assert(EstaBloqueado()); Debug.Assert(estados[bloque.IndiceMemoriaPrincipal] == EstadosD.Compartido); Debug.WriteLine("Cache " + solicitante.ID + ": Invalidando a quienes comparten el bloque " + bloque.Direccion); //Obtengo quienes son las caches que tienen bloqueN compartido List <int> lectores = usuarios[bloque.IndiceMemoriaPrincipal]; // Creo una copia de la lista de lectores sin la cache solicitante // Si es que se encuentra List <int> tmp = new List <int>(lectores); tmp.Remove(solicitante.ID); // TODO Mejorar este código para que reintente sobre las caches // Mientras no falle consecutivamente en todas foreach (int id in tmp) { CacheDatos cache = controlador.CachesDatos[id]; // Bloqueo la cache cache.Bloquear(this.Nombre); BloqueCacheDatos bloqueCache = cache[bloque.IndiceCache]; Debug.Assert(bloqueCache.Direccion == bloque.Direccion); // Invalido el bloque bloqueCache.Invalidar(); // Debloqueo la cache cache.Desbloquear(this.Nombre); } // O no hay nadie compartiendo el bloque o la solicitante es la unica que lo comparte Debug.Assert(lectores.Count == 0 || lectores[0] == solicitante.ID && lectores.Count == 1); }
/// <summary> /// Método que realmente se encarga de ejecutar la lógica de leer una palabra. /// Si no puede bloquear algo, tira una excepción del tipo RebootNeededException. /// </summary> /// <param name="info">Información de la palabra que se quiere leer</param> /// <returns>Palabra que se quiere leer</returns> private int Leer(InformacionPalabra info) { int palabraLeida = -1; // Se bloquea la cache this.Bloquear(this.Nombre); bloqueados.Add(this); // Se pregunta si es Hit if (!info.EsHit()) { // Se envia el bloqueV a memoria si está modificado EnviarAMemoriaBloqueVSiModificado(this[info.IndiceCache]); // Bloqueo el directorio que contiene la palabra que busco info.Directorio.Bloquear(this.Nombre); bloqueados.Add(info.Directorio); // Consulto el directorio del bloqueMemoria que contiene la palabra que busco // para ver si alguna cache lo tiene modificado CacheDatos modificante = info.Directorio.GetUsuarioQueModifica(this, info.Bloque); if (modificante == null) { // Traigo el bloqueMemoria de memoria BloqueCacheDatos.TraerBloqueCacheDatos(info.Bloque, controlador, this, true); } else { // Bloqueo la cache que modificó el dato modificante.Bloquear(this.Nombre); bloqueados.Add(modificante); // Se envía el bloque en la cache modificante a memoria modificante[info.IndiceCache].EnviarAMemoria(); // Se actualiza la información del bloque con lo último de memoria info.ActualizarBloque(); // Traigo el dato de la cache modificante BloqueCacheDatos.TraerBloqueCacheDatos(info.Bloque, controlador, this, false); // Desbloqueo la cache que modificó el dato modificante.Desbloquear(this.Nombre); bloqueados.Remove(modificante); } // Desbloqueo el directorio info.Directorio.Desbloquear(this.Nombre); bloqueados.Remove(info.Directorio); } // Leo la palabra palabraLeida = this[info.IndiceCache][info.IndicePalabra]; // Desbloqueo la cache this.Desbloquear(this.Nombre); bloqueados.Remove(this); // Devuelvo la palabra leída return(palabraLeida); }
/// <summary> /// Método que escribe una palabra en una dirección de memoria /// </summary> /// <param name="info">Guarda información de donde debe escribirse la palabra</param> /// <param name="palabra">Palabra que se quiere escribir</param> public void Escribir(InformacionPalabra info, int palabra) { //Se bloquea mi cache this.Bloquear(this.Nombre); bloqueados.Add(this); // Si es hit if (info.EsHit()) { BloqueCacheDatos bloqueN = this[info.IndiceCache]; if (bloqueN.Estado == EstadosB.Modificado) { // Si está en mi cache modificado nada más lo escribo bloqueN[info.IndicePalabra] = palabra; bloqueN.Estado = EstadosB.Modificado; } else { // Si lo tengo compartido, bloqueo el directorio correspondiente info.Directorio.Bloquear(this.Nombre); bloqueados.Add(info.Directorio); // Invalido a todos quienes compartan el bloque info.Directorio.InvalidarBloque(this, info.Bloque); // Escribo la palabra bloqueN[info.IndicePalabra] = palabra; bloqueN.Estado = EstadosB.Modificado; info.Directorio.ModificarBloque(this, bloqueN); // Desbloqueo el directorio info.Directorio.Desbloquear(this.Nombre); bloqueados.Remove(info.Directorio); } } else { // Se envia el bloqueV a memoria si está modificado EnviarAMemoriaBloqueVSiModificado(this[info.IndiceCache]); // Bloqueo el directorio que contiene la palabra que busco info.Directorio.Bloquear(this.Nombre); bloqueados.Add(info.Directorio); // Consulto el directorio del bloqueMemoria que contiene la palabra que busco // para ver si alguna cache lo tiene modificado CacheDatos modificante = info.Directorio.GetUsuarioQueModifica(this, info.Bloque); if (modificante == null) //Si no hay nadie que esté modificando en bloque { if (info.Directorio.CountUsuariosQueComparten(this, info.Bloque) > 0) { //Se les invalida el BloqueN a todas las caches que lo tengan compartido info.Directorio.InvalidarBloque(this, info.Bloque); } // Traigo el bloqueMemoria de memoria // El constructor pone el bloque en la cache BloqueCacheDatos.TraerBloqueCacheDatos(info.Bloque, controlador, this, true); } else { // Bloqueo la cache que modificó el dato modificante.Bloquear(this.Nombre); bloqueados.Add(modificante); // Se envía el bloque en la cache modificante a memoria modificante[info.IndiceCache].EnviarAMemoria(); // Se actualiza la información del bloque info.ActualizarBloque(); // Traigo el dato desde la cache modificante BloqueCacheDatos.TraerBloqueCacheDatos(info.Bloque, controlador, this, false); // Desbloqueo la cache que modificó el dato modificante.Desbloquear(this.Nombre); bloqueados.Remove(modificante); } // Escribo la palabra this[info.IndiceCache][info.IndicePalabra] = palabra; this[info.IndiceCache].Estado = EstadosB.Modificado; this[info.IndiceCache].Directorio.ModificarBloque(this, this[info.IndiceCache]); // Desbloqueo el directorio info.Directorio.Desbloquear(this.Nombre); bloqueados.Remove(info.Directorio); } // Desbloqueo mi cache this.Desbloquear(this.Nombre); bloqueados.Remove(this); }