Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
小 白蛋
Intellij Community
Commits
7211c819
Commit
7211c819
authored
6 years ago
by
Pavel Sergeev
Browse files
Options
Download
Plain Diff
Merge branch 'on-air' of git.labs.intellij.net:idea/community into on-air
parents
91c2ce56
34d198c2
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
platform/on-air-index/src/com/intellij/platform/onair/storage/api/TransientTree.java
+29
-0
...om/intellij/platform/onair/storage/api/TransientTree.java
platform/on-air-index/src/com/intellij/platform/onair/tree/BTree.java
+17
-20
...air-index/src/com/intellij/platform/onair/tree/BTree.java
platform/on-air-index/src/com/intellij/platform/onair/tree/BTreeCommon.java
+123
-0
...dex/src/com/intellij/platform/onair/tree/BTreeCommon.java
platform/on-air-index/src/com/intellij/platform/onair/tree/BasePage.java
+46
-195
...-index/src/com/intellij/platform/onair/tree/BasePage.java
platform/on-air-index/src/com/intellij/platform/onair/tree/BottomPage.java
+71
-47
...ndex/src/com/intellij/platform/onair/tree/BottomPage.java
platform/on-air-index/src/com/intellij/platform/onair/tree/IInternalPage.java
+10
-0
...x/src/com/intellij/platform/onair/tree/IInternalPage.java
platform/on-air-index/src/com/intellij/platform/onair/tree/IPage.java
+45
-0
...air-index/src/com/intellij/platform/onair/tree/IPage.java
platform/on-air-index/src/com/intellij/platform/onair/tree/InternalPage.java
+75
-54
...ex/src/com/intellij/platform/onair/tree/InternalPage.java
platform/on-air-index/src/com/intellij/platform/onair/tree/StoredBTreeUtil.java
+67
-0
...src/com/intellij/platform/onair/tree/StoredBTreeUtil.java
platform/on-air-index/src/com/intellij/platform/onair/tree/functional/BaseTransientPage.java
+97
-0
...lij/platform/onair/tree/functional/BaseTransientPage.java
platform/on-air-index/src/com/intellij/platform/onair/tree/functional/BottomTransientPage.java
+177
-0
...j/platform/onair/tree/functional/BottomTransientPage.java
platform/on-air-index/src/com/intellij/platform/onair/tree/functional/InternalTransientPage.java
+245
-0
...platform/onair/tree/functional/InternalTransientPage.java
platform/on-air-index/src/com/intellij/platform/onair/tree/functional/TransientBTree.java
+128
-0
...tellij/platform/onair/tree/functional/TransientBTree.java
platform/on-air-index/src/com/intellij/platform/onair/tree/functional/TransientBTreePrototype.java
+19
-0
...atform/onair/tree/functional/TransientBTreePrototype.java
platform/on-air-index/src/com/intellij/platform/onair/tree/functional/TransientBTreeUtil.java
+29
-0
...ij/platform/onair/tree/functional/TransientBTreeUtil.java
with
1178 additions
and
316 deletions
+1178
-316
platform/on-air-index/src/com/intellij/platform/onair/storage/api/TransientTree.java
0 → 100644
+
29
-
0
View file @
7211c819
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package
com.intellij.platform.onair.storage.api
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
public
interface
TransientTree
{
int
getKeySize
();
int
getBase
();
@Nullable
byte
[]
get
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
);
boolean
forEach
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
KeyValueConsumer
consumer
);
boolean
forEach
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
fromKey
,
@NotNull
KeyValueConsumer
consumer
);
TransientTree
put
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@NotNull
byte
[]
value
);
TransientTree
put
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@NotNull
byte
[]
value
,
boolean
overwrite
);
TransientTree
delete
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
);
TransientTree
delete
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@Nullable
byte
[]
value
);
TransientTree
flush
();
}
This diff is collapsed.
Click to expand it.
platform/on-air-index/src/com/intellij/platform/onair/tree/BTree.java
+
17
-
20
View file @
7211c819
...
...
@@ -34,6 +34,17 @@ public class BTree implements Tree {
Long
.
MIN_VALUE
;
}
public
BTree
(
Storage
storage
,
int
keySize
,
Address
rootAddress
,
long
startAddress
)
{
this
.
storage
=
storage
;
this
.
keySize
=
keySize
;
this
.
rootAddress
=
rootAddress
;
this
.
startAddress
=
startAddress
;
}
public
Storage
getStorage
()
{
return
storage
;
}
@Override
public
int
getKeySize
()
{
return
keySize
;
...
...
@@ -173,15 +184,15 @@ public class BTree implements Tree {
@Override
public
boolean
put
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@NotNull
byte
[]
value
,
boolean
overwrite
)
{
final
boolean
[]
result
=
new
boolean
[
1
];
final
BasePage
root
=
loadPage
(
novelty
,
rootAddress
).
getMutableCopy
(
novelty
,
this
);
final
BasePage
root
=
loadPage
(
novelty
,
rootAddress
).
getMutableCopy
(
novelty
);
final
BasePage
newSibling
=
root
.
put
(
novelty
,
key
,
value
,
overwrite
,
result
);
if
(
newSibling
!=
null
)
{
final
int
metadataOffset
=
(
keySize
+
BYTES_PER_ADDRESS
)
*
DEFAULT_BASE
;
final
byte
[]
bytes
=
new
byte
[
metadataOffset
+
2
];
bytes
[
metadataOffset
]
=
INTERNAL
;
bytes
[
metadataOffset
+
1
]
=
2
;
BasePage
.
set
(
0
,
root
.
getMinKey
(),
getKeySize
(),
bytes
,
root
.
address
.
getLowBytes
());
BasePage
.
set
(
1
,
newSibling
.
getMinKey
(),
getKeySize
(),
bytes
,
newSibling
.
address
.
getLowBytes
());
StoredBTreeUtil
.
set
(
0
,
root
.
getMinKey
(),
getKeySize
(),
bytes
,
root
.
address
.
getLowBytes
());
StoredBTreeUtil
.
set
(
1
,
newSibling
.
getMinKey
(),
getKeySize
(),
bytes
,
newSibling
.
address
.
getLowBytes
());
this
.
rootAddress
=
new
Address
(
novelty
.
alloc
(
bytes
));
}
else
{
...
...
@@ -198,7 +209,7 @@ public class BTree implements Tree {
@Override
public
boolean
delete
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@Nullable
byte
[]
value
)
{
final
boolean
[]
res
=
new
boolean
[
1
];
rootAddress
=
delete
(
novelty
,
loadPage
(
novelty
,
rootAddress
).
getMutableCopy
(
novelty
,
this
),
key
,
value
,
res
).
address
;
rootAddress
=
StoredBTreeUtil
.
delete
(
novelty
,
loadPage
(
novelty
,
rootAddress
).
getMutableCopy
(
novelty
),
key
,
value
,
res
).
address
;
return
res
[
0
];
}
...
...
@@ -212,6 +223,7 @@ public class BTree implements Tree {
return
loadPage
(
novelty
,
rootAddress
).
save
(
novelty
,
storage
,
consumer
);
}
@Override
public
BTree
snapshot
()
{
final
Address
root
=
rootAddress
;
if
(
root
.
isNovelty
())
{
...
...
@@ -228,7 +240,7 @@ public class BTree implements Tree {
return
address
.
isNovelty
()
&&
address
.
getLowBytes
()
>
startAddress
;
}
/* package */
BasePage
loadPage
(
@NotNull
Novelty
.
Accessor
novelty
,
Address
address
)
{
public
BasePage
loadPage
(
@NotNull
Novelty
.
Accessor
novelty
,
Address
address
)
{
final
boolean
isNovelty
=
address
.
isNovelty
();
final
byte
[]
bytes
=
isNovelty
?
novelty
.
lookup
(
address
.
getLowBytes
())
:
storage
.
lookup
(
address
);
if
(
bytes
==
null
)
{
...
...
@@ -279,21 +291,6 @@ public class BTree implements Tree {
return
new
BTree
(
storage
,
keySize
,
new
Address
(
novelty
.
alloc
(
bytes
)));
}
private
static
BasePage
delete
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
BasePage
root
,
@NotNull
byte
[]
key
,
@Nullable
byte
[]
value
,
boolean
[]
res
)
{
if
(
root
.
delete
(
novelty
,
key
,
value
))
{
root
=
root
.
mergeWithChildren
(
novelty
);
res
[
0
]
=
true
;
return
root
;
}
res
[
0
]
=
false
;
return
root
;
}
public
interface
ToString
{
String
renderKey
(
byte
[]
key
);
...
...
This diff is collapsed.
Click to expand it.
platform/on-air-index/src/com/intellij/platform/onair/tree/BTreeCommon.java
0 → 100644
+
123
-
0
View file @
7211c819
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package
com.intellij.platform.onair.tree
;
import
com.intellij.platform.onair.storage.api.KeyValueConsumer
;
import
com.intellij.platform.onair.storage.api.Novelty
;
import
org.jetbrains.annotations.NotNull
;
import
static
com
.
intellij
.
platform
.
onair
.
tree
.
ByteUtils
.
compare
;
public
class
BTreeCommon
{
public
static
boolean
traverseInternalPage
(
@NotNull
final
IInternalPage
page
,
@NotNull
Novelty
.
Accessor
novelty
,
int
fromIndex
,
@NotNull
byte
[]
fromKey
,
@NotNull
KeyValueConsumer
consumer
)
{
boolean
first
=
true
;
for
(
int
i
=
fromIndex
;
i
<
page
.
getSize
();
i
++)
{
IPage
child
=
page
.
getChild
(
novelty
,
i
);
if
(
first
)
{
if
(!
child
.
forEach
(
novelty
,
fromKey
,
consumer
))
{
return
false
;
}
first
=
false
;
}
else
{
if
(!
child
.
forEach
(
novelty
,
consumer
))
{
return
false
;
}
}
}
return
true
;
}
@SuppressWarnings
(
"unchecked"
)
public
static
<
T
extends
IPage
>
T
insertAt
(
@NotNull
T
page
,
int
base
,
@NotNull
Novelty
.
Accessor
novelty
,
int
pos
,
byte
[]
key
,
Object
child
)
{
if
(!
needSplit
(
page
,
base
))
{
page
.
insertDirectly
(
novelty
,
pos
,
key
,
child
);
return
null
;
}
else
{
int
splitPos
=
getSplitPos
(
page
,
pos
);
final
T
sibling
=
(
T
)
page
.
split
(
novelty
,
splitPos
,
page
.
getSize
()
-
splitPos
);
if
(
pos
>=
splitPos
)
{
// insert into right sibling
page
.
flush
(
novelty
);
insertAt
(
sibling
,
base
,
novelty
,
pos
-
splitPos
,
key
,
child
);
}
else
{
// insert into self
insertAt
(
sibling
,
base
,
novelty
,
pos
,
key
,
child
);
}
return
sibling
;
}
}
// TODO: extract Policy class
public
static
boolean
needSplit
(
@NotNull
final
IPage
page
,
final
int
base
)
{
return
page
.
getSize
()
>=
base
;
}
// TODO: extract Policy class
public
static
int
getSplitPos
(
@NotNull
final
IPage
page
,
final
int
insertPosition
)
{
// if inserting into the most right position - split as 8/1, otherwise - 1/1
final
int
pageSize
=
page
.
getSize
();
return
insertPosition
<
pageSize
?
pageSize
>>
1
:
(
pageSize
*
7
)
>>
3
;
}
// TODO: extract Policy class
public
static
boolean
needMerge
(
@NotNull
final
IPage
left
,
@NotNull
final
IPage
right
,
final
int
base
)
{
final
int
leftSize
=
left
.
getSize
();
final
int
rightSize
=
right
.
getSize
();
return
leftSize
==
0
||
rightSize
==
0
||
leftSize
+
rightSize
<=
((
base
*
7
)
>>
3
);
}
public
static
int
binarySearchGuess
(
byte
[]
backingArray
,
int
size
,
int
bytesPerKey
,
int
bytesPerAddress
,
byte
[]
key
)
{
int
index
=
binarySearch
(
backingArray
,
size
,
bytesPerKey
,
bytesPerAddress
,
key
);
if
(
index
<
0
)
{
index
=
Math
.
max
(
0
,
-
index
-
2
);
}
return
index
;
}
public
static
int
binarySearchRange
(
byte
[]
backingArray
,
int
size
,
int
bytesPerKey
,
int
bytesPerAddress
,
byte
[]
key
)
{
int
index
=
binarySearch
(
backingArray
,
size
,
bytesPerKey
,
bytesPerAddress
,
key
);
if
(
index
<
0
)
{
index
=
Math
.
max
(
0
,
-
index
-
1
);
}
return
index
;
}
public
static
int
binarySearch
(
byte
[]
backingArray
,
int
size
,
int
bytesPerKey
,
int
bytesPerAddress
,
byte
[]
key
)
{
final
int
bytesPerEntry
=
bytesPerKey
+
bytesPerAddress
;
int
low
=
0
;
int
high
=
size
-
1
;
while
(
low
<=
high
)
{
final
int
mid
=
(
low
+
high
)
>>>
1
;
final
int
offset
=
mid
*
bytesPerEntry
;
final
int
cmp
=
compare
(
backingArray
,
bytesPerKey
,
offset
,
key
,
bytesPerKey
,
0
);
if
(
cmp
<
0
)
{
low
=
mid
+
1
;
}
else
if
(
cmp
>
0
)
{
high
=
mid
-
1
;
}
else
{
// key found
return
mid
;
}
}
// key not found
return
-(
low
+
1
);
}
}
This diff is collapsed.
Click to expand it.
platform/on-air-index/src/com/intellij/platform/onair/tree/BasePage.java
+
46
-
195
View file @
7211c819
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package
com.intellij.platform.onair.tree
;
import
com.intellij.platform.onair.storage.api.*
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
...
...
@@ -10,11 +9,9 @@ import java.io.PrintStream;
import
java.util.Arrays
;
import
static
com
.
intellij
.
platform
.
onair
.
tree
.
BTree
.
BYTES_PER_ADDRESS
;
import
static
com
.
intellij
.
platform
.
onair
.
tree
.
ByteUtils
.
compare
;
import
static
com
.
intellij
.
platform
.
onair
.
tree
.
ByteUtils
.
readUnsignedLong
;
import
static
com
.
intellij
.
platform
.
onair
.
tree
.
ByteUtils
.
writeUnsignedLong
;
public
abstract
class
BasePage
{
public
abstract
class
BasePage
implements
IPage
{
protected
final
byte
[]
backingArray
;
protected
final
BTree
tree
;
protected
final
Address
address
;
...
...
@@ -28,38 +25,63 @@ public abstract class BasePage {
this
.
size
=
size
;
}
@Nullable
protected
abstract
byte
[]
get
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
final
byte
[]
key
);
public
Address
getAddress
()
{
return
address
;
}
@Override
public
int
getSize
()
{
return
size
;
}
@Override
public
void
flush
(
@NotNull
Novelty
.
Accessor
novelty
)
{
novelty
.
update
(
address
.
getLowBytes
(),
backingArray
);
}
@Override
public
boolean
isTransient
()
{
return
false
;
}
protected
abstract
BasePage
getChild
(
@NotNull
Novelty
.
Accessor
novelty
,
int
index
);
@Override
public
long
getMutableAddress
()
{
if
(!
address
.
isNovelty
())
{
throw
new
IllegalStateException
(
"address must be novelty"
);
}
return
address
.
getLowBytes
();
}
@Override
@NotNull
public
byte
[]
getMinKey
()
{
if
(
size
<=
0
)
{
throw
new
ArrayIndexOutOfBoundsException
(
"Page is empty."
);
}
return
Arrays
.
copyOf
(
backingArray
,
tree
.
getKeySize
());
// TODO: optimize
}
@Override
public
abstract
BasePage
mergeWithChildren
(
@NotNull
Novelty
.
Accessor
novelty
);
@Nullable
p
rotected
abstract
BasePage
put
(
@NotNull
Novelty
.
Accessor
novelty
,
p
ublic
abstract
BasePage
put
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@NotNull
byte
[]
value
,
boolean
overwrite
,
boolean
[]
result
);
protected
abstract
boolean
delete
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@Nullable
byte
[]
value
);
public
abstract
boolean
delete
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@Nullable
byte
[]
value
);
protected
abstract
BasePage
getMutableCopy
(
@NotNull
Novelty
.
Accessor
novelty
,
BTree
tree
);
protected
abstract
BasePage
getMutableCopy
(
@NotNull
Novelty
.
Accessor
novelty
);
protected
abstract
BasePage
split
(
@NotNull
Novelty
.
Accessor
novelty
,
int
from
,
int
length
);
protected
abstract
Address
save
(
@NotNull
final
Novelty
.
Accessor
novelty
,
@NotNull
final
Storage
storage
,
@NotNull
StorageConsumer
consumer
);
protected
abstract
Address
save
(
@NotNull
final
Novelty
.
Accessor
novelty
,
@NotNull
final
Storage
storage
,
@NotNull
StorageConsumer
consumer
);
protected
abstract
void
dump
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
PrintStream
out
,
int
level
,
BTree
.
ToString
renderer
);
protected
abstract
boolean
forEach
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
KeyValueConsumer
consumer
);
protected
abstract
boolean
forEach
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
fromKey
,
@NotNull
KeyValueConsumer
consumer
);
protected
abstract
BasePage
mergeWithChildren
(
@NotNull
Novelty
.
Accessor
novelty
);
protected
abstract
boolean
isBottom
();
// WARNING: this method allocates an array
protected
byte
[]
getKey
(
int
index
)
{
final
int
bytesPerKey
=
tree
.
getKeySize
();
...
...
@@ -77,10 +99,6 @@ public abstract class BasePage {
return
new
Address
(
highBytes
,
lowBytes
);
}
protected
byte
[]
getValue
(
@NotNull
Novelty
.
Accessor
novelty
,
int
index
)
{
return
tree
.
loadLeaf
(
novelty
,
getChildAddress
(
index
));
}
protected
void
incrementSize
()
{
if
(
size
>=
tree
.
getBase
())
{
throw
new
IllegalArgumentException
(
"Can't increase tree page size"
);
...
...
@@ -95,115 +113,6 @@ public abstract class BasePage {
setSize
(
size
-
value
);
}
@NotNull
protected
byte
[]
getMinKey
()
{
if
(
size
<=
0
)
{
throw
new
ArrayIndexOutOfBoundsException
(
"Page is empty."
);
}
return
Arrays
.
copyOf
(
backingArray
,
tree
.
getKeySize
());
// TODO: optimize
}
protected
int
binarySearchGuess
(
byte
[]
key
)
{
int
index
=
binarySearch
(
key
);
if
(
index
<
0
)
{
index
=
Math
.
max
(
0
,
-
index
-
2
);
}
return
index
;
}
protected
int
binarySearchRange
(
byte
[]
key
)
{
int
index
=
binarySearch
(
key
);
if
(
index
<
0
)
{
index
=
Math
.
max
(
0
,
-
index
-
1
);
}
return
index
;
}
protected
int
binarySearch
(
byte
[]
key
)
{
final
int
bytesPerKey
=
tree
.
getKeySize
();
final
int
bytesPerEntry
=
bytesPerKey
+
BYTES_PER_ADDRESS
;
int
low
=
0
;
int
high
=
size
-
1
;
while
(
low
<=
high
)
{
final
int
mid
=
(
low
+
high
)
>>>
1
;
final
int
offset
=
mid
*
bytesPerEntry
;
final
int
cmp
=
compare
(
backingArray
,
bytesPerKey
,
offset
,
key
,
bytesPerKey
,
0
);
if
(
cmp
<
0
)
{
low
=
mid
+
1
;
}
else
if
(
cmp
>
0
)
{
high
=
mid
-
1
;
}
else
{
// key found
return
mid
;
}
}
// key not found
return
-(
low
+
1
);
}
protected
void
flush
(
@NotNull
Novelty
.
Accessor
novelty
)
{
novelty
.
update
(
address
.
getLowBytes
(),
backingArray
);
}
protected
void
set
(
int
pos
,
byte
[]
key
,
long
lowAddressBytes
)
{
final
int
bytesPerKey
=
tree
.
getKeySize
();
if
(
key
.
length
!=
bytesPerKey
)
{
throw
new
IllegalArgumentException
(
"Invalid key length: need "
+
bytesPerKey
+
", got: "
+
key
.
length
);
}
set
(
pos
,
key
,
bytesPerKey
,
backingArray
,
lowAddressBytes
);
}
protected
BasePage
insertAt
(
@NotNull
Novelty
.
Accessor
novelty
,
int
pos
,
byte
[]
key
,
long
childAddress
)
{
if
(!
needSplit
(
this
))
{
insertDirectly
(
novelty
,
pos
,
key
,
childAddress
);
return
null
;
}
else
{
int
splitPos
=
getSplitPos
(
this
,
pos
);
final
BasePage
sibling
=
split
(
novelty
,
splitPos
,
size
-
splitPos
);
if
(
pos
>=
splitPos
)
{
// insert into right sibling
flush
(
novelty
);
sibling
.
insertAt
(
novelty
,
pos
-
splitPos
,
key
,
childAddress
);
}
else
{
// insert into self
insertAt
(
novelty
,
pos
,
key
,
childAddress
);
}
return
sibling
;
}
}
protected
void
insertDirectly
(
@NotNull
Novelty
.
Accessor
novelty
,
final
int
pos
,
@NotNull
byte
[]
key
,
long
childAddress
)
{
if
(
pos
<
size
)
{
copyChildren
(
pos
,
pos
+
1
);
}
set
(
pos
,
key
,
childAddress
);
incrementSize
();
flush
(
novelty
);
}
protected
void
copyChildren
(
final
int
from
,
final
int
to
)
{
if
(
from
>=
size
)
return
;
final
int
bytesPerEntry
=
tree
.
getKeySize
()
+
BYTES_PER_ADDRESS
;
System
.
arraycopy
(
backingArray
,
from
*
bytesPerEntry
,
backingArray
,
to
*
bytesPerEntry
,
(
size
-
from
)
*
bytesPerEntry
);
}
protected
void
mergeWith
(
BasePage
page
)
{
final
int
bytesPerEntry
=
tree
.
getKeySize
()
+
BYTES_PER_ADDRESS
;
System
.
arraycopy
(
page
.
backingArray
,
0
,
backingArray
,
size
*
bytesPerEntry
,
page
.
size
);
...
...
@@ -213,67 +122,9 @@ public abstract class BasePage {
backingArray
[
metadataOffset
+
1
]
=
(
byte
)
length
;
}
pr
ivate
void
setSize
(
int
updatedSize
)
{
pr
otected
void
setSize
(
int
updatedSize
)
{
final
int
sizeOffset
=
((
tree
.
getKeySize
()
+
BYTES_PER_ADDRESS
)
*
tree
.
getBase
())
+
1
;
backingArray
[
sizeOffset
]
=
(
byte
)
updatedSize
;
this
.
size
=
updatedSize
;
}
// TODO: extract Policy class
public
boolean
needSplit
(
@NotNull
final
BasePage
page
)
{
return
page
.
size
>=
tree
.
getBase
();
}
// TODO: extract Policy class
public
int
getSplitPos
(
@NotNull
final
BasePage
page
,
final
int
insertPosition
)
{
// if inserting into the most right position - split as 8/1, otherwise - 1/1
final
int
pageSize
=
page
.
size
;
return
insertPosition
<
pageSize
?
pageSize
>>
1
:
(
pageSize
*
7
)
>>
3
;
}
// TODO: extract Policy class
public
boolean
needMerge
(
@NotNull
final
BasePage
left
,
@NotNull
final
BasePage
right
)
{
final
int
leftSize
=
left
.
size
;
final
int
rightSize
=
right
.
size
;
return
leftSize
==
0
||
rightSize
==
0
||
leftSize
+
rightSize
<=
((
tree
.
getBase
()
*
7
)
>>
3
);
}
static
void
set
(
int
pos
,
byte
[]
key
,
int
bytesPerKey
,
byte
[]
backingArray
,
long
lowAddressBytes
)
{
final
int
offset
=
(
bytesPerKey
+
BYTES_PER_ADDRESS
)
*
pos
;
// write key
System
.
arraycopy
(
key
,
0
,
backingArray
,
offset
,
bytesPerKey
);
// write address
writeUnsignedLong
(
lowAddressBytes
,
8
,
backingArray
,
offset
+
bytesPerKey
);
writeUnsignedLong
(
0
,
8
,
backingArray
,
offset
+
bytesPerKey
+
8
);
}
static
void
set
(
int
pos
,
byte
[]
key
,
int
bytesPerKey
,
byte
[]
backingArray
,
byte
[]
inlineValue
)
{
int
offset
=
(
bytesPerKey
+
BYTES_PER_ADDRESS
)
*
pos
;
// write key
System
.
arraycopy
(
key
,
0
,
backingArray
,
offset
,
bytesPerKey
);
// write value
offset
+=
bytesPerKey
;
System
.
arraycopy
(
inlineValue
,
0
,
backingArray
,
offset
,
inlineValue
.
length
);
backingArray
[
offset
+
BYTES_PER_ADDRESS
-
1
]
=
(
byte
)
inlineValue
.
length
;
}
static
void
setChild
(
int
pos
,
int
bytesPerKey
,
byte
[]
backingArray
,
long
lowAddressBytes
,
long
highAddressBytes
)
{
final
int
offset
=
(
bytesPerKey
+
BYTES_PER_ADDRESS
)
*
pos
;
// write address
writeUnsignedLong
(
lowAddressBytes
,
8
,
backingArray
,
offset
+
bytesPerKey
);
writeUnsignedLong
(
highAddressBytes
,
8
,
backingArray
,
offset
+
bytesPerKey
+
8
);
}
static
void
setChild
(
int
pos
,
int
bytesPerKey
,
byte
[]
backingArray
,
byte
[]
inlineValue
)
{
final
int
offset
=
(
bytesPerKey
+
BYTES_PER_ADDRESS
)
*
pos
+
bytesPerKey
;
// write value
System
.
arraycopy
(
inlineValue
,
0
,
backingArray
,
offset
,
inlineValue
.
length
);
backingArray
[
offset
+
BYTES_PER_ADDRESS
-
1
]
=
(
byte
)
inlineValue
.
length
;
}
static
void
indent
(
PrintStream
out
,
int
level
)
{
for
(
int
i
=
0
;
i
<
level
;
i
++)
out
.
print
(
" "
);
}
}
This diff is collapsed.
Click to expand it.
platform/on-air-index/src/com/intellij/platform/onair/tree/BottomPage.java
+
71
-
47
View file @
7211c819
...
...
@@ -2,6 +2,7 @@
package
com.intellij.platform.onair.tree
;
import
com.intellij.platform.onair.storage.api.*
;
import
com.intellij.platform.onair.tree.functional.BaseTransientPage
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
...
...
@@ -9,6 +10,9 @@ import java.io.PrintStream;
import
java.util.Arrays
;
import
static
com
.
intellij
.
platform
.
onair
.
tree
.
BTree
.
BYTES_PER_ADDRESS
;
import
static
com
.
intellij
.
platform
.
onair
.
tree
.
StoredBTreeUtil
.
indent
;
import
static
com
.
intellij
.
platform
.
onair
.
tree
.
StoredBTreeUtil
.
set
;
import
static
com
.
intellij
.
platform
.
onair
.
tree
.
StoredBTreeUtil
.
setChild
;
public
class
BottomPage
extends
BasePage
{
protected
int
mask
;
...
...
@@ -20,8 +24,8 @@ public class BottomPage extends BasePage {
@Nullable
@Override
p
rotected
byte
[]
get
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
)
{
final
int
index
=
binarySearch
(
key
);
p
ublic
byte
[]
get
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
)
{
final
int
index
=
BTreeCommon
.
binarySearch
(
backingArray
,
size
,
tree
.
getKeySize
(),
BYTES_PER_ADDRESS
,
key
);
if
(
index
>=
0
)
{
return
getValue
(
novelty
,
index
);
}
...
...
@@ -29,7 +33,7 @@ public class BottomPage extends BasePage {
}
@Override
p
rotected
boolean
forEach
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
KeyValueConsumer
consumer
)
{
p
ublic
boolean
forEach
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
KeyValueConsumer
consumer
)
{
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
byte
[]
key
=
getKey
(
i
);
byte
[]
value
=
getValue
(
novelty
,
i
);
...
...
@@ -41,8 +45,8 @@ public class BottomPage extends BasePage {
}
@Override
p
rotected
boolean
forEach
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
fromKey
,
@NotNull
KeyValueConsumer
consumer
)
{
for
(
int
i
=
binarySearchRange
(
fromKey
);
i
<
size
;
i
++)
{
p
ublic
boolean
forEach
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
fromKey
,
@NotNull
KeyValueConsumer
consumer
)
{
for
(
int
i
=
BTreeCommon
.
binarySearchRange
(
backingArray
,
size
,
tree
.
getKeySize
(),
BYTES_PER_ADDRESS
,
fromKey
);
i
<
size
;
i
++)
{
byte
[]
key
=
getKey
(
i
);
byte
[]
value
=
getValue
(
novelty
,
i
);
if
(!
consumer
.
consume
(
key
,
value
))
{
...
...
@@ -54,8 +58,8 @@ public class BottomPage extends BasePage {
@Nullable
@Override
p
rotected
BasePage
put
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@NotNull
byte
[]
value
,
boolean
overwrite
,
boolean
[]
result
)
{
int
pos
=
binarySearch
(
key
);
p
ublic
BasePage
put
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@NotNull
byte
[]
value
,
boolean
overwrite
,
boolean
[]
result
)
{
int
pos
=
BTreeCommon
.
binarySearch
(
backingArray
,
size
,
tree
.
getKeySize
(),
BYTES_PER_ADDRESS
,
key
);
if
(
pos
>=
0
)
{
if
(
overwrite
)
{
final
int
bytesPerEntry
=
tree
.
getKeySize
()
+
BYTES_PER_ADDRESS
;
...
...
@@ -66,12 +70,12 @@ public class BottomPage extends BasePage {
}
else
{
// key found
if
((
mask
&
(
1L
<<
pos
))
==
0
)
{
/*
if ((mask & (1L << pos)) == 0) {
final Address childAddress = getChildAddress(pos);
/*
if (tree.canMutateInPlace(childAddress)) {
if (tree.canMutateInPlace(childAddress)) {
novelty.free(childAddress.getLowBytes());
}
*/
}
}
}
*/
final
long
childAddressLowBytes
=
novelty
.
alloc
(
value
);
mask
&=
~(
1
<<
pos
);
// drop mask bit
...
...
@@ -94,7 +98,7 @@ public class BottomPage extends BasePage {
page
=
insertValueAt
(
novelty
,
pos
,
key
,
value
);
}
else
{
page
=
insertAt
(
novelty
,
pos
,
key
,
novelty
.
alloc
(
value
)
)
;
page
=
BTreeCommon
.
insertAt
(
this
,
tree
.
getBase
(),
novelty
,
pos
,
key
,
value
);
}
result
[
0
]
=
true
;
tree
.
incrementSize
();
...
...
@@ -102,11 +106,11 @@ public class BottomPage extends BasePage {
}
@Override
p
rotected
boolean
delete
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@Nullable
byte
[]
value
)
{
final
int
pos
=
binarySearch
(
key
);
p
ublic
boolean
delete
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@Nullable
byte
[]
value
)
{
final
int
pos
=
BTreeCommon
.
binarySearch
(
backingArray
,
size
,
tree
.
getKeySize
(),
BYTES_PER_ADDRESS
,
key
);
if
(
pos
<
0
)
return
false
;
//
tree.addExpiredLoggable(keys
Address
es[
pos
]
);
//
novelty.free(getChild
Address
(
pos
)
);
copyChildren
(
pos
+
1
,
pos
);
tree
.
decrementSize
();
decrementSize
(
1
);
...
...
@@ -116,7 +120,7 @@ public class BottomPage extends BasePage {
}
@Override
p
rotected
BottomPage
split
(
@NotNull
Novelty
.
Accessor
novelty
,
int
from
,
int
length
)
{
p
ublic
BottomPage
split
(
@NotNull
Novelty
.
Accessor
novelty
,
int
from
,
int
length
)
{
final
BottomPage
result
=
copyOf
(
novelty
,
this
,
from
,
length
);
decrementSize
(
length
);
flush
(
novelty
);
...
...
@@ -124,7 +128,7 @@ public class BottomPage extends BasePage {
}
@Override
protected
BottomPage
getMutableCopy
(
@NotNull
Novelty
.
Accessor
novelty
,
BTree
tree
)
{
protected
BottomPage
getMutableCopy
(
@NotNull
Novelty
.
Accessor
novelty
)
{
if
(
tree
.
canMutateInPlace
(
address
))
{
return
this
;
}
...
...
@@ -135,6 +139,11 @@ public class BottomPage extends BasePage {
);
}
@Override
public
BaseTransientPage
getTransientCopy
(
long
epoch
)
{
throw
new
UnsupportedOperationException
();
// TODO
}
@Override
protected
Address
save
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
Storage
storage
,
@NotNull
StorageConsumer
consumer
)
{
final
byte
[]
resultBytes
=
Arrays
.
copyOf
(
backingArray
,
backingArray
.
length
);
...
...
@@ -159,14 +168,7 @@ public class BottomPage extends BasePage {
ByteUtils
.
writeUnsignedInt
(
mask
^
0x80000000
,
backingArray
,
bytesPerEntry
*
tree
.
getBase
()
+
2
);
}
@Override
protected
void
set
(
int
pos
,
byte
[]
key
,
long
lowAddressBytes
)
{
mask
&=
~(
1
<<
pos
);
// drop mask bit
updateMask
(
tree
.
getKeySize
()
+
BYTES_PER_ADDRESS
);
super
.
set
(
pos
,
key
,
lowAddressBytes
);
}
private
void
setValue
(
int
pos
,
byte
[]
key
,
byte
[]
value
)
{
private
void
setValue
(
int
pos
,
byte
[]
key
,
byte
[]
value
)
{
mask
|=
(
1
<<
pos
);
// set mask bit
updateMask
(
tree
.
getKeySize
()
+
BYTES_PER_ADDRESS
);
final
int
bytesPerKey
=
tree
.
getKeySize
();
...
...
@@ -178,13 +180,13 @@ public class BottomPage extends BasePage {
set
(
pos
,
key
,
bytesPerKey
,
backingArray
,
value
);
}
pr
otec
te
d
BasePage
insertValueAt
(
@NotNull
Novelty
.
Accessor
novelty
,
int
pos
,
byte
[]
key
,
byte
[]
value
)
{
if
(!
needSplit
(
this
))
{
pr
iva
te
BasePage
insertValueAt
(
@NotNull
Novelty
.
Accessor
novelty
,
int
pos
,
byte
[]
key
,
byte
[]
value
)
{
if
(!
BTreeCommon
.
needSplit
(
this
,
tree
.
getBase
()
))
{
insertValueDirectly
(
novelty
,
pos
,
key
,
value
);
return
null
;
}
else
{
int
splitPos
=
getSplitPos
(
this
,
pos
);
int
splitPos
=
BTreeCommon
.
getSplitPos
(
this
,
pos
);
final
BottomPage
sibling
=
split
(
novelty
,
splitPos
,
size
-
splitPos
);
if
(
pos
>=
splitPos
)
{
...
...
@@ -200,17 +202,6 @@ public class BottomPage extends BasePage {
}
}
@Override
protected
void
copyChildren
(
int
from
,
int
to
)
{
int
highBits
=
mask
&
(
0xFFFFFFFF
<<
from
);
int
lowBits
=
mask
&
~(
0xFFFFFFFF
<<
Math
.
min
(
from
,
to
));
this
.
mask
=
lowBits
|
highBits
<<
(
to
-
from
);
updateMask
(
tree
.
getKeySize
()
+
BYTES_PER_ADDRESS
);
super
.
copyChildren
(
from
,
to
);
}
private
void
insertValueDirectly
(
@NotNull
Novelty
.
Accessor
novelty
,
final
int
pos
,
@NotNull
byte
[]
key
,
@NotNull
byte
[]
value
)
{
if
(
pos
<
size
)
{
copyChildren
(
pos
,
pos
+
1
);
...
...
@@ -220,13 +211,12 @@ public class BottomPage extends BasePage {
flush
(
novelty
);
}
@Override
protected
byte
[]
getValue
(
@NotNull
Novelty
.
Accessor
novelty
,
int
index
)
{
private
byte
[]
getValue
(
@NotNull
Novelty
.
Accessor
novelty
,
int
index
)
{
if
((
mask
&
(
1L
<<
index
))
!=
0
)
{
return
getInlineValue
(
index
);
}
else
{
return
super
.
getValue
(
novelty
,
index
);
return
tree
.
loadLeaf
(
novelty
,
getChildAddress
(
index
)
)
;
}
}
...
...
@@ -243,17 +233,33 @@ public class BottomPage extends BasePage {
}
@Override
p
rotected
BasePage
get
Child
(
@NotNull
Novelty
.
Accessor
novelty
,
int
index
)
{
throw
new
UnsupportedOperationException
()
;
p
ublic
BasePage
mergeWith
Child
ren
(
@NotNull
Novelty
.
Accessor
novelty
)
{
return
this
;
}
@Override
protected
BasePage
mergeWithChildren
(
@NotNull
Novelty
.
Accessor
novelty
)
{
return
this
;
public
void
insertDirectly
(
@NotNull
Novelty
.
Accessor
novelty
,
final
int
pos
,
@NotNull
byte
[]
key
,
Object
child
)
{
if
(
pos
<
size
)
{
copyChildren
(
pos
,
pos
+
1
);
}
final
int
bytesPerKey
=
tree
.
getKeySize
();
if
(
key
.
length
!=
bytesPerKey
)
{
throw
new
IllegalArgumentException
(
"Invalid key length: need "
+
bytesPerKey
+
", got: "
+
key
.
length
);
}
mask
&=
~(
1
<<
pos
);
// drop mask bit
updateMask
(
tree
.
getKeySize
()
+
BYTES_PER_ADDRESS
);
set
(
pos
,
key
,
bytesPerKey
,
backingArray
,
novelty
.
alloc
((
byte
[])
child
));
incrementSize
();
flush
(
novelty
);
}
@Override
p
rotected
boolean
isBottom
()
{
p
ublic
boolean
isBottom
()
{
return
true
;
}
...
...
@@ -279,6 +285,24 @@ public class BottomPage extends BasePage {
}
}
private
void
copyChildren
(
int
from
,
int
to
)
{
int
highBits
=
mask
&
(
0xFFFFFFFF
<<
from
);
int
lowBits
=
mask
&
~(
0xFFFFFFFF
<<
Math
.
min
(
from
,
to
));
this
.
mask
=
lowBits
|
highBits
<<
(
to
-
from
);
updateMask
(
tree
.
getKeySize
()
+
BYTES_PER_ADDRESS
);
if
(
from
>=
size
)
return
;
final
int
bytesPerEntry
=
tree
.
getKeySize
()
+
BYTES_PER_ADDRESS
;
System
.
arraycopy
(
backingArray
,
from
*
bytesPerEntry
,
backingArray
,
to
*
bytesPerEntry
,
(
size
-
from
)
*
bytesPerEntry
);
}
private
static
BottomPage
copyOf
(
@NotNull
Novelty
.
Accessor
novelty
,
BottomPage
page
,
int
from
,
int
length
)
{
byte
[]
bytes
=
new
byte
[
page
.
backingArray
.
length
];
...
...
This diff is collapsed.
Click to expand it.
platform/on-air-index/src/com/intellij/platform/onair/tree/IInternalPage.java
0 → 100644
+
10
-
0
View file @
7211c819
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package
com.intellij.platform.onair.tree
;
import
com.intellij.platform.onair.storage.api.Novelty
;
import
org.jetbrains.annotations.NotNull
;
public
interface
IInternalPage
extends
IPage
{
IPage
getChild
(
@NotNull
Novelty
.
Accessor
novelty
,
final
int
index
);
}
This diff is collapsed.
Click to expand it.
platform/on-air-index/src/com/intellij/platform/onair/tree/IPage.java
0 → 100644
+
45
-
0
View file @
7211c819
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package
com.intellij.platform.onair.tree
;
import
com.intellij.platform.onair.storage.api.KeyValueConsumer
;
import
com.intellij.platform.onair.storage.api.Novelty
;
import
com.intellij.platform.onair.tree.functional.BaseTransientPage
;
import
org.jetbrains.annotations.NotNull
;
public
interface
IPage
{
// meta
int
getSize
();
boolean
isBottom
();
boolean
isTransient
();
// TODO: cleanup?
long
getMutableAddress
();
BaseTransientPage
getTransientCopy
(
long
epoch
);
// crud
byte
[]
getMinKey
();
byte
[]
get
(
Novelty
.
Accessor
novelty
,
byte
[]
key
);
boolean
forEach
(
Novelty
.
Accessor
novelty
,
KeyValueConsumer
consumer
);
boolean
forEach
(
Novelty
.
Accessor
novelty
,
byte
[]
key
,
KeyValueConsumer
consumer
);
// tree-specific methods
void
insertDirectly
(
@NotNull
Novelty
.
Accessor
novelty
,
final
int
pos
,
@NotNull
byte
[]
key
,
Object
child
);
IPage
mergeWithChildren
(
@NotNull
Novelty
.
Accessor
novelty
);
// del?
IPage
split
(
@NotNull
Novelty
.
Accessor
novelty
,
int
from
,
int
length
);
// save
void
flush
(
@NotNull
Novelty
.
Accessor
novelty
);
}
This diff is collapsed.
Click to expand it.
platform/on-air-index/src/com/intellij/platform/onair/tree/InternalPage.java
+
75
-
54
View file @
7211c819
...
...
@@ -2,6 +2,7 @@
package
com.intellij.platform.onair.tree
;
import
com.intellij.platform.onair.storage.api.*
;
import
com.intellij.platform.onair.tree.functional.BaseTransientPage
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
...
...
@@ -9,8 +10,10 @@ import java.io.PrintStream;
import
java.util.Arrays
;
import
static
com
.
intellij
.
platform
.
onair
.
tree
.
BTree
.
BYTES_PER_ADDRESS
;
import
static
com
.
intellij
.
platform
.
onair
.
tree
.
StoredBTreeUtil
.
indent
;
import
static
com
.
intellij
.
platform
.
onair
.
tree
.
StoredBTreeUtil
.
setChild
;
public
class
InternalPage
extends
BasePage
{
public
class
InternalPage
extends
BasePage
implements
IInternalPage
{
public
InternalPage
(
byte
[]
backingArray
,
BTree
tree
,
Address
address
,
int
size
)
{
super
(
backingArray
,
tree
,
address
,
size
);
...
...
@@ -18,16 +21,16 @@ public class InternalPage extends BasePage {
@Override
@Nullable
protected
byte
[]
get
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
)
{
final
int
index
=
binarySearch
(
key
);
public
byte
[]
get
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
)
{
final
int
index
=
BTreeCommon
.
binarySearch
(
backingArray
,
size
,
tree
.
getKeySize
(),
BYTES_PER_ADDRESS
,
key
);
return
index
<
0
?
getChild
(
novelty
,
Math
.
max
(-
index
-
2
,
0
)).
get
(
novelty
,
key
)
:
getChild
(
novelty
,
index
).
get
(
novelty
,
key
);
}
@Override
p
rotected
boolean
forEach
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
KeyValueConsumer
consumer
)
{
p
ublic
boolean
forEach
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
KeyValueConsumer
consumer
)
{
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
Address
childAddress
=
getChildAddress
(
i
);
BasePage
child
=
tree
.
loadPage
(
novelty
,
childAddress
);
BasePage
child
=
getChild
(
novelty
,
i
);
if
(!
child
.
forEach
(
novelty
,
consumer
))
{
return
false
;
}
...
...
@@ -36,29 +39,16 @@ public class InternalPage extends BasePage {
}
@Override
protected
boolean
forEach
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
fromKey
,
@NotNull
KeyValueConsumer
consumer
)
{
boolean
first
=
true
;
for
(
int
i
=
binarySearchGuess
(
fromKey
);
i
<
size
;
i
++)
{
Address
childAddress
=
getChildAddress
(
i
);
BasePage
child
=
tree
.
loadPage
(
novelty
,
childAddress
);
if
(
first
)
{
if
(!
child
.
forEach
(
novelty
,
fromKey
,
consumer
))
{
return
false
;
}
first
=
false
;
}
else
{
if
(!
child
.
forEach
(
novelty
,
consumer
))
{
return
false
;
}
}
}
return
true
;
public
boolean
forEach
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
fromKey
,
@NotNull
KeyValueConsumer
consumer
)
{
final
int
fromIndex
=
BTreeCommon
.
binarySearchGuess
(
backingArray
,
size
,
tree
.
getKeySize
(),
BYTES_PER_ADDRESS
,
fromKey
);
return
BTreeCommon
.
traverseInternalPage
(
this
,
novelty
,
fromIndex
,
fromKey
,
consumer
);
}
@Override
@Nullable
p
rotected
BasePage
put
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@NotNull
byte
[]
value
,
boolean
overwrite
,
boolean
[]
result
)
{
int
pos
=
binarySearch
(
key
);
p
ublic
BasePage
put
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@NotNull
byte
[]
value
,
boolean
overwrite
,
boolean
[]
result
)
{
int
pos
=
BTreeCommon
.
binarySearch
(
backingArray
,
size
,
tree
.
getKeySize
(),
BYTES_PER_ADDRESS
,
key
);
if
(
pos
>=
0
&&
!
overwrite
)
{
// key found and overwrite is not possible - error
...
...
@@ -71,22 +61,16 @@ public class InternalPage extends BasePage {
if
(
pos
<
0
)
pos
=
0
;
}
final
BasePage
child
=
getChild
(
novelty
,
pos
).
getMutableCopy
(
novelty
,
tree
);
final
BasePage
child
=
getChild
(
novelty
,
pos
).
getMutableCopy
(
novelty
);
final
BasePage
newChild
=
child
.
put
(
novelty
,
key
,
value
,
overwrite
,
result
);
// change min key for child
if
(
result
[
0
])
{
if
(!
child
.
address
.
isNovelty
())
{
throw
new
IllegalStateException
(
"child must be novelty"
);
}
set
(
pos
,
child
.
getMinKey
(),
child
.
address
.
getLowBytes
());
set
(
pos
,
child
.
getMinKey
(),
child
);
if
(
newChild
==
null
)
{
flush
(
novelty
);
}
else
{
if
(!
newChild
.
address
.
isNovelty
())
{
throw
new
IllegalStateException
(
"child must be novelty"
);
}
return
insertAt
(
novelty
,
pos
+
1
,
newChild
.
getMinKey
(),
newChild
.
address
.
getLowBytes
());
return
BTreeCommon
.
insertAt
(
this
,
tree
.
getBase
(),
novelty
,
pos
+
1
,
newChild
.
getMinKey
(),
newChild
);
}
}
...
...
@@ -94,35 +78,35 @@ public class InternalPage extends BasePage {
}
@Override
p
rotected
boolean
delete
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@Nullable
byte
[]
value
)
{
int
pos
=
binarySearchGuess
(
key
);
final
BasePage
child
=
getChild
(
novelty
,
pos
).
getMutableCopy
(
novelty
,
tree
);
p
ublic
boolean
delete
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@Nullable
byte
[]
value
)
{
int
pos
=
BTreeCommon
.
binarySearchGuess
(
backingArray
,
size
,
tree
.
getKeySize
(),
BYTES_PER_ADDRESS
,
key
);
final
BasePage
child
=
getChild
(
novelty
,
pos
).
getMutableCopy
(
novelty
);
if
(!
child
.
delete
(
novelty
,
key
,
value
))
{
return
false
;
}
// if first element was removed in child, then update min key
final
int
childSize
=
child
.
size
;
if
(
childSize
>
0
)
{
set
(
pos
,
child
.
getMinKey
(),
child
.
address
.
getLowBytes
()
);
set
(
pos
,
child
.
getMinKey
(),
child
);
}
if
(
pos
>
0
)
{
final
BasePage
left
=
getChild
(
novelty
,
pos
-
1
);
if
(
needMerge
(
left
,
child
))
{
if
(
BTreeCommon
.
needMerge
(
left
,
child
,
tree
.
getBase
()
))
{
// merge child into left sibling
// re-get mutable left
getChild
(
novelty
,
pos
-
1
).
getMutableCopy
(
novelty
,
tree
).
mergeWith
(
child
);
getChild
(
novelty
,
pos
-
1
).
getMutableCopy
(
novelty
).
mergeWith
(
child
);
removeChild
(
pos
);
}
}
else
if
(
pos
+
1
<
size
)
{
final
BasePage
right
=
getChild
(
novelty
,
pos
+
1
);
if
(
needMerge
(
child
,
right
))
{
if
(
BTreeCommon
.
needMerge
(
child
,
right
,
tree
.
getBase
()
))
{
// merge child with right sibling
final
BasePage
mutableChild
=
child
.
getMutableCopy
(
novelty
,
tree
);
final
BasePage
mutableChild
=
child
.
getMutableCopy
(
novelty
);
mutableChild
.
mergeWith
(
getChild
(
novelty
,
pos
+
1
));
removeChild
(
pos
);
// change key for link to right
set
(
pos
,
mutableChild
.
getMinKey
(),
mutableChild
.
address
.
getLowBytes
()
);
set
(
pos
,
mutableChild
.
getMinKey
(),
mutableChild
);
}
}
else
if
(
childSize
==
0
)
{
...
...
@@ -133,14 +117,14 @@ public class InternalPage extends BasePage {
}
@Override
p
rotected
Base
Page
split
(
@NotNull
Novelty
.
Accessor
novelty
,
int
from
,
int
length
)
{
final
I
nternal
Page
result
=
copyOf
(
novelty
,
this
,
from
,
length
);
p
ublic
I
Page
split
(
@NotNull
Novelty
.
Accessor
novelty
,
int
from
,
int
length
)
{
final
IPage
result
=
copyOf
(
novelty
,
this
,
from
,
length
);
decrementSize
(
length
);
return
result
;
}
@Override
protected
InternalPage
getMutableCopy
(
@NotNull
Novelty
.
Accessor
novelty
,
BTree
tree
)
{
protected
InternalPage
getMutableCopy
(
@NotNull
Novelty
.
Accessor
novelty
)
{
if
(
tree
.
canMutateInPlace
(
address
))
{
return
this
;
}
...
...
@@ -151,6 +135,11 @@ public class InternalPage extends BasePage {
);
}
@Override
public
BaseTransientPage
getTransientCopy
(
long
epoch
)
{
throw
new
UnsupportedOperationException
();
// TODO
}
@Override
protected
Address
save
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
Storage
storage
,
@NotNull
StorageConsumer
consumer
)
{
final
byte
[]
resultBytes
=
Arrays
.
copyOf
(
backingArray
,
backingArray
.
length
);
...
...
@@ -169,26 +158,31 @@ public class InternalPage extends BasePage {
@Override
@NotNull
p
rotected
BasePage
getChild
(
@NotNull
Novelty
.
Accessor
novelty
,
final
int
index
)
{
p
ublic
BasePage
getChild
(
@NotNull
Novelty
.
Accessor
novelty
,
final
int
index
)
{
return
tree
.
loadPage
(
novelty
,
getChildAddress
(
index
));
}
@Override
p
rotected
BasePage
mergeWithChildren
(
@NotNull
Novelty
.
Accessor
novelty
)
{
p
ublic
BasePage
mergeWithChildren
(
@NotNull
Novelty
.
Accessor
novelty
)
{
BasePage
result
=
this
;
while
(!
result
.
isBottom
()
&&
result
.
s
ize
==
1
)
{
result
=
result
.
getChild
(
novelty
,
0
);
while
(!
result
.
isBottom
()
&&
result
.
getS
ize
()
==
1
)
{
result
=
((
InternalPage
)
result
)
.
getChild
(
novelty
,
0
);
}
return
result
;
}
protected
void
removeChild
(
int
pos
)
{
copyChildren
(
pos
+
1
,
pos
);
decrementSize
(
1
);
@Override
public
void
insertDirectly
(
@NotNull
Novelty
.
Accessor
novelty
,
final
int
pos
,
@NotNull
byte
[]
key
,
Object
child
)
{
if
(
pos
<
size
)
{
copyChildren
(
pos
,
pos
+
1
);
}
set
(
pos
,
key
,
(
IPage
)
child
);
incrementSize
();
flush
(
novelty
);
}
@Override
p
rotected
boolean
isBottom
()
{
p
ublic
boolean
isBottom
()
{
return
false
;
}
...
...
@@ -205,6 +199,33 @@ public class InternalPage extends BasePage {
}
}
private
void
removeChild
(
int
pos
)
{
copyChildren
(
pos
+
1
,
pos
);
decrementSize
(
1
);
}
private
void
set
(
int
pos
,
byte
[]
key
,
IPage
child
)
{
final
int
bytesPerKey
=
tree
.
getKeySize
();
if
(
key
.
length
!=
bytesPerKey
)
{
throw
new
IllegalArgumentException
(
"Invalid key length: need "
+
bytesPerKey
+
", got: "
+
key
.
length
);
}
StoredBTreeUtil
.
set
(
pos
,
key
,
bytesPerKey
,
backingArray
,
child
.
getMutableAddress
());
}
private
void
copyChildren
(
final
int
from
,
final
int
to
)
{
if
(
from
>=
size
)
return
;
final
int
bytesPerEntry
=
tree
.
getKeySize
()
+
BYTES_PER_ADDRESS
;
System
.
arraycopy
(
backingArray
,
from
*
bytesPerEntry
,
backingArray
,
to
*
bytesPerEntry
,
(
size
-
from
)
*
bytesPerEntry
);
}
private
static
InternalPage
copyOf
(
@NotNull
Novelty
.
Accessor
novelty
,
InternalPage
page
,
int
from
,
int
length
)
{
byte
[]
bytes
=
new
byte
[
page
.
backingArray
.
length
];
...
...
This diff is collapsed.
Click to expand it.
platform/on-air-index/src/com/intellij/platform/onair/tree/StoredBTreeUtil.java
0 → 100644
+
67
-
0
View file @
7211c819
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package
com.intellij.platform.onair.tree
;
import
com.intellij.platform.onair.storage.api.Novelty
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
import
java.io.PrintStream
;
import
static
com
.
intellij
.
platform
.
onair
.
tree
.
BTree
.
BYTES_PER_ADDRESS
;
import
static
com
.
intellij
.
platform
.
onair
.
tree
.
ByteUtils
.
writeUnsignedLong
;
public
class
StoredBTreeUtil
{
public
static
BasePage
delete
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
BasePage
root
,
@NotNull
byte
[]
key
,
@Nullable
byte
[]
value
,
boolean
[]
res
)
{
if
(
root
.
delete
(
novelty
,
key
,
value
))
{
root
=
root
.
mergeWithChildren
(
novelty
);
res
[
0
]
=
true
;
return
root
;
}
res
[
0
]
=
false
;
return
root
;
}
public
static
void
set
(
int
pos
,
byte
[]
key
,
int
bytesPerKey
,
byte
[]
backingArray
,
long
lowAddressBytes
)
{
final
int
offset
=
(
bytesPerKey
+
BYTES_PER_ADDRESS
)
*
pos
;
// write key
System
.
arraycopy
(
key
,
0
,
backingArray
,
offset
,
bytesPerKey
);
// write address
writeUnsignedLong
(
lowAddressBytes
,
8
,
backingArray
,
offset
+
bytesPerKey
);
writeUnsignedLong
(
0
,
8
,
backingArray
,
offset
+
bytesPerKey
+
8
);
}
public
static
void
set
(
int
pos
,
byte
[]
key
,
int
bytesPerKey
,
byte
[]
backingArray
,
byte
[]
inlineValue
)
{
int
offset
=
(
bytesPerKey
+
BYTES_PER_ADDRESS
)
*
pos
;
// write key
System
.
arraycopy
(
key
,
0
,
backingArray
,
offset
,
bytesPerKey
);
// write value
offset
+=
bytesPerKey
;
System
.
arraycopy
(
inlineValue
,
0
,
backingArray
,
offset
,
inlineValue
.
length
);
backingArray
[
offset
+
BYTES_PER_ADDRESS
-
1
]
=
(
byte
)
inlineValue
.
length
;
}
public
static
void
setChild
(
int
pos
,
int
bytesPerKey
,
byte
[]
backingArray
,
long
lowAddressBytes
,
long
highAddressBytes
)
{
final
int
offset
=
(
bytesPerKey
+
BYTES_PER_ADDRESS
)
*
pos
;
// write address
writeUnsignedLong
(
lowAddressBytes
,
8
,
backingArray
,
offset
+
bytesPerKey
);
writeUnsignedLong
(
highAddressBytes
,
8
,
backingArray
,
offset
+
bytesPerKey
+
8
);
}
public
static
void
setChild
(
int
pos
,
int
bytesPerKey
,
byte
[]
backingArray
,
byte
[]
inlineValue
)
{
final
int
offset
=
(
bytesPerKey
+
BYTES_PER_ADDRESS
)
*
pos
+
bytesPerKey
;
// write value
System
.
arraycopy
(
inlineValue
,
0
,
backingArray
,
offset
,
inlineValue
.
length
);
backingArray
[
offset
+
BYTES_PER_ADDRESS
-
1
]
=
(
byte
)
inlineValue
.
length
;
}
public
static
void
indent
(
PrintStream
out
,
int
level
)
{
for
(
int
i
=
0
;
i
<
level
;
i
++)
out
.
print
(
" "
);
}
}
This diff is collapsed.
Click to expand it.
platform/on-air-index/src/com/intellij/platform/onair/tree/functional/BaseTransientPage.java
0 → 100644
+
97
-
0
View file @
7211c819
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package
com.intellij.platform.onair.tree.functional
;
import
com.intellij.platform.onair.storage.api.Novelty
;
import
com.intellij.platform.onair.tree.IPage
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
import
java.util.Arrays
;
public
abstract
class
BaseTransientPage
implements
IPage
{
protected
final
byte
[]
backingArray
;
// keys only
protected
final
TransientBTreePrototype
tree
;
protected
final
long
epoch
;
protected
int
size
;
// TODO: allow in-place update only for current epoch nodes
protected
BaseTransientPage
(
byte
[]
backingArray
,
TransientBTreePrototype
tree
,
int
size
,
long
epoch
)
{
this
.
backingArray
=
backingArray
;
this
.
tree
=
tree
;
this
.
size
=
size
;
this
.
epoch
=
epoch
;
}
@Override
public
int
getSize
()
{
return
size
;
}
@Override
public
boolean
isTransient
()
{
return
true
;
}
@Override
public
void
flush
(
@NotNull
Novelty
.
Accessor
novelty
)
{
// do nothing
}
@Override
public
long
getMutableAddress
()
{
throw
new
UnsupportedOperationException
();
}
/*@Override
public abstract IPage mergeWithChildren(@NotNull Novelty.Accessor novelty);*/
@Override
@NotNull
public
byte
[]
getMinKey
()
{
if
(
size
<=
0
)
{
throw
new
ArrayIndexOutOfBoundsException
(
"Page is empty."
);
}
return
Arrays
.
copyOf
(
backingArray
,
tree
.
keySize
);
// TODO: optimize
}
@Nullable
public
abstract
BaseTransientPage
put
(
@NotNull
Novelty
.
Accessor
novelty
,
long
epoch
,
@NotNull
byte
[]
key
,
@NotNull
byte
[]
value
,
boolean
overwrite
,
boolean
[]
result
);
public
abstract
boolean
delete
(
@NotNull
Novelty
.
Accessor
novelty
,
long
epoch
,
@NotNull
byte
[]
key
,
@Nullable
byte
[]
value
);
protected
void
incrementSize
()
{
if
(
size
>=
tree
.
base
)
{
throw
new
IllegalArgumentException
(
"Can't increase tree page size"
);
}
size
+=
1
;
}
protected
void
decrementSize
(
final
int
value
)
{
if
(
size
<
value
)
{
throw
new
IllegalArgumentException
(
"Can't decrease tree page size "
+
size
+
" on "
+
value
);
}
size
-=
value
;
}
// WARNING: this method allocates an array
protected
byte
[]
getKey
(
int
index
)
{
final
int
bytesPerKey
=
tree
.
keySize
;
byte
[]
result
=
new
byte
[
bytesPerKey
];
final
int
offset
=
bytesPerKey
*
index
;
System
.
arraycopy
(
backingArray
,
offset
,
result
,
0
,
bytesPerKey
);
return
result
;
}
protected
void
mergeWith
(
BaseTransientPage
page
)
{
final
int
bytesPerKey
=
tree
.
keySize
;
System
.
arraycopy
(
page
.
backingArray
,
0
,
backingArray
,
size
*
bytesPerKey
,
page
.
size
);
this
.
size
+=
page
.
size
;
}
}
This diff is collapsed.
Click to expand it.
platform/on-air-index/src/com/intellij/platform/onair/tree/functional/BottomTransientPage.java
0 → 100644
+
177
-
0
View file @
7211c819
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package
com.intellij.platform.onair.tree.functional
;
import
com.intellij.platform.onair.storage.api.Address
;
import
com.intellij.platform.onair.storage.api.KeyValueConsumer
;
import
com.intellij.platform.onair.storage.api.Novelty
;
import
com.intellij.platform.onair.tree.BTreeCommon
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
public
class
BottomTransientPage
extends
BaseTransientPage
{
protected
final
Object
[]
values
;
// Address | byte[]
public
BottomTransientPage
(
byte
[]
backingArray
,
TransientBTreePrototype
tree
,
int
size
,
long
epoch
,
Object
[]
values
)
{
super
(
backingArray
,
tree
,
size
,
epoch
);
this
.
values
=
values
;
}
@Nullable
@Override
public
byte
[]
get
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
)
{
final
int
index
=
BTreeCommon
.
binarySearch
(
backingArray
,
size
,
tree
.
keySize
,
0
,
key
);
if
(
index
>=
0
)
{
return
getValue
(
novelty
,
index
);
}
return
null
;
}
@Override
public
boolean
forEach
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
KeyValueConsumer
consumer
)
{
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
byte
[]
key
=
getKey
(
i
);
byte
[]
value
=
getValue
(
novelty
,
i
);
if
(!
consumer
.
consume
(
key
,
value
))
{
return
false
;
}
}
return
true
;
}
@Override
public
boolean
forEach
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
fromKey
,
@NotNull
KeyValueConsumer
consumer
)
{
for
(
int
i
=
BTreeCommon
.
binarySearchRange
(
backingArray
,
size
,
tree
.
keySize
,
0
,
fromKey
);
i
<
size
;
i
++)
{
byte
[]
key
=
getKey
(
i
);
byte
[]
value
=
getValue
(
novelty
,
i
);
if
(!
consumer
.
consume
(
key
,
value
))
{
return
false
;
}
}
return
true
;
}
@Nullable
@Override
public
BaseTransientPage
put
(
@NotNull
Novelty
.
Accessor
novelty
,
long
epoch
,
@NotNull
byte
[]
key
,
@NotNull
byte
[]
value
,
boolean
overwrite
,
boolean
[]
result
)
{
throw
new
UnsupportedOperationException
();
// TODO
}
@Override
public
boolean
delete
(
@NotNull
Novelty
.
Accessor
novelty
,
long
epoch
,
@NotNull
byte
[]
key
,
byte
[]
value
)
{
throw
new
UnsupportedOperationException
();
// TODO
}
@Override
public
void
insertDirectly
(
@NotNull
Novelty
.
Accessor
novelty
,
final
int
pos
,
@NotNull
byte
[]
key
,
Object
child
)
{
if
(
pos
<
size
)
{
copyChildren
(
pos
,
pos
+
1
);
}
final
int
bytesPerKey
=
tree
.
keySize
;
if
(
key
.
length
!=
bytesPerKey
)
{
throw
new
IllegalArgumentException
(
"Invalid key length: need "
+
bytesPerKey
+
", got: "
+
key
.
length
);
}
setTransient
(
pos
,
key
,
(
byte
[])
child
);
incrementSize
();
flush
(
novelty
);
}
@Override
public
BottomTransientPage
split
(
@NotNull
Novelty
.
Accessor
novelty
,
int
from
,
int
length
)
{
final
BottomTransientPage
result
=
copyOf
(
this
,
epoch
,
from
,
length
);
decrementSize
(
length
);
flush
(
novelty
);
return
result
;
}
@Override
public
BottomTransientPage
getTransientCopy
(
long
epoch
)
{
if
(
this
.
epoch
>=
epoch
)
{
return
this
;
}
else
{
return
copyOf
(
this
,
epoch
,
0
,
size
);
}
}
@Override
public
BaseTransientPage
mergeWithChildren
(
@NotNull
Novelty
.
Accessor
novelty
)
{
return
this
;
}
@Override
public
boolean
isBottom
()
{
return
true
;
}
private
byte
[]
getValue
(
@NotNull
Novelty
.
Accessor
novelty
,
int
index
)
{
final
Object
child
=
values
[
index
];
if
(
child
instanceof
byte
[])
{
return
(
byte
[])
child
;
}
final
Address
address
=
(
Address
)
child
;
final
boolean
isNovelty
=
address
.
isNovelty
();
return
isNovelty
?
novelty
.
lookup
(
address
.
getLowBytes
())
:
tree
.
storage
.
lookup
(
address
);
}
private
void
setTransient
(
int
pos
,
byte
[]
key
,
byte
[]
child
)
{
final
int
bytesPerKey
=
tree
.
keySize
;
final
int
offset
=
bytesPerKey
*
pos
;
// write key
System
.
arraycopy
(
key
,
0
,
backingArray
,
offset
,
bytesPerKey
);
// write value
values
[
pos
]
=
child
;
}
private
void
copyChildren
(
final
int
from
,
final
int
to
)
{
if
(
from
>=
size
)
return
;
final
int
bytesPerKey
=
tree
.
keySize
;
// copy keys
System
.
arraycopy
(
backingArray
,
from
*
bytesPerKey
,
backingArray
,
to
*
bytesPerKey
,
(
size
-
from
)
*
bytesPerKey
);
// copy values
System
.
arraycopy
(
values
,
from
,
values
,
to
,
(
size
-
from
)
);
}
private
static
BottomTransientPage
copyOf
(
BottomTransientPage
page
,
long
epoch
,
int
from
,
int
length
)
{
byte
[]
bytes
=
new
byte
[
page
.
backingArray
.
length
];
final
int
bytesPerKey
=
page
.
tree
.
keySize
;
// copy keys
System
.
arraycopy
(
page
.
backingArray
,
from
*
bytesPerKey
,
bytes
,
0
,
length
*
bytesPerKey
);
Object
[]
values
=
new
Object
[
page
.
values
.
length
];
// copy values
System
.
arraycopy
(
page
.
values
,
from
,
values
,
0
,
length
);
return
new
BottomTransientPage
(
bytes
,
page
.
tree
,
length
,
epoch
,
values
);
}
}
This diff is collapsed.
Click to expand it.
platform/on-air-index/src/com/intellij/platform/onair/tree/functional/InternalTransientPage.java
0 → 100644
+
245
-
0
View file @
7211c819
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package
com.intellij.platform.onair.tree.functional
;
import
com.intellij.platform.onair.storage.api.Address
;
import
com.intellij.platform.onair.storage.api.KeyValueConsumer
;
import
com.intellij.platform.onair.storage.api.Novelty
;
import
com.intellij.platform.onair.tree.BTreeCommon
;
import
com.intellij.platform.onair.tree.IInternalPage
;
import
com.intellij.platform.onair.tree.IPage
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
public
class
InternalTransientPage
extends
BaseTransientPage
implements
IInternalPage
{
protected
final
IPage
[]
children
;
// Address | IPage
public
InternalTransientPage
(
byte
[]
backingArray
,
TransientBTreePrototype
tree
,
int
size
,
long
epoch
,
IPage
[]
children
)
{
super
(
backingArray
,
tree
,
size
,
epoch
);
this
.
children
=
children
;
}
@Override
@Nullable
public
byte
[]
get
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
)
{
final
int
index
=
BTreeCommon
.
binarySearch
(
backingArray
,
size
,
tree
.
keySize
,
0
,
key
);
return
index
<
0
?
getChild
(
novelty
,
Math
.
max
(-
index
-
2
,
0
)).
get
(
novelty
,
key
)
:
getChild
(
novelty
,
index
).
get
(
novelty
,
key
);
}
@Override
public
boolean
forEach
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
KeyValueConsumer
consumer
)
{
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
IPage
child
=
getChild
(
novelty
,
i
);
if
(!
child
.
forEach
(
novelty
,
consumer
))
{
return
false
;
}
}
return
true
;
}
@Override
public
boolean
forEach
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
fromKey
,
@NotNull
KeyValueConsumer
consumer
)
{
final
int
fromIndex
=
BTreeCommon
.
binarySearchGuess
(
backingArray
,
size
,
tree
.
keySize
,
0
,
fromKey
);
return
BTreeCommon
.
traverseInternalPage
(
this
,
novelty
,
fromIndex
,
fromKey
,
consumer
);
}
@Override
@Nullable
public
BaseTransientPage
put
(
@NotNull
Novelty
.
Accessor
novelty
,
long
epoch
,
@NotNull
byte
[]
key
,
@NotNull
byte
[]
value
,
boolean
overwrite
,
boolean
[]
result
)
{
int
pos
=
BTreeCommon
.
binarySearch
(
backingArray
,
size
,
tree
.
keySize
,
0
,
key
);
if
(
pos
>=
0
&&
!
overwrite
)
{
// key found and overwrite is not possible - error
return
null
;
}
if
(
pos
<
0
)
{
pos
=
-
pos
-
2
;
// if insert after last - set to last
if
(
pos
<
0
)
pos
=
0
;
}
final
BaseTransientPage
child
=
getChild
(
novelty
,
pos
).
getTransientCopy
(
epoch
);
final
IPage
newChild
=
child
.
put
(
novelty
,
epoch
,
key
,
value
,
overwrite
,
result
);
// change min key for child
if
(
result
[
0
])
{
setTransient
(
pos
,
child
.
getMinKey
(),
child
);
if
(
newChild
==
null
)
{
flush
(
novelty
);
}
else
{
return
BTreeCommon
.
insertAt
(
this
,
tree
.
base
,
novelty
,
pos
+
1
,
newChild
.
getMinKey
(),
newChild
);
}
}
return
null
;
}
@Override
public
boolean
delete
(
@NotNull
Novelty
.
Accessor
novelty
,
long
epoch
,
@NotNull
byte
[]
key
,
@Nullable
byte
[]
value
)
{
int
pos
=
BTreeCommon
.
binarySearchGuess
(
backingArray
,
size
,
tree
.
keySize
,
0
,
key
);
final
BaseTransientPage
child
=
getChild
(
novelty
,
pos
).
getTransientCopy
(
epoch
);
if
(!
child
.
delete
(
novelty
,
epoch
,
key
,
value
))
{
return
false
;
}
// if first element was removed in child, then update min key
final
int
childSize
=
child
.
getSize
();
if
(
childSize
>
0
)
{
setTransient
(
pos
,
child
.
getMinKey
(),
child
);
}
if
(
pos
>
0
)
{
final
IPage
left
=
getChild
(
novelty
,
pos
-
1
);
if
(
BTreeCommon
.
needMerge
(
left
,
child
,
tree
.
base
))
{
// merge child into left sibling
// re-get mutable left
getChild
(
novelty
,
pos
-
1
).
getTransientCopy
(
epoch
).
mergeWith
(
child
);
removeChild
(
pos
);
}
}
else
if
(
pos
+
1
<
size
)
{
final
IPage
right
=
getChild
(
novelty
,
pos
+
1
);
if
(
BTreeCommon
.
needMerge
(
child
,
right
,
tree
.
base
))
{
// merge child with right sibling
final
BaseTransientPage
mutableChild
=
child
.
getTransientCopy
(
epoch
);
IPage
sibling
=
getChild
(
novelty
,
pos
+
1
);
mutableChild
.
mergeWith
(
sibling
.
getTransientCopy
(
epoch
));
removeChild
(
pos
);
// change key for link to right
setTransient
(
pos
,
mutableChild
.
getMinKey
(),
mutableChild
);
}
}
else
if
(
childSize
==
0
)
{
removeChild
(
pos
);
}
return
true
;
}
@Override
public
InternalTransientPage
getTransientCopy
(
long
epoch
)
{
if
(
this
.
epoch
>=
epoch
)
{
return
this
;
}
else
{
return
copyOf
(
this
,
epoch
,
0
,
size
);
}
}
@Override
public
IPage
split
(
@NotNull
Novelty
.
Accessor
novelty
,
int
from
,
int
length
)
{
final
IPage
result
=
copyOf
(
this
,
epoch
,
from
,
length
);
decrementSize
(
length
);
return
result
;
}
@Override
@NotNull
public
IPage
getChild
(
@NotNull
Novelty
.
Accessor
novelty
,
final
int
index
)
{
final
Object
child
=
children
[
index
];
if
(
child
instanceof
BaseTransientPage
)
{
return
(
BaseTransientPage
)
child
;
}
return
tree
.
storedTree
.
loadPage
(
novelty
,
(
Address
)
child
);
}
@Override
public
void
insertDirectly
(
@NotNull
Novelty
.
Accessor
novelty
,
final
int
pos
,
@NotNull
byte
[]
key
,
Object
child
)
{
if
(
pos
<
size
)
{
copyChildren
(
pos
,
pos
+
1
);
}
final
IPage
page
=
(
IPage
)
child
;
if
(
page
.
isTransient
())
{
setTransient
(
pos
,
key
,
page
);
}
else
{
throw
new
IllegalArgumentException
(
"non-transient child cannot be inserted here"
);
}
incrementSize
();
flush
(
novelty
);
}
@Override
public
boolean
isBottom
()
{
return
false
;
}
@Override
public
IPage
mergeWithChildren
(
@NotNull
Novelty
.
Accessor
novelty
)
{
IPage
result
=
this
;
while
(!
result
.
isBottom
()
&&
result
.
getSize
()
==
1
)
{
result
=
((
IInternalPage
)
result
).
getChild
(
novelty
,
0
);
}
return
result
;
}
@Override
protected
void
mergeWith
(
BaseTransientPage
page
)
{
System
.
arraycopy
(((
InternalTransientPage
)
page
).
children
,
0
,
children
,
size
,
page
.
size
);
super
.
mergeWith
(
page
);
}
private
void
removeChild
(
int
pos
)
{
copyChildren
(
pos
+
1
,
pos
);
decrementSize
(
1
);
}
private
void
setTransient
(
int
pos
,
byte
[]
key
,
IPage
child
)
{
final
int
bytesPerKey
=
tree
.
keySize
;
final
int
offset
=
bytesPerKey
*
pos
;
// write key
System
.
arraycopy
(
key
,
0
,
backingArray
,
offset
,
bytesPerKey
);
// write value
children
[
pos
]
=
child
;
}
private
void
copyChildren
(
final
int
from
,
final
int
to
)
{
if
(
from
>=
size
)
return
;
final
int
bytesPerKey
=
tree
.
keySize
;
// copy keys
System
.
arraycopy
(
backingArray
,
from
*
bytesPerKey
,
backingArray
,
to
*
bytesPerKey
,
(
size
-
from
)
*
bytesPerKey
);
// copy children
System
.
arraycopy
(
children
,
from
,
children
,
to
,
(
size
-
from
)
);
}
private
static
InternalTransientPage
copyOf
(
InternalTransientPage
page
,
long
epoch
,
int
from
,
int
length
)
{
byte
[]
bytes
=
new
byte
[
page
.
backingArray
.
length
];
final
int
bytesPerKey
=
page
.
tree
.
keySize
;
// copy keys
System
.
arraycopy
(
page
.
backingArray
,
from
*
bytesPerKey
,
bytes
,
0
,
length
*
bytesPerKey
);
IPage
[]
children
=
new
IPage
[
page
.
children
.
length
];
// copy children
System
.
arraycopy
(
page
.
children
,
from
,
children
,
0
,
length
);
return
new
InternalTransientPage
(
bytes
,
page
.
tree
,
length
,
epoch
,
children
);
}
}
This diff is collapsed.
Click to expand it.
platform/on-air-index/src/com/intellij/platform/onair/tree/functional/TransientBTree.java
0 → 100644
+
128
-
0
View file @
7211c819
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package
com.intellij.platform.onair.tree.functional
;
import
com.intellij.platform.onair.storage.api.*
;
import
com.intellij.platform.onair.tree.BTree
;
import
com.intellij.platform.onair.tree.BasePage
;
import
com.intellij.platform.onair.tree.IPage
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
public
class
TransientBTree
implements
TransientTree
{
final
TransientBTreePrototype
prototype
;
private
final
Object
root
;
private
final
long
epoch
;
public
TransientBTree
(
TransientBTreePrototype
prototype
,
Object
root
,
long
epoch
)
{
this
.
prototype
=
prototype
;
this
.
root
=
root
;
this
.
epoch
=
epoch
;
}
@Override
public
int
getKeySize
()
{
return
prototype
.
keySize
;
}
@Override
public
int
getBase
()
{
return
BTree
.
DEFAULT_BASE
;
}
@Nullable
@Override
public
byte
[]
get
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
)
{
return
root
(
novelty
).
get
(
novelty
,
key
);
}
@Override
public
boolean
forEach
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
KeyValueConsumer
consumer
)
{
return
root
(
novelty
).
forEach
(
novelty
,
consumer
);
}
@Override
public
boolean
forEach
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
fromKey
,
@NotNull
KeyValueConsumer
consumer
)
{
return
root
(
novelty
).
forEach
(
novelty
,
fromKey
,
consumer
);
}
@Override
public
TransientTree
put
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@NotNull
byte
[]
value
)
{
return
put
(
novelty
,
key
,
value
,
true
);
}
@Override
public
TransientTree
put
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@NotNull
byte
[]
value
,
boolean
overwrite
)
{
final
boolean
[]
result
=
new
boolean
[
1
];
final
BaseTransientPage
root
=
root
(
novelty
).
getTransientCopy
(
epoch
);
final
BaseTransientPage
newSibling
=
root
.
put
(
novelty
,
epoch
,
key
,
value
,
overwrite
,
result
);
final
BaseTransientPage
finalRoot
;
if
(
newSibling
!=
null
)
{
final
byte
[]
bytes
=
new
byte
[
getKeySize
()
*
getBase
()];
final
IPage
[]
children
=
new
IPage
[
getBase
()];
final
InternalTransientPage
internalRoot
=
new
InternalTransientPage
(
bytes
,
prototype
,
2
,
epoch
,
children
);
TransientBTreeUtil
.
set
(
0
,
root
.
getMinKey
(),
getKeySize
(),
bytes
);
children
[
0
]
=
root
;
TransientBTreeUtil
.
set
(
1
,
newSibling
.
getMinKey
(),
getKeySize
(),
bytes
);
children
[
1
]
=
newSibling
;
finalRoot
=
internalRoot
;
}
else
{
finalRoot
=
root
;
}
return
new
TransientBTree
(
prototype
,
finalRoot
,
epoch
);
}
@Override
public
TransientTree
delete
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
)
{
return
delete
(
novelty
,
key
,
null
);
}
@Override
public
TransientTree
delete
(
@NotNull
Novelty
.
Accessor
novelty
,
@NotNull
byte
[]
key
,
@Nullable
byte
[]
value
)
{
final
BaseTransientPage
root
=
root
(
novelty
).
getTransientCopy
(
epoch
);
final
IPage
updatedRoot
=
TransientBTreeUtil
.
delete
(
novelty
,
epoch
,
root
,
key
,
value
);
if
(
root
==
updatedRoot
)
{
return
this
;
}
else
{
// updatedRoot can be "downgraded" to stored page if some merge occurs
Object
finalRoot
=
updatedRoot
.
isTransient
()
?
updatedRoot
:
((
BasePage
)
updatedRoot
).
getAddress
();
return
new
TransientBTree
(
prototype
,
finalRoot
,
epoch
);
}
}
@Override
public
TransientTree
flush
()
{
if
(!(
root
instanceof
IPage
))
{
return
this
;
// already on disk
}
// TODO: flush pages
return
new
TransientBTree
(
prototype
,
root
,
epoch
+
1
);
}
@NotNull
private
IPage
root
(
@NotNull
Novelty
.
Accessor
novelty
)
{
if
(
root
instanceof
Address
)
{
return
loadRootPage
(
novelty
);
}
else
{
return
(
IPage
)
root
;
}
}
private
BasePage
loadRootPage
(
@NotNull
Novelty
.
Accessor
novelty
)
{
final
long
startAddress
;
final
Address
rootAddress
=
(
Address
)
root
;
if
(
rootAddress
.
isNovelty
())
{
startAddress
=
rootAddress
.
getLowBytes
();
}
else
{
startAddress
=
Long
.
MIN_VALUE
;
}
return
new
BTree
(
prototype
.
storage
,
prototype
.
keySize
,
rootAddress
,
startAddress
).
loadPage
(
novelty
,
rootAddress
);
}
}
This diff is collapsed.
Click to expand it.
platform/on-air-index/src/com/intellij/platform/onair/tree/functional/TransientBTreePrototype.java
0 → 100644
+
19
-
0
View file @
7211c819
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package
com.intellij.platform.onair.tree.functional
;
import
com.intellij.platform.onair.storage.api.Storage
;
import
com.intellij.platform.onair.tree.BTree
;
/*package*/
class
TransientBTreePrototype
{
final
BTree
storedTree
;
final
Storage
storage
;
final
int
keySize
;
final
int
base
;
/*package*/
TransientBTreePrototype
(
BTree
storedTree
,
Storage
storage
)
{
this
.
storedTree
=
storedTree
;
this
.
storage
=
storage
;
this
.
keySize
=
storedTree
.
getKeySize
();
this
.
base
=
storedTree
.
getBase
();
}
}
This diff is collapsed.
Click to expand it.
platform/on-air-index/src/com/intellij/platform/onair/tree/functional/TransientBTreeUtil.java
0 → 100644
+
29
-
0
View file @
7211c819
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package
com.intellij.platform.onair.tree.functional
;
import
com.intellij.platform.onair.storage.api.Novelty
;
import
com.intellij.platform.onair.tree.IPage
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
public
class
TransientBTreeUtil
{
public
static
IPage
delete
(
@NotNull
Novelty
.
Accessor
novelty
,
long
epoch
,
@NotNull
BaseTransientPage
root
,
@NotNull
byte
[]
key
,
@Nullable
byte
[]
value
)
{
if
(
root
.
delete
(
novelty
,
epoch
,
key
,
value
))
{
return
root
.
mergeWithChildren
(
novelty
);
}
return
root
;
}
public
static
void
set
(
int
pos
,
byte
[]
key
,
int
bytesPerKey
,
byte
[]
backingArray
)
{
final
int
offset
=
bytesPerKey
*
pos
;
// write key
System
.
arraycopy
(
key
,
0
,
backingArray
,
offset
,
bytesPerKey
);
}
}
This diff is collapsed.
Click to expand it.
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment
Menu
Projects
Groups
Snippets
Help