int allocateId() {
		synchronized (objectCache) {
			int oid;
			int curr = 1 - currIndex;

			setDirty();

			if (reuseOid && (oid = header.root[curr].freeList) != 0) {
				header.root[curr].freeList = (int) (getPos(oid) >> dbFlagsBits);
				Assert.that(header.root[curr].freeList >= 0);
				dirtyPagesMap[oid >>> (dbHandlesPerPageBits + 5)] |= 1 << ((oid >>> dbHandlesPerPageBits) & 31);
				return oid;
			}

			if (currIndexSize > dbMaxObjectOid) {
				throw new StorageError(StorageError.TOO_MUCH_OBJECTS);
			}

			if (currIndexSize >= header.root[curr].indexSize) {
				int oldIndexSize = header.root[curr].indexSize;
				int newIndexSize = oldIndexSize << 1;

				if (newIndexSize < oldIndexSize) {
					newIndexSize = Integer.MAX_VALUE & ~(dbHandlesPerPage - 1);

					if (newIndexSize <= oldIndexSize) {
						throw new StorageError(StorageError.NOT_ENOUGH_SPACE);
					}
				}

				long newIndex = allocate(newIndexSize * 8L, 0);

				if (currIndexSize >= header.root[curr].indexSize) {
					long oldIndex = header.root[curr].index;
					pool.copy(newIndex, oldIndex, currIndexSize * 8L);
					header.root[curr].index = newIndex;
					header.root[curr].indexSize = newIndexSize;
					free(oldIndex, oldIndexSize * 8L);
				}
				else {
					// index was already reallocated
					free(newIndex, newIndexSize * 8L);
				}
			}

			oid = currIndexSize;
			header.root[curr].indexUsed = ++currIndexSize;

			return oid;
		}
	}