Skip to content

Commit a87a7c5

Browse files
committed
Improve hierarchical lock
1 parent 14083c5 commit a87a7c5

1 file changed

Lines changed: 37 additions & 21 deletions

File tree

src/three/plugins/mvt/HierarchicalLock.js

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ const getKey = ( x, y, l ) => {
77
};
88

99
// Ref-counts active requests per (x, y, level) tile and fires a 'toggle' event when a tile
10-
// transitions between inactive (ref === 0) and active (ref > 0). Tiles can also be marked as
11-
// "loading", which will lock an existing parent tile as active to ensure coverage until the
12-
// child has loaded
10+
// transitions between inactive and active. A tile is considered active when its own 'active'
11+
// ref is non-zero AND it has no in-flight loads of its own ('loading' === 0). Tiles can also
12+
// be marked as "loading", which will lock an existing parent tile as active to ensure coverage
13+
// until the child has loaded.
1314
export class HierarchicalLock extends EventDispatcher {
1415

1516
constructor() {
@@ -51,11 +52,12 @@ export class HierarchicalLock extends EventDispatcher {
5152
}
5253

5354
const childLock = locks[ childKey ];
54-
childLock.loadingCount ++;
55+
childLock.loading ++;
56+
this._checkToggle( childKey );
5557

5658
// Only lock the ancestor on the first markLoading call — subsequent concurrent
5759
// loads for the same tile share the same ancestor hold
58-
if ( childLock.loadingCount === 1 ) {
60+
if ( childLock.loading === 1 ) {
5961

6062
while ( al > 0 ) {
6163

@@ -64,7 +66,7 @@ export class HierarchicalLock extends EventDispatcher {
6466
ay >>= 1;
6567

6668
const ancestorKey = getKey( ax, ay, al );
67-
if ( ancestorKey in locks ) {
69+
if ( ancestorKey in locks && locks[ ancestorKey ].dispatched ) {
6870

6971
// save the reference so we can unlock it later when load is finished
7072
this._incrLock( ax, ay, al, true );
@@ -91,10 +93,11 @@ export class HierarchicalLock extends EventDispatcher {
9193

9294
}
9395

94-
childLock.loadingCount --;
96+
childLock.loading --;
97+
this._checkToggle( childKey );
9598

9699
// Release the ancestor only when the last concurrent load finishes
97-
if ( childLock.loadingCount === 0 && childLock.lockedAncestor ) {
100+
if ( childLock.loading === 0 && childLock.lockedAncestor ) {
98101

99102
const { x: ax, y: ay, level: al } = childLock.lockedAncestor;
100103
this._incrLock( ax, ay, al, false );
@@ -111,7 +114,7 @@ export class HierarchicalLock extends EventDispatcher {
111114
_tryDeleteLock( key ) {
112115

113116
const lock = this.locks[ key ];
114-
if ( lock && lock.ref === 0 && lock.lockedAncestor === null && lock.loadingCount === 0 ) {
117+
if ( lock && lock.active === 0 && lock.lockedAncestor === null && lock.loading === 0 ) {
115118

116119
delete this.locks[ key ];
117120

@@ -125,14 +128,34 @@ export class HierarchicalLock extends EventDispatcher {
125128
x,
126129
y,
127130
level,
128-
ref: 0,
131+
active: 0,
132+
loading: 0,
129133
dispatched: false,
130134
lockedAncestor: null,
131-
loadingCount: 0,
132135
};
133136

134137
}
135138

139+
_checkToggle( key ) {
140+
141+
const { locks } = this;
142+
const lock = locks[ key ];
143+
if ( ! lock ) {
144+
145+
return;
146+
147+
}
148+
149+
const shouldShow = lock.loading === 0 && lock.active > 0;
150+
if ( shouldShow !== lock.dispatched ) {
151+
152+
lock.dispatched = shouldShow;
153+
this.dispatchEvent( { type: 'toggle', active: shouldShow, x: lock.x, y: lock.y, level: lock.level } );
154+
155+
}
156+
157+
}
158+
136159
_incrLock( x, y, level, incr ) {
137160

138161
const { locks } = this;
@@ -145,21 +168,14 @@ export class HierarchicalLock extends EventDispatcher {
145168
}
146169

147170
const lock = locks[ key ];
148-
lock.ref += incr ? 1 : - 1;
149-
if ( lock.ref < 0 ) {
171+
lock.active += incr ? 1 : - 1;
172+
if ( lock.active < 0 ) {
150173

151174
throw new Error( 'HierarchicalLock: ref count went negative — mismatched markActive/markInactive calls.' );
152175

153176
}
154177

155-
const active = lock.ref > 0;
156-
if ( active !== lock.dispatched ) {
157-
158-
lock.dispatched = active;
159-
this.dispatchEvent( { type: 'toggle', active, x, y, level } );
160-
161-
}
162-
178+
this._checkToggle( key );
163179
this._tryDeleteLock( key );
164180

165181
}

0 commit comments

Comments
 (0)