Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
LinuxSuRen
jenkins
提交
c32f006f
J
jenkins
项目概览
LinuxSuRen
/
jenkins
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
jenkins
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
c32f006f
编写于
9月 21, 2012
作者:
K
Kohsuke Kawaguchi
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Allow AbstractBuilds to be garbage collected (and reloaded lazy later)
上级
9e6d8f71
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
567 addition
and
54 deletion
+567
-54
core/src/main/java/hudson/model/AbstractBuild.java
core/src/main/java/hudson/model/AbstractBuild.java
+78
-17
core/src/main/java/hudson/model/Run.java
core/src/main/java/hudson/model/Run.java
+15
-3
core/src/main/java/hudson/model/RunMap.java
core/src/main/java/hudson/model/RunMap.java
+16
-5
core/src/main/java/jenkins/model/lazy/AbstractLazyLoadRunMap.java
.../main/java/jenkins/model/lazy/AbstractLazyLoadRunMap.java
+62
-29
core/src/main/java/jenkins/model/lazy/BuildReference.java
core/src/main/java/jenkins/model/lazy/BuildReference.java
+41
-0
core/src/main/java/jenkins/model/lazy/BuildReferenceMapAdapter.java
...ain/java/jenkins/model/lazy/BuildReferenceMapAdapter.java
+355
-0
未找到文件。
core/src/main/java/hudson/model/AbstractBuild.java
浏览文件 @
c32f006f
...
...
@@ -63,6 +63,7 @@ import hudson.util.LogTaskListener;
import
hudson.util.VariableResolver
;
import
jenkins.model.Jenkins
;
import
jenkins.model.lazy.AbstractLazyLoadRunMap.Direction
;
import
jenkins.model.lazy.BuildReference
;
import
org.kohsuke.stapler.Stapler
;
import
org.kohsuke.stapler.StaplerRequest
;
import
org.kohsuke.stapler.StaplerResponse
;
...
...
@@ -155,6 +156,20 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
*/
protected
transient
List
<
Environment
>
buildEnvironments
;
/**
* Pointers to form bi-directional link between adjacent {@link AbstractBuild}s.
*
* <p>
* Unlike {@link Run}, {@link AbstractBuild}s do lazy-loading, so we don't use
* {@link Run#previousBuild} and {@link Run#nextBuild}, and instead use these
* fields and point to {@link #selfReference} of adjacent builds.
*/
private
volatile
transient
BuildReference
<
R
>
previousBuild
,
nextBuild
;
/*package*/
final
transient
BuildReference
<
R
>
selfReference
=
new
BuildReference
<
R
>(
getId
(),
_this
());
protected
AbstractBuild
(
P
job
)
throws
IOException
{
super
(
job
);
}
...
...
@@ -171,32 +186,78 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
return
getParent
();
}
private
transient
boolean
previousBuildComputed
,
nextBuildComputed
;
@Override
void
dropLinks
()
{
super
.
dropLinks
();
if
(
nextBuild
!=
null
)
{
AbstractBuild
nb
=
nextBuild
.
get
();
if
(
nb
!=
null
)
nb
.
previousBuild
=
previousBuild
;
}
if
(
previousBuild
!=
null
)
{
AbstractBuild
pb
=
previousBuild
.
get
();
if
(
pb
!=
null
)
pb
.
nextBuild
=
nextBuild
;
}
}
@Override
public
R
getPreviousBuild
()
{
if
(
previousBuild
==
null
&&
!
previousBuildComputed
)
{
// having two neighbors pointing to each other is important to make RunMap.removeValue work
R
previousBuild
=
getParent
().
builds
.
search
(
number
-
1
,
Direction
.
DESC
);
if
(
previousBuild
!=
null
)
previousBuild
.
nextBuild
=
(
R
)
this
;
this
.
previousBuild
=
previousBuild
;
previousBuildComputed
=
true
;
while
(
true
)
{
BuildReference
<
R
>
r
=
previousBuild
;
// capture the value once
if
(
r
==
null
)
{
// having two neighbors pointing to each other is important to make RunMap.removeValue work
R
pb
=
getParent
().
builds
.
search
(
number
-
1
,
Direction
.
DESC
);
if
(
pb
!=
null
)
{
((
AbstractBuild
)
pb
).
nextBuild
=
selfReference
;
// establish bi-di link
this
.
previousBuild
=
pb
.
selfReference
;
return
pb
;
}
else
{
// this indicates that we know there's no previous build
// (as opposed to we don't know if/what our previous build is.
this
.
previousBuild
=
selfReference
;
return
null
;
}
}
if
(
r
==
selfReference
)
return
null
;
R
referent
=
r
.
get
();
if
(
referent
!=
null
)
return
referent
;
// the reference points to a GC-ed object, drop the reference and do it again
this
.
previousBuild
=
null
;
}
return
previousBuild
;
}
@Override
public
R
getNextBuild
()
{
if
(
nextBuild
==
null
&&
!
nextBuildComputed
)
{
// having two neighbors pointing to each other is important to make RunMap.removeValue work
R
nextBuild
=
getParent
().
builds
.
search
(
number
+
1
,
Direction
.
ASC
);
if
(
nextBuild
!=
null
)
nextBuild
.
previousBuild
=
(
R
)
this
;
this
.
nextBuild
=
nextBuild
;
nextBuildComputed
=
true
;
while
(
true
)
{
BuildReference
<
R
>
r
=
nextBuild
;
// capture the value once
if
(
r
==
null
)
{
// having two neighbors pointing to each other is important to make RunMap.removeValue work
R
nb
=
getParent
().
builds
.
search
(
number
+
1
,
Direction
.
ASC
);
if
(
nb
!=
null
)
{
((
AbstractBuild
)
nb
).
previousBuild
=
selfReference
;
// establish bi-di link
this
.
nextBuild
=
nb
.
selfReference
;
return
nb
;
}
else
{
// this indicates that we know there's no next build
// (as opposed to we don't know if/what our next build is.
this
.
nextBuild
=
selfReference
;
return
null
;
}
}
if
(
r
==
selfReference
)
return
null
;
R
referent
=
r
.
get
();
if
(
referent
!=
null
)
return
referent
;
// the reference points to a GC-ed object, drop the reference and do it again
this
.
nextBuild
=
null
;
}
return
nextBuild
;
}
/**
...
...
core/src/main/java/hudson/model/Run.java
浏览文件 @
c32f006f
/*
* The MIT License
*
* Copyright (c) 2004-201
0
, Sun Microsystems, Inc., Kohsuke Kawaguchi,
* Copyright (c) 2004-201
2
, Sun Microsystems, Inc., Kohsuke Kawaguchi,
* Daniel Dyer, Red Hat, Inc., Tom Huybrechts, Romain Seguy, Yahoo! Inc.,
* Darek Ostolski
* Darek Ostolski
, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
...
...
@@ -96,6 +96,7 @@ import javax.servlet.ServletException;
import
javax.servlet.http.HttpServletResponse
;
import
jenkins.model.Jenkins
;
import
jenkins.model.lazy.BuildReference
;
import
jenkins.util.io.OnMaster
;
import
net.sf.json.JSONObject
;
import
org.apache.commons.io.input.NullInputStream
;
...
...
@@ -338,7 +339,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* Obtains 'this' in a more type safe signature.
*/
@SuppressWarnings
({
"unchecked"
})
pr
ivate
RunT
_this
()
{
pr
otected
RunT
_this
()
{
return
(
RunT
)
this
;
}
...
...
@@ -690,6 +691,17 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
return
number
;
}
/**
* Called by {@link RunMap} to drop bi-directional links in preparation for
* deleting a build.
*/
/*package*/
void
dropLinks
()
{
if
(
nextBuild
!=
null
)
nextBuild
.
previousBuild
=
previousBuild
;
if
(
previousBuild
!=
null
)
previousBuild
.
nextBuild
=
nextBuild
;
}
public
RunT
getPreviousBuild
()
{
return
previousBuild
;
}
...
...
core/src/main/java/hudson/model/RunMap.java
浏览文件 @
c32f006f
...
...
@@ -24,6 +24,7 @@
package
hudson.model
;
import
jenkins.model.lazy.AbstractLazyLoadRunMap
;
import
jenkins.model.lazy.BuildReference
;
import
org.apache.commons.collections.comparators.ReverseComparator
;
import
java.io.File
;
...
...
@@ -52,6 +53,8 @@ import static jenkins.model.lazy.AbstractLazyLoadRunMap.Direction.*;
*
* @author Kohsuke Kawaguchi
*/
// in practice R is always bound by AbstractBuild, but making that change causes all kinds of
// signature breakage.
public
final
class
RunMap
<
R
extends
Run
<?,
R
>>
extends
AbstractLazyLoadRunMap
<
R
>
implements
Iterable
<
R
>
{
/**
* Read-only view of this map.
...
...
@@ -114,11 +117,7 @@ public final class RunMap<R extends Run<?,R>> extends AbstractLazyLoadRunMap<R>
@Override
public
boolean
removeValue
(
R
run
)
{
if
(
run
.
nextBuild
!=
null
)
run
.
nextBuild
.
previousBuild
=
run
.
previousBuild
;
if
(
run
.
previousBuild
!=
null
)
run
.
previousBuild
.
nextBuild
=
run
.
nextBuild
;
run
.
dropLinks
();
return
super
.
removeValue
(
run
);
}
...
...
@@ -170,6 +169,18 @@ public final class RunMap<R extends Run<?,R>> extends AbstractLazyLoadRunMap<R>
return
r
.
getId
();
}
/**
* Reuses the same reference as much as we can.
* <p>
* If concurrency ends up creating a few extra, that's OK, because
* we are really just trying to reduce the # of references we create.
*/
@Override
protected
BuildReference
<
R
>
createReference
(
R
r
)
{
if
(
r
instanceof
AbstractBuild
)
return
((
AbstractBuild
)
r
).
selfReference
;
else
return
super
.
createReference
(
r
);
}
@Override
protected
FilenameFilter
createDirectoryFilter
()
{
final
SimpleDateFormat
formatter
=
Run
.
ID_FORMATTER
.
get
();
...
...
core/src/main/java/jenkins/model/lazy/AbstractLazyLoadRunMap.java
浏览文件 @
c32f006f
...
...
@@ -23,12 +23,14 @@
*/
package
jenkins.model.lazy
;
import
hudson.model.Run
;
import
org.kohsuke.accmod.Restricted
;
import
org.kohsuke.accmod.restrictions.NoExternalUse
;
import
java.io.File
;
import
java.io.FilenameFilter
;
import
java.io.IOException
;
import
java.lang.ref.Reference
;
import
java.util.AbstractMap
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
...
...
@@ -104,13 +106,13 @@ public abstract class AbstractLazyLoadRunMap<R> extends AbstractMap<Integer,R> i
* Stores the mapping from build number to build, for builds that are already loaded.
*/
// copy on write
private
volatile
TreeMap
<
Integer
,
R
>
byNumber
=
new
TreeMap
<
Integer
,
R
>(
COMPARATOR
);
private
volatile
TreeMap
<
Integer
,
BuildReference
<
R
>>
byNumber
=
new
TreeMap
<
Integer
,
BuildReference
<
R
>
>(
COMPARATOR
);
/**
* Stores the build ID to build number for builds that we already know
*/
// copy on write
private
volatile
TreeMap
<
String
,
R
>
byId
=
new
TreeMap
<
String
,
R
>();
private
volatile
TreeMap
<
String
,
BuildReference
<
R
>>
byId
=
new
TreeMap
<
String
,
BuildReference
<
R
>
>();
/**
* Build IDs found as directories, in the ascending order.
...
...
@@ -181,14 +183,14 @@ public abstract class AbstractLazyLoadRunMap<R> extends AbstractMap<Integer,R> i
@Override
public
Set
<
Entry
<
Integer
,
R
>>
entrySet
()
{
return
Collections
.
unmodifiableSet
(
all
(
).
entrySet
());
return
Collections
.
unmodifiableSet
(
new
BuildReferenceMapAdapter
<
R
>(
this
,
all
()
).
entrySet
());
}
/**
* Returns a read-only view of records that has already been loaded.
*/
public
SortedMap
<
Integer
,
R
>
getLoadedBuilds
()
{
return
Collections
.
unmodifiableSortedMap
(
byNumber
);
return
Collections
.
unmodifiableSortedMap
(
new
BuildReferenceMapAdapter
<
R
>(
this
,
byNumber
)
);
}
/**
...
...
@@ -214,7 +216,7 @@ public abstract class AbstractLazyLoadRunMap<R> extends AbstractMap<Integer,R> i
assert
i
!=
null
;
}
return
Collections
.
unmodifiableSortedMap
(
byNumber
.
subMap
(
fromKey
,
toKey
));
return
Collections
.
unmodifiableSortedMap
(
new
BuildReferenceMapAdapter
<
R
>(
this
,
byNumber
.
subMap
(
fromKey
,
toKey
)
));
}
public
SortedMap
<
Integer
,
R
>
headMap
(
Integer
toKey
)
{
...
...
@@ -273,8 +275,12 @@ public abstract class AbstractLazyLoadRunMap<R> extends AbstractMap<Integer,R> i
* If DESC, finds the closest #M that satisfies M<=N.
*/
public
R
search
(
final
int
n
,
final
Direction
d
)
{
Entry
<
Integer
,
R
>
c
=
byNumber
.
ceilingEntry
(
n
);
if
(
c
!=
null
&&
c
.
getKey
()==
n
)
return
c
.
getValue
();
// found the exact #n
Entry
<
Integer
,
BuildReference
<
R
>>
c
=
byNumber
.
ceilingEntry
(
n
);
if
(
c
!=
null
&&
c
.
getKey
()==
n
)
{
R
r
=
c
.
getValue
().
get
();
if
(
r
!=
null
)
return
r
;
// found the exact #n
}
// at this point we know that we don't have #n loaded yet
...
...
@@ -332,11 +338,11 @@ public abstract class AbstractLazyLoadRunMap<R> extends AbstractMap<Integer,R> i
// first, narrow down the candidate IDs to try by using two known number-to-ID mapping
if
(
idOnDisk
.
isEmpty
())
return
null
;
Entry
<
Integer
,
R
>
f
=
byNumber
.
floorEntry
(
n
);
Entry
<
Integer
,
BuildReference
<
R
>
>
f
=
byNumber
.
floorEntry
(
n
);
// if bound is null, use a sentinel value
String
cid
=
c
==
null
?
"\u0000"
:
getIdOf
(
c
.
getValue
())
;
String
fid
=
f
==
null
?
"\uFFFF"
:
getIdOf
(
f
.
getValue
())
;
String
cid
=
c
==
null
?
"\u0000"
:
c
.
getValue
().
id
;
String
fid
=
f
==
null
?
"\uFFFF"
:
f
.
getValue
().
id
;
// We know that the build we are looking for exists in this range
// we will narrow this down via binary search
...
...
@@ -390,8 +396,9 @@ public abstract class AbstractLazyLoadRunMap<R> extends AbstractMap<Integer,R> i
}
public
R
getById
(
String
id
)
{
if
(
byId
.
containsKey
(
id
))
return
byId
.
get
(
id
);
if
(
byId
.
containsKey
(
id
))
{
return
unwrap
(
byId
.
get
(
id
));
}
return
load
(
id
,
true
);
}
...
...
@@ -409,11 +416,12 @@ public abstract class AbstractLazyLoadRunMap<R> extends AbstractMap<Integer,R> i
int
n
=
getNumberOf
(
r
);
copy
();
R
old
=
byId
.
put
(
id
,
r
);
byNumber
.
put
(
n
,
r
);
BuildReference
<
R
>
ref
=
createReference
(
r
);
BuildReference
<
R
>
old
=
byId
.
put
(
id
,
ref
);
byNumber
.
put
(
n
,
ref
);
/*
search relies on the fact that every objet added via
search relies on the fact that every obje
c
t added via
put() method be available in the xyzOnDisk index, so I'm adding them here
however, this is awfully inefficient. I wonder if there's any better way to do this?
*/
...
...
@@ -431,15 +439,21 @@ public abstract class AbstractLazyLoadRunMap<R> extends AbstractMap<Integer,R> i
numberOnDisk
=
a
;
}
return
old
;
return
unwrap
(
old
);
}
private
R
unwrap
(
Reference
<
R
>
ref
)
{
return
ref
!=
null
?
ref
.
get
()
:
null
;
}
@Override
public
synchronized
void
putAll
(
Map
<?
extends
Integer
,?
extends
R
>
rhs
)
{
copy
();
for
(
R
r
:
rhs
.
values
())
{
byId
.
put
(
getIdOf
(
r
),
r
);
byNumber
.
put
(
getNumberOf
(
r
),
r
);
String
id
=
getIdOf
(
r
);
BuildReference
<
R
>
ref
=
createReference
(
r
);
byId
.
put
(
id
,
ref
);
byNumber
.
put
(
getNumberOf
(
r
),
ref
);
}
}
...
...
@@ -452,7 +466,7 @@ public abstract class AbstractLazyLoadRunMap<R> extends AbstractMap<Integer,R> i
* @return
* fully populated map.
*/
private
TreeMap
<
Integer
,
R
>
all
()
{
private
TreeMap
<
Integer
,
BuildReference
<
R
>
>
all
()
{
if
(!
fullyLoaded
)
{
synchronized
(
this
)
{
if
(!
fullyLoaded
)
{
...
...
@@ -472,8 +486,8 @@ public abstract class AbstractLazyLoadRunMap<R> extends AbstractMap<Integer,R> i
* Creates a duplicate for the COW data structure in preparation for mutation.
*/
private
void
copy
()
{
byId
=
new
TreeMap
<
String
,
R
>(
byId
);
byNumber
=
new
TreeMap
<
Integer
,
R
>(
byNumber
);
byId
=
new
TreeMap
<
String
,
BuildReference
<
R
>
>(
byId
);
byNumber
=
new
TreeMap
<
Integer
,
BuildReference
<
R
>
>(
byNumber
);
}
/**
...
...
@@ -515,8 +529,11 @@ public abstract class AbstractLazyLoadRunMap<R> extends AbstractMap<Integer,R> i
if
(
r
==
null
)
return
null
;
if
(
copy
)
copy
();
byId
.
put
(
getIdOf
(
r
),
r
);
byNumber
.
put
(
getNumberOf
(
r
),
r
);
String
id
=
getIdOf
(
r
);
BuildReference
<
R
>
ref
=
createReference
(
r
);
byId
.
put
(
id
,
ref
);
byNumber
.
put
(
getNumberOf
(
r
),
ref
);
return
r
;
}
catch
(
IOException
e
)
{
LOGGER
.
log
(
Level
.
WARNING
,
"Failed to load "
+
dataDir
,
e
);
...
...
@@ -524,9 +541,23 @@ public abstract class AbstractLazyLoadRunMap<R> extends AbstractMap<Integer,R> i
return
null
;
}
/**
* Subtype to provide {@link Run#getNumber()} so that this class doesn't have to depend on it.
*/
protected
abstract
int
getNumberOf
(
R
r
);
/**
* Subtype to provide {@link Run#getId()} so that this class doesn't have to depend on it.
*/
protected
abstract
String
getIdOf
(
R
r
);
/**
* Allow subtype to capture a reference.
*/
protected
BuildReference
<
R
>
createReference
(
R
r
)
{
return
new
BuildReference
<
R
>(
getIdOf
(
r
),
r
);
}
/**
* Parses {@code R} instance from data in the specified directory.
*
...
...
@@ -541,19 +572,21 @@ public abstract class AbstractLazyLoadRunMap<R> extends AbstractMap<Integer,R> i
public
synchronized
boolean
removeValue
(
R
run
)
{
copy
();
byNumber
.
remove
(
getNumberOf
(
run
));
R
old
=
byId
.
remove
(
getIdOf
(
run
));
return
old
!=
null
;
BuildReference
<
R
>
old
=
byId
.
remove
(
getIdOf
(
run
));
return
unwrap
(
old
)
!=
null
;
}
/**
* Replaces all the current loaded Rs with the given ones.
*/
public
synchronized
void
reset
(
TreeMap
<
Integer
,
R
>
builds
)
{
TreeMap
<
Integer
,
R
>
byNumber
=
new
TreeMap
<
Integer
,
R
>(
COMPARATOR
);
TreeMap
<
String
,
R
>
byId
=
new
TreeMap
<
String
,
R
>(
COMPARATOR
);
TreeMap
<
Integer
,
BuildReference
<
R
>>
byNumber
=
new
TreeMap
<
Integer
,
BuildReference
<
R
>
>(
COMPARATOR
);
TreeMap
<
String
,
BuildReference
<
R
>>
byId
=
new
TreeMap
<
String
,
BuildReference
<
R
>
>(
COMPARATOR
);
for
(
R
r
:
builds
.
values
())
{
byId
.
put
(
getIdOf
(
r
),
r
);
byNumber
.
put
(
getNumberOf
(
r
),
r
);
String
id
=
getIdOf
(
r
);
BuildReference
<
R
>
ref
=
createReference
(
r
);
byId
.
put
(
id
,
ref
);
byNumber
.
put
(
getNumberOf
(
r
),
ref
);
}
this
.
byNumber
=
byNumber
;
...
...
core/src/main/java/jenkins/model/lazy/BuildReference.java
0 → 100644
浏览文件 @
c32f006f
package
jenkins.model.lazy
;
import
java.lang.ref.SoftReference
;
/**
* {@link SoftReference} to a build object.
*
* <p>
* To be able to re-retrieve the referent in case it is lost, this class
* remembers its ID (the job name is provided by the context because a {@link BuildReference}
* belongs to one and only {@link AbstractLazyLoadRunMap}.)
*
* <p>
* We use this ID for equality/hashCode so that we can have a collection of {@link BuildReference}
* and find things in it.
*
* @author Kohsuke Kawaguchi
*/
public
final
class
BuildReference
<
R
>
extends
SoftReference
<
R
>
{
final
String
id
;
public
BuildReference
(
String
id
,
R
referent
)
{
super
(
referent
);
this
.
id
=
id
;
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
return
true
;
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
return
false
;
BuildReference
that
=
(
BuildReference
)
o
;
return
id
.
equals
(
that
.
id
);
}
@Override
public
int
hashCode
()
{
return
id
.
hashCode
();
}
}
core/src/main/java/jenkins/model/lazy/BuildReferenceMapAdapter.java
0 → 100644
浏览文件 @
c32f006f
package
jenkins.model.lazy
;
import
groovy.util.MapEntry
;
import
hudson.util.AdaptedIterator
;
import
javax.annotation.Nullable
;
import
java.lang.reflect.Array
;
import
java.util.Collection
;
import
java.util.Comparator
;
import
java.util.Iterator
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.SortedMap
;
/**
* Take {@code SortedMap<Integer,BuildReference<R>>} and make it look like {@code SortedMap<Integer,R>}.
*
* When {@link BuildReference} lost the build object, we'll use {@link AbstractLazyLoadRunMap#getById(String)}
* to obtain one.
*
* @author Kohsuke Kawaguchi
*/
class
BuildReferenceMapAdapter
<
R
>
implements
SortedMap
<
Integer
,
R
>
{
private
final
AbstractLazyLoadRunMap
<
R
>
loader
;
private
final
SortedMap
<
Integer
,
BuildReference
<
R
>>
core
;
BuildReferenceMapAdapter
(
AbstractLazyLoadRunMap
<
R
>
loader
,
SortedMap
<
Integer
,
BuildReference
<
R
>>
core
)
{
this
.
loader
=
loader
;
this
.
core
=
core
;
}
private
R
unwrap
(
@Nullable
BuildReference
<
R
>
ref
)
{
if
(
ref
==
null
)
return
null
;
R
v
=
ref
.
get
();
if
(
v
==
null
)
v
=
loader
.
getById
(
ref
.
id
);
return
v
;
}
private
BuildReference
<
R
>
wrap
(
@Nullable
R
value
)
{
if
(
value
==
null
)
return
null
;
return
loader
.
createReference
(
value
);
}
public
Comparator
<?
super
Integer
>
comparator
()
{
return
core
.
comparator
();
}
public
SortedMap
<
Integer
,
R
>
subMap
(
Integer
fromKey
,
Integer
toKey
)
{
return
new
BuildReferenceMapAdapter
<
R
>(
loader
,
core
.
subMap
(
fromKey
,
toKey
));
}
public
SortedMap
<
Integer
,
R
>
headMap
(
Integer
toKey
)
{
return
new
BuildReferenceMapAdapter
<
R
>(
loader
,
core
.
headMap
(
toKey
));
}
public
SortedMap
<
Integer
,
R
>
tailMap
(
Integer
fromKey
)
{
return
new
BuildReferenceMapAdapter
<
R
>(
loader
,
core
.
tailMap
(
fromKey
));
}
public
Integer
firstKey
()
{
return
core
.
firstKey
();
}
public
Integer
lastKey
()
{
return
core
.
lastKey
();
}
public
Set
<
Integer
>
keySet
()
{
return
core
.
keySet
();
}
public
Collection
<
R
>
values
()
{
return
new
CollectionAdapter
(
core
.
values
());
}
public
Set
<
Entry
<
Integer
,
R
>>
entrySet
()
{
return
new
SetAdapter
(
core
.
entrySet
());
}
public
int
size
()
{
return
core
.
size
();
}
public
boolean
isEmpty
()
{
return
core
.
isEmpty
();
}
public
boolean
containsKey
(
Object
key
)
{
return
core
.
containsKey
(
key
);
}
public
boolean
containsValue
(
Object
value
)
{
return
core
.
containsValue
(
value
);
}
public
R
get
(
Object
key
)
{
return
unwrap
(
core
.
get
(
key
));
}
public
R
put
(
Integer
key
,
R
value
)
{
return
unwrap
(
core
.
put
(
key
,
wrap
(
value
)));
}
public
R
remove
(
Object
key
)
{
return
unwrap
(
core
.
remove
(
key
));
}
public
void
putAll
(
Map
<?
extends
Integer
,
?
extends
R
>
m
)
{
for
(
Entry
<?
extends
Integer
,
?
extends
R
>
e
:
m
.
entrySet
())
put
(
e
.
getKey
(),
e
.
getValue
());
}
public
void
clear
()
{
core
.
clear
();
}
@Override
public
boolean
equals
(
Object
o
)
{
return
core
.
equals
(
o
);
}
@Override
public
int
hashCode
()
{
return
core
.
hashCode
();
}
private
class
CollectionAdapter
implements
Collection
<
R
>
{
private
final
Collection
<
BuildReference
<
R
>>
core
;
private
CollectionAdapter
(
Collection
<
BuildReference
<
R
>>
core
)
{
this
.
core
=
core
;
}
public
int
size
()
{
return
core
.
size
();
}
public
boolean
isEmpty
()
{
return
core
.
isEmpty
();
}
public
boolean
contains
(
Object
o
)
{
// TODO: to properly pass this onto core, we need to wrap o into BuildReference but also needs to figure out ID.
throw
new
UnsupportedOperationException
();
}
public
Iterator
<
R
>
iterator
()
{
return
new
AdaptedIterator
<
BuildReference
<
R
>,
R
>(
core
.
iterator
())
{
protected
R
adapt
(
BuildReference
<
R
>
ref
)
{
return
unwrap
(
ref
);
}
};
}
public
Object
[]
toArray
()
{
return
_unwrap
(
core
.
toArray
());
}
public
<
T
>
T
[]
toArray
(
T
[]
a
)
{
int
size
=
size
();
T
[]
r
=
a
;
if
(
r
.
length
>
size
)
r
=
(
T
[])
Array
.
newInstance
(
a
.
getClass
().
getComponentType
(),
size
);
Iterator
<
R
>
itr
=
iterator
();
int
i
=
0
;
while
(
itr
.
hasNext
())
{
r
[
i
++]
=
(
T
)
itr
.
next
();
}
return
r
;
}
public
boolean
add
(
R
value
)
{
return
core
.
add
(
wrap
(
value
));
}
public
boolean
remove
(
Object
o
)
{
// return core.remove(o);
// TODO: to properly pass this onto core, we need to wrap o into BuildReference but also needs to figure out ID.
throw
new
UnsupportedOperationException
();
}
public
boolean
containsAll
(
Collection
<?>
c
)
{
for
(
Object
o
:
c
)
{
if
(!
contains
(
o
))
return
false
;
}
return
true
;
}
public
boolean
addAll
(
Collection
<?
extends
R
>
c
)
{
boolean
b
=
false
;
for
(
R
r
:
c
)
{
b
|=
add
(
r
);
}
return
b
;
}
public
boolean
removeAll
(
Collection
<?>
c
)
{
boolean
b
=
false
;
for
(
Object
o
:
c
)
{
b
|=
remove
(
o
);
}
return
b
;
}
public
boolean
retainAll
(
Collection
<?>
c
)
{
// TODO: to properly pass this onto core, we need to wrap o into BuildReference but also needs to figure out ID.
throw
new
UnsupportedOperationException
();
}
public
void
clear
()
{
core
.
clear
();
}
@Override
public
boolean
equals
(
Object
o
)
{
return
core
.
equals
(
o
);
}
@Override
public
int
hashCode
()
{
return
core
.
hashCode
();
}
private
Object
[]
_unwrap
(
Object
[]
r
)
{
for
(
int
i
=
0
;
i
<
r
.
length
;
i
++)
r
[
i
]
=
unwrap
((
BuildReference
<
R
>)
r
[
i
]);
return
r
;
}
}
private
class
SetAdapter
implements
Set
<
Entry
<
Integer
,
R
>>
{
private
final
Set
<
Entry
<
Integer
,
BuildReference
<
R
>>>
core
;
private
SetAdapter
(
Set
<
Entry
<
Integer
,
BuildReference
<
R
>>>
core
)
{
this
.
core
=
core
;
}
public
int
size
()
{
return
core
.
size
();
}
public
boolean
isEmpty
()
{
return
core
.
isEmpty
();
}
public
boolean
contains
(
Object
o
)
{
// TODO: to properly pass this onto core, we need to wrap o into BuildReference but also needs to figure out ID.
throw
new
UnsupportedOperationException
();
}
public
Iterator
<
Entry
<
Integer
,
R
>>
iterator
()
{
return
new
AdaptedIterator
<
Entry
<
Integer
,
BuildReference
<
R
>>,
Entry
<
Integer
,
R
>>(
core
.
iterator
())
{
protected
Entry
<
Integer
,
R
>
adapt
(
Entry
<
Integer
,
BuildReference
<
R
>>
e
)
{
return
_unwrap
(
e
);
}
};
}
public
Object
[]
toArray
()
{
return
_unwrap
(
core
.
toArray
());
}
public
<
T
>
T
[]
toArray
(
T
[]
a
)
{
int
size
=
size
();
T
[]
r
=
a
;
if
(
r
.
length
>
size
)
r
=
(
T
[])
Array
.
newInstance
(
a
.
getClass
().
getComponentType
(),
size
);
Iterator
<
Entry
<
Integer
,
R
>>
itr
=
iterator
();
int
i
=
0
;
while
(
itr
.
hasNext
())
{
r
[
i
++]
=
(
T
)
itr
.
next
();
}
return
r
;
}
public
boolean
add
(
Entry
<
Integer
,
R
>
value
)
{
return
core
.
add
(
_wrap
(
value
));
}
public
boolean
remove
(
Object
o
)
{
// return core.remove(o);
// TODO: to properly pass this onto core, we need to wrap o into BuildReference but also needs to figure out ID.
throw
new
UnsupportedOperationException
();
}
public
boolean
containsAll
(
Collection
<?>
c
)
{
for
(
Object
o
:
c
)
{
if
(!
contains
(
o
))
return
false
;
}
return
true
;
}
public
boolean
addAll
(
Collection
<?
extends
Entry
<
Integer
,
R
>>
c
)
{
boolean
b
=
false
;
for
(
Entry
<
Integer
,
R
>
r
:
c
)
{
b
|=
add
(
r
);
}
return
b
;
}
public
boolean
removeAll
(
Collection
<?>
c
)
{
boolean
b
=
false
;
for
(
Object
o
:
c
)
{
b
|=
remove
(
o
);
}
return
b
;
}
public
boolean
retainAll
(
Collection
<?>
c
)
{
// TODO: to properly pass this onto core, we need to wrap o into BuildReference but also needs to figure out ID.
throw
new
UnsupportedOperationException
();
}
public
void
clear
()
{
core
.
clear
();
}
@Override
public
boolean
equals
(
Object
o
)
{
return
core
.
equals
(
o
);
}
@Override
public
int
hashCode
()
{
return
core
.
hashCode
();
}
private
Entry
<
Integer
,
BuildReference
<
R
>>
_wrap
(
Entry
<
Integer
,
R
>
e
)
{
return
new
MapEntry
(
e
.
getKey
(),
wrap
(
e
.
getValue
()));
}
private
Entry
<
Integer
,
R
>
_unwrap
(
Entry
<
Integer
,
BuildReference
<
R
>>
e
)
{
return
new
MapEntry
(
e
.
getKey
(),
unwrap
(
e
.
getValue
()));
}
private
Object
[]
_unwrap
(
Object
[]
r
)
{
for
(
int
i
=
0
;
i
<
r
.
length
;
i
++)
r
[
i
]
=
_unwrap
((
Entry
)
r
[
i
]);
return
r
;
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录