Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

The fastest lakehouse layout is the one that serves your workload on your engine, data scale and maintenance schedule—not a universal winner. A useful benchmark keeps software, hardware, data and cache conditions constant; runs scan, filter, join and update workloads that resemble production; and records both latency and the execution details that explain it.

What a representative layout benchmark should answer

A benchmark should let you answer a narrowly defined question: which table layout performs better for these queries, at this data volume, on this engine and version, with this update pattern? That framing prevents a common mistake—treating a result from one table format, file size or cloud configuration as a permanent ranking.

Separate three things in your experiment:

  • Table format: the transaction-log and storage format, such as Delta Lake, Apache Hudi or Apache Iceberg.
  • Physical layout: partition keys, clustering or data-skipping settings, file-size distribution, compaction state and the number of files.
  • Execution environment: query engine and version, compute shape, object storage, runtime settings, reader implementation and cache state.

If you change all three at once, you can measure an end-to-end product choice, but you cannot claim that layout alone caused the difference. State which question your test addresses before collecting timings.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Start with the production workload

Inventory the access patterns

Write down who reads the table, which columns they filter or group by, which joins they perform, how fresh the data must be and how often rows are inserted, updated or deleted. Record high-cardinality predicates, skewed values, common date ranges, tenant or customer filters, and queries that repeatedly scan recent partitions. Include scheduled reports, dashboards, ad hoc analysis and data-science jobs if they share the table.

#1 Best Overall
Sale
Compressed Air Duster,130000RPM Super Power Cordless Air Duster,Rechargeable Brushless Blower,3 Gear Adjustable Blower with LED Light,Dust Remover for Computer/House/Outdoor/Car
  • Powerful Turbo Fan:CAGIWIRU Electric Air Duster have reached speed up to 130000RPM,Can efficient remove dust and debris.With LED light and Three Adjustable Speed to meet with different cleaning tasks.
  • With Attached USB C Fasting Charging cable.Charing 3 hours,Enjoy up to 240 minutes of use on the lowest setting, For third speed can use for 25mins.with four charging options to meet with your needs.
  • Wide Application: attached 5 different nozzles,making it suitable for a variety of scenes, such as car,pet, pc, keyboards, and other electronic devices. It also serves for office and home clean duster.
  • Handy Design & Portable:Cordless air duster electric nozzle is Light weight and small size, design and comfortable to hold and space saving, convenient to carry around. You can put it in your room or inside the car without taking up space.
  • Economical &Reusable: Built durable materials with a long-lasting battery,our CAGIWIRU air duster it's a sustainable alternative to disposable air cans.

Turn that inventory into query templates. Keep a copy of each production query’s logical shape, but parameterize dates, keys and limits so that every layout receives the same inputs. Preserve realistic selectivity: a query returning one tenant is not interchangeable with one returning half the table.

Use separate classes for separate behaviors

  • Scan and aggregation: full or broad date-range scans with grouping, sorting and aggregates. These expose throughput and the cost of reading many files.
  • Selective filters: predicates expected to skip most files. Measure whether partitioning, clustering or data skipping actually reduces bytes and files read.
  • Joins: joins using the keys and table sizes seen in production. Capture shuffle and spill behavior as well as elapsed time.
  • Point or narrow lookups: single-key or small-range requests when interactive latency matters.
  • Refresh and update operations: incremental loads, merges, deletes, compaction and optimization. A layout that wins reads may impose unacceptable write amplification.

Do not average these classes into one unexplained score. Report each class separately, then explain which class drives the business decision.

Choose a standard workload without losing production realism

TPC-DS is useful when its schemas and query shapes resemble your analytical workload. It supplies a repeatable scale factor and known queries, making results easier to compare across teams. It is not a substitute for production-specific filters, joins or update behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The Berkeley LHBench work used TPC-DS queries and then added lakehouse-specific tests: TPC-DS Refresh, a synthetic Merge Microbenchmark and a Large File Count test. That combination is a good model because query-only runs can miss merge costs, post-update read amplification and metadata overhead.

A practical suite has two layers:

  1. Reference layer: a stable subset of TPC-DS or another public workload for repeatability.
  2. Workload layer: parameterized production queries and refresh jobs selected from your access-pattern inventory.

Publish the exact query identifiers, SQL text or templates, parameter values, scale factor and data-generation procedure. If a query is excluded because your engine cannot run it, record the failure rather than silently dropping it.

Define layout variants before loading data

Make each candidate explicit. For every variant, record the format, partition or clustering keys, target file size, compaction and optimization state, sorting or data-skipping settings, write mode and any table properties. Load identical logical rows into every variant using the same generation and ingestion order.

Dimension What to hold constant What may vary as the test factor
Data Schema, row values, scale, null distribution, skew and generation seed Only the layout or format under test
Compute Worker count, instance type, memory, autoscaling limits and runtime configuration A separate experiment comparing compute profiles
Software Engine version, connector or reader version, table-format library and runtime image A separate version-upgrade experiment
Storage Object store, region, network path and encryption settings A separate storage-placement experiment
State Compaction policy, statistics, metadata freshness and table history Explicit cold, warm or post-maintenance scenarios
Queries SQL text, parameters, concurrency and order The query class or parameter set being studied

When comparing table formats and layouts together, label the result accordingly. “Format A was faster than format B in this environment” is supportable; “partitioning caused the improvement” is not if the reader implementation and file-writing behavior also changed.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
EVEO® Screen Cleaner Spray Kit (Streak-Free) TV Screen Cleaner for Smart TV, Lcd, LEd, Oled | Computer Screen Cleaner Spray and Wipe Microfiber Cloth - TV, Monitor, Laptop, iPad, Car - 6.7oz 1 Pack
  • Screen Cleaner is Your Screen’s New Bestfriend! - EVEO is proud to present a screen cleaner that’s perfectly suited for your TV. Meet your new screen cleaner, computer screen cleaner, laptop cleaner, iPad cleaner, Macbook,tv cleaner or any other electronic device. Our screen cleaner spray and wipe along with the included plush microfiber cloth, easily removes dust, fingerprints & other smudges on the screen’s surface. Clean effectively for a streak-free screen
  • Gentle on your Screens - Our screen cleaner spray and wipes is compatible to be used even for the most sensitive LCD, LED, CRT, and OLED screens in proper use. Be at ease knowing that this product is compatible with all the major brands: LG, SONY, Samsung, Sharp, iPad, iPhone, Android screens, Kindle, PC monitors - we’ve got you covered! Can be used as LCD screen cleaner, tv cleaner, smart tv screen cleaner, and more
  • Premium Super Soft Plush Microfiber Cloth - Included in this efficient screen cleaning kit. This screen cleaner spray and wipe has our signature plush microfiber cloth specially designed to comply with screens and monitors and leave them streak-free. Has been shown to effectively absorbs stubborn stains, zero streaks, and no fiber shedding. Always use this together with our screen cleaner for the best results
  • Easy-to-Use Screen Cleaner Kit + microfiber cleaning cloth - The EVEO Screen Cleaning Kit will easily be your new favorite tool when it comes to taking care of the things you love most, quick and easy solution for a streak-free screen. Simply screw on the sprayer gun on the screen cleaner bottle. Spray the cleaning liquid onto the microfiber cloth, then wipe the screen until desired cleanliness & shine is achieved.
  • Quality Screen Care Kit Worth Purchasing - Enjoy a convenient Screen Cleaner anytime, anywhere you need it. Your satisfaction is our top priority. We stand behind the quality of our products and that’s why, you shouldn’t be worrying at all. We manufacture the Best Screen Cleaner. and can be used for laptop cleaning kit, laptop screen cleaner, tv screen cleaner for smart tv. MacBook screen cleaner, monitor cleaner or screen cleaner spray for electronic devices with microfiber cleaning cloth

Control data scale, file sizes and file counts

Run at the scale where your decision matters. A layout that looks excellent at 100 GB may behave differently at multiple terabytes because metadata, listing and planning costs grow with file count. Preserve the file-size distribution produced by your intended ingestion process, then create a separate controlled test if you want to isolate file size.

Record, for every table:

  • Total logical and physical bytes.
  • Number of data files and their size distribution (minimum, median, maximum and meaningful percentiles).
  • Number of partitions or clustering ranges.
  • Statistics or data-skipping metadata available to the reader.
  • Delete files, change files or log records created by updates.
  • Compaction and optimization history.

Small files can increase listing, planning and task-launch overhead; very large files can reduce parallelism and make selective searches read more data than necessary. Treat the balance as a hypothesis and measure it rather than adopting a universal target.

Use a repeatable run protocol

Elapsed time from a single run is not a benchmark. Define the protocol before execution and apply it identically to every variant.

  1. Prepare an isolated table: load the same dataset, verify row counts and checksums, and document the resulting file inventory.
  2. Set the cache policy: choose cold-cache, warm-cache or both. For cold runs, clear or isolate filesystem, object-store and engine caches where your platform permits; for warm runs, execute a stated warm-up sequence.
  3. Stabilize the environment: pin the engine and runtime versions, worker configuration, autoscaling limits, object-store region and concurrency. Note other workloads that could contend for resources.
  4. Run a warm-up: compile or initialize the reader without including one-time startup costs in the reported query metric, or include those costs consistently in every variant.
  5. Execute each query repeatedly: use the same order and parameters for every table. Three runs, with the median reported, is the protocol used for LHBench’s 3 TB TPC-DS results; it is an example, not a universal minimum.
  6. Capture every outcome: retain successful timings, errors, retries, executor loss, out-of-memory events and timeouts. A failure is a result and must not be omitted from the denominator.
  7. Run maintenance scenarios: measure initial load, incremental write or merge, compaction and the first reads after each operation when those operations occur in production.
  8. Preserve raw records: store run-level metrics, query plans, configuration snapshots and timestamps so another engineer can calculate a different summary statistic.

Report the median and show spread—minimum/maximum or percentile values—rather than presenting only a single rounded number. If concurrency matters, add a separate concurrent test; do not mix single-user and multi-user timings.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Collect diagnostics that explain the timing

Latency tells you that variants differ; execution diagnostics tell you why. Collect the following whenever the engine exposes them:

  • Bytes read and bytes returned.
  • Files opened, files skipped and file-level or partition-level pruning.
  • Planning, metadata and log-replay time.
  • Number of tasks, task-duration distribution, shuffle bytes, spill and skew.
  • Scan throughput, CPU time and input wait time.
  • Write, merge, compaction and commit time.
  • Delete-file or change-file processing after updates.

Compare physical query plans as well as SQL text. The CIDR 2023 comparison reported that systems often produced the same Spark query plan, while most of the observed difference came from data-reading time. It also documented cases in which metadata operations and API-driven plan differences mattered. If plans match but bytes or files read differ, investigate the reader and file layout; if plans differ, do not attribute the result to layout alone.

Measure reads and writes together

Copy-on-Write

Copy-on-Write (CoW) rewrites files containing changed rows during an update. This can increase write amplification and commit work, but readers generally see consolidated data without needing to merge separate update files.

Rank #3
Sale
BladeHawks RGB Gaming Mouse Pad Extra Large Extended 31.5x12 Inch-Black | LED mouse pad with 14 lighting modes, covers keyboard & mouse, anti-slip rubber base, waterproof surface, USB powered
  • 【Large size】:Measuring 800 x 300 mm/ 31. 5×12 inches, which is wider and taller than others. Large mouse pad can perfectly fit your keyboard and mouse of any size, and there is also ample space for peripherals such as phones, tablets, etc.
  • 【LED backlight mouse pad】:Blade Hawks RGB mouse pad provides 7 static modes and 7 dynamic modes will give you the options you are looking for. Power-off memory function remembers the last lighting mode you selected. The super glow fiber Chroma will give you a colorful gaming setup that you want.
  • 【Anti-slip rubber base】:Made from Natural rubber, this gaming mousepad will firmly grip your desktop, allowing you to enjoy the ultimate precision in the games you are most passionate about. It also comes with a texture that enhances this ability even further.
  • 【Smooth and waterproof surface】: Micro-textured cloth surface, for extremely precise mouse control and a smooth movement. When liquid splashes on the gaming mouse pad, it forms water droplets and slides down. Will not delay your work or gameplay.
  • 【Plug and play】: This mouse and keyboard pad is powered by USB, plug and play, no driver required. One button control light modes. Press one time to change the lighting mode, press twice to change the brightness, press and hold about 3 seconds turn ON/OFF.

Merge-on-Read

Merge-on-Read (MoR) writes change data separately and defers some reconciliation to readers. Writes can be cheaper, while post-update reads may pay extra merge and metadata costs. Measure both sides of that trade-off:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Time the merge or refresh itself.
  2. Measure the first query after the merge and steady-state queries afterward.
  3. Record files and bytes read, including change or delete files.
  4. Measure compaction required to restore read performance.

In LHBench’s historical synthetic test, MoR began outperforming CoW for merge time at 100,000 updated rows, while post-merge latency was higher for MoR. That threshold belongs to the tested configuration, not a general crossover point.

Use refresh tests that resemble table maintenance

LHBench’s refresh design started with a 100 GB base dataset, applied 10 refreshes of 3% each and ran five queries—Q3, Q9, Q34, Q42 and Q59—before and after merges. You can adapt the pattern to your cadence: choose a base snapshot, apply the same number and size of increments your pipeline produces, and run representative reads after each update.

Keep separate columns for:

  • Incremental file-writing time.
  • Transaction or commit time.
  • Merge time by operation type.
  • Post-update query latency.
  • Compaction or optimization time.
  • Storage growth and residual change-file count.

Do not report only the final query speed. A layout that requires frequent expensive maintenance may cost more operationally even if its compacted snapshot reads quickly.

Stress metadata with a large-file-count test

To expose planning and listing behavior, vary file count while keeping logical data and file size controlled. LHBench’s large-file-count test used 10 MB files and increased the count from 1,000 to 200,000. In that setup, Delta showed 7×–20× better performance than the alternatives in the 200,000-file case. Those figures describe that historical setup; they are not a current universal ranking.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When reproducing the idea, measure:

  • Time spent listing or discovering files.
  • Metadata-log replay and planning latency.
  • Driver memory and task-generation time.
  • Number of files actually opened after pruning.
  • Failure or timeout behavior at the largest file counts.

Run this as a distinct stress test. It answers whether an operationally plausible small-file condition overwhelms the reader; it does not predict ordinary performance when tables are compacted.

Published evidence and how to interpret it

Result Conditions and qualification
Delta queries were 1.4× faster than Hudi and 1.7× faster than Iceberg Berkeley LHBench/CIDR-era 3 TB TPC-DS results using Spark on AWS EMR 6.9.0 (Spark 3.3.0), S3, Delta Lake 2.2.0, Hudi 0.12.0 and Iceberg 1.1.0; medians of three runs. Historical evidence, not a present-day ranking.
Hudi MoR merges were 1.3× faster than Hudi CoW LHBench refresh configuration; post-merge queries were 3.2× slower for MoR. The trade-off is specific to that test.
Iceberg 0.14.0 MoR merges were 1.4× faster than CoW LHBench test in which post-merge query performance remained similar between modes.
Delta was 7×–20× faster in the 200,000-file case Large File Count test with 10 MB files and file counts from 1,000 through 200,000; do not generalize beyond the tested setup.

These results are valuable because they show why a benchmark must include reader behavior, file inventory and maintenance—not because they establish a permanent winner. Software versions, writers, readers, file sizes and query plans can all change the outcome.

Rank #4
Sale
Vaydeer Wrist Rest for Keyboard and Mouse, Computer Ergonomic Wrist Support Pad, Soft Memory Foam Arm Cushion for Desk, Palm Hand Office Laptop Typing
  • 【Softer and More Comfortable】Vaydeer wrist rest has unique diamond pattern, which is the combination of softness and aesthetics. The materials of wrist rest are improved into higher quality memory foam and covered with silky smooth lycra. The computer wrist rest makes you as comfortable and cushiony as like rest your wrists on clouds.
  • 【Ergonomic Wrist Saver】The wrist rests for keyboard and mouse comes with a 17.32×3.15×0.83 inch keyboard wrist pad and a 5.94×3.15×0.83 inch mouse wrist support. Based on ergonomic design, the unique concave shape is the perfect fit for your wrist joints. The wrist rest pad fits most computer keyboards and laptops, improve hand and wrist posture, release your wrist and arm stress.
  • 【Non-Slip Rubber Bottom】Featuring an anti-skid silicone base on the bottom, this wrist keyboard support stays firmly in place on your desk, preventing the padding from sliding around, ensuring stable and consistent wrist support during extended computer sessions.
  • 【Better Experience & Pain Relief】Our keyboard arm rest is beneficial to alleviate the soreness caused by direct contact and friction between your arm and a hard desk surface, reducing the risk of wrist fatigue or carpal tunnel. The soft texture of memory foam can evenly distribute the pressure around your wrists and provide good support with just enough give.
  • 【Helpful in Multiple Scenarios】Whether you're working, studying, writing, typing, gaming, this keyboard and mouse rest combo is an essential accessory to add comfort and support to your hands and wrists. It’s also a great gift for men, women, family, friend, coworker, gamer, teacher, etc.

Test partitioning and clustering as hypotheses

Partitioning can make selective predicates inexpensive when the key aligns with common filters, but too many partitions create small files and metadata overhead. A broad scan may pay for many partition boundaries without gaining useful pruning. Test both the common selective query and the broad scan before choosing a key.

Databricks documentation advises avoiding over-partitioning in its Delta Lake context, recommends no partitioning for tables below 1 TB and says to expect at least 1 GB per partition. These are vendor recommendations for that platform, not industry-wide standards. Measure your own partition sizes, file counts and query behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Clustering is an alternative when access patterns are high-cardinality, skewed, rapidly changing or poorly served by a fixed partition key. Compare the candidate clustering keys against the same query suite and include reclustering or optimization cost in the maintenance measurements.

Current note on liquid clustering

Databricks describes liquid clustering as a way to simplify data-layout decisions and optimize query performance. Its documentation lists general availability for Delta Lake tables on Databricks Runtime 15.4 LTS and later, and public preview for Apache Iceberg tables on Runtime 16.4 LTS and later. Verify current documentation, writer support and reader compatibility before implementing because feature status and constraints can change.

The guidance particularly targets high-cardinality filters, skew, rapidly growing tables, concurrent writes, changing access patterns and cases where a partition key would create too many or too few partitions. Treat each recommendation as a candidate hypothesis: benchmark the proposed keys, compare maintenance work, and retain a fixed-partition or unclustered control.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Analyze results with a decision matrix

After collecting raw runs, create one row per query and layout. Include these columns:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Category Measurements Decision question
Read performance Median and spread, bytes read, files opened/skipped Does the layout improve the queries that matter?
Planning Metadata and planning time, driver work, failures Does file or log growth create an operational ceiling?
Write performance Initial load, incremental write, merge and commit time Can the pipeline meet its freshness window?
Post-update behavior Immediate and steady-state read latency, change-file count Does cheaper writing create read amplification?
Maintenance Compaction/reclustering time, storage growth and scheduling frequency What recurring cost is required to preserve performance?
Compatibility Engine, format, runtime and reader support Will all required jobs read and write the layout?

Set acceptance thresholds before looking at the winner—for example, a maximum dashboard latency, a refresh completion window or a cap on maintenance hours. A small read-time gain may not justify a large increase in refresh cost, and a layout that wins medians but times out under realistic file counts may be unsuitable.

Best Value
Sale
Under Desk Cable Management Tray No Drill, Metal Mesh Cable Management Under Desk with Clamp Mount, 2 Hole Cable Tray with Wire Management and Cord Organizer for Home Office Standing Desk
  • 【No Drill Mounted】Cable management tray can be assembled in as little as 3 minutes or less-simply. Side clips easily clampe the edge of desk, pass through the holes on the sides, and secure excess cables with baskets. Desk cable management supports inward or outward installation to meet your needs in different scenarios, and provides you with great convenience when collecting and organizing wires.
  • 【Rubber Pad Protects Desk】Wire organizer under desk built-in soft rubber pads on the clamp protect your desk from scratches, so you will not damage your furniture or office.
  • 【Sturdy and Beautiful】Cord management under desk is made of high-quality carbon steel and holds about 15 lbs. The wire basket has 2 holes on each side of the tray to enable your cables to pass freely. Cable baskets are suitable for desk thickness use from 0.4" to 2.4".
  • 【Space Saving & Keep Organized】Desk cable management tray holds all your power cords, outlet strips, USB hubs and computer transformers hidden from your feet, and the data cables will not enter the vacuum cleaner to keep your desk clean and tidy. Desk wire organizer is also suitable for use in the kitchen and outdoors.
  • 【Reduce Safety Risks】Cable tray under desk keeps all plugs away from your kids, no more worry about tripping. Using 2 holes wire tray saves extra space, helps you easily cabling and wire protection. The mesh design is not easy to accumulate dust, but avoids safety accidents caused by messy wires.

Common benchmark failures and fixes

Using one convenient query

Symptom: a layout wins a single aggregation and is declared best. Fix: add selective filters, joins, point lookups and the actual refresh path; report results by query class.

Changing engine settings between variants

Symptom: each table is tested with its vendor’s preferred runtime or tuning. Fix: hold compute, runtime and reader settings constant for a fair layout comparison, then run a separate optimized-product comparison if desired.

Mixing cold and warm cache runs

Symptom: the first variant benefits from a warm object-store or metadata cache. Fix: isolate cold runs, use a stated warm-up, and never compare an unlabelled mixture.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Ignoring small files

Symptom: a test uses freshly written files unlike production or assumes compaction is free. Fix: preserve production file-size distribution and measure compaction as part of the workload.

Dropping failures

Symptom: only successful timings appear in the report. Fix: count errors, retries, timeouts and out-of-memory events as outcomes and explain their impact.

Confusing format with layout

Symptom: a difference is attributed to partitioning even though the table format and reader changed. Fix: label the experiment as an end-to-end format comparison or add a controlled same-format layout comparison.

Reporting averages without raw variance

Symptom: a small apparent gain cannot be reproduced. Fix: retain run-level data, report the chosen statistic and show spread, timestamps and resource contention.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What a reproducible report should contain

Publish a methods block beside every result set. Include:

  • Dataset source, scale, schema, generation seed and refresh schedule.
  • Table format and exact version, engine and exact version, runtime image and reader libraries.
  • Cloud, region, object storage, worker types, worker count, memory and autoscaling limits.
  • Partition or clustering keys, file-size target, file count and size distribution.
  • Compaction, statistics and optimization state before each run.
  • Query text or immutable identifiers, parameter values, order and concurrency.
  • Cache policy, warm-up procedure, repetition count and summary statistic.
  • Raw timings, failures, bytes, files, planning time, shuffle metrics and write metrics.
  • Any deviations, retries, throttling or infrastructure incidents.

Attach query plans and table-inventory snapshots where possible. A reader should be able to tell whether a result came from pruning, faster scans, less metadata work, a different plan or simply a warmer cache.

Bottom line for choosing a layout

Build the benchmark around the workload you must serve, not around a format you hope will win. Use representative scans, selective predicates, joins and updates; keep data, software, compute and cache conditions fixed; repeat runs and report medians with variance; and collect files, bytes, planning and maintenance metrics alongside latency. Treat published multipliers and vendor thresholds as context, then validate the candidate layout on your own engine, versions, scale and refresh cadence.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.