En mulighed for at lave en cache i ASP Classic kunne være at benytte Session-objektet og et lille sæt rutiner til at hjælpe lidt med benarbejdet. På denne måde kan man med ganske få linier håndtere en simpel form for caching.

Når vi cacher noget  er det typisk for at optimere en adgang til data som ellers er tung at udføre. Det er dog til tider på bekostning af data's nyhedsværdi (altså hvor friske data er). Derfor vil vi gerne sikre en mulighed for, at de udløber efter en given periode. Perioden kan variere meget alt afhængig af hvilke data vi cacher, så derfor skal vores cachingfeature kunne håndtere dette behov.

En meget simpel model kunne se ud som følger:

' Sæt værdien
Session("vaerdi") = "En værdi"

' Hold øje med hvornår værdien er sat, så det senere
' er muligt, at beslutte om værdien er forældet
Session("vaerdi_time") = now

Når værdien så skal aflæses kan vi gøre som følger:

' Undersøg "friskheden" af data
if isdate(session("vaerdi_time")) then
  ' Undersøg om værdien er sat indenfor de seneste 5 minutter
  if datediff("s", session("vaerdi_time"), now) < 300 then
    ' Værdien er stadig frisk (nok), så den aflæses
    vaerdi = session("vaerdi")
  else
    ' Værdien er ikke "frisk" nok, så variablen sættes ikke
    ' (den tømmes faktisk for indhold)
    vaerdi = Empty
  end if
end if

Nu er det imidlertid noget bøvlet at skulle indsætte alt den kode hver gang man skal bruge en cached værdi (det er heller ikke særlig vedligeholdelsesvenligt!), så derfor må vi gøre det bedre. Heldigvis er det også muligt...

En indpakning af både selve tildeling af cacheværdien og aflæsningen af cachen kan opnåes rimelig let.

function setCache(key, value, timeout)
  ' Sæt værdien
  Session(key) = value

  ' Hold øje med hvornår værdien er sat, så det senere
  ' er muligt, at beslutte om værdien er forældet
  Session(key & "_time") = now

  ' Sæt det antal sekunder der skal gå inden værdien er forældet
  Session(key & "_timeout") = timeout

  ' returner værdien igen, så funktionen kan kaldes i kombination med
  ' tildeling af værdien der skal caches
  setCache = value
end function

function getCache(key)
  ' Undersøg "friskheden" af data
  if isdate(session(key & "_time")) then
    ' Undersøg om værdien er sat indenfor de seneste 5 minutter
    if datediff("s", session(key & "_time"), now) < session(key & "_timeout") then
      ' Værdien er stadig frisk (nok), så den aflæses
      getCache = session(key)
    else
      ' Værdien er ikke "frisk" nok, så variablen sættes ikke
      ' (den tømmes faktisk for indhold)
      getCache = Empty
    end if
  else
    getCache = Empty
  end if
end function

Herefter kan vi nu let cache en værdi:

setCache "vaerdi", "En værdi", 300

 og aflæse den igen:

vaerdi = getCache("vaerdi")
if isEmpty(vaerdi) then
  ' gør hvad der skal til for at lægge en opdateret værdi i cachen
  vaerdi = setCache("vaerdi", "En opdateret værdi", 300)
end if

Bemærk at vi kan bruge setCache til at tildele variablen den nye cachede værdi, så vi ikke behøver aflæse den påny efter gen-caching.

NB: Denne cache er baseret på session og du bør derfor afholde dig fra at lægge objekter i cachen. Hvis du alligevel forsøger, vil der givetvis opstå en fejl, da objekter håndteres anderledes en andre værdityper. En anden grund er, at session generelt er lidt følsom overfor hvad der puttes i den, Desuden vil for mange objekter i hukommelsen på session-niveau heller ikke skalere særlig godt. Så hold dig derfor til simple værdier, så som tal og strenge. Du kan som regel rimelig let omsætte disse værdier til objekter, hvis det er nødvendigt (f.eks. ved serialisering til strenge)...

Cachen kunne laves som en klasse der dels tillod indsættelse af værdier i cachen, dels aflæsning vha. nøglen. Ydermere kunne den kombineres med teknikken vedr. events (se aktiklen om "Events i ASP - 2"), således der blev kastet et event i det øjeblik for forsøgte at læse en cached værdi der var udløbet. På denne måde kan du isolere din kode til at genopfriske cachen i en funktion som bliver kaldt når det er nødvendigt. Det vil gøre brugen af den cachede værdi mere transparent, dvs. du behøver ikke forholde dig til om den cachede værdi er up to date - det vil den automatisk være når du får den tilbage fra cache-objektet.

class CCacheEventParameter
  private m_sender
  private m_key
  private m_updated

  private sub class_initialize()
    m_updated = false
  end sub

  public property get sender: set sender = m_sender: end property
  public property set sender(value): set m_sender = value: end property

  public property get key: key = m_key: end property
  public property let key(value): m_key = value: end property

  ' angiver om cachen er blevet opdateret. Denne egenskab SKAL sættes
  ' hvis cachen opdateres ved event-kaldet, ellers risikerer cachen
  ' at returnere en forældet værdi.
  public property get updated: updated = m_updated: end property
  public property let updated(value): m_updated = value: end property
end class

class CCache
  private m_ehRefreshCache  ' eventhook til melding om genopfriskning

  private sub class_initialize()
    set m_ehRefreshCache = new CEventHook
  end sub

  default public function getCache(key)
    ' Undersøg "friskheden" af data
    if isdate(session(key & "_time")) then
      ' Undersøg om værdien er sat indenfor de seneste "timeout-antal" sekunder
      if datediff("s", session(key & "_time"), now) > session(key & "_timeout") then
        ' Værdien er ikke "frisk" nok, så eventet der meddeler abonnenten om
        ' at værdien skal genopfriskes rejses.
        dim param: set param = new CCacheEventParameter
        set param.sender = me
        param.key = key
        call ehRefreshCache.raise(param)
        if param.updated then
          getCache = session(key)
        else
          getCache = Empty
        end if
      else
        getCache = session(key)
        if cbool(session(key & "_sliding")) then
          ' der er sliding timeout på denne værdi, så derfor skal
          ' "time" opdateres ved denne læsning...
          session(key & "_time") = now
        end if
      end if
    else
      getCache = Empty
    end if
  end function

  public function setCache(key, value, timeout, sliding)
    if not isEmpty(value) then
       ' Sæt værdien
      Session(key) = value

      ' Hold øje med hvornår værdien er sat, så det senere
      ' er muligt, at beslutte om værdien er forældet
      Session(key & "_time") = now

      ' Sæt det antal sekunder der skal gå inden værdien er forældet
      Session(key & "_timeout") = timeout

      ' Sæt om værdien skal udløbe afhængig af hvor ofte den bliver brugt,  
      ' dvs. timeout bliver genopfrisket for hver læsning af værdien i cachen
      ' således timeout er den tid der er gået siden sidste læsning
      Session(key & "_sliding") = sliding
    else
      ' Hvis value er Empty, fjern da oplysninger om værdien i cachen
      call Session.Contents.Remove(key)
      call Session.Contents.Remove(key & "_time")
      call Session.Contents.Remove(key & "_timeout")
      call Session.Contents.Remove(key & "_sliding")
      setCache = Empty
    end if

    ' returner værdien igen, så funktionen kan kaldes i kombination med
    ' tildeling af værdien der skal caches
    setCache = value
  end function

  public property get ehRefreshCache: set ehRefreshCache = m_ehRefreshCache: end property
end class

Vi kan nu sætte vores cache op således der reageres på forældede værdier:

dim cache: set cache = new CCache
call cache.ehRefreshCache.hookup("cache_refreshcache")

sub cache_refreshcache(obj)
  select case obj.key
    case "vaerdi"
      ' Her udføres den kode som skal sørge for at cachen bliver opdateret
      cache.setCache obj.key, "En ny værdi", 300
      ' Sæt updated til true, så cachen ved at den er blevet opdateret
      obj.updated = true
  end select
end sub

Selve aflæsningen kan så ske ved blot at kalde cache.getCache("vaerdi"), eller slet og ret cache("vaerdi"). Det sidste er muligt fordi vi har defineret getCache som default-property på objektet.

dim v: v = cache("vaerdi")
Response.Write v & "
"

Hele dette setup kan naturligvis også laves med udgangspunkt i Application-objektet og dermed gøre cachen global for alle brugere på websitet - det er det jo også lidt potentiale i...

 

 
Sidst opdateret: 04-09-2010 23:54:54
Tilmeld link | Tilføj Link | Tilføj Link | @-begynder
Erklæring om beskyttelse af personlige oplysninger

nope.dk - Danmarks Website Chart