1818use OCP \Files \NotFoundException ;
1919
2020class Manager implements IMountManager {
21- /** @var MountPoint[] */
21+ /** @var array<string, IMountPoint> */
2222 private array $ mounts = [];
23+ private bool $ areMountsSorted = false ;
24+ /** @var list<string>|null $mountKeys */
25+ private ?array $ mountKeys = null ;
2326 /** @var CappedMemoryCache<IMountPoint> */
2427 private CappedMemoryCache $ pathCache ;
2528 /** @var CappedMemoryCache<IMountPoint[]> */
@@ -32,44 +35,34 @@ public function __construct(SetupManagerFactory $setupManagerFactory) {
3235 $ this ->setupManager = $ setupManagerFactory ->create ($ this );
3336 }
3437
35- /**
36- * @param IMountPoint $mount
37- */
38- public function addMount (IMountPoint $ mount ) {
38+ public function addMount (IMountPoint $ mount ): void {
3939 $ this ->mounts [$ mount ->getMountPoint ()] = $ mount ;
4040 $ this ->pathCache ->clear ();
4141 $ this ->inPathCache ->clear ();
42+ $ this ->areMountsSorted = false ;
4243 }
4344
44- /**
45- * @param string $mountPoint
46- */
47- public function removeMount (string $ mountPoint ) {
45+ public function removeMount (string $ mountPoint ): void {
4846 $ mountPoint = Filesystem::normalizePath ($ mountPoint );
4947 if (\strlen ($ mountPoint ) > 1 ) {
5048 $ mountPoint .= '/ ' ;
5149 }
5250 unset($ this ->mounts [$ mountPoint ]);
5351 $ this ->pathCache ->clear ();
5452 $ this ->inPathCache ->clear ();
53+ $ this ->areMountsSorted = false ;
5554 }
5655
57- /**
58- * @param string $mountPoint
59- * @param string $target
60- */
61- public function moveMount (string $ mountPoint , string $ target ) {
56+ public function moveMount (string $ mountPoint , string $ target ): void {
6257 $ this ->mounts [$ target ] = $ this ->mounts [$ mountPoint ];
6358 unset($ this ->mounts [$ mountPoint ]);
6459 $ this ->pathCache ->clear ();
6560 $ this ->inPathCache ->clear ();
61+ $ this ->areMountsSorted = false ;
6662 }
6763
6864 /**
6965 * Find the mount for $path
70- *
71- * @param string $path
72- * @return IMountPoint
7366 */
7467 public function find (string $ path ): IMountPoint {
7568 $ this ->setupManager ->setupForPath ($ path );
@@ -79,8 +72,6 @@ public function find(string $path): IMountPoint {
7972 return $ this ->pathCache [$ path ];
8073 }
8174
82-
83-
8475 if (count ($ this ->mounts ) === 0 ) {
8576 $ this ->setupManager ->setupRoot ();
8677 if (count ($ this ->mounts ) === 0 ) {
@@ -120,15 +111,57 @@ public function findIn(string $path): array {
120111 return $ this ->inPathCache [$ path ];
121112 }
122113
114+ if (!$ this ->areMountsSorted ) {
115+ ksort ($ this ->mounts , SORT_STRING );
116+ $ this ->mountKeys = array_keys ($ this ->mounts );
117+ $ this ->areMountsSorted = true ;
118+ }
119+
120+ $ result = $ this ->binarySearch ($ this ->mounts , $ this ->mountKeys , $ path );
121+
122+ $ this ->inPathCache [$ path ] = $ result ;
123+ return $ result ;
124+ }
125+
126+ /**
127+ * Search for all entries in $sortedArray where $prefix is a prefix but not equal to their key.
128+ *
129+ * @template T
130+ * @param array<string, T> $sortedArray
131+ * @param list<string> $sortedKeys
132+ * @param string $prefix
133+ * @return list<T>
134+ */
135+ private function binarySearch (array $ sortedArray , array $ sortedKeys , string $ prefix ): array {
136+ $ low = 0 ;
137+ $ high = count ($ sortedArray ) - 1 ;
138+ $ start = null ;
139+
140+ // binary search
141+ while ($ low <= $ high ) {
142+ $ mid = ($ low + $ high ) >> 1 ;
143+ if ($ sortedKeys [$ mid ] < $ prefix ) {
144+ $ low = $ mid + 1 ;
145+ } else {
146+ $ start = $ mid ;
147+ $ high = $ mid - 1 ;
148+ }
149+ }
150+
123151 $ result = [];
124- $ pathLen = strlen ($ path );
125- foreach ($ this ->mounts as $ mountPoint => $ mount ) {
126- if (strlen ($ mountPoint ) > $ pathLen && str_starts_with ($ mountPoint , $ path )) {
127- $ result [] = $ mount ;
152+ if ($ start !== null ) {
153+ for ($ i = $ start , $ n = count ($ sortedKeys ); $ i < $ n ; $ i ++) {
154+ $ key = $ sortedKeys [$ i ];
155+ if (!str_starts_with ($ key , $ prefix )) {
156+ break ;
157+ }
158+
159+ if ($ key !== $ prefix ) {
160+ $ result [] = $ sortedArray [$ key ];
161+ }
128162 }
129163 }
130164
131- $ this ->inPathCache [$ path ] = $ result ;
132165 return $ result ;
133166 }
134167
@@ -201,7 +234,7 @@ public function getSetupManager(): SetupManager {
201234 *
202235 * @param string $path
203236 * @param string[] $mountProviders
204- * @return MountPoint []
237+ * @return IMountPoint []
205238 */
206239 public function getMountsByMountProvider (string $ path , array $ mountProviders ) {
207240 $ this ->getSetupManager ()->setupForProvider ($ path , $ mountProviders );
0 commit comments