mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-14 00:22:38 +03:00
Merge trunk into wasi-patches branch to clean up the diff view.
FossilOrigin-Name: 95de6742d3d96d2b21eec57195dc7a2236d3f61640633ae1baa36bf142a3485b
This commit is contained in:
@@ -20,6 +20,14 @@
|
||||
# above-listed o? target names.
|
||||
#
|
||||
# clean = clean up
|
||||
#
|
||||
# Required tools beyond those needed for the canonical builds:
|
||||
#
|
||||
# - Emscripten SDK: https://emscripten.org/docs/getting_started/downloads.html
|
||||
# - The bash shell
|
||||
# - GNU make, GNU sed, GNU awk, GNU grep (all in the $PATH)
|
||||
# - wasm-strip for release builds: https://github.com/WebAssembly/wabt
|
||||
# - InfoZip for 'dist' zip file
|
||||
########################################################################
|
||||
SHELL := $(shell which bash 2>/dev/null)
|
||||
MAKEFILE := $(lastword $(MAKEFILE_LIST))
|
||||
@@ -71,17 +79,19 @@ dir.jacc := jaccwabyt
|
||||
dir.common := common
|
||||
dir.fiddle := fiddle
|
||||
dir.tool := $(dir.top)/tool
|
||||
CLEAN_FILES += *~ $(dir.jacc)/*~ $(dir.api)/*~ $(dir.common)/*~ $(dir.fiddle)/*~
|
||||
|
||||
########################################################################
|
||||
# dir.dout = output dir for deliverables.
|
||||
#
|
||||
# MAINTENANCE REMINDER: the output .js and .wasm files of emcc must be
|
||||
# in _this_ dir, rather than a subdir, or else parts of the generated
|
||||
# code get confused and cannot load property. Specifically, when X.js
|
||||
# loads X.wasm, whether or not X.js uses the correct path for X.wasm
|
||||
# depends on how it's loaded: an HTML script tag will resolve it
|
||||
# intuitively, whereas a Worker's call to importScripts() will not.
|
||||
# That's a fundamental incompatibility with how URL resolution in
|
||||
# JS happens between those two contexts. See:
|
||||
# MAINTENANCE REMINDER: the output .js and .wasm files of certain emcc
|
||||
# buildables must be in _this_ dir, rather than a subdir, or else
|
||||
# parts of the generated code get confused and cannot load
|
||||
# property. Specifically, when X.js loads X.wasm, whether or not X.js
|
||||
# uses the correct path for X.wasm depends on how it's loaded: an HTML
|
||||
# script tag will resolve it intuitively, whereas a Worker's call to
|
||||
# importScripts() will not. That's a fundamental incompatibility with
|
||||
# how URL resolution in JS happens between those two contexts. See:
|
||||
#
|
||||
# https://zzz.buzz/2017/03/14/relative-uris-in-web-development/
|
||||
#
|
||||
@@ -104,11 +114,10 @@ ifeq (,$(wildcard $(dir.tmp)))
|
||||
dir._tmp := $(shell mkdir -p $(dir.tmp))
|
||||
endif
|
||||
|
||||
cflags.common := -I. -I.. -I$(dir.top)
|
||||
CLEAN_FILES += *~ $(dir.jacc)/*~ $(dir.api)/*~ $(dir.common)/*~
|
||||
emcc.WASM_BIGINT ?= 1
|
||||
sqlite3.c := $(dir.top)/sqlite3.c
|
||||
sqlite3.h := $(dir.top)/sqlite3.h
|
||||
# Most SQLITE_OPT flags are set in sqlite3-wasm.c but we need them
|
||||
# made explicit here for building speedtest1.c.
|
||||
SQLITE_OPT = \
|
||||
-DSQLITE_ENABLE_FTS5 \
|
||||
-DSQLITE_ENABLE_RTREE \
|
||||
@@ -130,43 +139,6 @@ SQLITE_OPT = \
|
||||
'-DSQLITE_DEFAULT_UNIX_VFS="unix-none"' \
|
||||
-DSQLITE_USE_URI=1 \
|
||||
-DSQLITE_WASM_ENABLE_C_TESTS
|
||||
# ^^^ most flags are set in sqlite3-wasm.c but we need them
|
||||
# made explicit here for building speedtest1.c.
|
||||
|
||||
ifneq (,$(filter release,$(MAKECMDGOALS)))
|
||||
emcc_opt ?= -Oz -flto
|
||||
else
|
||||
emcc_opt ?= -O0
|
||||
# ^^^^ build times for -O levels higher than 0 are painful at
|
||||
# dev-time.
|
||||
endif
|
||||
# When passing emcc_opt from the CLI, += and re-assignment have no
|
||||
# effect, so emcc_opt+=-g3 doesn't work. So...
|
||||
emcc_opt_full := $(emcc_opt) -g3
|
||||
# ^^^ ALWAYS use -g3. See below for why.
|
||||
#
|
||||
# ^^^ -flto improves runtime speed at -O0 considerably but doubles
|
||||
# build time.
|
||||
#
|
||||
# ^^^^ -O3, -Oz, -Os minify symbol names and there appears to be no
|
||||
# way around that except to use -g3, but -g3 causes the binary file
|
||||
# size to absolutely explode (approx. 5x larger). This minification
|
||||
# utterly breaks the resulting module, making it unsable except as
|
||||
# self-contained/self-referential-only code, as ALL of the exported
|
||||
# symbols get minified names.
|
||||
#
|
||||
# However, we have an option for using -Oz or -Os:
|
||||
#
|
||||
# Build with (-Os -g3) or (-Oz -g3) then use wasm-strip, from the wabt
|
||||
# tools package (https://github.com/WebAssembly/wabt), to strip the
|
||||
# debugging symbols. That results in a small build with unmangled
|
||||
# symbol names. -Oz gives ever-so-slightly better compression than
|
||||
# -Os: not quite 1% in some completely unscientific tests. Runtime
|
||||
# speed for the unit tests is all over the place either way so it's
|
||||
# difficult to say whether -Os gives any speed benefit over -Oz.
|
||||
#
|
||||
# (Much later: -O2 consistently gives the best speeds.)
|
||||
########################################################################
|
||||
|
||||
$(sqlite3.c) $(sqlite3.h):
|
||||
$(MAKE) -C $(dir.top) sqlite3.c
|
||||
@@ -186,13 +158,20 @@ else
|
||||
$(info Development build. Use '$(MAKE) release' for a smaller release build.)
|
||||
endif
|
||||
|
||||
# bin.version-info = binary to output various sqlite3 version info for
|
||||
# embedding in the JS files and in building the distribution zip file.
|
||||
# It must NOT be in $(dir.tmp) because we need it to survive the
|
||||
# cleanup process for the dist build to work properly.
|
||||
bin.version-info := $(dir.wasm)/version-info
|
||||
# ^^^^ NOT in $(dir.tmp) because we need it to survive the cleanup
|
||||
# process for the dist build to work properly.
|
||||
$(bin.version-info): $(dir.wasm)/version-info.c $(sqlite3.h) $(MAKEFILE)
|
||||
$(CC) -O0 -I$(dir.top) -o $@ $<
|
||||
DISTCLEAN_FILES += $(bin.version-info)
|
||||
|
||||
# bin.stripcomments is used for stripping C/C++-style comments from JS
|
||||
# files. The JS files contain large chunks of documentation which we
|
||||
# don't need for all builds. That app's -k flag is of particular
|
||||
# importance here, as it allows us to retain the opening comment
|
||||
# blocks, which contain the license header and version info.
|
||||
bin.stripccomments := $(dir.tool)/stripccomments
|
||||
$(bin.stripccomments): $(bin.stripccomments).c $(MAKEFILE)
|
||||
$(CC) -o $@ $<
|
||||
@@ -200,7 +179,8 @@ DISTCLEAN_FILES += $(bin.stripccomments)
|
||||
|
||||
|
||||
########################################################################
|
||||
# Transform $(1) to $(2) via ./c-pp -f $(1) ...
|
||||
# C-PP.FILTER: a $(call)able to transform $(1) to $(2) via ./c-pp -f
|
||||
# $(1) ...
|
||||
#
|
||||
# Historical notes:
|
||||
#
|
||||
@@ -226,27 +206,78 @@ DISTCLEAN_FILES += $(bin.stripccomments)
|
||||
bin.c-pp := ./c-pp
|
||||
$(bin.c-pp): c-pp.c $(sqlite3.c) $(MAKEFILE)
|
||||
$(CC) -O0 -o $@ c-pp.c $(sqlite3.c) '-DCMPP_DEFAULT_DELIM="//#"' -I$(dir.top)
|
||||
define C-PP.JS
|
||||
# $1 c-pp -D... flags
|
||||
# $2 = c-pp -f X.js
|
||||
# $3 = c-pp -o X.js
|
||||
$(3): $(2) $$(MAKEFILE) $$(bin.c-pp)
|
||||
$$(bin.c-pp) -f $(2) -o $$@ $(1)
|
||||
CLEAN_FILES += $(3)
|
||||
define C-PP.FILTER
|
||||
# Create $2 from $1 using $(bin.c-pp)
|
||||
# $1 = Input file: c-pp -f $(1).js
|
||||
# $2 = Output file: c-pp -o $(2).js
|
||||
# $3 = optional c-pp -D... flags
|
||||
$(2): $(1) $$(MAKEFILE) $$(bin.c-pp)
|
||||
$$(bin.c-pp) -f $(1) -o $$@ $(3)
|
||||
CLEAN_FILES += $(2)
|
||||
endef
|
||||
c-pp.D.vanilla ?=
|
||||
c-pp.D.esm ?= -Dsqlite3-es6-module-build
|
||||
# /end CPP-of-JS bits
|
||||
c-pp.D.esm ?= -Dtarget=es6-module
|
||||
# /end C-PP.FILTER
|
||||
########################################################################
|
||||
|
||||
|
||||
# cflags.common = C compiler flags for all builds
|
||||
cflags.common := -I. -I.. -I$(dir.top)
|
||||
# emcc.WASM_BIGINT = 1 for BigInt (C int64) support, else 0. The API
|
||||
# disables certain features if BigInt is not enabled and such builds
|
||||
# _are not tested_ on any regular basis.
|
||||
emcc.WASM_BIGINT ?= 1
|
||||
|
||||
# emcc_opt = optimization-related flags. These are primarily used by
|
||||
# the various oX targets. build times for -O levels higher than 0 are
|
||||
# painful at dev-time.
|
||||
emcc_opt ?= -O0
|
||||
|
||||
# When passing emcc_opt from the CLI, += and re-assignment have no
|
||||
# effect, so emcc_opt+=-g3 doesn't work. So...
|
||||
emcc_opt_full := $(emcc_opt) -g3
|
||||
# ^^^ ALWAYS use -g3. See below for why.
|
||||
#
|
||||
# ^^^ -flto improves runtime speed at -O0 considerably but doubles
|
||||
# build time.
|
||||
#
|
||||
# ^^^^ -O3, -Oz, -Os minify symbol names and there appears to be no
|
||||
# way around that except to use -g3, but -g3 causes the binary file
|
||||
# size to absolutely explode (approx. 5x larger). This minification
|
||||
# utterly breaks the resulting module, making it unsable except as
|
||||
# self-contained/self-referential-only code, as ALL of the exported
|
||||
# symbols get minified names.
|
||||
#
|
||||
# However, we have an option for using -Oz or -Os:
|
||||
#
|
||||
# Build with (-Os -g3) or (-Oz -g3) then use wasm-strip, from the wabt
|
||||
# tools package (https://github.com/WebAssembly/wabt), to strip the
|
||||
# debugging symbols. That results in a small build with unmangled
|
||||
# symbol names. -Oz gives ever-so-slightly better compression than
|
||||
# -Os: not quite 1% in some completely unscientific tests. Runtime
|
||||
# speed for the unit tests is all over the place either way so it's
|
||||
# difficult to say whether -Os gives any speed benefit over -Oz.
|
||||
#
|
||||
# Much practice has demonstrated that -O2 consistently gives the best
|
||||
# runtime speeds, but not by a large enough factor to rule out use of
|
||||
# -Oz when small deliverable size is a priority.
|
||||
########################################################################
|
||||
|
||||
# EXPORTED_FUNCTIONS.* = files for use with Emscripten's
|
||||
# -sEXPORTED_FUNCTION flag.
|
||||
EXPORTED_FUNCTIONS.api.in := $(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-api)
|
||||
EXPORTED_FUNCTIONS.api := $(dir.tmp)/EXPORTED_FUNCTIONS.api
|
||||
$(EXPORTED_FUNCTIONS.api): $(EXPORTED_FUNCTIONS.api.in) $(MAKEFILE)
|
||||
cat $(EXPORTED_FUNCTIONS.api.in) > $@
|
||||
cp $(EXPORTED_FUNCTIONS.api.in) $@
|
||||
|
||||
# sqlite3-license-version.js = generated JS file with the license
|
||||
# header and version info.
|
||||
sqlite3-license-version.js := $(dir.tmp)/sqlite3-license-version.js
|
||||
# sqlite3-license-version-header.js = JS file containing only the
|
||||
# license header.
|
||||
sqlite3-license-version-header.js := $(dir.api)/sqlite3-license-version-header.js
|
||||
# sqlite3-api-build-version.js = generated JS file which populates the
|
||||
# sqlite3.version object using $(bin.version-info).
|
||||
sqlite3-api-build-version.js := $(dir.tmp)/sqlite3-api-build-version.js
|
||||
# sqlite3-api.jses = the list of JS files which make up $(sqlite3-api.js), in
|
||||
# the order they need to be assembled.
|
||||
@@ -266,6 +297,8 @@ sqlite3-api.jses += $(dir.api)/sqlite3-api-cleanup.js
|
||||
SOAP.js := $(dir.api)/sqlite3-opfs-async-proxy.js
|
||||
sqlite3-worker1.js := $(dir.api)/sqlite3-worker1.js
|
||||
sqlite3-worker1-promiser.js := $(dir.api)/sqlite3-worker1-promiser.js
|
||||
# COPY_XAPI = a $(call)able function to copy $1 to $(dir.dout), where
|
||||
# $1 must be one of the "external" JS API files.
|
||||
define COPY_XAPI
|
||||
sqlite3-api.ext.jses += $$(dir.dout)/$$(notdir $(1))
|
||||
$$(dir.dout)/$$(notdir $(1)): $(1) $$(MAKEFILE)
|
||||
@@ -275,6 +308,9 @@ $(foreach X,$(SOAP.js) $(sqlite3-worker1.js) $(sqlite3-worker1-promiser.js),\
|
||||
$(eval $(call COPY_XAPI,$(X))))
|
||||
all: $(sqlite3-api.ext.jses)
|
||||
|
||||
# sqlite3-api.js.in = the generated sqlite3-api.js before it gets
|
||||
# preprocessed. It contains all of $(sqlite3-api.jses) but none of the
|
||||
# Emscripten-specific headers and footers.
|
||||
sqlite3-api.js.in := $(dir.tmp)/sqlite3-api.c-pp.js
|
||||
$(sqlite3-api.js.in): $(sqlite3-api.jses) $(MAKEFILE)
|
||||
@echo "Making $@..."
|
||||
@@ -293,15 +329,27 @@ $(sqlite3-api-build-version.js): $(bin.version-info) $(MAKEFILE)
|
||||
echo ';'; \
|
||||
echo '});'; \
|
||||
} > $@
|
||||
$(sqlite3-license-version.js): $(sqlite3.h) $(sqlite3-license-version-header.js) \
|
||||
$(MAKEFILE)
|
||||
@echo "Making $@..."; { \
|
||||
cat $(sqlite3-license-version-header.js); \
|
||||
echo '/*'; \
|
||||
echo '** This code was built from sqlite3 version...'; \
|
||||
echo "** "; \
|
||||
awk -e '/define SQLITE_VERSION/{$$1=""; print "**" $$0}' \
|
||||
-e '/define SQLITE_SOURCE_ID/{$$1=""; print "**" $$0}' $(sqlite3.h); \
|
||||
echo '*/'; \
|
||||
} > $@
|
||||
|
||||
########################################################################
|
||||
# --post-js and --pre-js are emcc flags we use to append/prepend JS to
|
||||
# the generated emscripten module file.
|
||||
# the generated emscripten module file. The following rules generate
|
||||
# various versions of those files for the vanilla and ESM builds.
|
||||
pre-js.js.in := $(dir.api)/pre-js.js
|
||||
pre-js.js.esm := $(dir.tmp)/pre-js.esm.js
|
||||
pre-js.js.vanilla := $(dir.tmp)/pre-js.vanilla.js
|
||||
$(eval $(call C-PP.JS,$(c-pp.D.vanilla),$(pre-js.js.in),$(pre-js.js.vanilla)))
|
||||
$(eval $(call C-PP.JS,$(c-pp.D.esm),$(pre-js.js.in),$(pre-js.js.esm)))
|
||||
$(eval $(call C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.vanilla),$(c-pp.D.vanilla)))
|
||||
$(eval $(call C-PP.FILTER,$(pre-js.js.in),$(pre-js.js.esm),$(c-pp.D.esm)))
|
||||
post-js.js.in := $(dir.tmp)/post-js.js
|
||||
post-js.js.vanilla := $(dir.tmp)/post-js.vanilla.js
|
||||
post-js.js.esm := $(dir.tmp)/post-js.esm.js
|
||||
@@ -316,17 +364,21 @@ $(post-js.js.in): $(post-jses.js) $(MAKEFILE)
|
||||
cat $$i; \
|
||||
echo "/* END FILE: $$i */"; \
|
||||
done > $@
|
||||
$(eval $(call C-PP.JS,$(c-pp.D.vanilla),$(post-js.js.in),$(post-js.js.vanilla)))
|
||||
$(eval $(call C-PP.JS,$(c-pp.D.esm),$(post-js.js.in),$(post-js.js.esm)))
|
||||
$(eval $(call C-PP.FILTER,$(post-js.js.in),$(post-js.js.vanilla),$(c-pp.D.vanilla)))
|
||||
$(eval $(call C-PP.FILTER,$(post-js.js.in),$(post-js.js.esm),$(c-pp.D.esm)))
|
||||
|
||||
# extern-post-js* and extern-pre-js* are files for use with
|
||||
# Emscripten's --extern-pre-js and --extern-post-js flags. These
|
||||
# rules make different copies for the vanilla and ESM builds.
|
||||
extern-post-js.js.in := $(dir.api)/extern-post-js.js
|
||||
extern-post-js.js.vanilla := $(dir.tmp)/extern-post-js.vanilla.js
|
||||
extern-post-js.js.esm := $(dir.tmp)/extern-post-js.esm.js
|
||||
$(eval $(call C-PP.JS,$(c-pp.D.vanilla),$(extern-post-js.js.in),$(extern-post-js.js.vanilla)))
|
||||
$(eval $(call C-PP.JS,$(c-pp.D.esm),$(extern-post-js.js.in),$(extern-post-js.js.esm)))
|
||||
$(eval $(call C-PP.FILTER,$(extern-post-js.js.in),$(extern-post-js.js.vanilla),$(c-pp.D.vanilla)))
|
||||
$(eval $(call C-PP.FILTER,$(extern-post-js.js.in),$(extern-post-js.js.esm),$(c-pp.D.esm)))
|
||||
extern-pre-js.js := $(dir.api)/extern-pre-js.js
|
||||
|
||||
# Emscripten flags for --[extern-][pre|post]-js=...
|
||||
# Emscripten flags for --[extern-][pre|post]-js=... for the
|
||||
# various builds.
|
||||
pre-post-common.flags := \
|
||||
--extern-pre-js=$(sqlite3-license-version.js)
|
||||
pre-post-common.flags.vanilla := \
|
||||
@@ -338,26 +390,21 @@ pre-post-common.flags.esm := \
|
||||
--post-js=$(post-js.js.esm) \
|
||||
--extern-post-js=$(extern-post-js.js.esm)
|
||||
|
||||
# pre-post-jses.deps.* = a list of dependencies for the
|
||||
# --[extern-][pre/post]-js files.
|
||||
pre-post-jses.deps.common := $(extern-pre-js.js) $(sqlite3-license-version.js)
|
||||
pre-post-jses.deps.vanilla := $(pre-post-jses.deps.common) \
|
||||
$(post-js.js.vanilla) $(extern-post-js.js.vanilla)
|
||||
pre-post-jses.deps.esm := $(pre-post-jses.deps.common) \
|
||||
$(post-js.js.esm) $(extern-post-js.js.esm)
|
||||
$(sqlite3-license-version.js): $(sqlite3.h) $(sqlite3-license-version-header.js) $(MAKEFILE)
|
||||
@echo "Making $@..."; { \
|
||||
cat $(sqlite3-license-version-header.js); \
|
||||
echo '/*'; \
|
||||
echo '** This code was built from sqlite3 version...'; \
|
||||
echo "** "; \
|
||||
awk -e '/define SQLITE_VERSION/{$$1=""; print "**" $$0}' \
|
||||
-e '/define SQLITE_SOURCE_ID/{$$1=""; print "**" $$0}' $(sqlite3.h); \
|
||||
echo '*/'; \
|
||||
} > $@
|
||||
|
||||
########################################################################
|
||||
# call-make-pre-js creates rules for pre-js-$(1).js. $1 = the base
|
||||
# name of the JS file on whose behalf this pre-js is for. $2 is the
|
||||
# build mode: one of (vanilla, esm).
|
||||
# call-make-pre-js is a $(call)able which creates rules for
|
||||
# pre-js-$(1).js. $1 = the base name of the JS file on whose behalf
|
||||
# this pre-js is for. $2 is the build mode: one of (vanilla, esm).
|
||||
# This sets up --[extern-][pre/post]-js flags in
|
||||
# $(pre-post-$(1).flags.$(2)) and dependencies in
|
||||
# $(pre-post-$(1).deps.$(2)).
|
||||
define call-make-pre-js
|
||||
pre-post-$(1).flags.$(2) ?=
|
||||
$$(dir.tmp)/pre-js-$(1)-$(2).js: $$(pre-js.js.$(2)) $$(MAKEFILE)
|
||||
@@ -374,29 +421,30 @@ pre-post-$(1).flags.$(2) += \
|
||||
$$(pre-post-common.flags.$(2)) \
|
||||
--pre-js=$$(dir.tmp)/pre-js-$(1)-$(2).js
|
||||
endef
|
||||
#$(error $(call call-make-pre-js,sqlite3-wasmfs))
|
||||
# /post-js and pre-js
|
||||
########################################################################
|
||||
|
||||
########################################################################
|
||||
# emcc flags for .c/.o/.wasm/.js.
|
||||
emcc.flags :=
|
||||
#emcc.flags += -v # _very_ loud but also informative about what it's doing
|
||||
# -g3 is needed to keep -O2 and higher from creating broken JS via
|
||||
# minification.
|
||||
ifeq (1,$(emcc.verbose))
|
||||
emcc.flags += -v
|
||||
# -v is _very_ loud but also informative about what it's doing
|
||||
endif
|
||||
|
||||
########################################################################
|
||||
# emcc flags for .c/.o.
|
||||
emcc.cflags :=
|
||||
emcc.cflags += -std=c99 -fPIC
|
||||
# -------------^^^^^^^^ we currently need c99 for WASM-specific sqlite3 APIs.
|
||||
# -------------^^^^^^^^ we need c99 for $(sqlite3-wasm.c).
|
||||
emcc.cflags += -I. -I$(dir.top)
|
||||
|
||||
########################################################################
|
||||
# emcc flags specific to building the final .js/.wasm file...
|
||||
# emcc flags specific to building .js/.wasm files...
|
||||
emcc.jsflags := -fPIC
|
||||
emcc.jsflags += --minify 0
|
||||
emcc.jsflags += --no-entry
|
||||
emcc.jsflags += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
|
||||
emcc.jsflags += -sMODULARIZE
|
||||
emcc.jsflags += -sSTRICT_JS
|
||||
emcc.jsflags += -sDYNAMIC_EXECUTION=0
|
||||
@@ -404,7 +452,9 @@ emcc.jsflags += -sNO_POLYFILL
|
||||
emcc.jsflags += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.api)
|
||||
emcc.exportedRuntimeMethods := \
|
||||
-sEXPORTED_RUNTIME_METHODS=FS,wasmMemory
|
||||
# FS ==> stdio/POSIX I/O proxies
|
||||
# FS ==> stdio/POSIX I/O proxies. Currently used explicitly only
|
||||
# by the fiddle app, and it must never be exposed to client code
|
||||
# via our APIs.
|
||||
# wasmMemory ==> required by our code for use with -sIMPORTED_MEMORY
|
||||
emcc.jsflags += $(emcc.exportedRuntimeMethods)
|
||||
emcc.jsflags += -sUSE_CLOSURE_COMPILER=0
|
||||
@@ -438,32 +488,44 @@ emcc.jsflags += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.$(emcc.INITIAL_MEMORY))
|
||||
|
||||
emcc.jsflags += $(emcc.environment)
|
||||
#emcc.jsflags += -sTOTAL_STACK=4194304
|
||||
|
||||
########################################################################
|
||||
# $(sqlite3.js.init-func) is the name Emscripten assigns our exported
|
||||
# module init/load function. This symbol name is hard-coded in
|
||||
# $(extern-post-js.js) as well as in numerous docs.
|
||||
#
|
||||
# "sqlite3InitModule" is the symbol we document for client use, so
|
||||
# that's the symbol name which must be exported, whether it comes from
|
||||
# Emscripten or our own code in extern-post-js.js.
|
||||
#
|
||||
# That said... we can change $(sqlite3.js.init-func) as long as the
|
||||
# name "sqlite3InitModule" is the one which gets exposed via the
|
||||
# resulting JS files. That can be accomplished via
|
||||
# extern-post-js.js. However... using a temporary symbol name here
|
||||
# and then adding sqlite3InitModule() ourselves results in 2 global
|
||||
# symbols: we cannot "delete" the Emscripten-defined
|
||||
# $(sqlite3.js.init-func) because it's declared with "var".
|
||||
sqlite3.js.init-func := sqlite3InitModule
|
||||
# ^^^^ $(sqlite3.js.init-func) symbol name is hard-coded in
|
||||
# $(extern-post-js.js) as well as in numerous docs. If changed, it
|
||||
# needs to be globally modified in *.js and all related documentation.
|
||||
|
||||
emcc.jsflags += -sEXPORT_NAME=$(sqlite3.js.init-func)
|
||||
emcc.jsflags += -sGLOBAL_BASE=4096 # HYPOTHETICALLY keep func table indexes from overlapping w/ heap addr.
|
||||
#emcc.jsflags += -sSTRICT # fails due to missing __syscall_...()
|
||||
#emcc.jsflags += -sALLOW_UNIMPLEMENTED_SYSCALLS
|
||||
#emcc.jsflags += -sFILESYSTEM=0 # only for experimentation. sqlite3 needs the FS API
|
||||
#emcc.jsflags += -sABORTING_MALLOC
|
||||
#emcc.jsflags += -sABORTING_MALLOC # only for experimentation
|
||||
emcc.jsflags += -sALLOW_TABLE_GROWTH
|
||||
# -sALLOW_TABLE_GROWTH is required for installing new SQL UDFs
|
||||
# ^^^^ -sALLOW_TABLE_GROWTH is required for installing new SQL UDFs
|
||||
emcc.jsflags += -Wno-limited-postlink-optimizations
|
||||
# ^^^^^ it likes to warn when we have "limited optimizations" via the -g3 flag.
|
||||
#emcc.jsflags += -sSTANDALONE_WASM # causes OOM errors, not sure why
|
||||
# https://lld.llvm.org/WebAssembly.html
|
||||
emcc.jsflags += -sERROR_ON_UNDEFINED_SYMBOLS=0
|
||||
# ^^^^ emcc likes to warn when we have "limited optimizations" via the
|
||||
# -g3 flag.
|
||||
# emcc.jsflags += -sSTANDALONE_WASM # causes OOM errors, not sure why.
|
||||
|
||||
# Re. undefined symbol handling, see: https://lld.llvm.org/WebAssembly.html
|
||||
emcc.jsflags += -sERROR_ON_UNDEFINED_SYMBOLS=1
|
||||
emcc.jsflags += -sLLD_REPORT_UNDEFINED
|
||||
#emcc.jsflags += --allow-undefined
|
||||
#emcc.jsflags += --import-undefined
|
||||
#emcc.jsflags += --unresolved-symbols=import-dynamic --experimental-pic
|
||||
#emcc.jsflags += --experimental-pic --unresolved-symbols=ingore-all --import-undefined
|
||||
#emcc.jsflags += --unresolved-symbols=ignore-all
|
||||
emcc.jsflags += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
|
||||
|
||||
########################################################################
|
||||
# -sMEMORY64=1 fails to load, erroring with:
|
||||
@@ -475,18 +537,21 @@ emcc.jsflags += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
|
||||
# new Uint8Array(wasm.heap8u().buffer, ptr, n)
|
||||
#
|
||||
# because ptr is now a BigInt, so is invalid for passing to arguments
|
||||
# which have strict must-be-a-Number requirements.
|
||||
# which have strict must-be-a-Number requirements. That aspect will
|
||||
# make any eventual port to 64-bit address space extremely painful, as
|
||||
# such constructs are found all over the place in the source code.
|
||||
########################################################################
|
||||
|
||||
|
||||
########################################################################
|
||||
# -sSINGLE_FILE:
|
||||
# https://github.com/emscripten-core/emscripten/blob/main/src/settings.js#L1704
|
||||
# -sSINGLE_FILE=1 would be really nice but we have to build with -g3
|
||||
# https://github.com/emscripten-core/emscripten/blob/main/src/settings.js
|
||||
#
|
||||
# -sSINGLE_FILE=1 would be _really_ nice but we have to build with -g3
|
||||
# for -O2 and higher to work (else minification breaks the code) and
|
||||
# cannot wasm-strip the binary before it gets encoded into the JS
|
||||
# file. The result is that the generated JS file is, because of the -g3
|
||||
# debugging info, _huge_.
|
||||
# file. The result is that the generated JS file is, because of the
|
||||
# -g3 debugging info, _huge_.
|
||||
########################################################################
|
||||
|
||||
sqlite3.js := $(dir.dout)/sqlite3.js
|
||||
@@ -503,55 +568,69 @@ sqlite3-wasm.c := $(dir.api)/sqlite3-wasm.c
|
||||
# instead of building a shared copy of sqlite3-wasm.o.
|
||||
$(eval $(call call-make-pre-js,sqlite3,vanilla))
|
||||
$(eval $(call call-make-pre-js,sqlite3,esm))
|
||||
$(sqlite3.js):
|
||||
$(sqlite3.js) $(sqlite3.mjs): $(MAKEFILE) $(sqlite3.wasm.obj) \
|
||||
$(EXPORTED_FUNCTIONS.api)
|
||||
$(sqlite3.js): $(pre-post-sqlite3.deps.vanilla)
|
||||
$(sqlite3.mjs): $(pre-post-sqlite3.deps.esm)
|
||||
# SQLITE3.xJS.RECIPE = Recipe body for $(sqlite3.js) and
|
||||
# $(sqlite3.mjs). $1 = one of (vanilla, esm).
|
||||
define SQLITE3.xJS.RECIPE
|
||||
@echo "Building $@ ..."
|
||||
$(emcc.bin) -o $@ $(emcc_opt_full) $(emcc.flags) \
|
||||
$(emcc.jsflags) \
|
||||
$(pre-post-sqlite3.flags.$(1)) $(emcc.flags.sqlite3.$(1)) \
|
||||
$(cflags.common) $(SQLITE_OPT) $(sqlite3-wasm.c)
|
||||
if [ esm = $(1) ]; then \
|
||||
sed -i -e '0,/^export default/{/^export default/d}' $@; \
|
||||
fi # work around an Emscripten annoyance. See emcc.flags.esm
|
||||
chmod -x $(sqlite3.wasm)
|
||||
$(maybe-wasm-strip) $(sqlite3.wasm)
|
||||
@ls -la $@ $(sqlite3.wasm)
|
||||
endef
|
||||
emcc.flags.sqlite3.vanilla :=
|
||||
emcc.flags.sqlite3.esm := -sEXPORT_ES6 -sUSE_ES6_IMPORT_META
|
||||
# Reminder: even if we use -sEXPORT_ES6=0, emcc _still_ adds:
|
||||
########################################################################
|
||||
# SQLITE3.xJS.RECIPE = the $(call)able recipe body for $(sqlite3.js)
|
||||
# and $(sqlite3.mjs). $1 = one of (vanilla, esm).
|
||||
#
|
||||
# Reminder for ESM builds: even if we use -sEXPORT_ES6=0, emcc _still_
|
||||
# adds:
|
||||
#
|
||||
# export default $(sqlite3.js.init-func);
|
||||
#
|
||||
# when building *.mjs, which is bad because we need to export an
|
||||
# overwritten version of that function and cannot "export default"
|
||||
# twice. Because of this, we have to sed $(sqlite3.mjs) to remove the
|
||||
# first instance of /^export default/.
|
||||
# _first_ instance (only) of /^export default/.
|
||||
#
|
||||
# Upstream RFE:
|
||||
# https://github.com/emscripten-core/emscripten/issues/18237
|
||||
########################################################################
|
||||
define SQLITE3.xJS.RECIPE
|
||||
@echo "Building $@ ..."
|
||||
$(emcc.bin) -o $@ $(emcc_opt_full) $(emcc.flags) \
|
||||
$(emcc.jsflags) \
|
||||
$(pre-post-sqlite3.flags.$(1)) $(emcc.flags.sqlite3.$(1)) \
|
||||
$(cflags.common) $(SQLITE_OPT) $(sqlite3-wasm.c)
|
||||
@if [ esm = $(1) ]; then \
|
||||
echo "Fragile workaround for an Emscripten annoyance. See emcc.flags.sqlite3.esm."; \
|
||||
sed -i -e '0,/^export default/{/^export default/d}' $@ || exit $$?; \
|
||||
if ! grep -q '^export default' $@; then \
|
||||
echo "Cannot find export default." 1>&2; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
fi
|
||||
chmod -x $(sqlite3.wasm)
|
||||
$(maybe-wasm-strip) $(sqlite3.wasm)
|
||||
@ls -la $@ $(sqlite3.wasm)
|
||||
endef
|
||||
emcc.flags.sqlite3.vanilla :=
|
||||
emcc.flags.sqlite3.esm := -sEXPORT_ES6 -sUSE_ES6_IMPORT_META
|
||||
$(sqlite3.js):
|
||||
$(call SQLITE3.xJS.RECIPE,vanilla)
|
||||
$(sqlite3.mjs):
|
||||
$(call SQLITE3.xJS.RECIPE,esm)
|
||||
########################################################################
|
||||
# We have to ensure that we do not build both $(sqlite3.js) and
|
||||
# $(sqlite3.mjs) in parallel because both result in the creation of
|
||||
# $(sqlite3.wasm). We have no(?) way to build just the .mjs file
|
||||
# without also building the .wasm file. i.e. we're building
|
||||
# $(sqlite3.wasm) twice, but that's apparently unavoidable (and
|
||||
# harmless, just a waste of build time).
|
||||
$(sqlite3.wasm): $(sqlite3.js)
|
||||
$(sqlite3.mjs): $(sqlite3.js)
|
||||
# We have to ensure that we do not build both $(sqlite3.js) and
|
||||
# $(sqlite3.mjs) in parallel because both result in the build of
|
||||
# $(sqlite3.wasm). We have no way to build just the .mjs file without
|
||||
# also building the .wasm file. i.e. we're building $(sqlite3.wasm)
|
||||
# twice, but that's unavoidable.
|
||||
CLEAN_FILES += $(sqlite3.js) $(sqlite3.mjs) $(sqlite3.wasm)
|
||||
all: $(sqlite3.mjs)
|
||||
wasm: $(sqlite3.mjs)
|
||||
# End main Emscripten-based module build
|
||||
# End main $(sqlite3.js) build
|
||||
########################################################################
|
||||
|
||||
########################################################################
|
||||
# batch-runner.js...
|
||||
# batch-runner.js is part of one of the test apps which reads in SQL
|
||||
# dumps generated by $(speedtest1) and executes them.
|
||||
dir.sql := sql
|
||||
speedtest1 := ../../speedtest1
|
||||
speedtest1.c := ../../test/speedtest1.c
|
||||
@@ -573,29 +652,30 @@ batch: batch-runner.list
|
||||
all: batch
|
||||
# end batch-runner.js
|
||||
########################################################################
|
||||
# speedtest1.js...
|
||||
# speedtest1-common.eflags = emcc flags used by multiple builds of speedtest1
|
||||
# Wasmified speedtest1 is our primary benchmarking tool.
|
||||
#
|
||||
# speedtest1.eflags.common = emcc flags used by multiple builds of speedtest1
|
||||
# speedtest1.eflags = emcc flags used by main build of speedtest1
|
||||
speedtest1-common.eflags := $(emcc_opt_full)
|
||||
speedtest1.eflags.common := $(emcc_opt_full)
|
||||
speedtest1.eflags :=
|
||||
speedtest1.eflags += -sENVIRONMENT=web
|
||||
speedtest1.eflags += -sALLOW_MEMORY_GROWTH
|
||||
speedtest1.eflags += -sINITIAL_MEMORY=$(emcc.INITIAL_MEMORY.$(emcc.INITIAL_MEMORY))
|
||||
speedtest1-common.eflags += -sINVOKE_RUN=0
|
||||
speedtest1-common.eflags += --no-entry
|
||||
#speedtest1-common.eflags += -flto
|
||||
speedtest1-common.eflags += -sABORTING_MALLOC
|
||||
speedtest1-common.eflags += -sSTRICT_JS
|
||||
speedtest1-common.eflags += -sMODULARIZE
|
||||
speedtest1-common.eflags += -Wno-limited-postlink-optimizations
|
||||
speedtest1.eflags.common += -sINVOKE_RUN=0
|
||||
speedtest1.eflags.common += --no-entry
|
||||
#speedtest1.eflags.common += -flto
|
||||
speedtest1.eflags.common += -sABORTING_MALLOC
|
||||
speedtest1.eflags.common += -sSTRICT_JS
|
||||
speedtest1.eflags.common += -sMODULARIZE
|
||||
speedtest1.eflags.common += -Wno-limited-postlink-optimizations
|
||||
EXPORTED_FUNCTIONS.speedtest1 := $(abspath $(dir.tmp)/EXPORTED_FUNCTIONS.speedtest1)
|
||||
speedtest1-common.eflags += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.speedtest1)
|
||||
speedtest1-common.eflags += $(emcc.exportedRuntimeMethods)
|
||||
speedtest1-common.eflags += -sALLOW_TABLE_GROWTH
|
||||
speedtest1-common.eflags += -sDYNAMIC_EXECUTION=0
|
||||
speedtest1-common.eflags += --minify 0
|
||||
speedtest1-common.eflags += -sEXPORT_NAME=$(sqlite3.js.init-func)
|
||||
speedtest1-common.eflags += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
|
||||
speedtest1.eflags.common += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.speedtest1)
|
||||
speedtest1.eflags.common += $(emcc.exportedRuntimeMethods)
|
||||
speedtest1.eflags.common += -sALLOW_TABLE_GROWTH
|
||||
speedtest1.eflags.common += -sDYNAMIC_EXECUTION=0
|
||||
speedtest1.eflags.common += --minify 0
|
||||
speedtest1.eflags.common += -sEXPORT_NAME=$(sqlite3.js.init-func)
|
||||
speedtest1.eflags.common += -sWASM_BIGINT=$(emcc.WASM_BIGINT)
|
||||
speedtest1.exit-runtime0 := -sEXIT_RUNTIME=0
|
||||
speedtest1.exit-runtime1 := -sEXIT_RUNTIME=1
|
||||
# Re -sEXIT_RUNTIME=1 vs 0: if it's 1 and speedtest1 crashes, we get
|
||||
@@ -628,8 +708,8 @@ $(speedtest1.js): $(MAKEFILE) $(speedtest1.cses) \
|
||||
$(EXPORTED_FUNCTIONS.speedtest1)
|
||||
@echo "Building $@ ..."
|
||||
$(emcc.bin) \
|
||||
$(speedtest1.eflags) $(speedtest1-common.eflags) $(speedtest1.cflags) \
|
||||
$(pre-post-speedtest1.flags.vanilla) \
|
||||
$(speedtest1.eflags) $(speedtest1.eflags.common) \
|
||||
$(speedtest1.cflags) $(pre-post-speedtest1.flags.vanilla) \
|
||||
$(SQLITE_OPT) \
|
||||
$(speedtest1.exit-runtime0) \
|
||||
-o $@ $(speedtest1.cses) -lm
|
||||
@@ -642,6 +722,29 @@ CLEAN_FILES += $(speedtest1.js) $(speedtest1.wasm)
|
||||
# end speedtest1.js
|
||||
########################################################################
|
||||
|
||||
########################################################################
|
||||
# tester1 is the main unit and regression test application and needs
|
||||
# to be able to run in 4 separate modes to cover the primary
|
||||
# client-side use cases:
|
||||
#
|
||||
# 1) Load sqlite3 in the main UI thread of a conventional script.
|
||||
# 2) Load sqlite3 in a conventional Worker thread.
|
||||
# 3) Load sqlite3 as an ES6 module (ESM) in the main thread.
|
||||
# 4) Load sqlite3 as an ESM worker. (Not all browsers support this.)
|
||||
#
|
||||
# To that end, we require two separate builds of tester1.js:
|
||||
#
|
||||
# tester1.js: cases 1 and 2
|
||||
# tester1.mjs: cases 3 and 4
|
||||
#
|
||||
# To create those, we filter tester1.c-pp.js with $(bin.c-pp)...
|
||||
$(eval $(call C-PP.FILTER,tester1.c-pp.js,tester1.js))
|
||||
$(eval $(call C-PP.FILTER,tester1.c-pp.js,tester1.mjs,$(c-pp.D.esm)))
|
||||
$(eval $(call C-PP.FILTER,tester1.c-pp.html,tester1.html))
|
||||
$(eval $(call C-PP.FILTER,tester1.c-pp.html,tester1-esm.html,$(c-pp.D.esm)))
|
||||
tester1: tester1.js tester1.mjs tester1.html tester1-esm.html
|
||||
all: tester1
|
||||
|
||||
########################################################################
|
||||
# Convenience rules to rebuild with various -Ox levels. Much
|
||||
# experimentation shows -O2 to be the clear winner in terms of speed.
|
||||
@@ -651,8 +754,8 @@ CLEAN_FILES += $(speedtest1.js) $(speedtest1.wasm)
|
||||
.PHONY: o0 o1 o2 o3 os oz
|
||||
o-xtra := -flto
|
||||
# ^^^^ -flto can have a considerably performance boost at -O0 but
|
||||
# doubles the build time and seems to have negligible effect on
|
||||
# higher optimization levels.
|
||||
# doubles the build time and seems to have negligible, if any, effect
|
||||
# on higher optimization levels.
|
||||
o0: clean
|
||||
$(MAKE) -e "emcc_opt=-O0"
|
||||
o1: clean
|
||||
@@ -670,16 +773,21 @@ oz: clean
|
||||
########################################################################
|
||||
# Sub-makes...
|
||||
|
||||
# sqlite.org/fiddle application...
|
||||
include fiddle.make
|
||||
|
||||
# Only add wasmfs if wasmfs.enable=1 or we're running (dist)clean
|
||||
ifneq (,$(filter wasmfs,$(MAKECMDGOALS)))
|
||||
wasmfs.enable ?= 1
|
||||
else
|
||||
wasmfs.enable ?= $(if $(filter %clean,$(MAKECMDGOALS)),1,0)
|
||||
endif
|
||||
ifeq (1,$(wasmfs.enable))
|
||||
# wasmfs build disabled 2022-10-19 per /chat discussion.
|
||||
# OPFS-over-wasmfs was initially a stopgap measure and a convenient
|
||||
# point of comparison for the OPFS sqlite3_vfs's performance, but it
|
||||
# currently doubles our deliverables and build maintenance burden for
|
||||
# little, if any, benefit.
|
||||
# little benefit.
|
||||
#
|
||||
########################################################################
|
||||
# Some platforms do not support the WASMFS build. Raspberry Pi OS is one
|
||||
@@ -699,15 +807,16 @@ endif
|
||||
########################################################################
|
||||
|
||||
########################################################################
|
||||
# Create deliverables:
|
||||
ifneq (,$(filter dist,$(MAKECMDGOALS)))
|
||||
# Create main client downloadable zip file:
|
||||
ifneq (,$(filter dist snapshot,$(MAKECMDGOALS)))
|
||||
include dist.make
|
||||
endif
|
||||
|
||||
########################################################################
|
||||
# Push files to public wasm-testing.sqlite.org server
|
||||
wasm-testing.include = $(dir.dout) *.js *.html \
|
||||
batch-runner.list $(dir.sql) $(dir.common) $(dir.fiddle) $(dir.jacc)
|
||||
wasm-testing.include = *.js *.html batch-runner.list \
|
||||
./tests \
|
||||
$(dir.dout) $(dir.sql) $(dir.common) $(dir.fiddle) $(dir.jacc)
|
||||
wasm-testing.exclude = sql/speedtest1.sql
|
||||
wasm-testing.dir = /jail/sites/wasm-testing
|
||||
wasm-testing.dest ?= wasm-testing:$(wasm-testing.dir)
|
||||
|
||||
@@ -7,6 +7,7 @@ _sqlite3_bind_null
|
||||
_sqlite3_bind_parameter_count
|
||||
_sqlite3_bind_parameter_index
|
||||
_sqlite3_bind_text
|
||||
_sqlite3_busy_timeout
|
||||
_sqlite3_changes
|
||||
_sqlite3_changes64
|
||||
_sqlite3_clear_bindings
|
||||
|
||||
@@ -8,24 +8,25 @@
|
||||
most of the associated JS code, runs outside of the
|
||||
Emscripten-generated module init scope, in the current
|
||||
global scope. */
|
||||
//#if sqlite3-es6-module-build
|
||||
//#if target=es6-module
|
||||
const toExportForES6 =
|
||||
//#endif
|
||||
(function(){
|
||||
/**
|
||||
In order to hide the sqlite3InitModule()'s resulting Emscripten
|
||||
module from downstream clients (and simplify our documentation by
|
||||
being able to elide those details), we rewrite
|
||||
sqlite3InitModule() to return the sqlite3 object.
|
||||
In order to hide the sqlite3InitModule()'s resulting
|
||||
Emscripten module from downstream clients (and simplify our
|
||||
documentation by being able to elide those details), we hide that
|
||||
function and expose a hand-written sqlite3InitModule() to return
|
||||
the sqlite3 object (most of the time).
|
||||
|
||||
Unfortunately, we cannot modify the module-loader/exporter-based
|
||||
impls which Emscripten installs at some point in the file above
|
||||
this.
|
||||
*/
|
||||
const originalInit =
|
||||
/*Maintenance reminde: DO NOT use `self.` here. It's correct
|
||||
for non-ES6 Module cases but wrong for ES6 modules because those
|
||||
resolve this symbol differently! */ sqlite3InitModule;
|
||||
/* Maintenance reminder: DO NOT use `self.` here. It's correct
|
||||
for non-ES6 Module cases but wrong for ES6 modules because those
|
||||
resolve this symbol differently. */ sqlite3InitModule;
|
||||
if(!originalInit){
|
||||
throw new Error("Expecting self.sqlite3InitModule to be defined by the Emscripten build.");
|
||||
}
|
||||
@@ -58,6 +59,9 @@ const toExportForES6 =
|
||||
li.pop();
|
||||
initModuleState.sqlite3Dir = li.join('/') + '/';
|
||||
}
|
||||
if(initModuleState.sqlite3Dir){
|
||||
initModuleState.sqlite3Dir = initModuleState.sqlite3Dir.replace(/[/]{2,}/g,'/');
|
||||
}
|
||||
|
||||
self.sqlite3InitModule = (...args)=>{
|
||||
//console.warn("Using replaced sqlite3InitModule()",self.location);
|
||||
@@ -104,16 +108,15 @@ const toExportForES6 =
|
||||
}
|
||||
/* Replace the various module exports performed by the Emscripten
|
||||
glue... */
|
||||
if (typeof exports === 'object' && typeof module === 'object')
|
||||
if (typeof exports === 'object' && typeof module === 'object'){
|
||||
module.exports = sqlite3InitModule;
|
||||
else if (typeof exports === 'object')
|
||||
}else if (typeof exports === 'object'){
|
||||
exports["sqlite3InitModule"] = sqlite3InitModule;
|
||||
}
|
||||
/* AMD modules get injected in a way we cannot override,
|
||||
so we can't handle those here. */
|
||||
//#if sqlite3-es6-module-build
|
||||
return self.sqlite3InitModule;
|
||||
//#endif
|
||||
return self.sqlite3InitModule /* required for ESM */;
|
||||
})();
|
||||
//#if sqlite3-es6-module-build
|
||||
//#if target=es6-module
|
||||
export default toExportForES6;
|
||||
//#endif
|
||||
|
||||
@@ -29,7 +29,7 @@ sqlite3InitModuleState.debugModule('self.location =',self.location);
|
||||
4) If none of the above apply, (prefix+path) is returned.
|
||||
*/
|
||||
Module['locateFile'] = function(path, prefix) {
|
||||
//#if sqlite3-es6-module-build
|
||||
//#if target=es6-module
|
||||
return new URL(path, import.meta.url).href;
|
||||
//#else
|
||||
'use strict';
|
||||
|
||||
@@ -92,7 +92,8 @@ const installOpfsVfs = function callee(options){
|
||||
}
|
||||
const urlParams = new URL(self.location.href).searchParams;
|
||||
if(undefined===options.verbose){
|
||||
options.verbose = urlParams.has('opfs-verbose') ? 3 : 2;
|
||||
options.verbose = urlParams.has('opfs-verbose')
|
||||
? (+urlParams.get('opfs-verbose') || 2) : 1;
|
||||
}
|
||||
if(undefined===options.sanityChecks){
|
||||
options.sanityChecks = urlParams.has('opfs-sanity-check');
|
||||
@@ -101,6 +102,8 @@ const installOpfsVfs = function callee(options){
|
||||
options.proxyUri = callee.defaultProxyUri;
|
||||
}
|
||||
|
||||
//console.warn("OPFS options =",options,self.location);
|
||||
|
||||
if('function' === typeof options.proxyUri){
|
||||
options.proxyUri = options.proxyUri();
|
||||
}
|
||||
@@ -167,7 +170,7 @@ const installOpfsVfs = function callee(options){
|
||||
return promiseReject_(err);
|
||||
};
|
||||
const W =
|
||||
//#if sqlite3-es6-module-build
|
||||
//#if target=es6-module
|
||||
new Worker(new URL(options.proxyUri, import.meta.url));
|
||||
//#else
|
||||
new Worker(options.proxyUri);
|
||||
@@ -340,6 +343,7 @@ const installOpfsVfs = function callee(options){
|
||||
'SQLITE_LOCK_PENDING',
|
||||
'SQLITE_LOCK_RESERVED',
|
||||
'SQLITE_LOCK_SHARED',
|
||||
'SQLITE_LOCKED',
|
||||
'SQLITE_MISUSE',
|
||||
'SQLITE_NOTFOUND',
|
||||
'SQLITE_OPEN_CREATE',
|
||||
@@ -1154,7 +1158,10 @@ const installOpfsVfs = function callee(options){
|
||||
[
|
||||
/* Truncate journal mode is faster than delete or wal for
|
||||
this vfs, per speedtest1. */
|
||||
"pragma journal_mode=truncate;"
|
||||
"pragma journal_mode=truncate;",
|
||||
/* Set a default busy-timeout handler to help OPFS dbs
|
||||
deal with multi-tab/multi-worker contention. */
|
||||
"pragma busy_timeout=2000;",
|
||||
/*
|
||||
This vfs benefits hugely from cache on moderate/large
|
||||
speedtest1 --size 50 and --size 100 workloads. We currently
|
||||
@@ -1162,7 +1169,7 @@ const installOpfsVfs = function callee(options){
|
||||
sqlite3.wasm. If that policy changes, the cache can
|
||||
be set here.
|
||||
*/
|
||||
//"pragma cache_size=-8388608;"
|
||||
//"pragma cache_size=-16384;"
|
||||
].join("")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -897,6 +897,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
the lines of sqlite3_prepare_v3(). The slightly problematic
|
||||
part is the final argument (text destructor). */
|
||||
],
|
||||
["sqlite3_busy_timeout","int", "sqlite3*", "int"],
|
||||
["sqlite3_close_v2", "int", "sqlite3*"],
|
||||
["sqlite3_changes", "int", "sqlite3*"],
|
||||
["sqlite3_clear_bindings","int", "sqlite3_stmt*"],
|
||||
|
||||
@@ -53,7 +53,7 @@ const state = Object.create(null);
|
||||
2 = warnings and errors
|
||||
3 = debug, warnings, and errors
|
||||
*/
|
||||
state.verbose = 2;
|
||||
state.verbose = 1;
|
||||
|
||||
const loggers = {
|
||||
0:console.error.bind(console),
|
||||
@@ -150,70 +150,6 @@ const getDirForFilename = async function f(absFilename, createDirs = false){
|
||||
return [dh, filename];
|
||||
};
|
||||
|
||||
/**
|
||||
An error class specifically for use with getSyncHandle(), the goal
|
||||
of which is to eventually be able to distinguish unambiguously
|
||||
between locking-related failures and other types, noting that we
|
||||
cannot currently do so because createSyncAccessHandle() does not
|
||||
define its exceptions in the required level of detail.
|
||||
*/
|
||||
class GetSyncHandleError extends Error {
|
||||
constructor(errorObject, ...msg){
|
||||
super();
|
||||
this.error = errorObject;
|
||||
this.message = [
|
||||
...msg, ': Original exception ['+errorObject.name+']:',
|
||||
errorObject.message
|
||||
].join(' ');
|
||||
this.name = 'GetSyncHandleError';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Returns the sync access handle associated with the given file
|
||||
handle object (which must be a valid handle object, as created by
|
||||
xOpen()), lazily opening it if needed.
|
||||
|
||||
In order to help alleviate cross-tab contention for a dabase,
|
||||
if an exception is thrown while acquiring the handle, this routine
|
||||
will wait briefly and try again, up to 3 times. If acquisition
|
||||
still fails at that point it will give up and propagate the
|
||||
exception.
|
||||
*/
|
||||
const getSyncHandle = async (fh)=>{
|
||||
if(!fh.syncHandle){
|
||||
const t = performance.now();
|
||||
log("Acquiring sync handle for",fh.filenameAbs);
|
||||
const maxTries = 4, msBase = 300;
|
||||
let i = 1, ms = msBase;
|
||||
for(; true; ms = msBase * ++i){
|
||||
try {
|
||||
//if(i<3) toss("Just testing getSyncHandle() wait-and-retry.");
|
||||
//TODO? A config option which tells it to throw here
|
||||
//randomly every now and then, for testing purposes.
|
||||
fh.syncHandle = await fh.fileHandle.createSyncAccessHandle();
|
||||
break;
|
||||
}catch(e){
|
||||
if(i === maxTries){
|
||||
throw new GetSyncHandleError(
|
||||
e, "Error getting sync handle.",maxTries,
|
||||
"attempts failed.",fh.filenameAbs
|
||||
);
|
||||
}
|
||||
warn("Error getting sync handle. Waiting",ms,
|
||||
"ms and trying again.",fh.filenameAbs,e);
|
||||
Atomics.wait(state.sabOPView, state.opIds.retry, 0, ms);
|
||||
}
|
||||
}
|
||||
log("Got sync handle for",fh.filenameAbs,'in',performance.now() - t,'ms');
|
||||
if(!fh.xLock){
|
||||
__autoLocks.add(fh.fid);
|
||||
log("Auto-locked",fh.fid,fh.filenameAbs);
|
||||
}
|
||||
}
|
||||
return fh.syncHandle;
|
||||
};
|
||||
|
||||
/**
|
||||
If the given file-holding object has a sync handle attached to it,
|
||||
that handle is remove and asynchronously closed. Though it may
|
||||
@@ -253,6 +189,98 @@ const closeSyncHandleNoThrow = async (fh)=>{
|
||||
}
|
||||
};
|
||||
|
||||
/* Release all auto-locks. */
|
||||
const closeAutoLocks = async ()=>{
|
||||
if(__autoLocks.size){
|
||||
/* Release all auto-locks. */
|
||||
for(const fid of __autoLocks){
|
||||
const fh = __openFiles[fid];
|
||||
await closeSyncHandleNoThrow(fh);
|
||||
log("Auto-unlocked",fid,fh.filenameAbs);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
An error class specifically for use with getSyncHandle(), the goal
|
||||
of which is to eventually be able to distinguish unambiguously
|
||||
between locking-related failures and other types, noting that we
|
||||
cannot currently do so because createSyncAccessHandle() does not
|
||||
define its exceptions in the required level of detail.
|
||||
*/
|
||||
class GetSyncHandleError extends Error {
|
||||
constructor(errorObject, ...msg){
|
||||
super();
|
||||
this.error = errorObject;
|
||||
this.message = [
|
||||
...msg, ': Original exception ['+errorObject.name+']:',
|
||||
errorObject.message
|
||||
].join(' ');
|
||||
this.name = 'GetSyncHandleError';
|
||||
}
|
||||
};
|
||||
GetSyncHandleError.convertRc = (e,rc)=>{
|
||||
if(0){
|
||||
/* This approach makes the very wild assumption that such a
|
||||
failure _is_ a locking error. In practice that appears to be
|
||||
the most common error, by far, but we cannot unambiguously
|
||||
distinguish that from other errors.
|
||||
|
||||
This approach is highly questionable.
|
||||
*/
|
||||
return (e instanceof GetSyncHandleError)
|
||||
? state.sq3Codes.SQLITE_IOERR_LOCK
|
||||
: rc;
|
||||
}else{
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
/**
|
||||
Returns the sync access handle associated with the given file
|
||||
handle object (which must be a valid handle object, as created by
|
||||
xOpen()), lazily opening it if needed.
|
||||
|
||||
In order to help alleviate cross-tab contention for a dabase,
|
||||
if an exception is thrown while acquiring the handle, this routine
|
||||
will wait briefly and try again, up to 3 times. If acquisition
|
||||
still fails at that point it will give up and propagate the
|
||||
exception.
|
||||
*/
|
||||
const getSyncHandle = async (fh)=>{
|
||||
if(!fh.syncHandle){
|
||||
const t = performance.now();
|
||||
log("Acquiring sync handle for",fh.filenameAbs);
|
||||
const maxTries = 6, msBase = 300;
|
||||
let i = 1, ms = msBase;
|
||||
for(; true; ms = msBase * ++i){
|
||||
try {
|
||||
//if(i<3) toss("Just testing getSyncHandle() wait-and-retry.");
|
||||
//TODO? A config option which tells it to throw here
|
||||
//randomly every now and then, for testing purposes.
|
||||
fh.syncHandle = await fh.fileHandle.createSyncAccessHandle();
|
||||
break;
|
||||
}catch(e){
|
||||
if(i === maxTries){
|
||||
throw new GetSyncHandleError(
|
||||
e, "Error getting sync handle.",maxTries,
|
||||
"attempts failed.",fh.filenameAbs
|
||||
);
|
||||
}
|
||||
warn("Error getting sync handle. Waiting",ms,
|
||||
"ms and trying again.",fh.filenameAbs,e);
|
||||
await closeAutoLocks();
|
||||
Atomics.wait(state.sabOPView, state.opIds.retry, 0, ms);
|
||||
}
|
||||
}
|
||||
log("Got sync handle for",fh.filenameAbs,'in',performance.now() - t,'ms');
|
||||
if(!fh.xLock){
|
||||
__autoLocks.add(fh.fid);
|
||||
log("Auto-locked",fh.fid,fh.filenameAbs);
|
||||
}
|
||||
}
|
||||
return fh.syncHandle;
|
||||
};
|
||||
|
||||
/**
|
||||
Stores the given value at state.sabOPView[state.opIds.rc] and then
|
||||
Atomics.notify()'s it.
|
||||
@@ -446,12 +474,12 @@ const vfsAsyncImpls = {
|
||||
wTimeStart('xFileSize');
|
||||
try{
|
||||
affirmLocked('xFileSize',fh);
|
||||
rc = await (await getSyncHandle(fh)).getSize();
|
||||
state.s11n.serialize(Number(rc));
|
||||
const sz = await (await getSyncHandle(fh)).getSize();
|
||||
state.s11n.serialize(Number(sz));
|
||||
rc = 0;
|
||||
}catch(e){
|
||||
state.s11n.storeException(2,e);
|
||||
rc = state.sq3Codes.SQLITE_IOERR;
|
||||
rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR);
|
||||
}
|
||||
wTimeEnd();
|
||||
storeAndNotify('xFileSize', rc);
|
||||
@@ -471,7 +499,7 @@ const vfsAsyncImpls = {
|
||||
__autoLocks.delete(fid);
|
||||
}catch(e){
|
||||
state.s11n.storeException(1,e);
|
||||
rc = state.sq3Codes.SQLITE_IOERR_LOCK;
|
||||
rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR_LOCK);
|
||||
fh.xLock = oldLockType;
|
||||
}
|
||||
wTimeEnd();
|
||||
@@ -545,7 +573,7 @@ const vfsAsyncImpls = {
|
||||
if(undefined===nRead) wTimeEnd();
|
||||
error("xRead() failed",e,fh);
|
||||
state.s11n.storeException(1,e);
|
||||
rc = state.sq3Codes.SQLITE_IOERR_READ;
|
||||
rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR_READ);
|
||||
}
|
||||
storeAndNotify('xRead',rc);
|
||||
mTimeEnd();
|
||||
@@ -579,7 +607,7 @@ const vfsAsyncImpls = {
|
||||
}catch(e){
|
||||
error("xTruncate():",e,fh);
|
||||
state.s11n.storeException(2,e);
|
||||
rc = state.sq3Codes.SQLITE_IOERR_TRUNCATE;
|
||||
rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR_TRUNCATE);
|
||||
}
|
||||
wTimeEnd();
|
||||
storeAndNotify('xTruncate',rc);
|
||||
@@ -619,7 +647,7 @@ const vfsAsyncImpls = {
|
||||
}catch(e){
|
||||
error("xWrite():",e,fh);
|
||||
state.s11n.storeException(1,e);
|
||||
rc = state.sq3Codes.SQLITE_IOERR_WRITE;
|
||||
rc = GetSyncHandleError.convertRc(e,state.sq3Codes.SQLITE_IOERR_WRITE);
|
||||
}
|
||||
wTimeEnd();
|
||||
storeAndNotify('xWrite',rc);
|
||||
@@ -746,22 +774,16 @@ const waitLoop = async function f(){
|
||||
/**
|
||||
waitTime is how long (ms) to wait for each Atomics.wait().
|
||||
We need to wake up periodically to give the thread a chance
|
||||
to do other things.
|
||||
to do other things. If this is too high (e.g. 500ms) then
|
||||
even two workers/tabs can easily run into locking errors.
|
||||
*/
|
||||
const waitTime = 500;
|
||||
const waitTime = 150;
|
||||
while(!flagAsyncShutdown){
|
||||
try {
|
||||
if('timed-out'===Atomics.wait(
|
||||
state.sabOPView, state.opIds.whichOp, 0, waitTime
|
||||
)){
|
||||
if(__autoLocks.size){
|
||||
/* Release all auto-locks. */
|
||||
for(const fid of __autoLocks){
|
||||
const fh = __openFiles[fid];
|
||||
await closeSyncHandleNoThrow(fh);
|
||||
log("Auto-unlocked",fid,fh.filenameAbs);
|
||||
}
|
||||
}
|
||||
await closeAutoLocks();
|
||||
continue;
|
||||
}
|
||||
const opId = Atomics.load(state.sabOPView, state.opIds.whichOp);
|
||||
@@ -791,7 +813,7 @@ navigator.storage.getDirectory().then(function(d){
|
||||
const opt = data.args;
|
||||
state.littleEndian = opt.littleEndian;
|
||||
state.asyncS11nExceptions = opt.asyncS11nExceptions;
|
||||
state.verbose = opt.verbose ?? 2;
|
||||
state.verbose = opt.verbose ?? 1;
|
||||
state.fileBufferSize = opt.fileBufferSize;
|
||||
state.sabS11nOffset = opt.sabS11nOffset;
|
||||
state.sabS11nSize = opt.sabS11nSize;
|
||||
|
||||
@@ -6,35 +6,38 @@
|
||||
# 'make dist' rules for creating a distribution archive of the WASM/JS
|
||||
# pieces, noting that we only build a dist of the built files, not the
|
||||
# numerous pieces required to build them.
|
||||
#
|
||||
# Use 'make snapshot' to create "snapshot" releases. They use a
|
||||
# distinctly different zip file and top directory name to distinguish
|
||||
# them from release builds.
|
||||
#######################################################################
|
||||
MAKEFILE.dist := $(lastword $(MAKEFILE_LIST))
|
||||
|
||||
########################################################################
|
||||
# Chicken/egg situation: we need $(bin.version-info) to get the version
|
||||
# info for the archive name, but that binary may not yet be built, and
|
||||
# won't be built until we expand the dependencies. We have to use a
|
||||
# temporary name for the archive.
|
||||
dist-name = sqlite-wasm-TEMP
|
||||
#ifeq (0,1)
|
||||
# $(info WARNING *******************************************************************)
|
||||
# $(info ** Be sure to create the desired build configuration before creating the)
|
||||
# $(info ** distribution archive. Use one of the following targets to do so:)
|
||||
# $(info **)
|
||||
# $(info ** o2: builds with -O2, resulting in the fastest builds)
|
||||
# $(info ** oz: builds with -Oz, resulting in the smallest builds)
|
||||
# $(info /WARNING *******************************************************************)
|
||||
#endif
|
||||
# Chicken/egg situation: we need $(bin.version-info) to get the
|
||||
# version info for the archive name, but that binary may not yet be
|
||||
# built, and won't be built until we expand the dependencies. Thus we
|
||||
# have to use a temporary name for the archive until we can get
|
||||
# that binary built.
|
||||
ifeq (,$(filter snapshot,$(MAKECMDGOALS)))
|
||||
dist-name-prefix := sqlite-wasm
|
||||
else
|
||||
dist-name-prefix := sqlite-wasm-snapshot-$(shell /usr/bin/date +%Y%m%d)
|
||||
endif
|
||||
dist-name := $(dist-name-prefix)-TEMP
|
||||
|
||||
########################################################################
|
||||
# dist.build must be the name of a target which triggers the
|
||||
# build of the files to be packed into the dist archive. The
|
||||
# intention is that it be one of (o0, o1, o2, o3, os, oz), each of
|
||||
# which uses like-named -Ox optimization level flags. The o2 target
|
||||
# provides the best overall runtime speeds. The oz target provides
|
||||
# slightly slower speeds (roughly 10%) with significantly smaller WASM
|
||||
# file sizes. Note that -O2 (the o2 target) results in faster binaries
|
||||
# than both -O3 and -Os (the o3 and os targets) in all tests run to
|
||||
# date.
|
||||
# dist.build must be the name of a target which triggers the build of
|
||||
# the files to be packed into the dist archive. The intention is that
|
||||
# it be one of (o0, o1, o2, o3, os, oz), each of which uses like-named
|
||||
# -Ox optimization level flags. The o2 target provides the best
|
||||
# overall runtime speeds. The oz target provides slightly slower
|
||||
# speeds (roughly 10%) with significantly smaller WASM file
|
||||
# sizes. Note that -O2 (the o2 target) results in faster binaries than
|
||||
# both -O3 and -Os (the o3 and os targets) in all tests run to
|
||||
# date. Our general policy is that we want the smallest binaries for
|
||||
# dist zip files, so use the oz build unless there is a compelling
|
||||
# reason not to.
|
||||
dist.build ?= oz
|
||||
|
||||
dist-dir.top := $(dist-name)
|
||||
@@ -42,7 +45,8 @@ dist-dir.jswasm := $(dist-dir.top)/$(notdir $(dir.dout))
|
||||
dist-dir.common := $(dist-dir.top)/common
|
||||
dist.top.extras := \
|
||||
demo-123.html demo-123-worker.html demo-123.js \
|
||||
tester1.html tester1-worker.html tester1-esm.html tester1.js \
|
||||
tester1.html tester1-worker.html tester1-esm.html \
|
||||
tester1.js tester1.mjs \
|
||||
demo-jsstorage.html demo-jsstorage.js \
|
||||
demo-worker1.html demo-worker1.js \
|
||||
demo-worker1-promiser.html demo-worker1-promiser.js
|
||||
@@ -51,7 +55,7 @@ dist.common.extras := \
|
||||
$(wildcard $(dir.common)/*.css) \
|
||||
$(dir.common)/SqliteTestUtil.js
|
||||
|
||||
.PHONY: dist
|
||||
.PHONY: dist snapshot
|
||||
########################################################################
|
||||
# dist: create the end-user deliverable archive.
|
||||
#
|
||||
@@ -83,7 +87,7 @@ dist: \
|
||||
@cp -p $(dist.common.extras) $(dist-dir.common)
|
||||
@set -e; \
|
||||
vnum=$$($(bin.version-info) --download-version); \
|
||||
vdir=sqlite-wasm-$$vnum; \
|
||||
vdir=$(dist-name-prefix)-$$vnum; \
|
||||
arczip=$$vdir.zip; \
|
||||
echo "Making $$arczip ..."; \
|
||||
rm -fr $$arczip $$vdir; \
|
||||
@@ -93,7 +97,7 @@ dist: \
|
||||
ls -la $$arczip; \
|
||||
set +e; \
|
||||
unzip -lv $$arczip || echo "Missing unzip app? Not fatal."
|
||||
|
||||
snapshot: dist
|
||||
# We need a separate `clean` rule to account for weirdness in
|
||||
# a sub-make, where we get a copy of the $(dist-name) dir
|
||||
# copied into the new $(dist-name) dir.
|
||||
|
||||
@@ -56,9 +56,15 @@
|
||||
utility code.</li>
|
||||
<li><a href='tester1-worker.html'>tester1-worker</a>: same thing
|
||||
but running in a Worker.</li>
|
||||
<li><a href='tester1-esm.html'>tester1-esm</a>: same thing
|
||||
but loaded in the main thread via an ES6 module. Note that
|
||||
not all browsers permit loading modules in Worker threads.
|
||||
<li><a href='tester1-esm.html'>tester1-esm</a>: same as
|
||||
<code>tester1</code> but loads sqlite3 in the main thread via
|
||||
an ES6 module.
|
||||
</li>
|
||||
<li><a href='tester1-worker.html?esm'>tester1-worker?esm</a>:
|
||||
same as <code>tester1-esm</code> but loads a Worker Module which
|
||||
then loads the sqlite3 API via an ES6 module. Note that
|
||||
not all browsers permit loading modules in Worker
|
||||
threads.
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
@@ -32,10 +32,6 @@
|
||||
and testing is currently done against a dev-channel release
|
||||
of Chrome (v107 as of 2022-09-26).
|
||||
</li>
|
||||
<li>Whether or not WASMFS/OPFS support is enabled on any given
|
||||
page may depend on build-time options which are <em>off by
|
||||
default</em>.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>The tests and demos...
|
||||
@@ -47,9 +43,16 @@
|
||||
utility code.</li>
|
||||
<li><a href='tester1-worker.html'>tester1-worker</a>: same thing
|
||||
but running in a Worker.</li>
|
||||
<li><a href='tester1-esm.html'>tester1-esm</a>: same thing
|
||||
but loaded in the main thread via an ES6 module. Note that
|
||||
not all browsers permit loading modules in Worker threads.
|
||||
<li><a href='tester1-esm.html'>tester1-esm</a>: same as
|
||||
<code>tester1</code> but loads sqlite3 in the main thread via
|
||||
an ES6 module.
|
||||
</li>
|
||||
<li><a href='tester1-worker.html?esm'>tester1-worker?esm</a>:
|
||||
same as <code>tester1-esm</code> but loads a Worker Module which
|
||||
then loads the sqlite3 API via an ES6 module. Note that
|
||||
not all browsers permit loading modules in Worker
|
||||
threads.
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>High-level apps and demos...
|
||||
@@ -101,6 +104,9 @@
|
||||
synchronous sqlite3_vfs interface and the async OPFS
|
||||
impl.
|
||||
</li>
|
||||
<li><a href='tests/opfs/concurrency/index.html'>OPFS concurrency</a>
|
||||
tests using multiple workers.
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<!--li><a href='x.html'></a></li-->
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
|
||||
<link rel="stylesheet" href="common/emscripten.css"/>
|
||||
<link rel="stylesheet" href="common/testing.css"/>
|
||||
<title>sqlite3 tester ESM #1 (UI thread)</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id='color-target'>sqlite3 WASM/JS tester ESM #1 (UI thread)</h1>
|
||||
<div class='input-wrapper'>
|
||||
<input type='checkbox' id='cb-log-reverse'>
|
||||
<label for='cb-log-reverse'>Reverse log order?</label>
|
||||
</div>
|
||||
<div id='test-output'></div>
|
||||
<script type="module" defer>
|
||||
import {default as sqlite3InitModule} from "./jswasm/sqlite3.mjs";
|
||||
self.sqlite3InitModule = sqlite3InitModule;
|
||||
console.log("Loaded sqlite3InitModule() via an ES6 module.");
|
||||
</script>
|
||||
<script src="tester1.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -6,7 +6,7 @@
|
||||
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
|
||||
<link rel="stylesheet" href="../common/emscripten.css"/>
|
||||
<link rel="stylesheet" href="../common/testing.css"/>
|
||||
<title>sqlite3 tester #1 (Worker thread)</title>
|
||||
<title>sqlite3 tester #1: Worker thread</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: monospace;
|
||||
@@ -14,7 +14,7 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id='color-target'>sqlite3 WASM/JS tester #1 (Worker thread)</h1>
|
||||
<h1 id='color-target'>sqlite3 tester #1: Worker thread</h1>
|
||||
<div>See <a href='tester1.html' target='tester1.html'>tester1.html</a>
|
||||
for the UI-thread variant.</div>
|
||||
<div class='input-wrapper'>
|
||||
@@ -40,7 +40,20 @@
|
||||
};
|
||||
cbReverse.addEventListener('change',cbReverseIt,true);
|
||||
cbReverseIt();
|
||||
const w = new Worker("tester1.js?sqlite3.dir=jswasm");
|
||||
const urlParams = new URL(self.location.href).searchParams;
|
||||
const workerArgs = [];
|
||||
if(urlParams.has('esm')){
|
||||
logHtml('warning',"Attempting to run an ES6 Worker Module, "+
|
||||
"which is not supported by all browsers! "+
|
||||
"e.g. Firefox (as of 2022-11) cannot do this.");
|
||||
workerArgs.push("tester1.mjs",{type:"module"});
|
||||
document.querySelectorAll('title,#color-target').forEach((e)=>{
|
||||
e.innerText = "sqlite3 tester #1: ES6 Worker Module";
|
||||
});
|
||||
}else{
|
||||
workerArgs.push("tester1.js?sqlite3.dir=jswasm");
|
||||
}
|
||||
const w = new Worker(...workerArgs);
|
||||
w.onmessage = function({data}){
|
||||
switch(data.type){
|
||||
case 'log':
|
||||
|
||||
@@ -6,7 +6,13 @@
|
||||
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
|
||||
<link rel="stylesheet" href="common/emscripten.css"/>
|
||||
<link rel="stylesheet" href="common/testing.css"/>
|
||||
<title>sqlite3 tester #1 (UI thread)</title>
|
||||
<title>sqlite3 tester #1:
|
||||
//#if target=es6-module
|
||||
ES6 Module in UI thread
|
||||
//#else
|
||||
UI thread
|
||||
//#endif
|
||||
</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: monospace;
|
||||
@@ -14,7 +20,7 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id='color-target'>sqlite3 WASM/JS tester #1 (UI thread)</h1>
|
||||
<h1 id='color-target'></h1>
|
||||
<div>See <a href='tester1-worker.html' target='tester1-worker.html'>tester1-worker.html</a>
|
||||
for the Worker-thread variant.</div>
|
||||
<div class='input-wrapper'>
|
||||
@@ -22,7 +28,15 @@
|
||||
<label for='cb-log-reverse'>Reverse log order?</label>
|
||||
</div>
|
||||
<div id='test-output'></div>
|
||||
<script>(function(){
|
||||
document.querySelector('h1').innerHTML =
|
||||
document.querySelector('title').innerHTML;
|
||||
})();</script>
|
||||
//#if target=es6-module
|
||||
<script src="tester1.mjs" type="module"></script>
|
||||
//#else
|
||||
<script src="jswasm/sqlite3.js"></script>
|
||||
<script src="tester1.js"></script>
|
||||
//#endif
|
||||
</body>
|
||||
</html>
|
||||
@@ -29,8 +29,25 @@
|
||||
a db in an early test and close it in a later test. Each test gets
|
||||
passed the sqlite3 namespace object as its only argument.
|
||||
*/
|
||||
/*
|
||||
This file is intended to be processed by c-pp to inject (or not)
|
||||
code specific to ES6 modules which is illegal in non-module code.
|
||||
|
||||
Non-ES6 module build and ES6 module for the main-thread:
|
||||
|
||||
./c-pp -f tester1.c-pp.js -o tester1.js
|
||||
|
||||
ES6 worker module build:
|
||||
|
||||
./c-pp -f tester1.c-pp.js -o tester1-esm.js -Dtarget=es6-module
|
||||
*/
|
||||
//#if target=es6-module
|
||||
import {default as sqlite3InitModule} from './jswasm/sqlite3.mjs';
|
||||
self.sqlite3InitModule = sqlite3InitModule;
|
||||
//#else
|
||||
'use strict';
|
||||
(function(){
|
||||
//#endif
|
||||
(function(self){
|
||||
/**
|
||||
Set up our output channel differently depending
|
||||
on whether we are running in a worker thread or
|
||||
@@ -1817,7 +1834,8 @@
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
log("Loading and initializing sqlite3 WASM module...");
|
||||
if(!isUIThread()){
|
||||
if(!self.sqlite3InitModule && !isUIThread()){
|
||||
/* Vanilla worker, as opposed to an ES6 module worker */
|
||||
/*
|
||||
If sqlite3.js is in a directory other than this script, in order
|
||||
to get sqlite3.js to resolve sqlite3.wasm properly, we have to
|
||||
@@ -1861,4 +1879,5 @@
|
||||
}
|
||||
TestUtil.runTests(sqlite3);
|
||||
});
|
||||
})();
|
||||
})(self);
|
||||
|
||||
48
ext/wasm/tests/opfs/concurrency/index.html
Normal file
48
ext/wasm/tests/opfs/concurrency/index.html
Normal file
@@ -0,0 +1,48 @@
|
||||
<!doctype html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
|
||||
<link rel="stylesheet" href="../../../common/testing.css"/>
|
||||
<title>sqlite3 OPFS Worker concurrency tester</title>
|
||||
<style>
|
||||
body { display: revert; }
|
||||
body > * {}
|
||||
#test-output {
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1></h1>
|
||||
<p>
|
||||
OPFS concurrency tester using multiple independent Workers.
|
||||
Disclaimer: concurrency in OPFS is currently a pain point
|
||||
and timing/concurrency mitigation in this environment is
|
||||
highly unpredictable!
|
||||
</p>
|
||||
<p>
|
||||
URL flags: pass a number of workers using
|
||||
the <code>workers=N</code> URL flag and the worker work interval
|
||||
as <code>interval=N</code> (milliseconds). Enable OPFS VFS
|
||||
verbosity with <code>verbose=1-3</code> (output goes to the
|
||||
dev console).
|
||||
</p>
|
||||
<p>Achtung: if it does not start to do anything within a couple of
|
||||
seconds, check the dev console: Chrome often fails with "cannot allocate
|
||||
WasmMemory" at startup. Closing and re-opening the tab usually resolves
|
||||
it.
|
||||
</p>
|
||||
<div class='input-wrapper'>
|
||||
<input type='checkbox' id='cb-log-reverse'>
|
||||
<label for='cb-log-reverse'>Reverse log order?</label>
|
||||
</div>
|
||||
<div id='test-output'></div>
|
||||
<script>(function(){
|
||||
document.querySelector('h1').innerHTML =
|
||||
document.querySelector('title').innerHTML;
|
||||
})();</script>
|
||||
<script src="test.js?sqlite3.dir=../../../jswasm"></script>
|
||||
</body>
|
||||
</html>
|
||||
111
ext/wasm/tests/opfs/concurrency/test.js
Normal file
111
ext/wasm/tests/opfs/concurrency/test.js
Normal file
@@ -0,0 +1,111 @@
|
||||
(async function(self){
|
||||
|
||||
const logCss = (function(){
|
||||
const mapToString = (v)=>{
|
||||
switch(typeof v){
|
||||
case 'number': case 'string': case 'boolean':
|
||||
case 'undefined': case 'bigint':
|
||||
return ''+v;
|
||||
default: break;
|
||||
}
|
||||
if(null===v) return 'null';
|
||||
if(v instanceof Error){
|
||||
v = {
|
||||
message: v.message,
|
||||
stack: v.stack,
|
||||
errorClass: v.name
|
||||
};
|
||||
}
|
||||
return JSON.stringify(v,undefined,2);
|
||||
};
|
||||
const normalizeArgs = (args)=>args.map(mapToString);
|
||||
const logTarget = document.querySelector('#test-output');
|
||||
const logCss = function(cssClass,...args){
|
||||
const ln = document.createElement('div');
|
||||
if(cssClass){
|
||||
for(const c of (Array.isArray(cssClass) ? cssClass : [cssClass])){
|
||||
ln.classList.add(c);
|
||||
}
|
||||
}
|
||||
ln.append(document.createTextNode(normalizeArgs(args).join(' ')));
|
||||
logTarget.append(ln);
|
||||
};
|
||||
const cbReverse = document.querySelector('#cb-log-reverse');
|
||||
const cbReverseKey = 'tester1:cb-log-reverse';
|
||||
const cbReverseIt = ()=>{
|
||||
logTarget.classList[cbReverse.checked ? 'add' : 'remove']('reverse');
|
||||
localStorage.setItem(cbReverseKey, cbReverse.checked ? 1 : 0);
|
||||
};
|
||||
cbReverse.addEventListener('change', cbReverseIt, true);
|
||||
if(localStorage.getItem(cbReverseKey)){
|
||||
cbReverse.checked = !!(+localStorage.getItem(cbReverseKey));
|
||||
}
|
||||
cbReverseIt();
|
||||
return logCss;
|
||||
})();
|
||||
const stdout = (...args)=>logCss('',...args);
|
||||
const stderr = (...args)=>logCss('error',...args);
|
||||
|
||||
const wait = async (ms)=>{
|
||||
return new Promise((resolve)=>setTimeout(resolve,ms));
|
||||
};
|
||||
|
||||
const urlArgsJs = new URL(document.currentScript.src).searchParams;
|
||||
const urlArgsHtml = new URL(self.location.href).searchParams;
|
||||
const options = Object.create(null);
|
||||
options.sqlite3Dir = urlArgsJs.get('sqlite3.dir');
|
||||
options.workerCount = (
|
||||
urlArgsHtml.has('workers') ? +urlArgsHtml.get('workers') : 3
|
||||
) || 3;
|
||||
options.opfsVerbose = (
|
||||
urlArgsHtml.has('verbose') ? +urlArgsHtml.get('verbose') : 1
|
||||
) || 1;
|
||||
options.interval = (
|
||||
urlArgsHtml.has('interval') ? +urlArgsHtml.get('interval') : 750
|
||||
) || 750;
|
||||
const workers = [];
|
||||
workers.post = (type,...args)=>{
|
||||
for(const w of workers) w.postMessage({type, payload:args});
|
||||
};
|
||||
workers.loadedCount = 0;
|
||||
workers.onmessage = function(msg){
|
||||
msg = msg.data;
|
||||
const prefix = 'Worker #'+msg.worker+':';
|
||||
switch(msg.type){
|
||||
case 'loaded':
|
||||
stdout(prefix,"loaded");
|
||||
if(++workers.loadedCount === workers.length){
|
||||
stdout("All workers loaded. Telling them to run...");
|
||||
workers.post('run');
|
||||
}
|
||||
break;
|
||||
case 'stdout': stdout(prefix,...msg.payload); break;
|
||||
case 'stderr': stderr(prefix,...msg.payload); break;
|
||||
case 'error': stderr(prefix,"ERROR:",...msg.payload); break;
|
||||
case 'finished':
|
||||
logCss('tests-pass',prefix,...msg.payload);
|
||||
break;
|
||||
case 'failed':
|
||||
logCss('tests-fail',prefix,"FAILED:",...msg.payload);
|
||||
break;
|
||||
default: logCss('error',"Unhandled message type:",msg); break;
|
||||
}
|
||||
};
|
||||
|
||||
stdout("Launching",options.workerCount,"workers...");
|
||||
workers.uri = (
|
||||
'worker.js?'
|
||||
+ 'sqlite3.dir='+options.sqlite3Dir
|
||||
+ '&interval='+options.interval
|
||||
+ '&opfs-verbose='+options.opfsVerbose
|
||||
);
|
||||
for(let i = 0; i < options.workerCount; ++i){
|
||||
stdout("Launching worker...");
|
||||
workers.push(new Worker(
|
||||
workers.uri+'&workerId='+(i+1)+(i ? '' : '&unlink-db')
|
||||
));
|
||||
}
|
||||
// Have to delay onmessage assignment until after the loop
|
||||
// to avoid that early workers get an undue head start.
|
||||
workers.forEach((w)=>w.onmessage = workers.onmessage);
|
||||
})(self);
|
||||
105
ext/wasm/tests/opfs/concurrency/worker.js
Normal file
105
ext/wasm/tests/opfs/concurrency/worker.js
Normal file
@@ -0,0 +1,105 @@
|
||||
importScripts(
|
||||
(new URL(self.location.href).searchParams).get('sqlite3.dir') + '/sqlite3.js'
|
||||
);
|
||||
self.sqlite3InitModule().then(async function(sqlite3){
|
||||
const urlArgs = new URL(self.location.href).searchParams;
|
||||
const wName = urlArgs.get('workerId') || Math.round(Math.random()*10000);
|
||||
const wPost = (type,...payload)=>{
|
||||
postMessage({type, worker: wName, payload});
|
||||
};
|
||||
const stdout = (...args)=>wPost('stdout',...args);
|
||||
const stderr = (...args)=>wPost('stderr',...args);
|
||||
if(!sqlite3.opfs){
|
||||
stderr("OPFS support not detected. Aborting.");
|
||||
return;
|
||||
}
|
||||
|
||||
const wait = async (ms)=>{
|
||||
return new Promise((resolve)=>setTimeout(resolve,ms));
|
||||
};
|
||||
|
||||
const dbName = 'concurrency-tester.db';
|
||||
if(urlArgs.has('unlink-db')){
|
||||
await sqlite3.opfs.unlink(dbName);
|
||||
stdout("Unlinked",dbName);
|
||||
}
|
||||
wPost('loaded');
|
||||
let db;
|
||||
const interval = Object.assign(Object.create(null),{
|
||||
delay: urlArgs.has('interval') ? (+urlArgs.get('interval') || 750) : 750,
|
||||
handle: undefined,
|
||||
count: 0
|
||||
});
|
||||
const finish = ()=>{
|
||||
if(db){
|
||||
if(!db.pointer) return;
|
||||
db.close();
|
||||
}
|
||||
if(interval.error){
|
||||
wPost('failed',"Ending work after interval #"+interval.count,
|
||||
"due to error:",interval.error);
|
||||
}else{
|
||||
wPost('finished',"Ending work after",interval.count,"intervals.");
|
||||
}
|
||||
};
|
||||
const run = async function(){
|
||||
db = new sqlite3.opfs.OpfsDb(dbName,'c');
|
||||
sqlite3.capi.sqlite3_busy_timeout(db.pointer, 5000);
|
||||
db.transaction((db)=>{
|
||||
db.exec([
|
||||
"create table if not exists t1(w TEXT UNIQUE ON CONFLICT REPLACE,v);",
|
||||
"create table if not exists t2(w TEXT UNIQUE ON CONFLICT REPLACE,v);"
|
||||
]);
|
||||
});
|
||||
|
||||
const maxIterations = 10;
|
||||
stdout("Starting interval-based db updates with delay of",interval.delay,"ms.");
|
||||
const doWork = async ()=>{
|
||||
const tm = new Date().getTime();
|
||||
++interval.count;
|
||||
const prefix = "v(#"+interval.count+")";
|
||||
stdout("Setting",prefix,"=",tm);
|
||||
try{
|
||||
db.exec({
|
||||
sql:"INSERT OR REPLACE INTO t1(w,v) VALUES(?,?)",
|
||||
bind: [wName, new Date().getTime()]
|
||||
});
|
||||
//stdout("Set",prefix);
|
||||
}catch(e){
|
||||
interval.error = e;
|
||||
}
|
||||
};
|
||||
if(1){/*use setInterval()*/
|
||||
interval.handle = setInterval(async ()=>{
|
||||
await doWork();
|
||||
if(interval.error || maxIterations === interval.count){
|
||||
clearInterval(interval.handle);
|
||||
finish();
|
||||
}
|
||||
}, interval.delay);
|
||||
}else{
|
||||
/*This approach provides no concurrency whatsoever: each worker
|
||||
is run to completion before any others can work.*/
|
||||
let i;
|
||||
for(i = 0; i < maxIterations; ++i){
|
||||
await doWork();
|
||||
if(interval.error) break;
|
||||
await wait(interval.ms);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}/*run()*/;
|
||||
|
||||
self.onmessage = function({data}){
|
||||
switch(data.type){
|
||||
case 'run': run().catch((e)=>{
|
||||
if(!interval.error) interval.error = e;
|
||||
finish();
|
||||
});
|
||||
break;
|
||||
default:
|
||||
stderr("Unhandled message type '"+data.type+"'.");
|
||||
break;
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -101,7 +101,7 @@ $(speedtest1-wasmfs.js): $(speedtest1.cses) $(sqlite3-wasmfs.js) \
|
||||
$(EXPORTED_FUNCTIONS.speedtest1)
|
||||
@echo "Building $@ ..."
|
||||
$(emcc.bin) \
|
||||
$(speedtest1-wasmfs.eflags) $(speedtest1-common.eflags) \
|
||||
$(speedtest1-wasmfs.eflags) $(speedtest1.eflags.common) \
|
||||
$(pre-post-speedtest1-wasmfs.flags) \
|
||||
$(speedtest1.cflags) \
|
||||
$(sqlite3-wasmfs.cflags) \
|
||||
|
||||
48
manifest
48
manifest
@@ -1,5 +1,5 @@
|
||||
C Remove\scheck\sfor\sWASM_WASI\smacro\swhen\sdetecting\swasi\scompilation\smode,\sas\sthat\smacro\sis\sproject-specific.\sRely\sonly\son\s__wasi__\s(exposed\sby\sclang)\sto\sdetect\swasi\scompilation\smode.
|
||||
D 2022-11-20T15:30:42.968
|
||||
C Merge\strunk\sinto\swasi-patches\sbranch\sto\sclean\sup\sthe\sdiff\sview.
|
||||
D 2022-11-21T16:03:19.238
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@@ -488,25 +488,25 @@ F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
|
||||
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
|
||||
F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
|
||||
F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
|
||||
F ext/wasm/GNUmakefile 1e38a4f7147d621bd2138d13938ef34157bcf47908325baa6b06cd02c5e3ef89
|
||||
F ext/wasm/GNUmakefile bc1696a1189f4c571b3d878b8f3a67c1f4b52c222f52d356027a5a0c707337c7
|
||||
F ext/wasm/README-dist.txt 2d670b426fc7c613b90a7d2f2b05b433088fe65181abead970980f0a4a75ea20
|
||||
F ext/wasm/README.md ef39861aa21632fdbca0bdd469f78f0096f6449a720f3f39642594af503030e9
|
||||
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 9120c2f8f51fa85f46dcf4dcb6b12f4a807d428f6089b99cdb08d8ddfcfd88b2
|
||||
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api b4d68c97d14944b48d55e06aa44f544a6f56a7fa2bcb6f9e030936a5b2a9479a
|
||||
F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
|
||||
F ext/wasm/api/README.md 29276a845e57004e82efba61fa5866fd05f9137380a1dc26dc4c6d65264cd81c
|
||||
F ext/wasm/api/extern-post-js.js 015121df2c903cf12d51507227b756ab3626036d8e9d610a2a2c15b3f54afe4d
|
||||
F ext/wasm/api/extern-post-js.js 31400dd1c0ae3458a0e6510229e59318e45eac402a75dd703c2950b9b5758b46
|
||||
F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e7a4d11d43c5c8f41
|
||||
F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08902f15c34720ee4a1
|
||||
F ext/wasm/api/post-js-header.js d6ab3dfef4a06960d28a7eaa338d4e2a1a5981e9b38718168bbde8fdb2a439b8
|
||||
F ext/wasm/api/pre-js.js 1156a7fb9de817bb1cb39ad90b76aa93fbb9dcf950a1f2d6f547e5976872be36
|
||||
F ext/wasm/api/pre-js.js b88499dc303c21fc3f55f2c364a0f814f587b60a95784303881169f9e91c1d5f
|
||||
F ext/wasm/api/sqlite3-api-cleanup.js ecdc69dbfccfe26146f04799fcfd4a6f5790d46e7e3b9b6e9b0491f92ed8ae34
|
||||
F ext/wasm/api/sqlite3-api-glue.js 056f44b82c126358a0175e08a892d56fadfce177b0d7a0012502a6acf67ea6d5
|
||||
F ext/wasm/api/sqlite3-api-oo1.js e9a83489bbb4838ce0aee46eaaa9350e0e25a5b926b565e4f5ae8e840e4fbaed
|
||||
F ext/wasm/api/sqlite3-api-opfs.js 9f115a37dafe8067bce8812996d2deff45741c6e39f7aad7b48f5fbbd822dba5
|
||||
F ext/wasm/api/sqlite3-api-prologue.js fd526fa017fa2578673ca18158354515c719e719a5d93f2f6d0e43f39170430e
|
||||
F ext/wasm/api/sqlite3-api-opfs.js 38d368e33f470f9ba196f1a2b0c9ce076c930c70df233c345a246f1ad4c26d3b
|
||||
F ext/wasm/api/sqlite3-api-prologue.js 08e96d26d329e8c1e08813fe0b84ee93e0e78b087efdd6eb2809ae2672902437
|
||||
F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f
|
||||
F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3
|
||||
F ext/wasm/api/sqlite3-opfs-async-proxy.js 24d1c1982a012d998907105a4ff1ff6881bf462395e90c06326817701e69f093
|
||||
F ext/wasm/api/sqlite3-opfs-async-proxy.js 1ec10873f1d59d305f6f3b435c50a1b75d693d5fb739b226f3da46fcbb11261a
|
||||
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
|
||||
F ext/wasm/api/sqlite3-wasm.c 8fc8f47680df0e9a6c0f2f03cb004148645ecc983aa216daba09cb21f7e092a2
|
||||
F ext/wasm/api/sqlite3-worker1-promiser.js 0c7a9826dbf82a5ed4e4f7bf7816e825a52aff253afbf3350431f5773faf0e4b
|
||||
@@ -527,14 +527,14 @@ F ext/wasm/demo-worker1-promiser.html 1de7c248c7c2cfd4a5783d2aa154bce62d74c6de98
|
||||
F ext/wasm/demo-worker1-promiser.js b85a2bb1b918db4f09dfa24419241cb3edad7791389425c2505092e9b715017d
|
||||
F ext/wasm/demo-worker1.html 2c178c1890a2beb5a5fecb1453e796d067a4b8d3d2a04d65ca2eb1ab2c68ef5d
|
||||
F ext/wasm/demo-worker1.js a619adffc98b75b66c633b00f747b856449a134a9a0357909287d80a182d70fa
|
||||
F ext/wasm/dist.make 4b55c8a7926bbab4936adab6a08eca524085fc47bc3b08f41918df5b4665da3d
|
||||
F ext/wasm/dist.make 11b98da79385701a568a4728671821fe2524c1d1ecd05ff2e24cb3e33b2c6c4f
|
||||
F ext/wasm/fiddle.make 2812c44c9bafb5be9c8767963d1b9f374d77af7795fcaa06483c03e7059dea74
|
||||
F ext/wasm/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f
|
||||
F ext/wasm/fiddle/fiddle-worker.js b4a0c8ab6c0983218543ca771c45f6075449f63a1dcf290ae5a681b2cba8800d
|
||||
F ext/wasm/fiddle/fiddle.js 974b995119ac443685d7d94d3b3c58c6a36540e9eb3fed7069d5653284071715
|
||||
F ext/wasm/fiddle/index.html 5daf54e8f3d7777cbb1ca4f93affe28858dbfff25841cb4ab81d694efed28ec2
|
||||
F ext/wasm/index-dist.html 6bfb3591e40f7c23626730df587f533e983e996d4d1fb67244fb6a88fe6cf9a6
|
||||
F ext/wasm/index.html 49f58dddc29f6394b6e8a93e42768de59380c258454b68b9182e1946d13a4a4b
|
||||
F ext/wasm/index-dist.html c4337617c4d6d4d0796827cec28ac81d128c6f911dcf888a290a32ad50890408
|
||||
F ext/wasm/index.html 5be176de5be8ae96889798f803fef4f6a2ef31cee305a0430ca4629f6ae04c27
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.js 95f573de1826474c9605dda620ee622fcb1673ae74f191eb324c0853aa4dcb66
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.md 9aa6951b529a8b29f578ec8f0355713c39584c92cf1708f63ba0cf917cb5b68e
|
||||
F ext/wasm/module-symbols.html b8eebafef8e536624bbe5f7a3da40c07a9062b843dfd3161a0bb72cbb6763dc5
|
||||
@@ -549,12 +549,14 @@ F ext/wasm/sql/000-mandelbrot.sql 775337a4b80938ac8146aedf88808282f04d02d983d826
|
||||
F ext/wasm/sql/001-sudoku.sql 35b7cb7239ba5d5f193bc05ec379bcf66891bce6f2a5b3879f2f78d0917299b5
|
||||
F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555e685bce3da8c3f
|
||||
F ext/wasm/test-opfs-vfs.js 44363db07b2a20e73b0eb1808de4400ca71b703af718d0fa6d962f15e73bf2ac
|
||||
F ext/wasm/tester1-esm.html 8d226a21b20707dbd66d68a3990141f0392fc781a281291d3dc59f38a3555887
|
||||
F ext/wasm/tester1-worker.html 51bf39e2b87f974ae3d5bc3086e2fb36d258f3698c54f6e21ba4b3b99636fa27
|
||||
F ext/wasm/tester1.html 624ec41cd9f78a1f2b6d7df70aaa7a6394396b1f2455ecbd6de5775c1275b121
|
||||
F ext/wasm/tester1.js bff806de454de115922d78c056f11d523ec7ed9ed3839d4e21433a9f72558b88
|
||||
F ext/wasm/tester1-worker.html 5ef353348c37cf2e4fd0b23da562d3275523e036260b510734e9a3239ba8c987
|
||||
F ext/wasm/tester1.c-pp.html 74aa9b31c75f12490653f814b53c3dd39f40cd3f70d6a53a716f4e8587107399 w ext/wasm/tester1.html
|
||||
F ext/wasm/tester1.c-pp.js 0c129495d057c77788b59715152d51f9bf9002ebbcce759ef8b028272ce3519d w ext/wasm/tester1.js
|
||||
F ext/wasm/tests/opfs/concurrency/index.html bb9b0f6da86df34c67fa506db9c45b7c4cf0045a211611cc6b8d2b53fa983481
|
||||
F ext/wasm/tests/opfs/concurrency/test.js 5993c08657d547d3a26b78ff3480122aed2b7361823bc127e96e558931093aff
|
||||
F ext/wasm/tests/opfs/concurrency/worker.js df065bb386ff994951f7fbdd76e12f16e58fbef0e929b2caf74553359da40afc
|
||||
F ext/wasm/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd72273503ae7d5
|
||||
F ext/wasm/wasmfs.make 8aa7565f9de8dd3c291ad8c3ceb1a2c67a3eb31a8e531070b25c6c6b1f0278bf
|
||||
F ext/wasm/wasmfs.make 8fea9b4f3cde06141de1fc4c586ab405bd32c3f401554f4ebb18c797401a678d
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0
|
||||
@@ -578,9 +580,9 @@ F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf
|
||||
F src/backup.c a2891172438e385fdbe97c11c9745676bec54f518d4447090af97189fd8e52d7
|
||||
F src/bitvec.c 7c849aac407230278445cb069bebc5f89bf2ddd87c5ed9459b070a9175707b3d
|
||||
F src/btmutex.c 6ffb0a22c19e2f9110be0964d0731d2ef1c67b5f7fabfbaeb7b9dabc4b7740ca
|
||||
F src/btree.c e8fae9a95ea9561aebc41e467a9ee9ba9150ca373031e65773d62ff02d8250d2
|
||||
F src/btree.c 522df0f1173495e06c5589f0b17a61f53a212017b82be53171133fcfc0e1e90a
|
||||
F src/btree.h 4fcbb0b041013071dd5e9f53c538d49916c092e6ad8842185985e5270a0792de
|
||||
F src/btreeInt.h 8ce1332edd89dfd2461d561ac10a0ab5601c8e06200cb5230596c3caaf54482e
|
||||
F src/btreeInt.h 88ad499c92b489afedbfefc3f067c4d15023ec021afe622db240dc9d2277cfa5
|
||||
F src/build.c d3e43e950e4e377c1d451a4862556792acdef1faba14a03f899d30d09731c48b
|
||||
F src/callback.c 4cd7225b26a97f7de5fee5ae10464bed5a78f2adefe19534cc2095b3a8ca484a
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
@@ -711,7 +713,7 @@ F src/upsert.c 5303dc6c518fa7d4b280ec65170f465c7a70b7ac2b22491598f6d0b4875b3145
|
||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||
F src/util.c 0be191521ff6d2805995f4910f0b6231b42843678b2efdc1abecaf39929a673f
|
||||
F src/vacuum.c 84ce7f01f8a7a08748e107a441db83bcec13970190ddcb0c9ff522adbc1c23fd
|
||||
F src/vdbe.c 0c7cb1b934ad8611e14e7efaf2c3a95df7dd3f7964d63ea07fef42a23df86131
|
||||
F src/vdbe.c c2d6d0c0c343d8ebffef996c73cbb69e337225f757fea7fe5c0e3ea14662adec
|
||||
F src/vdbe.h 58675f47dcf3105bab182c3ad3726efd60ffd003e954386904ac9107d0d2b743
|
||||
F src/vdbeInt.h 17b7461ffcf9ee760d1341731715a419f6b8c763089a7ece25c2e8098d702b3f
|
||||
F src/vdbeapi.c 1e8713d0b653acb43cd1bdf579c40e005c4844ea90f414f065946a83db3c27fb
|
||||
@@ -2057,8 +2059,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 9b8b15a779158ec7c39d936f6bfa6a35e12063a36933341ade051809993a5678
|
||||
R eab0332091536d080c020fa14b102cbe
|
||||
P d469ac0c448eced26a697751ce9be316e8bc3cd029fda2b50966523c7850854f 5f564bf7de7ce3ad7bedb5f06b3086ceaec55da768a60d74059fa4fba4328567
|
||||
R c6e7dc02521e7ecf758d690fc58cd968
|
||||
U stephan
|
||||
Z 0c7f0b6e6cee222ce3be0bf4f50c95f1
|
||||
Z ef5aed11fc17ce6d5e08251a18764500
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
@@ -1 +1 @@
|
||||
d469ac0c448eced26a697751ce9be316e8bc3cd029fda2b50966523c7850854f
|
||||
95de6742d3d96d2b21eec57195dc7a2236d3f61640633ae1baa36bf142a3485b
|
||||
185
src/btree.c
185
src/btree.c
@@ -1900,62 +1900,67 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
||||
** Only the following combinations are supported. Anything different
|
||||
** indicates a corrupt database files:
|
||||
**
|
||||
** PTF_ZERODATA
|
||||
** PTF_ZERODATA | PTF_LEAF
|
||||
** PTF_LEAFDATA | PTF_INTKEY
|
||||
** PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF
|
||||
** PTF_ZERODATA (0x02, 2)
|
||||
** PTF_LEAFDATA | PTF_INTKEY (0x05, 5)
|
||||
** PTF_ZERODATA | PTF_LEAF (0x0a, 10)
|
||||
** PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF (0x0d, 13)
|
||||
*/
|
||||
static int decodeFlags(MemPage *pPage, int flagByte){
|
||||
BtShared *pBt; /* A copy of pPage->pBt */
|
||||
|
||||
assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) );
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
pPage->leaf = (u8)(flagByte>>3); assert( PTF_LEAF == 1<<3 );
|
||||
flagByte &= ~PTF_LEAF;
|
||||
pPage->childPtrSize = 4-4*pPage->leaf;
|
||||
pBt = pPage->pBt;
|
||||
if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
|
||||
/* EVIDENCE-OF: R-07291-35328 A value of 5 (0x05) means the page is an
|
||||
** interior table b-tree page. */
|
||||
assert( (PTF_LEAFDATA|PTF_INTKEY)==5 );
|
||||
/* EVIDENCE-OF: R-26900-09176 A value of 13 (0x0d) means the page is a
|
||||
** leaf table b-tree page. */
|
||||
assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
|
||||
pPage->intKey = 1;
|
||||
if( pPage->leaf ){
|
||||
pPage->max1bytePayload = pBt->max1bytePayload;
|
||||
if( flagByte>=(PTF_ZERODATA | PTF_LEAF) ){
|
||||
pPage->childPtrSize = 0;
|
||||
pPage->leaf = 1;
|
||||
if( flagByte==(PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF) ){
|
||||
pPage->intKeyLeaf = 1;
|
||||
pPage->xCellSize = cellSizePtrTableLeaf;
|
||||
pPage->xParseCell = btreeParseCellPtr;
|
||||
pPage->intKey = 1;
|
||||
pPage->maxLocal = pBt->maxLeaf;
|
||||
pPage->minLocal = pBt->minLeaf;
|
||||
}else if( flagByte==(PTF_ZERODATA | PTF_LEAF) ){
|
||||
pPage->intKey = 0;
|
||||
pPage->intKeyLeaf = 0;
|
||||
pPage->xCellSize = cellSizePtr;
|
||||
pPage->xParseCell = btreeParseCellPtrIndex;
|
||||
pPage->maxLocal = pBt->maxLocal;
|
||||
pPage->minLocal = pBt->minLocal;
|
||||
}else{
|
||||
pPage->intKey = 0;
|
||||
pPage->intKeyLeaf = 0;
|
||||
pPage->xCellSize = cellSizePtr;
|
||||
pPage->xParseCell = btreeParseCellPtrIndex;
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
}else{
|
||||
pPage->childPtrSize = 4;
|
||||
pPage->leaf = 0;
|
||||
if( flagByte==(PTF_ZERODATA) ){
|
||||
pPage->intKey = 0;
|
||||
pPage->intKeyLeaf = 0;
|
||||
pPage->xCellSize = cellSizePtr;
|
||||
pPage->xParseCell = btreeParseCellPtrIndex;
|
||||
pPage->maxLocal = pBt->maxLocal;
|
||||
pPage->minLocal = pBt->minLocal;
|
||||
}else if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
|
||||
pPage->intKeyLeaf = 0;
|
||||
pPage->xCellSize = cellSizePtrNoPayload;
|
||||
pPage->xParseCell = btreeParseCellPtrNoPayload;
|
||||
pPage->intKey = 1;
|
||||
pPage->maxLocal = pBt->maxLeaf;
|
||||
pPage->minLocal = pBt->minLeaf;
|
||||
}else{
|
||||
pPage->intKey = 0;
|
||||
pPage->intKeyLeaf = 0;
|
||||
pPage->xCellSize = cellSizePtr;
|
||||
pPage->xParseCell = btreeParseCellPtrIndex;
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
pPage->maxLocal = pBt->maxLeaf;
|
||||
pPage->minLocal = pBt->minLeaf;
|
||||
}else if( flagByte==PTF_ZERODATA ){
|
||||
/* EVIDENCE-OF: R-43316-37308 A value of 2 (0x02) means the page is an
|
||||
** interior index b-tree page. */
|
||||
assert( (PTF_ZERODATA)==2 );
|
||||
/* EVIDENCE-OF: R-59615-42828 A value of 10 (0x0a) means the page is a
|
||||
** leaf index b-tree page. */
|
||||
assert( (PTF_ZERODATA|PTF_LEAF)==10 );
|
||||
pPage->intKey = 0;
|
||||
pPage->intKeyLeaf = 0;
|
||||
pPage->xCellSize = cellSizePtr;
|
||||
pPage->xParseCell = btreeParseCellPtrIndex;
|
||||
pPage->maxLocal = pBt->maxLocal;
|
||||
pPage->minLocal = pBt->minLocal;
|
||||
}else{
|
||||
/* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
|
||||
** an error. */
|
||||
pPage->intKey = 0;
|
||||
pPage->intKeyLeaf = 0;
|
||||
pPage->xCellSize = cellSizePtr;
|
||||
pPage->xParseCell = btreeParseCellPtrIndex;
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
pPage->max1bytePayload = pBt->max1bytePayload;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -6601,7 +6606,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
|
||||
/* If the database supports auto-vacuum, write an entry in the pointer-map
|
||||
** to indicate that the page is free.
|
||||
*/
|
||||
if( ISAUTOVACUUM ){
|
||||
if( ISAUTOVACUUM(pBt) ){
|
||||
ptrmapPut(pBt, iPage, PTRMAP_FREEPAGE, 0, &rc);
|
||||
if( rc ) goto freepage_out;
|
||||
}
|
||||
@@ -7041,24 +7046,20 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
|
||||
** in pTemp or the original pCell) and also record its index.
|
||||
** Allocating a new entry in pPage->aCell[] implies that
|
||||
** pPage->nOverflow is incremented.
|
||||
**
|
||||
** *pRC must be SQLITE_OK when this routine is called.
|
||||
*/
|
||||
static void insertCell(
|
||||
static int insertCell(
|
||||
MemPage *pPage, /* Page into which we are copying */
|
||||
int i, /* New cell becomes the i-th cell of the page */
|
||||
u8 *pCell, /* Content of the new cell */
|
||||
int sz, /* Bytes of content in pCell */
|
||||
u8 *pTemp, /* Temp storage space for pCell, if needed */
|
||||
Pgno iChild, /* If non-zero, replace first 4 bytes with this value */
|
||||
int *pRC /* Read and write return code from here */
|
||||
Pgno iChild /* If non-zero, replace first 4 bytes with this value */
|
||||
){
|
||||
int idx = 0; /* Where to write new cell content in data[] */
|
||||
int j; /* Loop counter */
|
||||
u8 *data; /* The content of the whole page */
|
||||
u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */
|
||||
|
||||
assert( *pRC==SQLITE_OK );
|
||||
assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
|
||||
assert( MX_CELL(pPage->pBt)<=10921 );
|
||||
assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB );
|
||||
@@ -7093,14 +7094,13 @@ static void insertCell(
|
||||
}else{
|
||||
int rc = sqlite3PagerWrite(pPage->pDbPage);
|
||||
if( rc!=SQLITE_OK ){
|
||||
*pRC = rc;
|
||||
return;
|
||||
return rc;
|
||||
}
|
||||
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
|
||||
data = pPage->aData;
|
||||
assert( &data[pPage->cellOffset]==pPage->aCellIdx );
|
||||
rc = allocateSpace(pPage, sz, &idx);
|
||||
if( rc ){ *pRC = rc; return; }
|
||||
if( rc ){ return rc; }
|
||||
/* The allocateSpace() routine guarantees the following properties
|
||||
** if it returns successfully */
|
||||
assert( idx >= 0 );
|
||||
@@ -7127,13 +7127,16 @@ static void insertCell(
|
||||
assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell || CORRUPT_DB );
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
if( pPage->pBt->autoVacuum ){
|
||||
int rc = SQLITE_OK;
|
||||
/* The cell may contain a pointer to an overflow page. If so, write
|
||||
** the entry for the overflow page into the pointer map.
|
||||
*/
|
||||
ptrmapPutOvflPtr(pPage, pPage, pCell, pRC);
|
||||
ptrmapPutOvflPtr(pPage, pPage, pCell, &rc);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -7234,14 +7237,16 @@ struct CellArray {
|
||||
** computed.
|
||||
*/
|
||||
static void populateCellCache(CellArray *p, int idx, int N){
|
||||
MemPage *pRef = p->pRef;
|
||||
u16 *szCell = p->szCell;
|
||||
assert( idx>=0 && idx+N<=p->nCell );
|
||||
while( N>0 ){
|
||||
assert( p->apCell[idx]!=0 );
|
||||
if( p->szCell[idx]==0 ){
|
||||
p->szCell[idx] = p->pRef->xCellSize(p->pRef, p->apCell[idx]);
|
||||
if( szCell[idx]==0 ){
|
||||
szCell[idx] = pRef->xCellSize(pRef, p->apCell[idx]);
|
||||
}else{
|
||||
assert( CORRUPT_DB ||
|
||||
p->szCell[idx]==p->pRef->xCellSize(p->pRef, p->apCell[idx]) );
|
||||
szCell[idx]==pRef->xCellSize(pRef, p->apCell[idx]) );
|
||||
}
|
||||
idx++;
|
||||
N--;
|
||||
@@ -7443,8 +7448,8 @@ static int pageFreeArray(
|
||||
int nRet = 0;
|
||||
int i;
|
||||
int iEnd = iFirst + nCell;
|
||||
u8 *pFree = 0;
|
||||
int szFree = 0;
|
||||
u8 *pFree = 0; /* \__ Parameters for pending call to */
|
||||
int szFree = 0; /* / freeSpace() */
|
||||
|
||||
for(i=iFirst; i<iEnd; i++){
|
||||
u8 *pCell = pCArray->apCell[i];
|
||||
@@ -7465,6 +7470,9 @@ static int pageFreeArray(
|
||||
return 0;
|
||||
}
|
||||
}else{
|
||||
/* The current cell is adjacent to and before the pFree cell.
|
||||
** Combine the two regions into one to reduce the number of calls
|
||||
** to freeSpace(). */
|
||||
pFree = pCell;
|
||||
szFree += sz;
|
||||
}
|
||||
@@ -7672,7 +7680,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
|
||||
** be marked as dirty. Returning an error code will cause a
|
||||
** rollback, undoing any changes made to the parent page.
|
||||
*/
|
||||
if( ISAUTOVACUUM ){
|
||||
if( ISAUTOVACUUM(pBt) ){
|
||||
ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno, &rc);
|
||||
if( szCell>pNew->minLocal ){
|
||||
ptrmapPutOvflPtr(pNew, pNew, pCell, &rc);
|
||||
@@ -7700,8 +7708,8 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
|
||||
|
||||
/* Insert the new divider cell into pParent. */
|
||||
if( rc==SQLITE_OK ){
|
||||
insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
|
||||
0, pPage->pgno, &rc);
|
||||
rc = insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
|
||||
0, pPage->pgno);
|
||||
}
|
||||
|
||||
/* Set the right-child pointer of pParent to point to the new page. */
|
||||
@@ -7810,7 +7818,7 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
|
||||
/* If this is an auto-vacuum database, update the pointer-map entries
|
||||
** for any b-tree or overflow pages that pTo now contains the pointers to.
|
||||
*/
|
||||
if( ISAUTOVACUUM ){
|
||||
if( ISAUTOVACUUM(pBt) ){
|
||||
*pRC = setChildPtrmaps(pTo);
|
||||
}
|
||||
}
|
||||
@@ -8234,15 +8242,17 @@ static int balance_nonroot(
|
||||
d = r + 1 - leafData;
|
||||
(void)cachedCellSize(&b, d);
|
||||
do{
|
||||
int szR, szD;
|
||||
assert( d<nMaxCells );
|
||||
assert( r<nMaxCells );
|
||||
(void)cachedCellSize(&b, r);
|
||||
szR = cachedCellSize(&b, r);
|
||||
szD = b.szCell[d];
|
||||
if( szRight!=0
|
||||
&& (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+(i==k-1?0:2)))){
|
||||
&& (bBulk || szRight+szD+2 > szLeft-(szR+(i==k-1?0:2)))){
|
||||
break;
|
||||
}
|
||||
szRight += b.szCell[d] + 2;
|
||||
szLeft -= b.szCell[r] + 2;
|
||||
szRight += szD + 2;
|
||||
szLeft -= szR + 2;
|
||||
cntNew[i-1] = r;
|
||||
r--;
|
||||
d--;
|
||||
@@ -8296,7 +8306,7 @@ static int balance_nonroot(
|
||||
cntOld[i] = b.nCell;
|
||||
|
||||
/* Set the pointer-map entry for the new sibling page. */
|
||||
if( ISAUTOVACUUM ){
|
||||
if( ISAUTOVACUUM(pBt) ){
|
||||
ptrmapPut(pBt, pNew->pgno, PTRMAP_BTREE, pParent->pgno, &rc);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto balance_cleanup;
|
||||
@@ -8389,7 +8399,7 @@ static int balance_nonroot(
|
||||
** updated. This happens below, after the sibling pages have been
|
||||
** populated, not here.
|
||||
*/
|
||||
if( ISAUTOVACUUM ){
|
||||
if( ISAUTOVACUUM(pBt) ){
|
||||
MemPage *pOld;
|
||||
MemPage *pNew = pOld = apNew[0];
|
||||
int cntOldNext = pNew->nCell + pNew->nOverflow;
|
||||
@@ -8486,7 +8496,7 @@ static int balance_nonroot(
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto balance_cleanup;
|
||||
}
|
||||
insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno, &rc);
|
||||
rc = insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno);
|
||||
if( rc!=SQLITE_OK ) goto balance_cleanup;
|
||||
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
|
||||
}
|
||||
@@ -8582,7 +8592,7 @@ static int balance_nonroot(
|
||||
);
|
||||
copyNodeContent(apNew[0], pParent, &rc);
|
||||
freePage(apNew[0], &rc);
|
||||
}else if( ISAUTOVACUUM && !leafCorrection ){
|
||||
}else if( ISAUTOVACUUM(pBt) && !leafCorrection ){
|
||||
/* Fix the pointer map entries associated with the right-child of each
|
||||
** sibling page. All other pointer map entries have already been taken
|
||||
** care of. */
|
||||
@@ -8603,7 +8613,7 @@ static int balance_nonroot(
|
||||
}
|
||||
|
||||
#if 0
|
||||
if( ISAUTOVACUUM && rc==SQLITE_OK && apNew[0]->isInit ){
|
||||
if( ISAUTOVACUUM(pBt) && rc==SQLITE_OK && apNew[0]->isInit ){
|
||||
/* The ptrmapCheckPages() contains assert() statements that verify that
|
||||
** all pointer map pages are set correctly. This is helpful while
|
||||
** debugging. This is usually disabled because a corrupt database may
|
||||
@@ -8665,7 +8675,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = allocateBtreePage(pBt,&pChild,&pgnoChild,pRoot->pgno,0);
|
||||
copyNodeContent(pRoot, pChild, &rc);
|
||||
if( ISAUTOVACUUM ){
|
||||
if( ISAUTOVACUUM(pBt) ){
|
||||
ptrmapPut(pBt, pgnoChild, PTRMAP_BTREE, pRoot->pgno, &rc);
|
||||
}
|
||||
}
|
||||
@@ -8997,7 +9007,6 @@ int sqlite3BtreeInsert(
|
||||
int idx;
|
||||
MemPage *pPage;
|
||||
Btree *p = pCur->pBtree;
|
||||
BtShared *pBt = p->pBt;
|
||||
unsigned char *oldCell;
|
||||
unsigned char *newCell = 0;
|
||||
|
||||
@@ -9016,7 +9025,7 @@ int sqlite3BtreeInsert(
|
||||
** not to clear the cursor here.
|
||||
*/
|
||||
if( pCur->curFlags & BTCF_Multiple ){
|
||||
rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur);
|
||||
rc = saveAllCursors(p->pBt, pCur->pgnoRoot, pCur);
|
||||
if( rc ) return rc;
|
||||
if( loc && pCur->iPage<0 ){
|
||||
/* This can only happen if the schema is corrupt such that there is more
|
||||
@@ -9040,8 +9049,8 @@ int sqlite3BtreeInsert(
|
||||
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
assert( (pCur->curFlags & BTCF_WriteFlag)!=0
|
||||
&& pBt->inTransaction==TRANS_WRITE
|
||||
&& (pBt->btsFlags & BTS_READ_ONLY)==0 );
|
||||
&& p->pBt->inTransaction==TRANS_WRITE
|
||||
&& (p->pBt->btsFlags & BTS_READ_ONLY)==0 );
|
||||
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
|
||||
|
||||
/* Assert that the caller has been consistent. If this cursor was opened
|
||||
@@ -9158,26 +9167,28 @@ int sqlite3BtreeInsert(
|
||||
pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno,
|
||||
loc==0 ? "overwrite" : "new entry"));
|
||||
assert( pPage->isInit || CORRUPT_DB );
|
||||
newCell = pBt->pTmpSpace;
|
||||
newCell = p->pBt->pTmpSpace;
|
||||
assert( newCell!=0 );
|
||||
assert( BTREE_PREFORMAT==OPFLAG_PREFORMAT );
|
||||
if( flags & BTREE_PREFORMAT ){
|
||||
rc = SQLITE_OK;
|
||||
szNew = pBt->nPreformatSize;
|
||||
szNew = p->pBt->nPreformatSize;
|
||||
if( szNew<4 ) szNew = 4;
|
||||
if( ISAUTOVACUUM && szNew>pPage->maxLocal ){
|
||||
if( ISAUTOVACUUM(p->pBt) && szNew>pPage->maxLocal ){
|
||||
CellInfo info;
|
||||
pPage->xParseCell(pPage, newCell, &info);
|
||||
if( info.nPayload!=info.nLocal ){
|
||||
Pgno ovfl = get4byte(&newCell[szNew-4]);
|
||||
ptrmapPut(pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc);
|
||||
ptrmapPut(p->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc);
|
||||
if( NEVER(rc) ) goto end_insert;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
rc = fillInCell(pPage, newCell, pX, &szNew);
|
||||
if( rc ) goto end_insert;
|
||||
}
|
||||
if( rc ) goto end_insert;
|
||||
assert( szNew==pPage->xCellSize(pPage, newCell) );
|
||||
assert( szNew <= MX_CELL_SIZE(pBt) );
|
||||
assert( szNew <= MX_CELL_SIZE(p->pBt) );
|
||||
idx = pCur->ix;
|
||||
if( loc==0 ){
|
||||
CellInfo info;
|
||||
@@ -9197,7 +9208,7 @@ int sqlite3BtreeInsert(
|
||||
testcase( pCur->curFlags & BTCF_ValidOvfl );
|
||||
invalidateOverflowCache(pCur);
|
||||
if( info.nSize==szNew && info.nLocal==info.nPayload
|
||||
&& (!ISAUTOVACUUM || szNew<pPage->minLocal)
|
||||
&& (!ISAUTOVACUUM(p->pBt) || szNew<pPage->minLocal)
|
||||
){
|
||||
/* Overwrite the old cell with the new if they are the same size.
|
||||
** We could also try to do this if the old cell is smaller, then add
|
||||
@@ -9227,7 +9238,7 @@ int sqlite3BtreeInsert(
|
||||
}else{
|
||||
assert( pPage->leaf );
|
||||
}
|
||||
insertCell(pPage, idx, newCell, szNew, 0, 0, &rc);
|
||||
rc = insertCell(pPage, idx, newCell, szNew, 0, 0);
|
||||
assert( pPage->nOverflow==0 || rc==SQLITE_OK );
|
||||
assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
|
||||
|
||||
@@ -9300,7 +9311,6 @@ end_insert:
|
||||
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
|
||||
*/
|
||||
int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){
|
||||
int rc = SQLITE_OK;
|
||||
BtShared *pBt = pDest->pBt;
|
||||
u8 *aOut = pBt->pTmpSpace; /* Pointer to next output buffer */
|
||||
const u8 *aIn; /* Pointer to next input buffer */
|
||||
@@ -9323,7 +9333,9 @@ int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){
|
||||
if( nIn==nRem && nIn<pDest->pPage->maxLocal ){
|
||||
memcpy(aOut, aIn, nIn);
|
||||
pBt->nPreformatSize = nIn + (aOut - pBt->pTmpSpace);
|
||||
return SQLITE_OK;
|
||||
}else{
|
||||
int rc = SQLITE_OK;
|
||||
Pager *pSrcPager = pSrc->pBt->pPager;
|
||||
u8 *pPgnoOut = 0;
|
||||
Pgno ovflIn = 0;
|
||||
@@ -9375,7 +9387,7 @@ int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){
|
||||
MemPage *pNew = 0;
|
||||
rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);
|
||||
put4byte(pPgnoOut, pgnoNew);
|
||||
if( ISAUTOVACUUM && pPageOut ){
|
||||
if( ISAUTOVACUUM(pBt) && pPageOut ){
|
||||
ptrmapPut(pBt, pgnoNew, PTRMAP_OVERFLOW2, pPageOut->pgno, &rc);
|
||||
}
|
||||
releasePage(pPageOut);
|
||||
@@ -9391,9 +9403,8 @@ int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){
|
||||
|
||||
releasePage(pPageOut);
|
||||
sqlite3PagerUnref(pPageIn);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -9548,7 +9559,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
||||
assert( pTmp!=0 );
|
||||
rc = sqlite3PagerWrite(pLeaf->pDbPage);
|
||||
if( rc==SQLITE_OK ){
|
||||
insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc);
|
||||
rc = insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n);
|
||||
}
|
||||
dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc);
|
||||
if( rc ) return rc;
|
||||
|
||||
@@ -674,9 +674,9 @@ struct BtCursor {
|
||||
** So, this macro is defined instead.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
#define ISAUTOVACUUM (pBt->autoVacuum)
|
||||
#define ISAUTOVACUUM(pBt) (pBt->autoVacuum)
|
||||
#else
|
||||
#define ISAUTOVACUUM 0
|
||||
#define ISAUTOVACUUM(pBt) 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -5579,6 +5579,7 @@ case OP_Insert: {
|
||||
x.nZero = 0;
|
||||
}
|
||||
x.pKey = 0;
|
||||
assert( BTREE_PREFORMAT==OPFLAG_PREFORMAT );
|
||||
rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
|
||||
(pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)),
|
||||
seekResult
|
||||
|
||||
Reference in New Issue
Block a user