mirror of
https://github.com/gnosygnu/xowa.git
synced 2026-03-02 03:49:30 +00:00
Mass_parse: Change page_cache to LRU cache [#483]
This commit is contained in:
117
400_xowa/src/gplx/core/lists/caches/Lru_cache.java
Normal file
117
400_xowa/src/gplx/core/lists/caches/Lru_cache.java
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
|
||||
You may use XOWA according to either of these licenses as is most appropriate
|
||||
for your project on a case-by-case basis.
|
||||
|
||||
The terms of each license can be found in the source code repository:
|
||||
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.core.lists.caches; import gplx.*; import gplx.core.*; import gplx.core.lists.*;
|
||||
public class Lru_cache {
|
||||
private final Hash_adp map = Hash_adp_.New();
|
||||
private long max;
|
||||
private long cur = 0;
|
||||
private Lru_node head;
|
||||
private Lru_node tail;
|
||||
private long evicts;
|
||||
public void Max_(long max) {
|
||||
this.max = max;
|
||||
}
|
||||
public long Evicts() {return evicts;}
|
||||
public long Cur() {return cur;}
|
||||
public Object Get_or_null(Object key) {
|
||||
Lru_node nde = (Lru_node)map.Get_by(key);
|
||||
if (nde == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Del_node_from_linked_list(nde);
|
||||
Add_to_tail(nde);
|
||||
|
||||
return nde.Val();
|
||||
}
|
||||
public void Set(Object key, Object val, long size) {
|
||||
Lru_node nde = (Lru_node)map.Get_by(key);
|
||||
if (nde != null) {
|
||||
nde.Val_(val);
|
||||
|
||||
Del_node_from_linked_list(nde);
|
||||
Add_to_tail(nde);
|
||||
}
|
||||
else {
|
||||
while (cur + size > max) {
|
||||
Del_node_from_this(head);
|
||||
evicts++;
|
||||
}
|
||||
|
||||
nde = new Lru_node(key, val, size);
|
||||
Add_to_tail(nde);
|
||||
map.Add(key, nde);
|
||||
cur += size;
|
||||
}
|
||||
}
|
||||
public void Del(Object key) {
|
||||
Lru_node nde = (Lru_node)map.Get_by(key);
|
||||
if (nde != null) {
|
||||
Del_node_from_this(nde);
|
||||
}
|
||||
}
|
||||
public void Clear() {
|
||||
map.Clear();
|
||||
head = null;
|
||||
tail = null;
|
||||
cur = 0;
|
||||
}
|
||||
private void Del_node_from_this(Lru_node nde) {
|
||||
map.Del(nde.Key());
|
||||
cur -= nde.Size();
|
||||
Del_node_from_linked_list(nde);
|
||||
}
|
||||
private void Del_node_from_linked_list(Lru_node nde) {
|
||||
if (nde.Prv() == null)
|
||||
head = nde.Nxt();
|
||||
else
|
||||
nde.Prv().Nxt_(nde.Nxt());
|
||||
|
||||
if (nde.Nxt() == null)
|
||||
tail = nde.Prv();
|
||||
else
|
||||
nde.Nxt().Prv_(nde.Prv());
|
||||
}
|
||||
private void Add_to_tail(Lru_node nde) {
|
||||
if (tail != null)
|
||||
tail.Nxt_(nde);
|
||||
|
||||
nde.Prv_(tail);
|
||||
nde.Nxt_(null);
|
||||
tail = nde;
|
||||
|
||||
if (head == null)
|
||||
head = tail;
|
||||
}
|
||||
}
|
||||
class Lru_node {
|
||||
private final Object key;
|
||||
private Object val;
|
||||
private final long size;
|
||||
private Lru_node prv;
|
||||
private Lru_node nxt;
|
||||
|
||||
public Lru_node(Object key, Object val, long size) {
|
||||
this.key = key;
|
||||
this.val = val;
|
||||
this.size = size;
|
||||
}
|
||||
public Object Key() {return key;}
|
||||
public Object Val() {return val;} public void Val_(Object v) {this.val = v;}
|
||||
public long Size() {return size;}
|
||||
public Lru_node Prv() {return prv;} public void Prv_(Lru_node v) {this.prv = v;}
|
||||
public Lru_node Nxt() {return nxt;} public void Nxt_(Lru_node v) {this.nxt = v;}
|
||||
}
|
||||
116
400_xowa/src/gplx/core/lists/caches/Lru_cache_tst.java
Normal file
116
400_xowa/src/gplx/core/lists/caches/Lru_cache_tst.java
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
|
||||
You may use XOWA according to either of these licenses as is most appropriate
|
||||
for your project on a case-by-case basis.
|
||||
|
||||
The terms of each license can be found in the source code repository:
|
||||
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.core.lists.caches; import gplx.*; import gplx.core.*; import gplx.core.lists.*;
|
||||
import org.junit.*; import gplx.core.tests.*;
|
||||
import gplx.xowa.wikis.data.tbls.*; import gplx.xowa.wikis.nss.*;
|
||||
public class Lru_cache_tst {
|
||||
private final Lru_cache_fxt fxt = new Lru_cache_fxt();
|
||||
@Test public void Get_one() {
|
||||
fxt.Init__max(10);
|
||||
fxt.Exec__set("a", 5);
|
||||
fxt.Test__get_y("a");
|
||||
}
|
||||
@Test public void Pop_one() {
|
||||
fxt.Init__max(10);
|
||||
fxt.Exec__set("a", 10);
|
||||
fxt.Exec__set("b", 10);
|
||||
fxt.Test__get_n("a");
|
||||
fxt.Test__get_y("b");
|
||||
}
|
||||
@Test public void Add_many() {
|
||||
fxt.Init__max(10);
|
||||
fxt.Exec__set("a", 4);
|
||||
fxt.Exec__set("b", 3);
|
||||
fxt.Exec__set("c", 2);
|
||||
fxt.Exec__set("d", 1);
|
||||
fxt.Test__get_y("a", "b", "c", "d");
|
||||
}
|
||||
@Test public void Pop_many() {
|
||||
fxt.Init__max(10);
|
||||
fxt.Exec__set("a", 4);
|
||||
fxt.Exec__set("b", 3);
|
||||
fxt.Exec__set("c", 2);
|
||||
fxt.Exec__set("d", 1);
|
||||
fxt.Exec__set("e", 6);
|
||||
fxt.Test__get_y("c", "d", "e");
|
||||
fxt.Test__get_n("a", "b");
|
||||
}
|
||||
@Test public void Set_repeatedly() {
|
||||
fxt.Init__max(10);
|
||||
fxt.Exec__set("a", "a1", 10);
|
||||
fxt.Exec__set("a", "a2", 10);
|
||||
fxt.Exec__set("a", "a3", 10);
|
||||
fxt.Test__get_val("a", "a3");
|
||||
}
|
||||
@Test public void Set_bumps_priority() {
|
||||
fxt.Init__max(10);
|
||||
fxt.Exec__set("a", 2);
|
||||
fxt.Exec__set("b", 3);
|
||||
fxt.Exec__set("c", 2);
|
||||
fxt.Exec__set("a", 2);
|
||||
fxt.Exec__set("d", 7);
|
||||
fxt.Test__get_y("a", "d");
|
||||
fxt.Test__get_n("b", "c");
|
||||
}
|
||||
@Test public void Del() {
|
||||
fxt.Init__max(10);
|
||||
fxt.Exec__set("a", 2);
|
||||
fxt.Exec__set("b", 2);
|
||||
fxt.Exec__del("b");
|
||||
fxt.Test__get_y("a");
|
||||
fxt.Test__get_n("b");
|
||||
}
|
||||
@Test public void Clear() {
|
||||
fxt.Init__max(10);
|
||||
fxt.Exec__set("a", 2);
|
||||
fxt.Exec__set("b", 2);
|
||||
fxt.Exec__clear();
|
||||
fxt.Test__get_n("a", "b");
|
||||
}
|
||||
}
|
||||
class Lru_cache_fxt {
|
||||
private final Lru_cache cache = new Lru_cache();
|
||||
public void Init__max(long max) {
|
||||
cache.Max_(max);
|
||||
}
|
||||
public void Exec__set(String key, long size) {
|
||||
cache.Set(key, key, size);
|
||||
}
|
||||
public void Exec__set(String key, String val, long size) {
|
||||
cache.Set(key, val, size);
|
||||
}
|
||||
public void Exec__del(String key) {
|
||||
cache.Del(key);
|
||||
}
|
||||
public void Exec__clear() {
|
||||
cache.Clear();
|
||||
}
|
||||
public void Test__get_y(String... keys) {
|
||||
for (String key : keys)
|
||||
Test__get(key, key);
|
||||
}
|
||||
public void Test__get_n(String... keys) {
|
||||
for (String key : keys)
|
||||
Test__get(key, null);
|
||||
}
|
||||
public void Test__get_val(String key, String val) {
|
||||
Test__get(key, val);
|
||||
}
|
||||
private void Test__get(String key, String expd) {
|
||||
Object actl = cache.Get_or_null(key);
|
||||
Gftest.Eq__obj_or_null(expd, actl);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user