Skip to content

Commit 8294ebe

Browse files
authored
HierarchicalLock: Add loading locking replacement (#1628)
* Update hierarchical lock * Updates
1 parent 2066c5a commit 8294ebe

1 file changed

Lines changed: 155 additions & 63 deletions

File tree

src/three/plugins/mvt/HierarchicalLock.js

Lines changed: 155 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ export class HierarchicalLock extends EventDispatcher {
2424
// mark the tile as "active", meaning it should be visible
2525
markActive( x, y, level ) {
2626

27-
this._incrLock( x, y, level, true );
27+
this._incrActiveLock( x, y, level, true );
2828

2929
}
3030

3131
markInactive( x, y, level ) {
3232

33-
this._incrLock( x, y, level, false );
33+
this._incrActiveLock( x, y, level, false );
3434

3535
}
3636

@@ -40,132 +40,180 @@ export class HierarchicalLock extends EventDispatcher {
4040

4141
const { locks } = this;
4242
const childKey = getKey( x, y, level );
43-
let ax = x;
44-
let ay = y;
45-
let al = level;
43+
this._ensureLock( childKey, x, y, level );
44+
45+
const childLock = locks[ childKey ];
46+
childLock.loading ++;
4647

47-
// Create the lock for the child and mark it as loading
48-
if ( ! ( childKey in locks ) ) {
48+
if ( childLock.loading === 1 && childLock.active > 0 ) {
4949

50-
locks[ childKey ] = this._createLock( x, y, level );
50+
this._lockAncestor( x, y, level );
5151

5252
}
5353

54+
this._tryFireEvent( childKey );
55+
56+
}
57+
58+
unmarkLoading( x, y, level ) {
59+
60+
const { locks } = this;
61+
const childKey = getKey( x, y, level );
5462
const childLock = locks[ childKey ];
55-
childLock.loading ++;
56-
this._checkToggle( childKey );
63+
childLock.loading --;
64+
65+
if ( childLock.loading === 0 && childLock.active > 0 ) {
66+
67+
this._unlockAncestor( x, y, level );
68+
69+
}
70+
71+
this._tryFireEvent( childKey );
72+
this._tryDeleteLock( childKey );
73+
74+
}
75+
76+
//
77+
78+
_lockAncestor( x, y, level ) {
79+
80+
const { locks } = this;
81+
const childKey = getKey( x, y, level );
82+
const childLock = locks[ childKey ];
83+
this._ensureLock( childKey, x, y, level );
84+
if ( childLock.lockedAncestor ) return;
85+
86+
let ax = x;
87+
let ay = y;
88+
let al = level;
5789

5890
// Only lock the ancestor on the first markLoading call — subsequent concurrent
5991
// loads for the same tile share the same ancestor hold
60-
if ( childLock.loading === 1 ) {
92+
while ( al > 0 ) {
6193

62-
while ( al > 0 ) {
94+
al --;
95+
ax >>= 1;
96+
ay >>= 1;
6397

64-
al --;
65-
ax >>= 1;
66-
ay >>= 1;
98+
const ancestorKey = getKey( ax, ay, al );
99+
this._ensureLock( ancestorKey, ax, ay, al );
100+
locks[ ancestorKey ].loadingDescendants.add( childKey );
67101

68-
const ancestorKey = getKey( ax, ay, al );
69-
if ( ancestorKey in locks && locks[ ancestorKey ].dispatched ) {
102+
// save the reference so we can unlock it later when load is finished
103+
if ( locks[ ancestorKey ].dispatched && ! childLock.lockedAncestor ) {
70104

71-
// save the reference so we can unlock it later when load is finished
72-
this._incrLock( ax, ay, al, true );
73-
childLock.lockedAncestor = { x: ax, y: ay, level: al };
74-
break;
75-
76-
}
105+
this._incrActiveLock( ax, ay, al, true );
106+
childLock.lockedAncestor = { x: ax, y: ay, level: al };
77107

78108
}
79109

80110
}
81111

82112
}
83113

84-
unmarkLoading( x, y, level ) {
114+
_unlockAncestor( x, y, level ) {
85115

86116
const { locks } = this;
87117
const childKey = getKey( x, y, level );
88118
const childLock = locks[ childKey ];
119+
if ( ! childLock ) return;
89120

90-
if ( ! childLock ) {
121+
// unmark the descendants list
122+
let ax = x;
123+
let ay = y;
124+
let al = level;
125+
while ( al > 0 ) {
91126

92-
throw new Error( 'HierarchicalLock: unmarkLoading called without a matching markLoading.' );
127+
al --;
128+
ax >>= 1;
129+
ay >>= 1;
93130

94-
}
131+
const ancestorKey = getKey( ax, ay, al );
132+
locks[ ancestorKey ].loadingDescendants.delete( childKey );
133+
this._tryDeleteLock( ancestorKey );
95134

96-
childLock.loading --;
97-
this._checkToggle( childKey );
135+
}
98136

99-
// Release the ancestor only when the last concurrent load finishes
100-
if ( childLock.loading === 0 && childLock.lockedAncestor ) {
137+
// remove the locked ancestor
138+
if ( childLock.lockedAncestor ) {
101139

102-
const { x: ax, y: ay, level: al } = childLock.lockedAncestor;
103-
this._incrLock( ax, ay, al, false );
140+
// unlock the ancestor
141+
const { x: lx, y: ly, level: ll } = childLock.lockedAncestor;
142+
this._incrActiveLock( lx, ly, ll, false );
104143
childLock.lockedAncestor = null;
105144

106145
}
107146

108-
this._tryDeleteLock( childKey );
109-
110147
}
111148

112-
//
113-
149+
// delete the lock if all the fields have been settled
114150
_tryDeleteLock( key ) {
115151

116152
const lock = this.locks[ key ];
117-
if ( lock && lock.active === 0 && lock.lockedAncestor === null && lock.loading === 0 ) {
153+
if (
154+
lock && lock.active === 0 &&
155+
lock.lockedAncestor === null &&
156+
lock.loading === 0 &&
157+
lock.loadingDescendants.size === 0
158+
) {
118159

119160
delete this.locks[ key ];
120161

121162
}
122163

123164
}
124165

125-
_createLock( x, y, level ) {
166+
// ensure the lock exists
167+
_ensureLock( key, x, y, level ) {
126168

127-
return {
128-
x,
129-
y,
130-
level,
131-
active: 0,
132-
loading: 0,
133-
dispatched: false,
134-
lockedAncestor: null,
135-
};
169+
const { locks } = this;
170+
if ( ! ( key in locks ) ) {
171+
172+
locks[ key ] = {
173+
x,
174+
y,
175+
level,
176+
active: 0,
177+
loading: 0,
178+
dispatched: false,
179+
lockedAncestor: null,
180+
loadingDescendants: new Set(),
181+
};
182+
183+
}
184+
185+
return locks[ key ];
136186

137187
}
138188

139-
_checkToggle( key ) {
189+
// checks whether an event should be fired
190+
_tryFireEvent( key ) {
140191

141192
const { locks } = this;
142193
const lock = locks[ key ];
143-
if ( ! lock ) {
144-
145-
return;
146-
147-
}
148194

149195
const shouldShow = lock.loading === 0 && lock.active > 0;
150196
if ( shouldShow !== lock.dispatched ) {
151197

152198
lock.dispatched = shouldShow;
153-
this.dispatchEvent( { type: 'toggle', active: shouldShow, x: lock.x, y: lock.y, level: lock.level } );
199+
this.dispatchEvent( {
200+
type: 'toggle',
201+
active: shouldShow,
202+
x: lock.x,
203+
y: lock.y,
204+
level: lock.level,
205+
} );
154206

155207
}
156208

157209
}
158210

159-
_incrLock( x, y, level, incr ) {
211+
// increments the active lock for the tile
212+
_incrActiveLock( x, y, level, incr ) {
160213

161214
const { locks } = this;
162215
const key = getKey( x, y, level );
163-
164-
if ( ! ( key in locks ) ) {
165-
166-
locks[ key ] = this._createLock( x, y, level );
167-
168-
}
216+
this._ensureLock( key, x, y, level );
169217

170218
const lock = locks[ key ];
171219
lock.active += incr ? 1 : - 1;
@@ -175,7 +223,51 @@ export class HierarchicalLock extends EventDispatcher {
175223

176224
}
177225

178-
this._checkToggle( key );
226+
// try to lock the ancestors if the lock became active and is loading
227+
if ( lock && lock.loading > 0 ) {
228+
229+
if ( incr && lock.active === 1 ) {
230+
231+
this._lockAncestor( x, y, level );
232+
233+
} else if ( ! incr && lock.active === 0 ) {
234+
235+
this._unlockAncestor( x, y, level );
236+
237+
}
238+
239+
}
240+
241+
// replace all the existing locks up this chain
242+
if ( incr && lock.active === 1 ) {
243+
244+
lock.loadingDescendants.forEach( key => {
245+
246+
const childLock = locks[ key ];
247+
if ( childLock.lockedAncestor ) {
248+
249+
const { x: lx, y: ly, level: ll } = childLock.lockedAncestor;
250+
this.markInactive( lx, ly, ll );
251+
lock.active ++;
252+
253+
childLock.lockedAncestor.x = x;
254+
childLock.lockedAncestor.y = y;
255+
childLock.lockedAncestor.level = level;
256+
257+
} else if ( lock.loading === 0 && childLock.active > 0 && childLock.loading > 0 ) {
258+
259+
// No ancestor was dispatched when this descendant started loading;
260+
// this tile is now visible so use it as the placeholder.
261+
lock.active ++;
262+
childLock.lockedAncestor = { x, y, level };
263+
264+
}
265+
266+
} );
267+
268+
}
269+
270+
this._tryFireEvent( key );
179271
this._tryDeleteLock( key );
180272

181273
}

0 commit comments

Comments
 (0)