/// <summary>
 /// Puede levantar AbortarEsperarMorirException debido al protocolo Esperar-Morir
 /// </summary>
 /// <param name="transaccion">Transaccion que solicita el bloqueo</param>
 /// <param name="condiciones">Condiciones por la que bloquear</param>
 /// <param name="tipoBloqueo">Tipo de bloqueo que solicita</param>
 /// <returns></returns>
 internal DescriptorBloqueo bloquear(Transaccion transaccion,
                                     Condicion condicion, TipoBloqueo tipoBloqueo)
 {
     lock (Entradas)
     {
         foreach (EntradaBloqueo entrada in Entradas)
         {
             if (entrada.igualCondicion(condicion))
             {
                 if (entrada.permiteBloqueo(condicion, tipoBloqueo))
                 {
                     return(entrada.bloquear(transaccion, tipoBloqueo));
                 }
                 entrada.encolarBloqueo(transaccion); //-> aqui puede leventar exception por protocolo esperar morir
                 while ((entrada.Bloqueado &&
                         !entrada.permiteBloqueo(condicion, tipoBloqueo)) ||
                        !entrada.desencolarSiEsElSiguiente(transaccion))
                 {
                     Monitor.Wait(entradas);
                 }
                 if (tipoBloqueo == TipoBloqueo.BLOQUEO_LECTURA)
                 {
                     Monitor.PulseAll(entradas);//porque no eran los primeros, se volvieron a bloquear
                 }
                 return(entrada.bloquear(transaccion, tipoBloqueo));
             }
         }
         //no estaba la entrada
         EntradaBloqueo nuevaEntrada = new EntradaBloqueo(this, tipoBloqueo, condicion);
         Entradas.Add(nuevaEntrada);
         return(nuevaEntrada.bloquear(transaccion, tipoBloqueo));
     }
 }
 internal EntradaBloqueo(ControladorConcurrencia controladorConcurrencia,
                         TipoBloqueo tipo, Condicion condicion)
 {
     this.controladorConcurrencia = controladorConcurrencia;
     this.tipo      = tipo;
     this.condicion = condicion;
 }
 internal Boolean permiteBloqueo(Condicion condicion, TipoBloqueo tipo)
 {
     if (igualCondicion(condicion) && Bloqueado)
     {
         //si alguno de los 2 es de escritura, no se puede
         if (this.Tipo == TipoBloqueo.BLOQUEO_ESCRITURA || tipo == TipoBloqueo.BLOQUEO_ESCRITURA)
         {
             return(false);
         }
     }
     //distina condicion, o ambos de lectura
     return(true);
 }
        /// <summary>
        /// Bloquea para esa transaccion, debe controlarse antes de llamar a este mensaje
        /// </summary>
        /// <param name="transaccion"></param>
        internal DescriptorBloqueo bloquear(Transaccion transaccion, TipoBloqueo tipo)
        {
            //este control es por las dudas
            if (Tipo == TipoBloqueo.BLOQUEO_ESCRITURA &&
                Bloqueado)
            {
                throw new Exception("Ya estaba bloqueado como escritura");
            }

            bloqueado = true;
            this.tipo = tipo;
            bloqueados.Add(transaccion);
            DescriptorBloqueo descriptor = new DescriptorBloqueo(this, transaccion);

            transaccion.agregarBloqueado(descriptor);
            return(descriptor);
        }
 /// <summary>
 /// Puede levantar AbortarEsperarMorirException debido al protocolo Esperar-Morir
 /// <para>Esto indica que la transaccion se abortó</para>
 /// </summary>
 /// <param name="transaccion"></param>
 /// <param name="tabla"></param>
 /// <param name="condicion"></param>
 /// <param name="tipoBloque"></param>
 /// <returns></returns>
 public void bloquear(Transaccion transaccion,
                      Condicion condicion, TipoBloqueo tipoBloque)
 {
     controladorConcurrencia.bloquear(transaccion, condicion, tipoBloque);
 }