1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id: VisitedObjects.java,v 0f73af5ae3da 2010/05/10 05:38:40 alexander $
*/
package com.sleepycat.persist.impl;
/**
* Keeps track of a set of visited objects and their corresponding offset in a
* byte array. This uses a resizable int array for speed and simplicity. If
* in the future the array resizing or linear search are performance issues, we
* could try using an IdentityHashMap instead.
*
* @author Mark Hayes
*/
class VisitedObjects {
/*
* Offset to indicate that the visited object is stored in the primary key
* byte array.
*/
static final int PRI_KEY_VISITED_OFFSET = Integer.MAX_VALUE - 1;
/* Used by RecordOutput to prevent illegal nested references. */
static final int PROHIBIT_REF_OFFSET = Integer.MAX_VALUE - 2;
/* Used by RecordInput to prevent illegal nested references. */
static final Object PROHIBIT_REF_OBJECT = new Object();
static final String PROHIBIT_NESTED_REF_MSG =
"Cannot embed a reference to a proxied object in the proxy; for " +
"example, a collection may not be an element of the collection " +
"because collections are proxied";
private static final int INIT_LEN = 50;
private Object[] objects;
private int[] offsets;
private int nextIndex;
/**
* Creates an empty set.
*/
VisitedObjects() {
objects = new Object[INIT_LEN];
offsets = new int[INIT_LEN];
nextIndex = 0;
}
/**
* Adds a visited object and offset, growing the visited arrays as needed.
* @return the index of the new slot.
*/
int add(Object o, int offset) {
int i = nextIndex;
nextIndex += 1;
if (nextIndex > objects.length) {
growVisitedArrays();
}
objects[i] = o;
offsets[i] = offset;
return i;
}
/**
* Sets the object for an existing slot index.
*/
void setObject(int index, Object o) {
objects[index] = o;
}
/**
* Sets the offset for an existing slot index.
*/
void setOffset(int index, int offset) {
offsets[index] = offset;
}
/**
* Returns the offset for a visited object, or -1 if never visited.
*/
int getOffset(Object o) {
for (int i = 0; i < nextIndex; i += 1) {
if (objects[i] == o) {
return offsets[i];
}
}
return -1;
}
/**
* Returns the visited object for a given offset, or null if never visited.
*/
Object getObject(int offset) {
for (int i = 0; i < nextIndex; i += 1) {
if (offsets[i] == offset) {
return objects[i];
}
}
return null;
}
/**
* Replaces a given object in the list. Used when an object is converted
* after adding it to the list.
*/
void replaceObject(Object existing, Object replacement) {
for (int i = nextIndex - 1; i >= 0; i -= 1) {
if (objects[i] == existing) {
objects[i] = replacement;
return;
}
}
assert false;
}
/**
* Doubles the size of the visited arrays.
*/
private void growVisitedArrays() {
int oldLen = objects.length;
int newLen = oldLen * 2;
Object[] newObjects = new Object[newLen];
int[] newOffsets = new int[newLen];
System.arraycopy(objects, 0, newObjects, 0, oldLen);
System.arraycopy(offsets, 0, newOffsets, 0, oldLen);
objects = newObjects;
offsets = newOffsets;
}
}
|