Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
2895f2b5
提交
2895f2b5
authored
10月 23, 2012
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
LIRS cache: use a better secondary hash function.
上级
e8500c3d
隐藏空白字符变更
内嵌
并排
正在显示
3 个修改的文件
包含
829 行增加
和
168 行删除
+829
-168
CalculateHashConstant.java
h2/src/test/org/h2/test/store/CalculateHashConstant.java
+526
-0
CacheLIRS.java
h2/src/tools/org/h2/dev/store/cache/CacheLIRS.java
+141
-84
CacheLongKeyLIRS.java
h2/src/tools/org/h2/dev/store/cache/CacheLongKeyLIRS.java
+162
-84
没有找到文件。
h2/src/test/org/h2/test/store/CalculateHashConstant.java
0 → 100644
浏览文件 @
2895f2b5
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
test
.
store
;
import
java.io.File
;
import
java.io.FileOutputStream
;
import
java.math.BigInteger
;
import
java.util.Arrays
;
import
java.util.BitSet
;
import
java.util.Collections
;
import
java.util.HashSet
;
import
java.util.Random
;
import
java.util.Set
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
org.h2.security.AES
;
/**
* Calculate the constant for the secondary hash function, so that the hash
* function mixes the input bits as much as possible.
*/
public
class
CalculateHashConstant
implements
Runnable
{
private
static
BitSet
primeNumbers
=
new
BitSet
();
private
static
int
[]
randomValues
;
private
static
AtomicInteger
high
=
new
AtomicInteger
(
0x20
);
private
static
Set
<
Integer
>
candidates
=
Collections
.
synchronizedSet
(
new
HashSet
<
Integer
>());
private
int
constant
;
private
int
[]
fromTo
=
new
int
[
32
*
32
];
private
AES
aes
=
new
AES
();
{
aes
.
setKey
(
"Hello Welt Hallo Welt"
.
getBytes
());
}
private
byte
[]
data
=
new
byte
[
16
];
/**
* Run just this test.
*
* @param args ignored
*/
public
static
void
main
(
String
...
args
)
throws
Exception
{
for
(
int
i
=
0x0
;
i
<
0x10000
;
i
++)
{
if
(
BigInteger
.
valueOf
(
i
).
isProbablePrime
(
20
))
{
primeNumbers
.
set
(
i
);
}
}
randomValues
=
getRandomValues
(
1000
,
1
);
Random
r
=
new
Random
(
1
);
for
(
int
i
=
0
;
i
<
randomValues
.
length
;
i
++)
{
randomValues
[
i
]
=
r
.
nextInt
();
}
Thread
[]
threads
=
new
Thread
[
8
];
for
(
int
i
=
0
;
i
<
8
;
i
++)
{
threads
[
i
]
=
new
Thread
(
new
CalculateHashConstant
());
threads
[
i
].
start
();
}
for
(
int
i
=
0
;
i
<
8
;
i
++)
{
threads
[
i
].
join
();
}
int
finalCount
=
10000
;
int
[]
randomValues
=
getRandomValues
(
finalCount
,
10
);
System
.
out
.
println
();
System
.
out
.
println
(
"AES:"
);
CalculateHashConstant
test
=
new
CalculateHashConstant
();
int
[]
minMax
;
int
av
=
0
;
test
=
new
CalculateHashConstant
()
{
public
int
hash
(
int
x
)
{
return
secureHash
(
x
);
}
};
minMax
=
test
.
getDependencies
(
test
,
randomValues
);
System
.
out
.
println
(
"Dependencies: "
+
minMax
[
0
]
+
".."
+
minMax
[
1
]);
av
=
0
;
for
(
int
j
=
0
;
j
<
100
;
j
++)
{
av
+=
test
.
getAvalanche
(
test
,
randomValues
[
j
]);
}
System
.
out
.
println
(
"AvalancheSum: "
+
av
);
minMax
=
test
.
getEffect
(
test
,
finalCount
*
10
,
11
);
System
.
out
.
println
(
"Effect: "
+
minMax
[
0
]
+
".."
+
minMax
[
1
]);
test
=
new
CalculateHashConstant
();
int
best
=
0
;
int
dist
=
Integer
.
MAX_VALUE
;
for
(
int
i
:
new
int
[]
{
0x10b5383
,
0x10b65f3
,
0x1170d8b
,
0x118e97b
,
0x1190d8b
,
0x11ab37d
,
0x11c65f3
,
0x1228357
,
0x122a837
,
0x122a907
,
0x12b24f7
,
0x12c4d05
,
0x131a907
,
0x131afa3
,
0x131b683
,
0x132927d
,
0x13298fb
,
0x134a837
,
0x13698fb
,
0x136afa3
,
0x138da0b
,
0x138f563
,
0x13957c5
,
0x1470b1b
,
0x148e97b
,
0x14b5827
,
0x150a837
,
0x151c97d
,
0x151ed3d
,
0x1525707
,
0x1534b07
,
0x1570b9b
,
0x158d283
,
0x15933eb
,
0x15947cb
,
0x15b5f33
,
0x166da7d
,
0x16af4a3
,
0x16b0b47
,
0x16ca907
,
0x16ee585
,
0x17609a3
,
0x1770b23
,
0x17a2507
,
0x1855383
,
0x18b5383
,
0x18d9f3b
,
0x18db37d
,
0x1922507
,
0x1960d3d
,
0x1990d4f
,
0x1991a7b
,
0x19b4b07
,
0x19b5383
,
0x19d9f3b
,
0x1a2b683
,
0x1a40d8b
,
0x1a4b08d
,
0x1a698fb
,
0x1a6cf9b
,
0x1a714bd
,
0x1a89283
,
0x1aa86c3
,
0x1b14e0b
,
0x1b196fb
,
0x1b1f2bd
,
0x1b30b1b
,
0x1b32507
,
0x1b44f75
,
0x1b50ce3
,
0x1b5927d
,
0x1b6afa3
,
0x1b8a6f7
,
0x1baa907
,
0x1bb2507
,
0x1c2a6f7
,
0x1c48357
,
0x1c957c5
,
0x1cb8357
,
0x1cc4d05
,
0x1cd9283
,
0x1ce2683
,
0x1d198fb
,
0x1d45383
,
0x1d4ed3d
,
0x1d598fb
,
0x1d8d283
,
0x1d95f3b
,
0x1db24f7
,
0x1db5383
,
0x1db997d
,
0x1e465f3
,
0x1f198fb
,
0x1f2b683
,
0x1f4a837
,
0x20998fb
,
0x20eb683
,
0x214a907
,
0x2152ec3
,
0x2169f3b
,
0x216ed3d
,
0x218a6f7
,
0x2194b07
,
0x21c5707
,
0x22158f9
,
0x2250d4f
,
0x2252507
,
0x2297d63
,
0x22aed3d
,
0x22b5383
,
0x22ca7d7
,
0x23596fb
,
0x23633eb
,
0x23957c5
,
0x23b24f7
,
0x2476e7b
,
0x24a57c5
,
0x24b5383
,
0x252ebb7
,
0x254f547
,
0x258d283
,
0x2595707
,
0x25957c5
,
0x25c5707
,
0x262a837
,
0x2638357
,
0x2645827
,
0x265f2bd
,
0x266f2bd
,
0x268a6f7
,
0x26a0b23
,
0x26cce7b
,
0x2730b47
,
0x2750b23
,
0x275b683
,
0x28465f3
,
0x2850d4f
,
0x28d0b47
,
0x291c97d
,
0x2922507
,
0x2941a7b
,
0x294a907
,
0x294b683
,
0x295f2bd
,
0x2969f3b
,
0x296cfb5
,
0x2976e7b
,
0x2989f3b
,
0x29933eb
,
0x29a907
,
0x29b2683
,
0x29c8357
,
0x29d9f3b
,
0x2a1a907
,
0x2a45383
,
0x2a52f75
,
0x2a85383
,
0x2aacf9b
,
0x2ac5f33
,
0x2ad1a7b
,
0x2ad2507
,
0x2b2b683
,
0x2b3af8b
,
0x2b63e65
,
0x2b8da0b
,
0x2b9416b
,
0x2bb24f7
,
0x2c4b37d
,
0x2c6cf9b
,
0x2ca0d13
,
0x2cb2507
,
0x2cb2983
,
0x2cce97b
,
0x2ce305b
,
0x2ceb683
,
0x2d14e0b
,
0x2d1a7b
,
0x2d2507
,
0x2d2af8b
,
0x2d41a7b
,
0x2d7467b
,
0x2d8d283
,
0x2d960bb
,
0x2dab683
,
0x2db5f33
,
0x2dd5f3b
,
0x2e2ebb7
,
0x2e32e85
,
0x2e6a7c9
,
0x2e85383
,
0x2e8e585
,
0x2e960bb
,
0x2f3afa3
,
0x2f62fa5
,
0x30e8639
,
0x3132983
,
0x3150d4f
,
0x315cf9b
,
0x3162fa5
,
0x316ce7b
,
0x31914bd
,
0x31a927d
,
0x31ea83b
,
0x31f1a7b
,
0x3285383
,
0x3289f3b
,
0x32933eb
,
0x329afa3
,
0x32a5707
,
0x32a6f7
,
0x32ae585
,
0x32b1a7b
,
0x32b4b07
,
0x32b5383
,
0x32b5827
,
0x32ee97b
,
0x330be5b
,
0x3314e0b
,
0x33317a5
,
0x333af8b
,
0x335afa3
,
0x335b37d
,
0x3371a7b
,
0x3393e65
,
0x339a907
,
0x33d1a7b
,
0x3425707
,
0x34606d3
,
0x347b37d
,
0x349305b
,
0x34b2683
,
0x34b683
,
0x34dafa3
,
0x34ec97d
,
0x3512683
,
0x3515383
,
0x3515707
,
0x352e585
,
0x353af75
,
0x354b683
,
0x355ed3d
,
0x3562fa5
,
0x356f2bd
,
0x3574135
,
0x359afa3
,
0x35ad283
,
0x35b2683
,
0x35d9f3b
,
0x361ed3d
,
0x3671a7b
,
0x3672fa5
,
0x36cbe5b
,
0x37598fb
,
0x375c97d
,
0x37ca907
,
0x389a907
,
0x38c65f3
,
0x38cf547
,
0x38e33eb
,
0x3931a7b
,
0x39598fb
,
0x3979283
,
0x398ce7b
,
0x39933eb
,
0x39960bb
,
0x39b1a87
,
0x39b5f33
,
0x39c8333
,
0x39d2507
,
0x3a55827
,
0x3a89f3b
,
0x3a9f2bd
,
0x3ab2983
,
0x3aba7d7
,
0x3adafa3
,
0x3b196fb
,
0x3b29f3b
,
0x3b32e85
,
0x3b4e97b
,
0x3b9260b
,
0x3bb5383
,
0x3c4a907
,
0x3c4c97d
,
0x3c6cf9b
,
0x3c95707
,
0x3ca57c5
,
0x3caa907
,
0x3cb2683
,
0x3cb2983
,
0x3ce305b
,
0x3d158f9
,
0x3d15f65
,
0x3d2c685
,
0x3d34b07
,
0x3d76e7b
,
0x3d8d283
,
0x3d8f563
,
0x3dae585
,
0x3dd60bb
,
0x3e5c97d
,
0x3eb2683
,
0x3eb467b
,
0x3f5927d
,
0x3f596fb
,
0x414e585
,
0x424b37d
,
0x425afa3
,
0x42e5383
,
0x4315f65
,
0x4325707
,
0x434b683
,
0x4485383
,
0x448e97b
,
0x44996fb
,
0x44b3e65
,
0x44eafa3
,
0x4515707
,
0x4532983
,
0x4533e65
,
0x453e585
,
0x454b683
,
0x454e97b
,
0x45598fb
,
0x455a907
,
0x456f2bd
,
0x4595f3b
,
0x45d9f3b
,
0x461a907
,
0x462a837
,
0x4645827
,
0x46a2fa5
,
0x46aa213
,
0x46acf9b
,
0x46b2507
,
0x46ba837
,
0x4715707
,
0x472f547
,
0x475c97d
,
0x4799283
,
0x47a0d3d
,
0x47ca907
,
0x482a907
,
0x4835707
,
0x4844b07
,
0x48933eb
,
0x48ab683
,
0x48b5827
,
0x491d0e7
,
0x4922507
,
0x4929f3b
,
0x492e97b
,
0x4933eb
,
0x4934b07
,
0x49598fb
,
0x495f2bd
,
0x4962fa5
,
0x496b683
,
0x499da7d
,
0x499ed3d
,
0x49ab683
,
0x4a2f547
,
0x4a32e85
,
0x4a5f2bd
,
0x4a696fb
,
0x4aacf9b
,
0x4ab5383
,
0x4aba837
,
0x4aeb683
,
0x4aeda7d
,
0x4b0f69b
,
0x4b12fa5
,
0x4b13e65
,
0x4b5a907
,
0x4b5afa3
,
0x4b8afa3
,
0x4b8e585
,
0x4b8f58d
,
0x4ba5707
,
0x4bc5707
,
0x4c2a837
,
0x4c5b37d
,
0x4c5ed3d
,
0x4c67d8d
,
0x4c8f58d
,
0x4c933eb
,
0x4caec5d
,
0x4cd17a5
,
0x4ce305b
,
0x4cf179b
,
0x4cfc979
,
0x4d0be5b
,
0x4d1ed3d
,
0x4d2507
,
0x4d30d8b
,
0x4d32983
,
0x4d40ae5
,
0x4d40d8b
,
0x4d4f697
,
0x4d8e97b
,
0x4d9f2bd
,
0x4da0d3d
,
0x4dce585
,
0x4dd1a7b
,
0x4df467b
,
0x4e25707
,
0x4e4c97d
,
0x4e63833
,
0x4eb1a7b
,
0x4eb2683
,
0x4eb683
,
0x4ece97b
,
0x4eee585
,
0x4f13e65
,
0x4f6afa3
,
0x504b37d
,
0x50e2683
,
0x50eb683
,
0x5132e85
,
0x514b08d
,
0x516e97b
,
0x5198fb
,
0x519f2bd
,
0x51ab37d
,
0x51b2683
,
0x522a837
,
0x5232983
,
0x52465f3
,
0x52660bb
,
0x528b3ed
,
0x5294193
,
0x5294e0b
,
0x52a57c5
,
0x52eaf8b
,
0x52eda7d
,
0x52ee585
,
0x530be93
,
0x5314e0b
,
0x532e97b
,
0x5340b1b
,
0x535279d
,
0x53598fb
,
0x5429283
,
0x54a0b23
,
0x54b24f7
,
0x54d17a5
,
0x54eb683
,
0x55198fb
,
0x5523e65
,
0x55357c5
,
0x553e585
,
0x555cf9b
,
0x55a24f7
,
0x55d2507
,
0x55eda7d
,
0x5645f33
,
0x567ecdd
,
0x56a0d3d
,
0x571305b
,
0x5714e0b
,
0x574a837
,
0x57a5707
,
0x57b65f3
,
0x57c65f3
,
0x5879283
,
0x58ba837
,
0x58ded3d
,
0x59598fb
,
0x5989f3b
,
0x598a83b
,
0x59957c5
,
0x599f2bd
,
0x59bd37b
,
0x59ca907
,
0x59d9f3b
,
0x59e60bb
,
0x5a4b37d
,
0x5a64133
,
0x5a6cf9b
,
0x5a89f3b
,
0x5a927d
,
0x5a94165
,
0x5a94193
,
0x5a958f9
,
0x5a960bb
,
0x5aac3d3
,
0x5ad98fb
,
0x5ae98fb
,
0x5b198fb
,
0x5b2e97b
,
0x5b40b5d
,
0x5b5c97d
,
0x5b75f33
,
0x5b8afa3
,
0x5b94e0b
,
0x5ba24f7
,
0x5cab683
,
0x5cb0b47
,
0x5cb0ce5
,
0x5cba7d7
,
0x5d0be93
,
0x5d12683
,
0x5d20cc7
,
0x5d3e585
,
0x5e2a907
,
0x5e3467b
,
0x5e5c97d
,
0x5e89f3b
,
0x5eb2683
,
0x5f598fb
,
0x5f5a907
,
0x676e7b
,
0x695705
,
0x6b2983
,
0x8998fb
,
0x8ab683
,
0x94a837
,
0x95f2bd
,
0x991a7b
,
0x995705
,
0xa714bd
,
0xa90a63
,
0xa933eb
,
0xad98fb
,
0xb365f3
,
0xb4a907
,
0xb598fb
,
0xb5c97d
,
0xb5ed3d
,
0xb698fb
,
0xbd279d
,
0xc55383
,
0xc7b37d
,
0xc8da0b
,
0xca0b23
,
0xca96fb
,
0xcacf9b
,
0xcb2683
,
0xcd1a7b
,
0xd45383
,
0xd4e585
,
0xd6afa3
,
0xd94e0b
,
0xdaf547
,
0xdb1a7b
,
0xdca907
,
0xdd2e85
,
0xe6da7d
,
0xe94e0b
,
0xe9a907
,
0xeca7d7
,
0xf4a837
})
{
// for(int i : candidates) {
test
.
constant
=
i
;
System
.
out
.
println
();
System
.
out
.
println
(
"Constant: 0x"
+
Integer
.
toHexString
(
i
));
minMax
=
test
.
getDependencies
(
test
,
randomValues
);
System
.
out
.
println
(
"Dependencies: "
+
minMax
[
0
]
+
".."
+
minMax
[
1
]);
int
d
=
minMax
[
1
]
-
minMax
[
0
];
av
=
0
;
for
(
int
j
=
0
;
j
<
100
;
j
++)
{
av
+=
test
.
getAvalanche
(
test
,
randomValues
[
j
]);
}
System
.
out
.
println
(
"AvalancheSum: "
+
av
);
minMax
=
test
.
getEffect
(
test
,
finalCount
*
10
,
11
);
System
.
out
.
println
(
"Effect: "
+
minMax
[
0
]
+
".."
+
minMax
[
1
]);
d
+=
minMax
[
1
]
-
minMax
[
0
];
if
(
d
<
dist
)
{
dist
=
d
;
best
=
i
;
}
}
System
.
out
.
println
();
System
.
out
.
println
(
"Best constant: 0x"
+
Integer
.
toHexString
(
best
));
test
.
constant
=
best
;
long
collisions
=
test
.
getCollisionCount
();
System
.
out
.
println
(
"Collisions: "
+
collisions
);
}
/**
* Store a random file to be analyzed by the Diehard test.
*/
void
storeRandomFile
()
throws
Exception
{
File
f
=
new
File
(
System
.
getProperty
(
"user.home"
)
+
"/temp/rand.txt"
);
FileOutputStream
out
=
new
FileOutputStream
(
f
);
CalculateHashConstant
test
=
new
CalculateHashConstant
();
// Random r = new Random(1);
byte
[]
buff
=
new
byte
[
4
];
// tt.constant = 0x29a907;
for
(
int
i
=
0
;
i
<
10000000
/
8
;
i
++)
{
int
y
=
test
.
hash
(
i
);
// int y = r.nextInt();
writeInt
(
buff
,
0
,
y
);
out
.
write
(
buff
);
}
out
.
close
();
}
private
static
int
[]
getRandomValues
(
int
count
,
int
seed
)
{
int
[]
values
=
new
int
[
count
];
Random
r
=
new
Random
(
seed
);
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
values
[
i
]
=
r
.
nextInt
();
}
return
values
;
}
public
void
run
()
{
while
(
true
)
{
int
currentHigh
=
high
.
getAndIncrement
();
// if (currentHigh > 0x2d) {
if
(
currentHigh
>
0xffff
)
{
break
;
}
System
.
out
.
println
(
"testing "
+
Integer
.
toHexString
(
currentHigh
)
+
"...."
);
addCandidates
(
currentHigh
);
}
}
private
void
addCandidates
(
int
currentHigh
)
{
for
(
int
low
=
0
;
low
<=
0xffff
;
low
++)
{
// the lower 16 bits have to be a prime number
if
(!
primeNumbers
.
get
(
low
))
{
continue
;
}
int
i
=
(
currentHigh
<<
16
)
|
low
;
constant
=
i
;
// after one bit changes in the input,
// on average 16 bits of the output change
int
av
=
getAvalanche
(
this
,
0
);
if
(
Math
.
abs
(
av
-
16000
)
>
130
)
{
continue
;
}
av
=
getAvalanche
(
this
,
0xffffffff
);
if
(
Math
.
abs
(
av
-
16000
)
>
130
)
{
continue
;
}
long
es
=
getEffectSquare
(
this
,
randomValues
);
if
(
es
>
259000
)
{
continue
;
}
int
[]
minMax
=
getEffect
(
this
,
10000
,
1
);
if
(!
isWithin
(
4800
,
5200
,
minMax
))
{
continue
;
}
minMax
=
getDependencies
(
this
,
randomValues
);
// aes: 7788..8183
if
(!
isWithin
(
7720
,
8240
,
minMax
))
{
continue
;
}
minMax
=
getEffect
(
this
,
100000
,
3
);
if
(!
isWithin
(
49000
,
51000
,
minMax
))
{
continue
;
}
System
.
out
.
println
(
Integer
.
toHexString
(
i
)
+
" hit av:"
+
av
+
" bits:"
+
Integer
.
bitCount
(
i
)
+
" es:"
+
es
+
" prime:"
+
BigInteger
.
valueOf
(
i
).
isProbablePrime
(
15
));
candidates
.
add
(
i
);
}
}
long
getCollisionCount
()
{
BitSet
set
=
new
BitSet
();
BitSet
neg
=
new
BitSet
();
long
collisions
=
0
;
long
t
=
System
.
currentTimeMillis
();
for
(
int
i
=
Integer
.
MIN_VALUE
;
i
!=
Integer
.
MAX_VALUE
;
i
++)
{
int
x
=
hash
(
i
);
if
(
x
>=
0
)
{
if
(
set
.
get
(
x
))
{
collisions
++;
}
else
{
set
.
set
(
x
);
}
}
else
{
x
=
-(
x
+
1
);
if
(
neg
.
get
(
x
))
{
collisions
++;
}
else
{
neg
.
set
(
x
);
}
}
if
((
i
&
0xfffff
)
==
0
)
{
long
n
=
System
.
currentTimeMillis
();
if
(
n
-
t
>
5000
)
{
System
.
out
.
println
(
Integer
.
toHexString
(
constant
)
+
" "
+
Integer
.
toHexString
(
i
)
+
" collisions: "
+
collisions
);
t
=
n
;
}
}
}
return
collisions
;
}
private
static
boolean
isWithin
(
int
min
,
int
max
,
int
[]
range
)
{
return
range
[
0
]
>=
min
&&
range
[
1
]
<=
max
;
}
/**
* Calculate how much the bit changes (output bits that change if an input
* bit is changed) are independent of each other.
*
* @param the hash object
* @param values the values to test with
* @return the minimum and maximum number of output bits that are changed in
* combination with another output bit
*/
int
[]
getDependencies
(
CalculateHashConstant
h
,
int
[]
values
)
{
Arrays
.
fill
(
fromTo
,
0
);
for
(
int
x
:
values
)
{
for
(
int
shift
=
0
;
shift
<
32
;
shift
++)
{
int
x1
=
h
.
hash
(
x
);
int
x2
=
h
.
hash
(
x
^
(
1
<<
shift
));
int
x3
=
x1
^
x2
;
for
(
int
s
=
0
;
s
<
32
;
s
++)
{
if
((
x3
&
(
1
<<
s
))
!=
0
)
{
for
(
int
s2
=
0
;
s2
<
32
;
s2
++)
{
if
(
s
==
s2
)
{
continue
;
}
if
((
x3
&
(
1
<<
s2
))
!=
0
)
{
fromTo
[
s
*
32
+
s2
]++;
}
}
}
}
}
}
int
a
=
Integer
.
MAX_VALUE
,
b
=
Integer
.
MIN_VALUE
;
for
(
int
x
:
fromTo
)
{
if
(
x
==
0
)
{
continue
;
}
if
(
x
<
a
)
{
a
=
x
;
}
if
(
x
>
b
)
{
b
=
x
;
}
}
return
new
int
[]
{
a
,
b
};
}
/**
* Calculate the number of bits that change if a single bit is changed
* multiplied by 1000 (expected: 16000 +/- 5%).
*
* @param the hash object
* @param value the base value
* @return the number of bit changes multiplied by 1000
*/
int
getAvalanche
(
CalculateHashConstant
h
,
int
value
)
{
int
changedBitsSum
=
0
;
for
(
int
i
=
0
;
i
<
32
;
i
++)
{
int
x
=
value
^
(
1
<<
i
);
for
(
int
shift
=
0
;
shift
<
32
;
shift
++)
{
int
x1
=
h
.
hash
(
x
);
int
x2
=
h
.
hash
(
x
^
(
1
<<
shift
));
int
x3
=
x1
^
x2
;
changedBitsSum
+=
Integer
.
bitCount
(
x3
);
}
}
return
changedBitsSum
*
1000
/
32
/
32
;
}
/**
* Calculate the sum of the square of the distance to the expected
* probability that an output bit changes if an input bit is changed. The
* lower the value, the better.
*
* @param the hash object
* @param values the values to test with
* @return sum(distance^2)
*/
long
getEffectSquare
(
CalculateHashConstant
h
,
int
[]
values
)
{
Arrays
.
fill
(
fromTo
,
0
);
int
total
=
0
;
for
(
int
x
:
values
)
{
for
(
int
shift
=
0
;
shift
<
32
;
shift
++)
{
int
x1
=
h
.
hash
(
x
);
int
x2
=
h
.
hash
(
x
^
(
1
<<
shift
));
int
x3
=
x1
^
x2
;
for
(
int
s
=
0
;
s
<
32
;
s
++)
{
if
((
x3
&
(
1
<<
s
))
!=
0
)
{
fromTo
[
shift
*
32
+
s
]++;
total
++;
}
}
}
}
long
sqDist
=
0
;
int
expected
=
total
/
32
/
32
;
for
(
int
x
:
fromTo
)
{
int
dist
=
Math
.
abs
(
x
-
expected
);
sqDist
+=
dist
*
dist
;
}
return
sqDist
;
}
/**
* Calculate if the all bit changes (that an output bit changes if an input
* bit is changed) are within a certain range.
*
* @param h the hash object
* @param count the number of values to test
* @param seed the random seed
* @return the minimum and maximum value of all input-to-output bit changes
*/
int
[]
getEffect
(
CalculateHashConstant
h
,
int
count
,
int
seed
)
{
Random
r
=
new
Random
();
r
.
setSeed
(
seed
);
Arrays
.
fill
(
fromTo
,
0
);
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
int
x
=
r
.
nextInt
();
for
(
int
shift
=
0
;
shift
<
32
;
shift
++)
{
int
x1
=
h
.
hash
(
x
);
int
x2
=
h
.
hash
(
x
^
(
1
<<
shift
));
int
x3
=
x1
^
x2
;
for
(
int
s
=
0
;
s
<
32
;
s
++)
{
if
((
x3
&
(
1
<<
s
))
!=
0
)
{
fromTo
[
shift
*
32
+
s
]++;
}
}
}
}
int
a
=
Integer
.
MAX_VALUE
,
b
=
Integer
.
MIN_VALUE
;
for
(
int
x
:
fromTo
)
{
if
(
x
<
a
)
{
a
=
x
;
}
if
(
x
>
b
)
{
b
=
x
;
}
}
return
new
int
[]
{
a
,
b
};
}
/**
* The hash method.
*
* @param x the input
* @return the output
*/
int
hash
(
int
x
)
{
// return secureHash(x);
x
=
((
x
>>>
16
)
^
x
)
*
constant
;
x
=
((
x
>>>
16
)
^
x
)
*
constant
;
x
=
(
x
>>>
16
)
^
x
;
return
x
;
}
/**
* Calculate a hash using AES.
*
* @param x the input
* @return the output
*/
int
secureHash
(
int
x
)
{
Arrays
.
fill
(
data
,
(
byte
)
0
);
writeInt
(
data
,
0
,
x
);
aes
.
encrypt
(
data
,
0
,
16
);
return
readInt
(
data
,
0
);
}
private
static
void
writeInt
(
byte
[]
buff
,
int
pos
,
int
x
)
{
buff
[
pos
++]
=
(
byte
)
(
x
>>
24
);
buff
[
pos
++]
=
(
byte
)
(
x
>>
16
);
buff
[
pos
++]
=
(
byte
)
(
x
>>
8
);
buff
[
pos
++]
=
(
byte
)
x
;
}
private
static
int
readInt
(
byte
[]
buff
,
int
pos
)
{
return
(
buff
[
pos
++]
<<
24
)
+
((
buff
[
pos
++]
&
0xff
)
<<
16
)
+
((
buff
[
pos
++]
&
0xff
)
<<
8
)
+
(
buff
[
pos
]
&
0xff
);
}
}
h2/src/tools/org/h2/dev/store/cache/CacheLIRS.java
浏览文件 @
2895f2b5
/*
/*
* Copyright 2004-201
2
H2 Group. Multiple-Licensed under the H2 License,
* Copyright 2004-201
1
H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
* Initial Developer: H2 Group
...
@@ -55,13 +55,14 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -55,13 +55,14 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
*/
*/
private
int
averageMemory
;
private
int
averageMemory
;
private
Segment
<
K
,
V
>[]
segments
;
private
final
Segment
<
K
,
V
>[]
segments
;
private
int
segmentCount
;
private
final
int
segmentCount
;
private
int
segmentShift
;
private
final
int
segmentShift
;
private
int
segmentMask
;
private
final
int
segmentMask
;
private
final
int
stackMoveDistance
;
private
final
int
stackMoveDistance
;
@SuppressWarnings
(
"unchecked"
)
private
CacheLIRS
(
long
maxMemory
,
int
averageMemory
,
int
segmentCount
,
int
stackMoveDistance
)
{
private
CacheLIRS
(
long
maxMemory
,
int
averageMemory
,
int
segmentCount
,
int
stackMoveDistance
)
{
setMaxMemory
(
maxMemory
);
setMaxMemory
(
maxMemory
);
setAverageMemory
(
averageMemory
);
setAverageMemory
(
averageMemory
);
...
@@ -69,20 +70,22 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -69,20 +70,22 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
throw
new
IllegalArgumentException
(
"The segment count must be a power of 2, is "
+
segmentCount
);
throw
new
IllegalArgumentException
(
"The segment count must be a power of 2, is "
+
segmentCount
);
}
}
this
.
segmentCount
=
segmentCount
;
this
.
segmentCount
=
segmentCount
;
this
.
segmentMask
=
segmentCount
-
1
;
this
.
stackMoveDistance
=
stackMoveDistance
;
this
.
stackMoveDistance
=
stackMoveDistance
;
segments
=
new
Segment
[
segmentCount
];
clear
();
clear
();
this
.
segmentShift
=
Integer
.
numberOfTrailingZeros
(
segments
[
0
].
entries
.
length
);
}
}
@SuppressWarnings
(
"unchecked"
)
/**
* Remove all entries.
*/
public
void
clear
()
{
public
void
clear
()
{
segmentMask
=
segmentCount
-
1
;
long
max
=
Math
.
max
(
1
,
maxMemory
/
segmentCount
);
segments
=
new
Segment
[
segmentCount
];
for
(
int
i
=
0
;
i
<
segmentCount
;
i
++)
{
for
(
int
i
=
0
;
i
<
segmentCount
;
i
++)
{
long
max
=
Math
.
max
(
1
,
maxMemory
/
segmentCount
);
segments
[
i
]
=
new
Segment
<
K
,
V
>(
segments
[
i
]
=
new
Segment
<
K
,
V
>(
max
,
averageMemory
,
stackMoveDistance
);
max
,
averageMemory
,
stackMoveDistance
);
}
}
segmentShift
=
Integer
.
numberOfTrailingZeros
(
segments
[
0
].
sizeMapArray
());
}
}
private
Entry
<
K
,
V
>
find
(
Object
key
)
{
private
Entry
<
K
,
V
>
find
(
Object
key
)
{
...
@@ -91,8 +94,8 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -91,8 +94,8 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
}
}
/**
/**
* Check whether there is a resident entry for the given key. This
method
* Check whether there is a resident entry for the given key. This
* does not adjust the internal state of the cache.
*
method
does not adjust the internal state of the cache.
*
*
* @param key the key (may not be null)
* @param key the key (may not be null)
* @return true if there is a resident entry
* @return true if there is a resident entry
...
@@ -115,14 +118,14 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -115,14 +118,14 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
}
}
/**
/**
* Add an entry to the cache. The entry may or may not exist in the
cache
* Add an entry to the cache. The entry may or may not exist in the
*
yet. This method will usually mark unknown entries as cold and known
*
cache yet. This method will usually mark unknown entries as cold and
* entries as hot.
*
known
entries as hot.
*
*
* @param key the key (may not be null)
* @param key the key (may not be null)
* @param value the value (may not be null)
* @param value the value (may not be null)
* @param memory the memory used for the given entry
* @param memory the memory used for the given entry
* @return the old value, or null if there
i
s no resident entry
* @return the old value, or null if there
wa
s no resident entry
*/
*/
public
V
put
(
K
key
,
V
value
,
int
memory
)
{
public
V
put
(
K
key
,
V
value
,
int
memory
)
{
int
hash
=
getHash
(
key
);
int
hash
=
getHash
(
key
);
...
@@ -134,17 +137,18 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -134,17 +137,18 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
*
*
* @param key the key (may not be null)
* @param key the key (may not be null)
* @param value the value (may not be null)
* @param value the value (may not be null)
* @return the old value, or null if there
i
s no resident entry
* @return the old value, or null if there
wa
s no resident entry
*/
*/
public
V
put
(
K
key
,
V
value
)
{
public
V
put
(
K
key
,
V
value
)
{
return
put
(
key
,
value
,
averageMemory
);
return
put
(
key
,
value
,
averageMemory
);
}
}
/**
/**
* Remove an entry. Both resident and non-resident entries can be removed.
* Remove an entry. Both resident and non-resident entries can be
* removed.
*
*
* @param key the key (may not be null)
* @param key the key (may not be null)
* @return the old value, or null if there
i
s no resident entry
* @return the old value, or null if there
wa
s no resident entry
*/
*/
public
synchronized
V
remove
(
Object
key
)
{
public
synchronized
V
remove
(
Object
key
)
{
int
hash
=
getHash
(
key
);
int
hash
=
getHash
(
key
);
...
@@ -164,8 +168,8 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -164,8 +168,8 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
/**
/**
* Get the value for the given key if the entry is cached. This method
* Get the value for the given key if the entry is cached. This method
* adjusts the internal state of the cache
, to ensure commonly used entries
* adjusts the internal state of the cache
sometimes, to ensure commonly
* stay in the cache.
*
used entries
stay in the cache.
*
*
* @param key the key (may not be null)
* @param key the key (may not be null)
* @return the value, or null if there is no resident entry
* @return the value, or null if there is no resident entry
...
@@ -180,12 +184,20 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -180,12 +184,20 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
return
segments
[
segmentIndex
];
return
segments
[
segmentIndex
];
}
}
/**
* Get the hash code for the given key. The hash code is
* further enhanced to spread the values more evenly.
*
* @param key the key
* @return the hash code
*/
static
int
getHash
(
Object
key
)
{
static
int
getHash
(
Object
key
)
{
int
hash
=
key
.
hashCode
();
int
hash
=
key
.
hashCode
();
// Doug Lea's supplemental secondaryHash function (inlined)
// a supplemental secondary hash function
// to protect against hash codes that don't differ in low order bits
// to protect against hash codes that don't differ much
hash
^=
(
hash
>>>
20
)
^
(
hash
>>>
12
);
hash
=
((
hash
>>>
16
)
^
hash
)
*
0x45d9f3b
;
hash
^=
(
hash
>>>
7
)
^
(
hash
>>>
4
);
hash
=
((
hash
>>>
16
)
^
hash
)
*
0x45d9f3b
;
hash
=
(
hash
>>>
16
)
^
hash
;
return
hash
;
return
hash
;
}
}
...
@@ -197,15 +209,15 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -197,15 +209,15 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
public
long
getUsedMemory
()
{
public
long
getUsedMemory
()
{
long
x
=
0
;
long
x
=
0
;
for
(
Segment
<
K
,
V
>
s
:
segments
)
{
for
(
Segment
<
K
,
V
>
s
:
segments
)
{
x
+=
s
.
getUsedMemory
()
;
x
+=
s
.
usedMemory
;
}
}
return
x
;
return
x
;
}
}
/**
/**
* Set the maximum memory this cache should use. This will not
immediately
* Set the maximum memory this cache should use. This will not
*
cause entries to get removed however; it will only change the limit. To
*
immediately cause entries to get removed however; it will only change
* resize the internal array, call the clear method.
*
the limit. To
resize the internal array, call the clear method.
*
*
* @param maxMemory the maximum size (1 or larger)
* @param maxMemory the maximum size (1 or larger)
*/
*/
...
@@ -223,8 +235,8 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -223,8 +235,8 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
}
}
/**
/**
* Set the average memory used per entry. It is used to calculate the
length
* Set the average memory used per entry. It is used to calculate the
* of the internal array.
*
length
of the internal array.
*
*
* @param averageMemory the average memory used (1 or larger)
* @param averageMemory the average memory used (1 or larger)
*/
*/
...
@@ -261,7 +273,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -261,7 +273,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
/**
/**
* Create a new cache with the given number of entries, and the default
* Create a new cache with the given number of entries, and the default
* settings (an average size of 1 per entry, 16 segments, and stack move
* settings (an average size of 1 per entry, 16 segments, and stack move
* distance equals to the max
entry size
divided by 100).
* distance equals to the max
imum number of entries
divided by 100).
*
*
* @param maxEntries the maximum number of entries
* @param maxEntries the maximum number of entries
* @return the cache
* @return the cache
...
@@ -319,7 +331,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -319,7 +331,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
public
int
sizeNonResident
()
{
public
int
sizeNonResident
()
{
int
x
=
0
;
int
x
=
0
;
for
(
Segment
<
K
,
V
>
s
:
segments
)
{
for
(
Segment
<
K
,
V
>
s
:
segments
)
{
x
+=
s
.
sizeNonResident
()
;
x
+=
s
.
queue2Size
;
}
}
return
x
;
return
x
;
}
}
...
@@ -332,7 +344,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -332,7 +344,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
public
int
sizeMapArray
()
{
public
int
sizeMapArray
()
{
int
x
=
0
;
int
x
=
0
;
for
(
Segment
<
K
,
V
>
s
:
segments
)
{
for
(
Segment
<
K
,
V
>
s
:
segments
)
{
x
+=
s
.
sizeMapArray
()
;
x
+=
s
.
entries
.
length
;
}
}
return
x
;
return
x
;
}
}
...
@@ -345,7 +357,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -345,7 +357,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
public
int
sizeHot
()
{
public
int
sizeHot
()
{
int
x
=
0
;
int
x
=
0
;
for
(
Segment
<
K
,
V
>
s
:
segments
)
{
for
(
Segment
<
K
,
V
>
s
:
segments
)
{
x
+=
s
.
sizeHot
()
;
x
+=
s
.
mapSize
-
s
.
queueSize
-
s
.
queue2Size
;
}
}
return
x
;
return
x
;
}
}
...
@@ -358,7 +370,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -358,7 +370,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
public
int
size
()
{
public
int
size
()
{
int
x
=
0
;
int
x
=
0
;
for
(
Segment
<
K
,
V
>
s
:
segments
)
{
for
(
Segment
<
K
,
V
>
s
:
segments
)
{
x
+=
s
.
size
()
;
x
+=
s
.
mapSize
-
s
.
queue2Size
;
}
}
return
x
;
return
x
;
}
}
...
@@ -388,56 +400,56 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -388,56 +400,56 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
static
class
Segment
<
K
,
V
>
{
static
class
Segment
<
K
,
V
>
{
/**
/**
* How many other item are to be moved to the top of the stack before
* The number of (hot, cold, and non-resident) entries in the map.
* the current item is moved.
*/
*/
private
final
int
stackMoveDistanc
e
;
int
mapSiz
e
;
/**
/**
* The
maximum memory this cache should use
.
* The
size of the LIRS queue for resident cold entries
.
*/
*/
private
long
maxMemory
;
int
queueSize
;
/**
/**
* The
average memory used by one entry
.
* The
size of the LIRS queue for non-resident cold entries
.
*/
*/
private
int
averageMemory
;
int
queue2Size
;
/**
/**
* The
currently used memory
.
* The
map array. The size is always a power of 2
.
*/
*/
private
long
usedMemory
;
Entry
<
K
,
V
>[]
entries
;
/**
/**
* The
number of (hot, cold, and non-resident) entries in the map
.
* The
currently used memory
.
*/
*/
private
int
mapSize
;
long
usedMemory
;
/**
/**
*
The bit mask that is applied to the key hash code to get the index in th
e
*
How many other item are to be moved to the top of the stack befor
e
*
map array. The mask is the length of the array minus one
.
*
the current item is moved
.
*/
*/
private
int
mask
;
private
final
int
stackMoveDistance
;
/**
/**
* The
LIRS stack siz
e.
* The
maximum memory this cache should us
e.
*/
*/
private
int
stackSize
;
private
long
maxMemory
;
/**
/**
* The
size of the LIRS queue for resident cold entries
.
* The
average memory used by one entry
.
*/
*/
private
int
queueSize
;
private
int
averageMemory
;
/**
/**
* The size of the LIRS queue for non-resident cold entries.
* The bit mask that is applied to the key hash code to get the index in the
* map array. The mask is the length of the array minus one.
*/
*/
private
int
queue2Size
;
private
int
mask
;
/**
/**
* The
map array. The size is always a power of 2
.
* The
LIRS stack size
.
*/
*/
private
Entry
<
K
,
V
>[]
entries
;
private
int
stackSize
;
/**
/**
* The stack of recently referenced elements. This includes all hot entries,
* The stack of recently referenced elements. This includes all hot entries,
...
@@ -475,7 +487,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -475,7 +487,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
clear
();
clear
();
}
}
synchronized
void
clear
()
{
private
void
clear
()
{
// calculate the size of the map array
// calculate the size of the map array
// assume a fill factor of at most 80%
// assume a fill factor of at most 80%
...
@@ -509,16 +521,27 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -509,16 +521,27 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
stackSize
=
queueSize
=
queue2Size
=
0
;
stackSize
=
queueSize
=
queue2Size
=
0
;
}
}
V
peek
(
K
key
,
int
hash
)
{
/**
Entry
<
K
,
V
>
e
=
find
(
key
,
hash
);
* Get the memory used for the given key.
return
e
==
null
?
null
:
e
.
value
;
*
}
* @param key the key (may not be null)
* @param hash the hash
* @return the memory, or 0 if there is no resident entry
*/
int
getMemory
(
K
key
,
int
hash
)
{
int
getMemory
(
K
key
,
int
hash
)
{
Entry
<
K
,
V
>
e
=
find
(
key
,
hash
);
Entry
<
K
,
V
>
e
=
find
(
key
,
hash
);
return
e
==
null
?
0
:
e
.
memory
;
return
e
==
null
?
0
:
e
.
memory
;
}
}
/**
* Get the value for the given key if the entry is cached. This method
* adjusts the internal state of the cache sometimes, to ensure commonly
* used entries stay in the cache.
*
* @param key the key (may not be null)
* @param hash the hash
* @return the value, or null if there is no resident entry
*/
V
get
(
Object
key
,
int
hash
)
{
V
get
(
Object
key
,
int
hash
)
{
Entry
<
K
,
V
>
e
=
find
(
key
,
hash
);
Entry
<
K
,
V
>
e
=
find
(
key
,
hash
);
if
(
e
==
null
)
{
if
(
e
==
null
)
{
...
@@ -586,6 +609,17 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -586,6 +609,17 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
}
}
}
}
/**
* Add an entry to the cache. The entry may or may not exist in the
* cache yet. This method will usually mark unknown entries as cold and
* known entries as hot.
*
* @param key the key (may not be null)
* @param hash the hash
* @param value the value (may not be null)
* @param memory the memory used for the given entry
* @return the old value, or null if there was no resident entry
*/
synchronized
V
put
(
K
key
,
int
hash
,
V
value
,
int
memory
)
{
synchronized
V
put
(
K
key
,
int
hash
,
V
value
,
int
memory
)
{
if
(
value
==
null
)
{
if
(
value
==
null
)
{
throw
new
NullPointerException
();
throw
new
NullPointerException
();
...
@@ -616,6 +650,14 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -616,6 +650,14 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
return
old
;
return
old
;
}
}
/**
* Remove an entry. Both resident and non-resident entries can be
* removed.
*
* @param key the key (may not be null)
* @param hash the hash
* @return the old value, or null if there was no resident entry
*/
synchronized
V
remove
(
Object
key
,
int
hash
)
{
synchronized
V
remove
(
Object
key
,
int
hash
)
{
int
index
=
hash
&
mask
;
int
index
=
hash
&
mask
;
Entry
<
K
,
V
>
e
=
entries
[
index
];
Entry
<
K
,
V
>
e
=
entries
[
index
];
...
@@ -725,6 +767,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -725,6 +767,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
* Try to find an entry in the map.
* Try to find an entry in the map.
*
*
* @param key the key
* @param key the key
* @param hash the hash
* @return the entry (might be a non-resident)
* @return the entry (might be a non-resident)
*/
*/
Entry
<
K
,
V
>
find
(
Object
key
,
int
hash
)
{
Entry
<
K
,
V
>
find
(
Object
key
,
int
hash
)
{
...
@@ -783,6 +826,14 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -783,6 +826,14 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
}
}
}
}
/**
* Get the list of keys. This method allows to read the internal state of
* the cache.
*
* @param cold if true, only keys for the cold entries are returned
* @param nonResident true for non-resident entries
* @return the key list
*/
synchronized
List
<
K
>
keys
(
boolean
cold
,
boolean
nonResident
)
{
synchronized
List
<
K
>
keys
(
boolean
cold
,
boolean
nonResident
)
{
ArrayList
<
K
>
keys
=
new
ArrayList
<
K
>();
ArrayList
<
K
>
keys
=
new
ArrayList
<
K
>();
if
(
cold
)
{
if
(
cold
)
{
...
@@ -798,15 +849,24 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -798,15 +849,24 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
return
keys
;
return
keys
;
}
}
int
size
()
{
/**
return
mapSize
-
queue2Size
;
* Check whether there is a resident entry for the given key. This
}
* method does not adjust the internal state of the cache.
*
* @param key the key (may not be null)
* @param hash the hash
* @return true if there is a resident entry
*/
boolean
containsKey
(
Object
key
,
int
hash
)
{
boolean
containsKey
(
Object
key
,
int
hash
)
{
Entry
<
K
,
V
>
e
=
find
(
key
,
hash
);
Entry
<
K
,
V
>
e
=
find
(
key
,
hash
);
return
e
!=
null
&&
e
.
value
!=
null
;
return
e
!=
null
&&
e
.
value
!=
null
;
}
}
/**
* Get the set of keys for resident entries.
*
* @return the set of keys
*/
synchronized
Set
<
K
>
keySet
()
{
synchronized
Set
<
K
>
keySet
()
{
HashSet
<
K
>
set
=
new
HashSet
<
K
>();
HashSet
<
K
>
set
=
new
HashSet
<
K
>();
for
(
Entry
<
K
,
V
>
e
=
stack
.
stackNext
;
e
!=
stack
;
e
=
e
.
stackNext
)
{
for
(
Entry
<
K
,
V
>
e
=
stack
.
stackNext
;
e
!=
stack
;
e
=
e
.
stackNext
)
{
...
@@ -818,22 +878,13 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -818,22 +878,13 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
return
set
;
return
set
;
}
}
int
sizeHot
()
{
/**
return
mapSize
-
queueSize
-
queue2Size
;
* Set the maximum memory this cache should use. This will not
}
* immediately cause entries to get removed however; it will only change
* the limit. To resize the internal array, call the clear method.
int
sizeNonResident
()
{
*
return
queue2Size
;
* @param maxMemory the maximum size (1 or larger)
}
*/
int
sizeMapArray
()
{
return
entries
.
length
;
}
long
getUsedMemory
()
{
return
usedMemory
;
}
void
setMaxMemory
(
long
maxMemory
)
{
void
setMaxMemory
(
long
maxMemory
)
{
if
(
maxMemory
<=
0
)
{
if
(
maxMemory
<=
0
)
{
throw
new
IllegalArgumentException
(
"Max memory must be larger than 0"
);
throw
new
IllegalArgumentException
(
"Max memory must be larger than 0"
);
...
@@ -841,6 +892,12 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
...
@@ -841,6 +892,12 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
this
.
maxMemory
=
maxMemory
;
this
.
maxMemory
=
maxMemory
;
}
}
/**
* Set the average memory used per entry. It is used to calculate the
* length of the internal array.
*
* @param averageMemory the average memory used (1 or larger)
*/
void
setAverageMemory
(
int
averageMemory
)
{
void
setAverageMemory
(
int
averageMemory
)
{
if
(
averageMemory
<=
0
)
{
if
(
averageMemory
<=
0
)
{
throw
new
IllegalArgumentException
(
"Average memory must be larger than 0"
);
throw
new
IllegalArgumentException
(
"Average memory must be larger than 0"
);
...
...
h2/src/tools/org/h2/dev/store/cache/CacheLongKeyLIRS.java
浏览文件 @
2895f2b5
/*
/*
* Copyright 2004-201
2
H2 Group. Multiple-Licensed under the H2 License,
* Copyright 2004-201
1
H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
* Initial Developer: H2 Group
...
@@ -53,13 +53,14 @@ public class CacheLongKeyLIRS<V> {
...
@@ -53,13 +53,14 @@ public class CacheLongKeyLIRS<V> {
*/
*/
private
int
averageMemory
;
private
int
averageMemory
;
private
Segment
<
V
>[]
segments
;
private
final
Segment
<
V
>[]
segments
;
private
int
segmentCount
;
private
final
int
segmentCount
;
private
int
segmentShift
;
private
final
int
segmentShift
;
private
int
segmentMask
;
private
final
int
segmentMask
;
private
final
int
stackMoveDistance
;
private
final
int
stackMoveDistance
;
@SuppressWarnings
(
"unchecked"
)
private
CacheLongKeyLIRS
(
long
maxMemory
,
int
averageMemory
,
int
segmentCount
,
int
stackMoveDistance
)
{
private
CacheLongKeyLIRS
(
long
maxMemory
,
int
averageMemory
,
int
segmentCount
,
int
stackMoveDistance
)
{
setMaxMemory
(
maxMemory
);
setMaxMemory
(
maxMemory
);
setAverageMemory
(
averageMemory
);
setAverageMemory
(
averageMemory
);
...
@@ -67,20 +68,22 @@ public class CacheLongKeyLIRS<V> {
...
@@ -67,20 +68,22 @@ public class CacheLongKeyLIRS<V> {
throw
new
IllegalArgumentException
(
"The segment count must be a power of 2, is "
+
segmentCount
);
throw
new
IllegalArgumentException
(
"The segment count must be a power of 2, is "
+
segmentCount
);
}
}
this
.
segmentCount
=
segmentCount
;
this
.
segmentCount
=
segmentCount
;
this
.
segmentMask
=
segmentCount
-
1
;
this
.
stackMoveDistance
=
stackMoveDistance
;
this
.
stackMoveDistance
=
stackMoveDistance
;
segments
=
new
Segment
[
segmentCount
];
clear
();
clear
();
this
.
segmentShift
=
Integer
.
numberOfTrailingZeros
(
segments
[
0
].
entries
.
length
);
}
}
@SuppressWarnings
(
"unchecked"
)
/**
* Remove all entries.
*/
public
void
clear
()
{
public
void
clear
()
{
segmentMask
=
segmentCount
-
1
;
long
max
=
Math
.
max
(
1
,
maxMemory
/
segmentCount
);
segments
=
new
Segment
[
segmentCount
];
for
(
int
i
=
0
;
i
<
segmentCount
;
i
++)
{
for
(
int
i
=
0
;
i
<
segmentCount
;
i
++)
{
long
max
=
Math
.
max
(
1
,
maxMemory
/
segmentCount
);
segments
[
i
]
=
new
Segment
<
V
>(
segments
[
i
]
=
new
Segment
<
V
>(
max
,
averageMemory
,
stackMoveDistance
);
max
,
averageMemory
,
stackMoveDistance
);
}
}
segmentShift
=
Integer
.
numberOfTrailingZeros
(
segments
[
0
].
sizeMapArray
());
}
}
private
Entry
<
V
>
find
(
long
key
)
{
private
Entry
<
V
>
find
(
long
key
)
{
...
@@ -89,8 +92,8 @@ public class CacheLongKeyLIRS<V> {
...
@@ -89,8 +92,8 @@ public class CacheLongKeyLIRS<V> {
}
}
/**
/**
* Check whether there is a resident entry for the given key. This
method
* Check whether there is a resident entry for the given key. This
* does not adjust the internal state of the cache.
*
method
does not adjust the internal state of the cache.
*
*
* @param key the key (may not be null)
* @param key the key (may not be null)
* @return true if there is a resident entry
* @return true if there is a resident entry
...
@@ -113,14 +116,14 @@ public class CacheLongKeyLIRS<V> {
...
@@ -113,14 +116,14 @@ public class CacheLongKeyLIRS<V> {
}
}
/**
/**
* Add an entry to the cache. The entry may or may not exist in the
cache
* Add an entry to the cache. The entry may or may not exist in the
*
yet. This method will usually mark unknown entries as cold and known
*
cache yet. This method will usually mark unknown entries as cold and
* entries as hot.
*
known
entries as hot.
*
*
* @param key the key (may not be null)
* @param key the key (may not be null)
* @param value the value (may not be null)
* @param value the value (may not be null)
* @param memory the memory used for the given entry
* @param memory the memory used for the given entry
* @return the old value, or null if there
i
s no resident entry
* @return the old value, or null if there
wa
s no resident entry
*/
*/
public
V
put
(
long
key
,
V
value
,
int
memory
)
{
public
V
put
(
long
key
,
V
value
,
int
memory
)
{
int
hash
=
getHash
(
key
);
int
hash
=
getHash
(
key
);
...
@@ -132,17 +135,18 @@ public class CacheLongKeyLIRS<V> {
...
@@ -132,17 +135,18 @@ public class CacheLongKeyLIRS<V> {
*
*
* @param key the key (may not be null)
* @param key the key (may not be null)
* @param value the value (may not be null)
* @param value the value (may not be null)
* @return the old value, or null if there
i
s no resident entry
* @return the old value, or null if there
wa
s no resident entry
*/
*/
public
V
put
(
long
key
,
V
value
)
{
public
V
put
(
long
key
,
V
value
)
{
return
put
(
key
,
value
,
averageMemory
);
return
put
(
key
,
value
,
averageMemory
);
}
}
/**
/**
* Remove an entry. Both resident and non-resident entries can be removed.
* Remove an entry. Both resident and non-resident entries can be
* removed.
*
*
* @param key the key (may not be null)
* @param key the key (may not be null)
* @return the old value, or null if there
i
s no resident entry
* @return the old value, or null if there
wa
s no resident entry
*/
*/
public
synchronized
V
remove
(
long
key
)
{
public
synchronized
V
remove
(
long
key
)
{
int
hash
=
getHash
(
key
);
int
hash
=
getHash
(
key
);
...
@@ -162,8 +166,8 @@ public class CacheLongKeyLIRS<V> {
...
@@ -162,8 +166,8 @@ public class CacheLongKeyLIRS<V> {
/**
/**
* Get the value for the given key if the entry is cached. This method
* Get the value for the given key if the entry is cached. This method
* adjusts the internal state of the cache
, to ensure commonly used entries
* adjusts the internal state of the cache
sometimes, to ensure commonly
* stay in the cache.
*
used entries
stay in the cache.
*
*
* @param key the key (may not be null)
* @param key the key (may not be null)
* @return the value, or null if there is no resident entry
* @return the value, or null if there is no resident entry
...
@@ -178,12 +182,20 @@ public class CacheLongKeyLIRS<V> {
...
@@ -178,12 +182,20 @@ public class CacheLongKeyLIRS<V> {
return
segments
[
segmentIndex
];
return
segments
[
segmentIndex
];
}
}
/**
* Get the hash code for the given key. The hash code is
* further enhanced to spread the values more evenly.
*
* @param key the key
* @return the hash code
*/
static
int
getHash
(
long
key
)
{
static
int
getHash
(
long
key
)
{
int
hash
=
(
int
)
((
key
>>>
32
)
^
key
);
int
hash
=
(
int
)
((
key
>>>
32
)
^
key
);
// Doug Lea's supplemental secondaryHash function (inlined)
// a supplemental secondary hash function
// to protect against hash codes that don't differ in low order bits
// to protect against hash codes that don't differ much
hash
^=
(
hash
>>>
20
)
^
(
hash
>>>
12
);
hash
=
((
hash
>>>
16
)
^
hash
)
*
0x45d9f3b
;
hash
^=
(
hash
>>>
7
)
^
(
hash
>>>
4
);
hash
=
((
hash
>>>
16
)
^
hash
)
*
0x45d9f3b
;
hash
=
(
hash
>>>
16
)
^
hash
;
return
hash
;
return
hash
;
}
}
...
@@ -195,15 +207,15 @@ public class CacheLongKeyLIRS<V> {
...
@@ -195,15 +207,15 @@ public class CacheLongKeyLIRS<V> {
public
long
getUsedMemory
()
{
public
long
getUsedMemory
()
{
long
x
=
0
;
long
x
=
0
;
for
(
Segment
<
V
>
s
:
segments
)
{
for
(
Segment
<
V
>
s
:
segments
)
{
x
+=
s
.
getUsedMemory
()
;
x
+=
s
.
usedMemory
;
}
}
return
x
;
return
x
;
}
}
/**
/**
* Set the maximum memory this cache should use. This will not
immediately
* Set the maximum memory this cache should use. This will not
*
cause entries to get removed however; it will only change the limit. To
*
immediately cause entries to get removed however; it will only change
* resize the internal array, call the clear method.
*
the limit. To
resize the internal array, call the clear method.
*
*
* @param maxMemory the maximum size (1 or larger)
* @param maxMemory the maximum size (1 or larger)
*/
*/
...
@@ -221,8 +233,8 @@ public class CacheLongKeyLIRS<V> {
...
@@ -221,8 +233,8 @@ public class CacheLongKeyLIRS<V> {
}
}
/**
/**
* Set the average memory used per entry. It is used to calculate the
length
* Set the average memory used per entry. It is used to calculate the
* of the internal array.
*
length
of the internal array.
*
*
* @param averageMemory the average memory used (1 or larger)
* @param averageMemory the average memory used (1 or larger)
*/
*/
...
@@ -259,7 +271,7 @@ public class CacheLongKeyLIRS<V> {
...
@@ -259,7 +271,7 @@ public class CacheLongKeyLIRS<V> {
/**
/**
* Create a new cache with the given number of entries, and the default
* Create a new cache with the given number of entries, and the default
* settings (an average size of 1 per entry, 16 segments, and stack move
* settings (an average size of 1 per entry, 16 segments, and stack move
* distance equals to the max
entry size
divided by 100).
* distance equals to the max
imum number of entries
divided by 100).
*
*
* @param maxEntries the maximum number of entries
* @param maxEntries the maximum number of entries
* @return the cache
* @return the cache
...
@@ -317,7 +329,7 @@ public class CacheLongKeyLIRS<V> {
...
@@ -317,7 +329,7 @@ public class CacheLongKeyLIRS<V> {
public
int
sizeNonResident
()
{
public
int
sizeNonResident
()
{
int
x
=
0
;
int
x
=
0
;
for
(
Segment
<
V
>
s
:
segments
)
{
for
(
Segment
<
V
>
s
:
segments
)
{
x
+=
s
.
sizeNonResident
()
;
x
+=
s
.
queue2Size
;
}
}
return
x
;
return
x
;
}
}
...
@@ -330,7 +342,7 @@ public class CacheLongKeyLIRS<V> {
...
@@ -330,7 +342,7 @@ public class CacheLongKeyLIRS<V> {
public
int
sizeMapArray
()
{
public
int
sizeMapArray
()
{
int
x
=
0
;
int
x
=
0
;
for
(
Segment
<
V
>
s
:
segments
)
{
for
(
Segment
<
V
>
s
:
segments
)
{
x
+=
s
.
sizeMapArray
()
;
x
+=
s
.
entries
.
length
;
}
}
return
x
;
return
x
;
}
}
...
@@ -343,7 +355,7 @@ public class CacheLongKeyLIRS<V> {
...
@@ -343,7 +355,7 @@ public class CacheLongKeyLIRS<V> {
public
int
sizeHot
()
{
public
int
sizeHot
()
{
int
x
=
0
;
int
x
=
0
;
for
(
Segment
<
V
>
s
:
segments
)
{
for
(
Segment
<
V
>
s
:
segments
)
{
x
+=
s
.
sizeHot
()
;
x
+=
s
.
mapSize
-
s
.
queueSize
-
s
.
queue2Size
;
}
}
return
x
;
return
x
;
}
}
...
@@ -356,7 +368,7 @@ public class CacheLongKeyLIRS<V> {
...
@@ -356,7 +368,7 @@ public class CacheLongKeyLIRS<V> {
public
int
size
()
{
public
int
size
()
{
int
x
=
0
;
int
x
=
0
;
for
(
Segment
<
V
>
s
:
segments
)
{
for
(
Segment
<
V
>
s
:
segments
)
{
x
+=
s
.
size
()
;
x
+=
s
.
mapSize
-
s
.
queue2Size
;
}
}
return
x
;
return
x
;
}
}
...
@@ -393,14 +405,30 @@ public class CacheLongKeyLIRS<V> {
...
@@ -393,14 +405,30 @@ public class CacheLongKeyLIRS<V> {
return
list
;
return
list
;
}
}
/**
* Check whether the cache is empty.
*
* @return true if it is empty
*/
public
boolean
isEmpty
()
{
public
boolean
isEmpty
()
{
return
size
()
==
0
;
return
size
()
==
0
;
}
}
/**
* Check whether the given value is stored.
*
* @param value the value
* @return true if it is stored
*/
public
boolean
containsValue
(
Object
value
)
{
public
boolean
containsValue
(
Object
value
)
{
return
getMap
().
containsValue
(
value
);
return
getMap
().
containsValue
(
value
);
}
}
/**
* Convert this cache to a map.
*
* @return the map
*/
public
Map
<
Long
,
V
>
getMap
()
{
public
Map
<
Long
,
V
>
getMap
()
{
HashMap
<
Long
,
V
>
map
=
new
HashMap
<
Long
,
V
>();
HashMap
<
Long
,
V
>
map
=
new
HashMap
<
Long
,
V
>();
for
(
long
k
:
keySet
())
{
for
(
long
k
:
keySet
())
{
...
@@ -412,6 +440,11 @@ public class CacheLongKeyLIRS<V> {
...
@@ -412,6 +440,11 @@ public class CacheLongKeyLIRS<V> {
return
map
;
return
map
;
}
}
/**
* Add all elements of the map to this cache.
*
* @param m the map
*/
public
void
putAll
(
Map
<
Long
,
?
extends
V
>
m
)
{
public
void
putAll
(
Map
<
Long
,
?
extends
V
>
m
)
{
for
(
Map
.
Entry
<
Long
,
?
extends
V
>
e
:
m
.
entrySet
())
{
for
(
Map
.
Entry
<
Long
,
?
extends
V
>
e
:
m
.
entrySet
())
{
// copy only non-null entries
// copy only non-null entries
...
@@ -427,56 +460,56 @@ public class CacheLongKeyLIRS<V> {
...
@@ -427,56 +460,56 @@ public class CacheLongKeyLIRS<V> {
static
class
Segment
<
V
>
{
static
class
Segment
<
V
>
{
/**
/**
* How many other item are to be moved to the top of the stack before
* The number of (hot, cold, and non-resident) entries in the map.
* the current item is moved.
*/
*/
private
final
int
stackMoveDistanc
e
;
int
mapSiz
e
;
/**
/**
* The
maximum memory this cache should use
.
* The
size of the LIRS queue for resident cold entries
.
*/
*/
private
long
maxMemory
;
int
queueSize
;
/**
/**
* The
average memory used by one entry
.
* The
size of the LIRS queue for non-resident cold entries
.
*/
*/
private
int
averageMemory
;
int
queue2Size
;
/**
/**
* The
currently used memory
.
* The
map array. The size is always a power of 2
.
*/
*/
private
long
usedMemory
;
Entry
<
V
>[]
entries
;
/**
/**
* The
number of (hot, cold, and non-resident) entries in the map
.
* The
currently used memory
.
*/
*/
private
int
mapSize
;
long
usedMemory
;
/**
/**
*
The bit mask that is applied to the key hash code to get the index in th
e
*
How many other item are to be moved to the top of the stack befor
e
*
map array. The mask is the length of the array minus one
.
*
the current item is moved
.
*/
*/
private
int
mask
;
private
final
int
stackMoveDistance
;
/**
/**
* The
LIRS stack siz
e.
* The
maximum memory this cache should us
e.
*/
*/
private
int
stackSize
;
private
long
maxMemory
;
/**
/**
* The
size of the LIRS queue for resident cold entries
.
* The
average memory used by one entry
.
*/
*/
private
int
queueSize
;
private
int
averageMemory
;
/**
/**
* The size of the LIRS queue for non-resident cold entries.
* The bit mask that is applied to the key hash code to get the index in the
* map array. The mask is the length of the array minus one.
*/
*/
private
int
queue2Size
;
private
int
mask
;
/**
/**
* The
map array. The size is always a power of 2
.
* The
LIRS stack size
.
*/
*/
private
Entry
<
V
>[]
entries
;
private
int
stackSize
;
/**
/**
* The stack of recently referenced elements. This includes all hot entries,
* The stack of recently referenced elements. This includes all hot entries,
...
@@ -514,7 +547,7 @@ public class CacheLongKeyLIRS<V> {
...
@@ -514,7 +547,7 @@ public class CacheLongKeyLIRS<V> {
clear
();
clear
();
}
}
synchronized
void
clear
()
{
private
void
clear
()
{
// calculate the size of the map array
// calculate the size of the map array
// assume a fill factor of at most 80%
// assume a fill factor of at most 80%
...
@@ -548,16 +581,27 @@ public class CacheLongKeyLIRS<V> {
...
@@ -548,16 +581,27 @@ public class CacheLongKeyLIRS<V> {
stackSize
=
queueSize
=
queue2Size
=
0
;
stackSize
=
queueSize
=
queue2Size
=
0
;
}
}
V
peek
(
long
key
,
int
hash
)
{
/**
Entry
<
V
>
e
=
find
(
key
,
hash
);
* Get the memory used for the given key.
return
e
==
null
?
null
:
e
.
value
;
*
}
* @param key the key (may not be null)
* @param hash the hash
* @return the memory, or 0 if there is no resident entry
*/
int
getMemory
(
long
key
,
int
hash
)
{
int
getMemory
(
long
key
,
int
hash
)
{
Entry
<
V
>
e
=
find
(
key
,
hash
);
Entry
<
V
>
e
=
find
(
key
,
hash
);
return
e
==
null
?
0
:
e
.
memory
;
return
e
==
null
?
0
:
e
.
memory
;
}
}
/**
* Get the value for the given key if the entry is cached. This method
* adjusts the internal state of the cache sometimes, to ensure commonly
* used entries stay in the cache.
*
* @param key the key (may not be null)
* @param hash the hash
* @return the value, or null if there is no resident entry
*/
V
get
(
long
key
,
int
hash
)
{
V
get
(
long
key
,
int
hash
)
{
Entry
<
V
>
e
=
find
(
key
,
hash
);
Entry
<
V
>
e
=
find
(
key
,
hash
);
if
(
e
==
null
)
{
if
(
e
==
null
)
{
...
@@ -625,6 +669,17 @@ public class CacheLongKeyLIRS<V> {
...
@@ -625,6 +669,17 @@ public class CacheLongKeyLIRS<V> {
}
}
}
}
/**
* Add an entry to the cache. The entry may or may not exist in the
* cache yet. This method will usually mark unknown entries as cold and
* known entries as hot.
*
* @param key the key (may not be null)
* @param hash the hash
* @param value the value (may not be null)
* @param memory the memory used for the given entry
* @return the old value, or null if there was no resident entry
*/
synchronized
V
put
(
long
key
,
int
hash
,
V
value
,
int
memory
)
{
synchronized
V
put
(
long
key
,
int
hash
,
V
value
,
int
memory
)
{
if
(
value
==
null
)
{
if
(
value
==
null
)
{
throw
new
NullPointerException
();
throw
new
NullPointerException
();
...
@@ -655,6 +710,14 @@ public class CacheLongKeyLIRS<V> {
...
@@ -655,6 +710,14 @@ public class CacheLongKeyLIRS<V> {
return
old
;
return
old
;
}
}
/**
* Remove an entry. Both resident and non-resident entries can be
* removed.
*
* @param key the key (may not be null)
* @param hash the hash
* @return the old value, or null if there was no resident entry
*/
synchronized
V
remove
(
long
key
,
int
hash
)
{
synchronized
V
remove
(
long
key
,
int
hash
)
{
int
index
=
hash
&
mask
;
int
index
=
hash
&
mask
;
Entry
<
V
>
e
=
entries
[
index
];
Entry
<
V
>
e
=
entries
[
index
];
...
@@ -764,6 +827,7 @@ public class CacheLongKeyLIRS<V> {
...
@@ -764,6 +827,7 @@ public class CacheLongKeyLIRS<V> {
* Try to find an entry in the map.
* Try to find an entry in the map.
*
*
* @param key the key
* @param key the key
* @param hash the hash
* @return the entry (might be a non-resident)
* @return the entry (might be a non-resident)
*/
*/
Entry
<
V
>
find
(
long
key
,
int
hash
)
{
Entry
<
V
>
find
(
long
key
,
int
hash
)
{
...
@@ -822,6 +886,14 @@ public class CacheLongKeyLIRS<V> {
...
@@ -822,6 +886,14 @@ public class CacheLongKeyLIRS<V> {
}
}
}
}
/**
* Get the list of keys. This method allows to read the internal state of
* the cache.
*
* @param cold if true, only keys for the cold entries are returned
* @param nonResident true for non-resident entries
* @return the key list
*/
synchronized
List
<
Long
>
keys
(
boolean
cold
,
boolean
nonResident
)
{
synchronized
List
<
Long
>
keys
(
boolean
cold
,
boolean
nonResident
)
{
ArrayList
<
Long
>
keys
=
new
ArrayList
<
Long
>();
ArrayList
<
Long
>
keys
=
new
ArrayList
<
Long
>();
if
(
cold
)
{
if
(
cold
)
{
...
@@ -837,15 +909,24 @@ public class CacheLongKeyLIRS<V> {
...
@@ -837,15 +909,24 @@ public class CacheLongKeyLIRS<V> {
return
keys
;
return
keys
;
}
}
int
size
()
{
/**
return
mapSize
-
queue2Size
;
* Check whether there is a resident entry for the given key. This
}
* method does not adjust the internal state of the cache.
*
* @param key the key (may not be null)
* @param hash the hash
* @return true if there is a resident entry
*/
boolean
containsKey
(
long
key
,
int
hash
)
{
boolean
containsKey
(
long
key
,
int
hash
)
{
Entry
<
V
>
e
=
find
(
key
,
hash
);
Entry
<
V
>
e
=
find
(
key
,
hash
);
return
e
!=
null
&&
e
.
value
!=
null
;
return
e
!=
null
&&
e
.
value
!=
null
;
}
}
/**
* Get the set of keys for resident entries.
*
* @return the set of keys
*/
synchronized
Set
<
Long
>
keySet
()
{
synchronized
Set
<
Long
>
keySet
()
{
HashSet
<
Long
>
set
=
new
HashSet
<
Long
>();
HashSet
<
Long
>
set
=
new
HashSet
<
Long
>();
for
(
Entry
<
V
>
e
=
stack
.
stackNext
;
e
!=
stack
;
e
=
e
.
stackNext
)
{
for
(
Entry
<
V
>
e
=
stack
.
stackNext
;
e
!=
stack
;
e
=
e
.
stackNext
)
{
...
@@ -857,22 +938,13 @@ public class CacheLongKeyLIRS<V> {
...
@@ -857,22 +938,13 @@ public class CacheLongKeyLIRS<V> {
return
set
;
return
set
;
}
}
int
sizeHot
()
{
/**
return
mapSize
-
queueSize
-
queue2Size
;
* Set the maximum memory this cache should use. This will not
}
* immediately cause entries to get removed however; it will only change
* the limit. To resize the internal array, call the clear method.
int
sizeNonResident
()
{
*
return
queue2Size
;
* @param maxMemory the maximum size (1 or larger)
}
*/
int
sizeMapArray
()
{
return
entries
.
length
;
}
long
getUsedMemory
()
{
return
usedMemory
;
}
void
setMaxMemory
(
long
maxMemory
)
{
void
setMaxMemory
(
long
maxMemory
)
{
if
(
maxMemory
<=
0
)
{
if
(
maxMemory
<=
0
)
{
throw
new
IllegalArgumentException
(
"Max memory must be larger than 0"
);
throw
new
IllegalArgumentException
(
"Max memory must be larger than 0"
);
...
@@ -880,6 +952,12 @@ public class CacheLongKeyLIRS<V> {
...
@@ -880,6 +952,12 @@ public class CacheLongKeyLIRS<V> {
this
.
maxMemory
=
maxMemory
;
this
.
maxMemory
=
maxMemory
;
}
}
/**
* Set the average memory used per entry. It is used to calculate the
* length of the internal array.
*
* @param averageMemory the average memory used (1 or larger)
*/
void
setAverageMemory
(
int
averageMemory
)
{
void
setAverageMemory
(
int
averageMemory
)
{
if
(
averageMemory
<=
0
)
{
if
(
averageMemory
<=
0
)
{
throw
new
IllegalArgumentException
(
"Average memory must be larger than 0"
);
throw
new
IllegalArgumentException
(
"Average memory must be larger than 0"
);
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论