private final void commit0() {
		int i, j, n;
		int curr = currIndex;
		int[] map = dirtyPagesMap;
		int oldIndexSize = header.root[curr].indexSize;
		int newIndexSize = header.root[1 - curr].indexSize;
		int nPages = committedIndexSize >>> dbHandlesPerPageBits;
		Page pg;

		if (newIndexSize > oldIndexSize) {
			cloneBitmap(header.root[curr].index, oldIndexSize * 8L);
			long newIndex;

			while (true) {
				newIndex = allocate(newIndexSize * 8L, 0);

				if (newIndexSize == header.root[1 - curr].indexSize) {
					break;
				}

				free(newIndex, newIndexSize * 8L);
				newIndexSize = header.root[1 - curr].indexSize;
			}

			header.root[1 - curr].shadowIndex = newIndex;
			header.root[1 - curr].shadowIndexSize = newIndexSize;
			free(header.root[curr].index, oldIndexSize * 8L);
		}

		long currSize = header.root[1 - curr].size;

		for (i = 0; i < nPages; i++) {
			if ((map[i >> 5] & (1 << (i & 31))) != 0) {
				Page srcIndex = pool.getPage(header.root[1 - curr].index
						+ (long) i * Page.pageSize);
				Page dstIndex = pool.getPage(header.root[curr].index + (long) i
						* Page.pageSize);

				for (j = 0; j < Page.pageSize; j += 8) {
					long pos = Bytes.unpack8(dstIndex.data, j);

					if (Bytes.unpack8(srcIndex.data, j) != pos
							&& pos < currSize) {
						if ((pos & dbFreeHandleFlag) == 0) {
							if ((pos & dbPageObjectFlag) != 0) {
								free(pos & ~dbFlagsMask, Page.pageSize);
							}
							else if (pos != 0) {
								int offs = (int) pos & (Page.pageSize - 1);
								pg = pool.getPage(pos - offs);
								free(pos, ObjectHeader.getSize(pg.data, offs));
								pool.unfix(pg);
							}
						}
					}
				}

				pool.unfix(srcIndex);
				pool.unfix(dstIndex);
			}
		}

		n = committedIndexSize & (dbHandlesPerPage - 1);

		if (n != 0 && (map[i >> 5] & (1 << (i & 31))) != 0) {
			Page srcIndex = pool.getPage(header.root[1 - curr].index + (long) i
					* Page.pageSize);
			Page dstIndex = pool.getPage(header.root[curr].index + (long) i
					* Page.pageSize);
			j = 0;

			do {
				long pos = Bytes.unpack8(dstIndex.data, j);

				if (Bytes.unpack8(srcIndex.data, j) != pos && pos < currSize) {
					if ((pos & dbFreeHandleFlag) == 0) {
						if ((pos & dbPageObjectFlag) != 0) {
							free(pos & ~dbFlagsMask, Page.pageSize);
						}
						else if (pos != 0) {
							int offs = (int) pos & (Page.pageSize - 1);
							pg = pool.getPage(pos - offs);
							free(pos, ObjectHeader.getSize(pg.data, offs));
							pool.unfix(pg);
						}
					}
				}

				j += 8;
			}
			while (--n != 0);

			pool.unfix(srcIndex);
			pool.unfix(dstIndex);
		}

		for (i = 0; i <= nPages; i++) {
			if ((map[i >> 5] & (1 << (i & 31))) != 0) {
				pg = pool.putPage(header.root[1 - curr].index + (long) i
						* Page.pageSize);

				for (j = 0; j < Page.pageSize; j += 8) {
					Bytes.pack8(pg.data, j, Bytes.unpack8(pg.data, j)
							& ~dbModifiedFlag);
				}

				pool.unfix(pg);
			}
		}

		if (currIndexSize > committedIndexSize) {
			long page = (header.root[1 - curr].index + committedIndexSize * 8L)
					& ~(Page.pageSize - 1);
			long end = (header.root[1 - curr].index + Page.pageSize - 1 + currIndexSize * 8L)
					& ~(Page.pageSize - 1);

			while (page < end) {
				pg = pool.putPage(page);

				for (j = 0; j < Page.pageSize; j += 8) {
					Bytes.pack8(pg.data, j, Bytes.unpack8(pg.data, j)
							& ~dbModifiedFlag);
				}

				pool.unfix(pg);
				page += Page.pageSize;
			}
		}

		header.root[1 - curr].usedSize = usedSize;
		pg = pool.putPage(0);
		header.pack(pg.data);
		pool.flush();
		pool.modify(pg);
		Assert.that(header.transactionId == transactionId);
		header.transactionId = ++transactionId;
		header.curr = curr ^= 1;
		header.dirty = true;
		header.pack(pg.data);
		pool.unfix(pg);
		pool.flush();
		header.root[1 - curr].size = header.root[curr].size;
		header.root[1 - curr].indexUsed = currIndexSize;
		header.root[1 - curr].freeList = header.root[curr].freeList;
		header.root[1 - curr].bitmapEnd = header.root[curr].bitmapEnd;
		header.root[1 - curr].rootObject = header.root[curr].rootObject;
		header.root[1 - curr].classDescList = header.root[curr].classDescList;
		header.root[1 - curr].bitmapExtent = header.root[curr].bitmapExtent;

		if (currIndexSize == 0 || newIndexSize != oldIndexSize) {
			header.root[1 - curr].index = header.root[curr].shadowIndex;
			header.root[1 - curr].indexSize = header.root[curr].shadowIndexSize;
			header.root[1 - curr].shadowIndex = header.root[curr].index;
			header.root[1 - curr].shadowIndexSize = header.root[curr].indexSize;
			pool.copy(header.root[1 - curr].index, header.root[curr].index,
					currIndexSize * 8L);
			i = (currIndexSize + dbHandlesPerPage * 32 - 1) >>> (dbHandlesPerPageBits + 5);

			while (--i >= 0) {
				map[i] = 0;
			}
		}
		else {
			for (i = 0; i < nPages; i++) {
				if ((map[i >> 5] & (1 << (i & 31))) != 0) {
					map[i >> 5] -= (1 << (i & 31));
					pool.copy(header.root[1 - curr].index + (long) i
							* Page.pageSize, header.root[curr].index + (long) i
							* Page.pageSize, Page.pageSize);
				}
			}

			if (currIndexSize > i * dbHandlesPerPage
					&& ((map[i >> 5] & (1 << (i & 31))) != 0 || currIndexSize != committedIndexSize)) {
				pool.copy(header.root[1 - curr].index + (long) i
						* Page.pageSize, header.root[curr].index + (long) i
						* Page.pageSize, 8L * currIndexSize - (long) i
						* Page.pageSize);
				j = i >>> 5;
				n = (currIndexSize + dbHandlesPerPage * 32 - 1) >>> (dbHandlesPerPageBits + 5);

				while (j < n) {
					map[j++] = 0;
				}
			}
		}

		gcDone = false;
		currIndex = curr;
		committedIndexSize = currIndexSize;

		if (multiclientSupport) {
			pool.flush();
			pg = pool.putPage(0);
			header.dirty = false;
			header.pack(pg.data);
			pool.unfix(pg);
			pool.flush();
		}

		if (listener != null) {
			listener.onTransactionCommit();
		}
	}