dak ブログ

python、rubyなどのプログラミング、MySQL、サーバーの設定などの備忘録。レゴの写真も。

TypeScript で TTL つきキャッシュを実装

2024-02-23 15:02:11 | Node.js
TypeScript での TTL つきキャッシュの実装例です。
※2024/02/26 にバグを修正

オブジェクトの登録時刻がキャッシュ作成時に指定した TTL を過ぎると、キャッシュを参照した際に undefined を返却します。

キャッシュの実装で利用している list の実装は以下にあります。
Typescript での双方向連結リスト
■キャッシュの実装
/**
 *
 * Cache with TTL
 *
 */

import { Node, List } from '../list/lib/list';
import { SimpleCache } from 'SimpleCache';


export class TtlCache {
  private _max_size: number;
  private _list: List = new List();
  private _hash: any = {};
  private _ttl_msec: number;
  
  public constructor(max_size: number, ttl_msec: number) {
    if (max_size < 1) max_size = 1;
    this._max_size = max_size;
    this._ttl_msec = ttl_msec;
  }
  
  public get(key: string) {
    super.get(key);
    // obj = [key, obj, time];
    const now = (new Date()).getTime();
    const node = this._hash[key];
    if (node === undefined) return undefined;
    
    if (node.obj[2] + this._ttl_msec < now) {
      // timeout
      this._list.remove_node(node);
      delete this._hash[key];
      return undefined;
    }

    this._list.remove(node);
    this._list.push(node);
    return node.obj[1];
  }
  

  public set(key: string, obj: any) {
    // obj = [key, obj, time];
    // update obj if exists
    const now = (new Date()).getTime();
    let node = this._hash[key];
    if (node === undefined) {
      const node = new Node([key, obj, now]);
      this.push(node);
      
      if (this._list.length > this._max_size) {
	this._list.shift_node();
	delete this._hash[key];
      }
    }
    else {
      node.obj = [key, obj, now];
      this.remove_node(node);
      this.push_node(node);
    }
    return obj;
  }
}

■実行例
import { setTimeout } from 'timers/promises';
import { TtlCache } from './TtlCache';


async function test_set() {
  const cache = new TtlCache(8, 1000);
  
  const num = 10;
  for (let i = 0; i < num; i++) {
    const key = `key_${i}`;
    const value = `value_${i}`;
    cache.set(key, value);
    const time = (new Date()).getTime();
    console.log(`${time} ${key}: ${value}`);
  }

  console.log('');
  await setTimeout(500);

  for (let i = 0; i < num; i++) {
    await setTimeout(100);
    const key = `key_${i}`;
    const value = cache.get(key);
    const time = (new Date()).getTime();
    console.log(`${time} ${key}: ${value}`);
  }
  
  return 0;
}

async function main() {
  let errs = 0;
  errs += await test_set();
  
  return 0;
}

main();

■実行結果
1708956725261 key_0: value_0
1708956725262 key_1: value_1
1708956725262 key_2: value_2
1708956725262 key_3: value_3
1708956725262 key_4: value_4
1708956725262 key_5: value_5
1708956725262 key_6: value_6
1708956725262 key_7: value_7
1708956725262 key_8: value_8
1708956725262 key_9: value_9

1708956725870 key_0: undefined
1708956725973 key_1: undefined
1708956726076 key_2: value_2
1708956726179 key_3: value_3
1708956726280 key_4: undefined
1708956726384 key_5: undefined
1708956726492 key_6: undefined
1708956726595 key_7: undefined
1708956726699 key_8: undefined
1708956726806 key_9: undefined


この記事についてブログを書く
« TypeScript でシンプルなキャ... | トップ | python で svg を png に変換 »

Node.js」カテゴリの最新記事