Re: [HACKERS] Window function optimisation, allow pushdowns of items matching PARTITION BY clauses
David Rowley dgrow...@gmail.com writes: [ wfunc_pushdown_partitionby_v0.4.patch ] I've committed this with the addition of a volatility check and some other basically-cosmetic adjustments. regards, tom lane -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] better atomics - v0.5
On Wed, Jun 25, 2014 at 10:44 PM, Andres Freund and...@2ndquadrant.com wrote: Attached is a new version of the atomic operations patch. Lots has changed since the last post: * gcc, msvc work. acc, xlc, sunpro have blindly written support which should be relatively easy to fix up. All try to implement TAS, 32 bit atomic add, 32 bit compare exchange; some do it for 64bit as well. I have reviewed msvc part of patch and below are my findings: 1. +pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, + uint32 *expected, uint32 newval) +{ + bool ret; + uint32 current; + current = InterlockedCompareExchange(ptr-value, newval, *expected); Is there a reason why using InterlockedCompareExchange() is better than using InterlockedCompareExchangeAcquire() variant? *Acquire or *Release variants can provide acquire memory ordering semantics for processors which support the same else will be defined as InterlockedCompareExchange. 2. +pg_atomic_compare_exchange_u32_impl() { .. + *expected = current; } Can we implement this API without changing expected value? I mean if the InterlockedCompareExchange() is success, then it will store the newval in ptr-value, else *ret* will be false. I am not sure if there is anything implementation specific in changing *expected*. I think this value is required for lwlock patch, but I am wondering why can't the same be achieved if we just return the *current* value and then let lwlock patch do the handling based on it. This will have another advantage that our pg_* API will also have similar signature as native API's. 3. Is there a overhead of using Add, instead of increment/decrement version of Interlocked? I could not find any evidence which can clearly indicate, if one is better than other except some recommendation in below link which suggests to *maintain reference count*, use Increment/Decrement Refer *The Locking Cookbook* in below link: http://blogs.technet.com/b/winserverperformance/archive/2008/05/21/designing-applications-for-high-performance-part-ii.aspx However, when I tried to check the instructions each function generates, then I don't find anything which suggests that *Add variant can be slow. Refer Instructions for both functions: cPublicProc _InterlockedIncrement,1 cPublicFpo 1,0 mov ecx,Addend ; get pointer to addend variable mov eax,1 ; set increment value Lock1: lock xadd[ecx],eax ; interlocked increment inc eax ; adjust return value stdRET _InterlockedIncrement; stdENDP _InterlockedIncrement cPublicProc _InterlockedExchangeAdd, 2 cPublicFpo 2,0 mov ecx, [esp + 4] ; get addend address mov eax, [esp + 8] ; get increment value Lock4: lock xadd[ecx], eax ; exchange add stdRET _InterlockedExchangeAdd stdENDP _InterlockedExchangeAdd For details, refer link: http://read.pudn.com/downloads3/sourcecode/windows/248345/win2k/private/windows/base/client/i386/critsect.asm__.htm I don't think there is any need of change in current implementation, however I just wanted to share my analysis, so that if any one else can see any point in preferring one or the other way of implementation. 4. #pragma intrinsic(_ReadWriteBarrier) #define pg_compiler_barrier_impl() _ReadWriteBarrier() #ifndef pg_memory_barrier_impl #define pg_memory_barrier_impl() MemoryBarrier() #endif There is a Caution notice in microsoft site indicating _ReadWriteBarrier/MemoryBarrier are deprected. Please refer below link: http://msdn.microsoft.com/en-us/library/f20w0x5e(v=vs.110).aspx When I checked previous versions of MSVC, I noticed that these are supported on x86, IPF, x64 till VS2008 and supported only on x86, x64 for VS2012 onwards. Link for VS2010 support: http://msdn.microsoft.com/en-us/library/f20w0x5e(v=vs.100).aspx 5. + * atomics-generic-msvc.h .. + * Portions Copyright (c) 2013, PostgreSQL Global Development Group Shouldn't copyright notice be 2014? 6. pg_atomic_compare_exchange_u32() It is better to have comments above this and all other related functions. With Regards, Amit Kapila. EnterpriseDB: http://www.enterprisedb.com
Re: [HACKERS] better atomics - v0.5
On 2014-06-28 11:58:41 +0530, Amit Kapila wrote: On Wed, Jun 25, 2014 at 10:44 PM, Andres Freund and...@2ndquadrant.com wrote: Attached is a new version of the atomic operations patch. Lots has changed since the last post: * gcc, msvc work. acc, xlc, sunpro have blindly written support which should be relatively easy to fix up. All try to implement TAS, 32 bit atomic add, 32 bit compare exchange; some do it for 64bit as well. I have reviewed msvc part of patch and below are my findings: Thanks for looking at it - I pretty much wrote that part blindly. 1. +pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, + uint32 *expected, uint32 newval) +{ + bool ret; + uint32 current; + current = InterlockedCompareExchange(ptr-value, newval, *expected); Is there a reason why using InterlockedCompareExchange() is better than using InterlockedCompareExchangeAcquire() variant? Two things: a) compare_exchange is a read/write operator and so far I've defined it to have full barrier semantics (documented in atomics.h). I'd be happy to discuss which semantics we want for which operation. b) It's only supported from vista onwards. Afaik we still support XP. c) It doesn't make any difference on x86 ;) *Acquire or *Release variants can provide acquire memory ordering semantics for processors which support the same else will be defined as InterlockedCompareExchange. 2. +pg_atomic_compare_exchange_u32_impl() { .. + *expected = current; } Can we implement this API without changing expected value? I mean if the InterlockedCompareExchange() is success, then it will store the newval in ptr-value, else *ret* will be false. I am not sure if there is anything implementation specific in changing *expected*. I think this value is required for lwlock patch, but I am wondering why can't the same be achieved if we just return the *current* value and then let lwlock patch do the handling based on it. This will have another advantage that our pg_* API will also have similar signature as native API's. Many usages of compare/exchange require that you'll get the old value back in an atomic fashion. Unfortunately the Interlocked* API doesn't provide a nice way to do that. Note that this definition of compare/exchange both maps nicely to C11's atomics and the actual x86 cmpxchg instruction. I've generally tried to mimick C11's API as far as it's possible. There's some limitations because we can't do generic types and such, but other than that. 3. Is there a overhead of using Add, instead of increment/decrement version of Interlocked? There's a theoretical difference for IA64 which has a special increment/decrement operation which can only change the value by a rather limited number of values. I don't think it's worth to care. 4. #pragma intrinsic(_ReadWriteBarrier) #define pg_compiler_barrier_impl() _ReadWriteBarrier() #ifndef pg_memory_barrier_impl #define pg_memory_barrier_impl() MemoryBarrier() #endif There is a Caution notice in microsoft site indicating _ReadWriteBarrier/MemoryBarrier are deprected. It seemed to be the most widely available API, and it's what barrier.h already used. Do you have a different suggestion? 6. pg_atomic_compare_exchange_u32() It is better to have comments above this and all other related functions. Check atomics.h, there's comments above it: /* * pg_atomic_compare_exchange_u32 - CAS operation * * Atomically compare the current value of ptr with *expected and store newval * iff ptr and *expected have the same value. The current value of *ptr will * always be stored in *expected. * * Return whether the values have been exchanged. * * Full barrier semantics. */ Thanks, Andres Freund -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] better atomics - v0.5
On 2014-06-27 22:47:02 -0400, Robert Haas wrote: On Fri, Jun 27, 2014 at 2:00 PM, Andres Freund and...@2ndquadrant.com wrote: On 2014-06-27 13:15:25 -0400, Robert Haas wrote: On Thu, Jun 26, 2014 at 3:04 PM, Andres Freund and...@2ndquadrant.com wrote: I don't really see usecases where it's not related data that's being touched, but: The point is that the fastpath (not using a spinlock) might touch the atomic variable, even while the slowpath has acquired the spinlock. So the slowpath can't just use non-atomic operations on the atomic variable. Imagine something like releasing a buffer pin while somebody else is doing something that requires holding the buffer header spinlock. If the atomic variable can be manipulated without the spinlock under *any* circumstances, then how is it a good idea to ever manipulate it with the spinlock? That seems hard to reason about, and unnecessary. Critical sections for spinlocks should be short and contain only the instructions that need protection, and clearly the atomic op is not one of those. Imagine the situation for the buffer header spinlock which is one of the bigger performance issues atm. We could aim to replace all usages of that with clever and complicated logic, but it's hard. The IMO reasonable (and prototyped) way to do it is to make the common paths lockless, but fall back to the spinlock for the more complicated situations. For the buffer header that means that pin/unpin and buffer lookup are lockless, but IO and changing the identity of a buffer still require the spinlock. My attempts to avoid the latter basically required a buffer header specific reimplementation of spinlocks. To make pin/unpin et al safe without acquiring the spinlock the pincount and the flags had to be moved into one variable so that when incrementing the pincount you automatically get the flagbits back. If it's currently valid all is good, otherwise the spinlock needs to be acquired. But for that to work you need to set flags while the spinlock is held. Possibly you can come up with ways to avoid that, but I am pretty damn sure that the code will be less robust by forbidding atomics inside a critical section, not the contrary. It's a good idea to avoid it, but not at all costs. You might be right, but I'm not convinced. Why? Anything I can do to convince you of this? Note that other users of atomics (e.g. the linux kernel) widely use atomics inside spinlock protected regions. Does the lwlock scalability patch work this way, too? No. I've moved one add/sub inside a critical section in the current version while debugging, but it's not required at all. I generally think it makes sense to document the suggestion of moving atomics outside, but not make it a requirement. What I'm basically afraid of is that this will work fine in many cases but have really ugly failure modes. That's pretty much what happens with spinlocks already - the overhead is insignificant at low levels of contention but as the spinlock starts to become contended the CPUs all fight over the cache line and performance goes to pot. ISTM that making the spinlock critical section significantly longer by putting atomic ops in there could appear to win in some cases while being very bad in others. Well, I'm not saying it's something I suggest doing all the time. But if using an atomic op in the slow path allows you to remove the spinlock from 99% of the cases I don't see it having a significant impact. In most scenarios (where atomics aren't emulated, i.e. platforms we expect to used in heavily concurrent cases) the spinlock and the atomic will be on the same cacheline making stalls much less likely. Greetings, Andres Freund -- Andres Freund http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training Services -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] Spinlocks and compiler/memory barriers
On 2014-06-27 22:34:19 -0400, Robert Haas wrote: On Fri, Jun 27, 2014 at 2:04 PM, Andres Freund and...@2ndquadrant.com wrote: On 2014-06-27 13:04:02 -0400, Robert Haas wrote: On Thu, Jun 26, 2014 at 6:40 PM, Tom Lane t...@sss.pgh.pa.us wrote: Andres Freund and...@2ndquadrant.com writes: On 2014-06-26 14:13:07 -0700, Tom Lane wrote: Surely it had better be a read barrier as well? I don't immediately see why it has to be read barrier? Hoisting a load from after the release into the locked area of code should be safe? No doubt, but delaying a read till after the unlocking write would certainly not be safe. AFAICT, README.barrier completely fails to define what we think the semantics of pg_read_barrier and pg_write_barrier actually are, so if you believe that a write barrier prevents reordering of reads relative to writes, you'd better propose some new text for that file. It certainly doesn't say that today. The relevant text is in barrier.h Note that that definition of a write barrier is *not* sufficient for the release of a lock... As I said elsewhere I think all the barrier definitions, except maybe alpha, luckily seem to be strong enough for that anyway. Do we want to introduce acquire/release barriers? Or do we want to redefine the current barriers to be strong enough for that? Well, unless we're prepared to dump support for an awful lot of platfomrs, trying to support acquire and release barriers on every platform we support is a doomed effort. Hm? Just declare them to be as heavy as we need them? Already several platforms fall back to more heavyweight operations than necessary? The definitions of the barriers implemented by barrier.h are the same as the ones that Linux has (minus read-barrier-depends) Linux has smb_load_acquire()/smp_store_release() for locks on all platforms. If we were going to use any of those in s_lock.h, it'd have to be pg_memory_barrier(), but I don't think making s_lock.h dependent on barrier.h is the way to go. I think we should just adjust s_lock.h in a minimal way, using inline assembler or tweaking the existing assembler or whatever. Isn't that just going to be repeating the contents of barrier.h pretty much again? How are you suggesting we deal with the generic S_UNLOCK case without having a huge ifdef? Why do we build an abstraction layer (barrier.h) and then not use it? Greetings, Andres Freund -- Andres Freund http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training Services -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] Window function optimisation, allow pushdowns of items matching PARTITION BY clauses
On 28 June 2014 18:12, Tom Lane t...@sss.pgh.pa.us wrote: David Rowley dgrow...@gmail.com writes: [ wfunc_pushdown_partitionby_v0.4.patch ] I've committed this with the addition of a volatility check and some other basically-cosmetic adjustments. Great, thank you for making the required changes. Vik, thank you for reviewing the patch. Regards David Rowley regards, tom lane
Re: [HACKERS] Add a filed to PageHeaderData
On Tue, Jun 24, 2014 at 10:18 PM, Pavan Deolasee pavan.deola...@gmail.com wrote: On Tue, Jun 24, 2014 at 3:40 PM, Kevin Grittner kgri...@ymail.com wrote: Soroosh Sardari soroosh.sard...@gmail.com wrote: I check this problem with a virgin source code of postgresql-9.3.2. So the bug is not for my codes. By the way, following code has two different output and it is weird. I can confirm that I see the difference in 9.3.2, and that I don't see the difference in 9.3.4. Upgrade. http://www.postgresql.org/support/versioning/ There's really no point in reporting a possible bug on a version with known bugs which have already had fixes published. FWIW I can reproduce this on HEAD with the attached patch. I could reproduce this on a 64-bit Ubuntu as well as 64-bit Mac OSX. Very confusing it is because I tried with various values for N in char[N] array and it fails for N=20. Other values I tried are 4, 12, 22, 24 and the test passes for all of them. The logic for trying other values is to see if pd_linp[] starting on un-aligned boundary can trigger the issue. But there seem to be no correlation. postgres=# select version(); PostgreSQL 9.5devel on x86_64-apple-darwin13.2.0, compiled by Apple LLVM version 5.1 (clang-503.0.38) (based on LLVM 3.4svn), 64-bit postgres=# -- test SP-GiST index that's been built incrementally postgres=# create table test_range_spgist(ir int4range); postgres=# create index test_range_spgist_idx on test_range_spgist using spgist (ir); postgres=# insert into test_range_spgist select int4range(g, g+10) from generate_series(1,586) g; INSERT 0 586 postgres=# SET enable_seqscan= t; postgres=# SET enable_indexscan = f; postgres=# SET enable_bitmapscan = f; postgres=# select * from test_range_spgist where ir -|- int4range(100,500); ir --- [90,100) [500,510) (2 rows) postgres=# SET enable_seqscan= f; postgres=# select * from test_range_spgist where ir -|- int4range(100,500); ir --- [90,100) [500,510) (2 rows) At this point, both rows are visible via index scan as well as seq scan. postgres=# insert into test_range_spgist select int4range(g, g+10) from generate_series(587,587) g; INSERT 0 1 postgres=# select * from test_range_spgist where ir -|- int4range(100,500); ir -- [90,100) (1 row) Ouch. The second row somehow disappeared. postgres=# SET enable_seqscan= t; postgres=# select * from test_range_spgist where ir -|- int4range(100,500); ir --- [90,100) [500,510) (2 rows) So the last INSERT suddenly makes one row disappear via the index scan though its still reachable via seq scan. I tried looking at the SP-Gist code but clearly I don't understand it a whole lot to figure out the issue, if one exists. Thanks, Pavan -- Pavan Deolasee http://www.linkedin.com/in/pavandeolasee Is there any plug in to examine each page of spgist index? Unfortunately pageinspect only work for btree index.
Re: [Fwd: Re: [HACKERS] proposal: new long psql parameter --on-error-stop]
Hello I modified description of setting system variables in dependency on O.S. Regards Pavel 2014-06-27 8:54 GMT+02:00 Pavel Stehule pavel.steh...@gmail.com: Hello thank you Peter, so now only setting for MS Windows is missing? Regards Pavel 2014-06-26 21:57 GMT+02:00 Petr Jelinek p...@2ndquadrant.com: Hello, I went through the patch, seems mostly fine, I adjusted some wording, removed the default .pgpass file info since it's not accurate, and replaced couple of phrases with (hopefully) more informative ones. -- Petr Jelinek http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training Services commit 44ba9d7fc1816dde4605ef59ea68b92b8ceb1c57 Author: Pavel Stehule pavel.steh...@gooddata.com Date: Sat Jun 28 14:19:47 2014 +0200 initial diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index ee6ec3a..6a172dc 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -556,6 +556,15 @@ EOF /listitem /varlistentry +varlistentry + termoption--help-variables//term + listitem + para + Show help about applicationpsql/application variables, + and exit. + /para + /listitem +/varlistentry /variablelist /refsect1 diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index 3aa3c16..d7da7c3 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -78,12 +78,13 @@ usage(void) printf(_( -f, --file=FILENAME execute commands from file, then exit\n)); printf(_( -l, --list list available databases, then exit\n)); printf(_( -v, --set=, --variable=NAME=VALUE\n - set psql variable NAME to VALUE\n)); + set psql variable NAME to VALUE e.g.: -v ON_ERROR_STOP=1\n)); printf(_( -V, --versionoutput version information, then exit\n)); printf(_( -X, --no-psqlrc do not read startup file (~/.psqlrc)\n)); printf(_( -1 (\one\), --single-transaction\n execute as a single transaction (if non-interactive)\n)); printf(_( -?, --help show this help, then exit\n)); + printf(_( --help-variables show a list of all specially treated variables, then exit\n)); printf(_(\nInput and output options:\n)); printf(_( -a, --echo-all echo all input from script\n)); @@ -279,6 +280,98 @@ slashUsage(unsigned short int pager) } +/* + * show list of available variables (options) from command line + */ +void +help_variables(void) +{ + printf(_(List of specially treated variables.\n)); + + printf(_(psql variables:\n)); + printf(_(Usage:\n)); + printf(_( psql --set=NAME=VALUE\n or \\set NAME VALUE in interactive mode\n\n)); + + printf(_( AUTOCOMMIT successful SQL commands are automatically committed\n)); + printf(_( COMP_KEYWORD_CASE determines which letter case to use when completing an SQL key word\n)); + printf(_( DBNAME name of currently connected database\n)); + printf(_( ECHO control what input can be written to standard output [all, queries]\n)); + printf(_( ECHO_HIDDENdisplay internal queries executed by backslash commands\n)); + printf(_( ENCODING current client character set encoding\n)); + printf(_( FETCH_COUNTthe number of result rows to fetch and display at a time\n + (default: 0=unlimited)\n)); + printf(_( HISTCONTROLcontrol history list [ignorespace, ignoredups, ignoreboth]\n)); + printf(_( HISTFILE file name used to store the history list\n)); + printf(_( HISTSIZE the number of commands to store in the command history\n)); + printf(_( HOST the currently connected database server\n)); + printf(_( IGNOREEOF if unset, sending an EOF to interactive session terminates application\n)); + printf(_( LASTOIDthe value of last affected OID\n)); + printf(_( ON_ERROR_ROLLBACK when on, the error doesn't stop transaction (uses implicit SAVEPOINTs)\n)); + printf(_( ON_ERROR_STOP stop batch execution after error\n)); + printf(_( PORT server port of the current connection\n)); + printf(_( PROMPT1, PROMPT2, PROMPT3\n + specify the psql prompt\n)); + printf(_( QUIET run quietly (same as -q option)\n)); + printf(_( SINGLELINE end of line terminates SQL command mode (same as -S option)\n)); + printf(_( SINGLESTEP single-step mode (same as -s option)\n)); + printf(_( USER the database user currently connected as\n)); + printf(_( VERBOSITY control verbosity of error reports [default, verbose, terse]\n)); + + printf(_(\nPrinting options:\n)); + printf(_(Usage:\n)); + printf(_( psql --pset=NAME[=VALUE]\n or \\pset NAME [VALUE] in interactive mode\n\n)); + + printf(_( border border style (number)\n)); + printf(_(
Re: [HACKERS] Cluster name in ps output
Hi, On 2014-06-26 23:03:24 +0100, Thomas Munro wrote: + {cluster_name, PGC_POSTMASTER, CONN_AUTH_SETTINGS, + gettext_noop(Sets the name of the cluster that appears in 'ps' output.), + NULL, + GUC_IS_NAME + }, + cluster_name, + , + NULL, NULL, NULL + }, + In my opinion this should rather be LOGGING or LOGGING_WHAT rather than CONN_AUTH_SETTINGS. I don't really see what place it it in the latter category? Possibly you've copied it from bonjour? But that's in the category because it's used to advertises connections which isn't the case for cluster_name. I also don't see a reason for it to be marked as GUC_IS_NAME? That's about truncating it so it fits into a sql identifer. Not that it should ever play a role... +#cluster_name = '' # visible in ps output if set + # (change requires restart) Not sure if referring to ps is the best thing here. Maybe 'visible in the processes name if set'? Same for the GUC's description string. Otherwise it looks good to me. Greetings, Andres Freund -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] Spinlocks and compiler/memory barriers
On Sat, Jun 28, 2014 at 4:31 AM, Andres Freund and...@2ndquadrant.com wrote: Do we want to introduce acquire/release barriers? Or do we want to redefine the current barriers to be strong enough for that? Well, unless we're prepared to dump support for an awful lot of platfomrs, trying to support acquire and release barriers on every platform we support is a doomed effort. Hm? Just declare them to be as heavy as we need them? Already several platforms fall back to more heavyweight operations than necessary? Can't we keep this simple for starters? Strength-reducing the existing operations is yet a third problem, on top of the already-existing problems of (1) making spinlock operations compiler barriers and (2) fixing any buggy implementations. I'm explicitly trying to avoid defining this in a way that means we need a Gigantic Patch that Changes Everything. The definitions of the barriers implemented by barrier.h are the same as the ones that Linux has (minus read-barrier-depends) Linux has smb_load_acquire()/smp_store_release() for locks on all platforms. You mean smp. If we were going to use any of those in s_lock.h, it'd have to be pg_memory_barrier(), but I don't think making s_lock.h dependent on barrier.h is the way to go. I think we should just adjust s_lock.h in a minimal way, using inline assembler or tweaking the existing assembler or whatever. Isn't that just going to be repeating the contents of barrier.h pretty much again? No, I think it's going to be *much* simpler than that. How about I take a crack at this next week and then either (a) I'll see why it's a bad idea and we can go from there or (b) you can review what I come up with and tell me why it sucks? How are you suggesting we deal with the generic S_UNLOCK case without having a huge ifdef? Why do we build an abstraction layer (barrier.h) and then not use it? Because (1) the abstraction doesn't fit very well unless we do a lot of additional work to build acquire and release barriers for every platform we support and (2) I don't have much confidence that we can depend on the spinlock fallback for barriers without completely breaking obscure platforms, and I'd rather make a more minimal set of changes. -- Robert Haas EnterpriseDB: http://www.enterprisedb.com The Enterprise PostgreSQL Company -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] Spinlocks and compiler/memory barriers
On 2014-06-28 09:25:32 -0400, Robert Haas wrote: On Sat, Jun 28, 2014 at 4:31 AM, Andres Freund and...@2ndquadrant.com wrote: Do we want to introduce acquire/release barriers? Or do we want to redefine the current barriers to be strong enough for that? Well, unless we're prepared to dump support for an awful lot of platfomrs, trying to support acquire and release barriers on every platform we support is a doomed effort. Hm? Just declare them to be as heavy as we need them? Already several platforms fall back to more heavyweight operations than necessary? Can't we keep this simple for starters? Strength-reducing the existing operations is yet a third problem, on top of the already-existing problems of (1) making spinlock operations compiler barriers and (2) fixing any buggy implementations. I'm explicitly trying to avoid defining this in a way that means we need a Gigantic Patch that Changes Everything. I actually mean that we can just define release barriers to be full memory barriers for platforms where we don't want to think about it. Not that we should weaken barriers. No, I think it's going to be *much* simpler than that. How about I take a crack at this next week and then either (a) I'll see why it's a bad idea and we can go from there or (b) you can review what I come up with and tell me why it sucks? Ok. I think that's going in the wrong direction (duplication of nontrivial knowledge), but maybe I'm taking a to 'purist' approach here. Prove me wrong :) You'll pick up the clobber changes from my patch? How are you suggesting we deal with the generic S_UNLOCK case without having a huge ifdef? Why do we build an abstraction layer (barrier.h) and then not use it? Because (1) the abstraction doesn't fit very well unless we do a lot of additional work to build acquire and release barriers for every platform we support and Meh. Something like the (untested): #if !defined(pg_release_barrier) defined(pg_read_barrier) defined(pg_write_barrier) #define pg_release_barrier() do { pg_read_barrier(); pg_write_barrier();} while (0) #elif !defined(pg_release_barrier) #define pg_release_barrier() pg_memory_barrier() #endif before the fallback definition of pg_read/write_barrier should suffice? (2) I don't have much confidence that we can depend on the spinlock fallback for barriers without completely breaking obscure platforms, and I'd rather make a more minimal set of changes. Well, it's the beginning of the cycle. And we're already depending on barriers for correctness (and it's not getting less), so I don't really see what avoiding barrier usage buys us except harder to find breakage? Greetings, Andres Freund -- Andres Freund http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training Services -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] Spinlocks and compiler/memory barriers
On 2014-06-28 15:41:46 +0200, Andres Freund wrote: On 2014-06-28 09:25:32 -0400, Robert Haas wrote: No, I think it's going to be *much* simpler than that. How about I take a crack at this next week and then either (a) I'll see why it's a bad idea and we can go from there or (b) you can review what I come up with and tell me why it sucks? Ok. I think that's going in the wrong direction (duplication of nontrivial knowledge), but maybe I'm taking a to 'purist' approach here. Prove me wrong :) What I forgot: I'm also pretty sure that the more lockless stuff we introduce the more places are going to need acquire/release semantics... Greetings, Andres Freund -- Andres Freund http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training Services -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] delta relations in AFTER triggers
David Fetter da...@fetter.org wrote: On Sat, Jun 21, 2014 at 11:06:26AM -0700, Kevin Grittner wrote: Here is v2. I've taken the liberty of making an extension that uses this. Preliminary tests indicate a 10x performance improvement over the user-space hack I did that's similar in functionality. Wow, this goes well beyond what I expected for a review! Thanks! As I said in an earlier post, I think that this is best committed as a series of patches, one for the core portion and one for each PL which implements the ability to use the transition (delta) relations in AFTER triggers. Your extension covers the C trigger angle, and it seems to me to be worth committing to contrib as a sample of how to use this feature in C. It is very encouraging that you were able to use this without touching what I did in core, and that it runs 10x faster than the alternatives before the patch. Because this review advances the patch so far, it may be feasible to get it committed in this CF. I'll see what is needed to get there and maybe have a patch toward that end in a few days. The minimum that would require, IMV, is a plpgsql implementation, moving the new pg_trigger columns to the variable portion of the record so they can be null capable, more docs, and regression tests. -- Kevin Grittner EDB: http://www.enterprisedb.com The Enterprise PostgreSQL Company -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
[HACKERS] Re: proposal: ignore null fields in not relation type composite type based constructors
Hello I am sending small patch, that allows ignore nulls in row_to_json function. It allow significant size reduction of generated JSON documents. Regards Pavel 2014-05-25 7:53 GMT+02:00 Pavel Stehule pavel.steh...@gmail.com: Hello In Czech Postgres mailing list was user request for serialization to json without null values. He needs a similar behave like XMLFOREST has - it ignores NULLs In some situations and conversions, when your table is +/- sparse matrix, this request is valid postgres=# select hstore(omega) from omega; hstore ─ a=10, b=20, c=NULL a=NULL, b=20, c=30 (2 rows) Proposed function postgres=# select hstore(omega, ignore_nulls := true) from omega; hstore ─ a=10, b=20 b=20, c=30 (2 rows) What do you thinking about this proposal? Regards Pavel commit c97bb5fd8b6c68a1141430d47964ebc3488f4429 Author: Pavel Stehule pavel.steh...@gooddata.com Date: Sat Jun 28 17:40:47 2014 +0200 initial diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index f475458..d46b90d 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -10290,11 +10290,12 @@ table2-mapping /row row entry - literalrow_to_json(record [, pretty_bool])/literal + literalrow_to_json(record [, pretty_bool [, ignore_nulls] ])/literal /entry entry Returns the row as a JSON object. Line feeds will be added between - level-1 elements if parameterpretty_bool/parameter is true. + level-1 elements if parameterpretty_bool/parameter is true. Ignore + NULL when parameterignore_nulls/parameter is true. /entry entryliteralrow_to_json(row(1,'foo'))/literal/entry entryliteral{f1:1,f2:foo}/literal/entry diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c index 841dd1a..22e1dd6 100644 --- a/src/backend/utils/adt/json.c +++ b/src/backend/utils/adt/json.c @@ -77,7 +77,8 @@ static void report_invalid_token(JsonLexContext *lex); static int report_json_context(JsonLexContext *lex); static char *extract_mb_char(char *s); static void composite_to_json(Datum composite, StringInfo result, - bool use_line_feeds); + bool use_line_feeds, + bool ignore_nulls); static void array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, Datum *vals, bool *nulls, int *valcount, JsonTypeCategory tcategory, Oid outfuncoid, @@ -1355,7 +1356,7 @@ datum_to_json(Datum val, bool is_null, StringInfo result, array_to_json_internal(val, result, false); break; case JSONTYPE_COMPOSITE: - composite_to_json(val, result, false); + composite_to_json(val, result, false, false); break; case JSONTYPE_BOOL: outputstr = DatumGetBool(val) ? true : false; @@ -1560,7 +1561,8 @@ array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds) * Turn a composite / record into JSON. */ static void -composite_to_json(Datum composite, StringInfo result, bool use_line_feeds) +composite_to_json(Datum composite, StringInfo result, bool use_line_feeds, +bool ignore_nulls) { HeapTupleHeader td; Oid tupType; @@ -1599,6 +1601,12 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds) if (tupdesc-attrs[i]-attisdropped) continue; + val = heap_getattr(tuple, i + 1, tupdesc, isnull); + + /* Don't serialize NULL field when we don't want it */ + if (isnull ignore_nulls) + continue; + if (needsep) appendStringInfoString(result, sep); needsep = true; @@ -1607,8 +1615,6 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds) escape_json(result, attname); appendStringInfoChar(result, ':'); - val = heap_getattr(tuple, i + 1, tupdesc, isnull); - if (isnull) { tcategory = JSONTYPE_NULL; @@ -1700,7 +1706,7 @@ row_to_json(PG_FUNCTION_ARGS) result = makeStringInfo(); - composite_to_json(array, result, false); + composite_to_json(array, result, false, false); PG_RETURN_TEXT_P(cstring_to_text_with_len(result-data, result-len)); } @@ -1717,7 +1723,25 @@ row_to_json_pretty(PG_FUNCTION_ARGS) result = makeStringInfo(); - composite_to_json(array, result, use_line_feeds); + composite_to_json(array, result, use_line_feeds, false); + + PG_RETURN_TEXT_P(cstring_to_text_with_len(result-data, result-len)); +} + +/* + * SQL function row_to_json(row, prettybool, ignore_nulls) + */ +extern Datum +row_to_json_pretty_choosy(PG_FUNCTION_ARGS) +{ + Datum array = PG_GETARG_DATUM(0); + bool use_line_feeds = PG_GETARG_BOOL(1); + bool ignore_nulls = PG_GETARG_BOOL(2); + StringInfo result; + + result = makeStringInfo(); + + composite_to_json(array, result, use_line_feeds, ignore_nulls); PG_RETURN_TEXT_P(cstring_to_text_with_len(result-data, result-len)); } diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index
Re: [HACKERS] better atomics - v0.5
On 06/27/2014 08:15 PM, Robert Haas wrote: On Thu, Jun 26, 2014 at 3:04 PM, Andres Freund and...@2ndquadrant.com wrote: I don't really see usecases where it's not related data that's being touched, but: The point is that the fastpath (not using a spinlock) might touch the atomic variable, even while the slowpath has acquired the spinlock. So the slowpath can't just use non-atomic operations on the atomic variable. Imagine something like releasing a buffer pin while somebody else is doing something that requires holding the buffer header spinlock. If the atomic variable can be manipulated without the spinlock under *any* circumstances, then how is it a good idea to ever manipulate it with the spinlock? With the WALInsertLock scaling stuff in 9.4, there are now two variables protected by a spinlock: the current WAL insert location, and the prev pointer (CurrBytePos and PrevBytePos). To insert a new WAL record, you need to grab the spinlock to update both of them atomically. But to just read the WAL insert pointer, you could do an atomic read of CurrBytePos if the architecture supports it - now you have to grab the spinlock. Admittedly that's just an atomic read, not an atomic compare and exchange or fetch-and-add. Or if the architecture has an atomic 128-bit compare exchange op you could replace the spinlock with that. But it's not hard to imagine similar situations where you sometimes need to lock a larger data structure to modify it atomically, but sometimes you just need to modify part of it and an atomic op would suffice. I thought Andres' LWLock patch also did something like that. If the lock is not contended, you can acquire it with an atomic compare exchange to increment the exclusive/shared counter. But to manipulate the wait queue, you need the spinlock. - Heikki -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] ALTER SYSTEM RESET?
Re: Vik Fearing 2014-06-27 53ad15f7.2060...@dalibo.com On 06/27/2014 08:49 AM, Vik Fearing wrote: This third patch reformats the documentation in the way I expected it to be committed. Amit, I added this to the next commitfest with your name as reviewer. https://commitfest.postgresql.org/action/patch_view?id=1495 Please update the status as you see fit. Isn't this 9.4 material? It seems like an oversight in the ALTER SYSTEM implementation, and people will be expecting ALTER SYTEM (RE)SET guc to just work like (RE)SET guc. It was mentioned by Alvaro there: http://www.postgresql.org/message-id/20130802173458.go5...@eldon.alvh.no-ip.org Christoph -- c...@df7cb.de | http://www.df7cb.de/ -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] How about a proper TEMPORARY TABLESPACE?
Hi Hackers, I have worked on that patch a little more. So now I have functional patch (although still WIP) attached. The feature works as following: - Added a boolean parameter only_temp_files to pg_tablespace.spcoptions; - This parameter can be set to true only during CREATE TABLESPACE, not on ALTER TABLESPACE (I have thought of ways of implementing the latter, and I'd like to discuss it more latter); - On the creation of relations, it is checked if it is a temporary-tablespace, and an error occurs when it is and the relation is not temporary (temp table or index on a temp table); - When a temporary file (either relation file or sort/agg file) is created inside a temporary-tablespace, the entire directories structure is created on-demand (e.g. if pg_tblspc/oid/TABLESPACE_VERSION_DIRECTORY is missing, it is created on demand) it is done on OpenTemporaryFileInTablespace, at fd.c (I wonder if shouldn't we do that for any tablespace) and on TablespaceCreateDbspace, at tablespace.c. I still haven't change documentation, as I think I need some insights about the changes. I have some more thoughts about the syntax and I still think that TEMP LOCATION syntax is better suited for this patch. First because of the nature of the changes I made, it seems more suitable to a column on pg_tablespace rather than an option. Second because no ALTER is available (so far) and I think it is odd to have an option that can't be changed. Third, I think TEMP keyword is more clear and users can be more used to it. Thoughts? I'm going to add the CF app entry next. Could I get some review now or after discussion about how things are going (remember I'm a newbie on this, so I'm a little lost)? Regards, -- Matheus de Oliveira Analista de Banco de Dados Dextra Sistemas - MPS.Br nível F! www.dextra.com.br/postgres *** a/src/backend/access/common/reloptions.c --- b/src/backend/access/common/reloptions.c *** *** 71,76 static relopt_bool boolRelOpts[] = --- 71,84 }, { { + only_temp_files, + Allow only temporary files to be created on this tablespace, + RELOPT_KIND_TABLESPACE + }, + false + }, + { + { fastupdate, Enables \fast update\ feature for this GIN index, RELOPT_KIND_GIN *** *** 1337,1343 tablespace_reloptions(Datum reloptions, bool validate) int numoptions; static const relopt_parse_elt tab[] = { {random_page_cost, RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, random_page_cost)}, ! {seq_page_cost, RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, seq_page_cost)} }; options = parseRelOptions(reloptions, validate, RELOPT_KIND_TABLESPACE, --- 1345,1352 int numoptions; static const relopt_parse_elt tab[] = { {random_page_cost, RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, random_page_cost)}, ! {seq_page_cost, RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, seq_page_cost)}, ! {only_temp_files, RELOPT_TYPE_BOOL, offsetof(TableSpaceOpts, only_temp_files)} }; options = parseRelOptions(reloptions, validate, RELOPT_KIND_TABLESPACE, *** a/src/backend/commands/dbcommands.c --- b/src/backend/commands/dbcommands.c *** *** 394,399 createdb(const CreatedbStmt *stmt) --- 394,405 (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg(pg_global cannot be used as default tablespace))); + /* can't create a database on temporary tablespace */ + if (is_tablespace_temp_only(dst_deftablespace)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg(this tablespace only allows temporary files))); + /* * If we are trying to change the default tablespace of the template, * we require that the template not have any files in the new default *** *** 1083,1088 movedb(const char *dbname, const char *tblspcname) --- 1089,1100 (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg(pg_global cannot be used as default tablespace))); + /* can't create a database on temporary tablespace */ + if (is_tablespace_temp_only(dst_tblspcoid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg(this tablespace only allows temporary files))); + /* * No-op if same tablespace */ *** a/src/backend/commands/indexcmds.c --- b/src/backend/commands/indexcmds.c *** *** 432,437 DefineIndex(Oid relationId, --- 432,446 get_tablespace_name(tablespaceId)); } + /* Can't save relations on temporary tablespace */ + if (rel-rd_rel-relpersistence != RELPERSISTENCE_TEMP + is_tablespace_temp_only(OidIsValid(tablespaceId) ? tablespaceId : MyDatabaseTableSpace)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg(this tablespace only allows temporary files))); + } + /* * Force shared indexes into the pg_global tablespace. This is a bit of a * hack but seems simpler than marking them in the BKI commands. On the ***
Re: [HACKERS] proposal (9.5) : psql unicode border line styles
Hello rebase for 9.5 test: \pset linestyle unicode \pset border 2 \pset unicode_header_linestyle double \l Regards Pavel 2014-03-11 21:17 GMT+01:00 Pavel Stehule pavel.steh...@gmail.com: Hello I had to reduce allowed line style to single or double, because unicode allows only combination single,double or single,thick postgres=# \l List of databases Name| Owner | Encoding | Collate |Ctype| Access privileges ---+--+--+-+-+--- postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres + | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres + | | | | | postgres=CTc/postgres (3 rows) postgres=# \pset border 2 Border style (border) is 2. postgres=# \pset linestyle unicode Line style (linestyle) is unicode. postgres=# \l List of databases ┌───┬──┬──┬─┬─┬───┐ │ Name│ Owner │ Encoding │ Collate │Ctype│ Access privileges │ ├───┼──┼──┼─┼─┼───┤ │ postgres │ postgres │ UTF8 │ en_US.UTF-8 │ en_US.UTF-8 │ │ │ template0 │ postgres │ UTF8 │ en_US.UTF-8 │ en_US.UTF-8 │ =c/postgres ↵│ │ │ │ │ │ │ postgres=CTc/postgres │ │ template1 │ postgres │ UTF8 │ en_US.UTF-8 │ en_US.UTF-8 │ =c/postgres ↵│ │ │ │ │ │ │ postgres=CTc/postgres │ └───┴──┴──┴─┴─┴───┘ (3 rows) postgres=# \pset unicode_header_linestyle double Unicode border linestyle is double. postgres=# \l List of databases ┌───┬──┬──┬─┬─┬───┐ │ Name│ Owner │ Encoding │ Collate │Ctype│ Access privileges │ ╞═══╪══╪══╪═╪═╪═══╡ │ postgres │ postgres │ UTF8 │ en_US.UTF-8 │ en_US.UTF-8 │ │ │ template0 │ postgres │ UTF8 │ en_US.UTF-8 │ en_US.UTF-8 │ =c/postgres ↵│ │ │ │ │ │ │ postgres=CTc/postgres │ │ template1 │ postgres │ UTF8 │ en_US.UTF-8 │ en_US.UTF-8 │ =c/postgres ↵│ │ │ │ │ │ │ postgres=CTc/postgres │ └───┴──┴──┴─┴─┴───┘ (3 rows) postgres=# Regards Pavel 2014-03-07 19:24 GMT+01:00 Pavel Stehule pavel.steh...@gmail.com: Hello I am returning back to this topic. Last time I proposed styles: http://www.postgresql.org/message-id/cafj8prclgoktryjpbtoncpgyftrcz-zgfowdc1jqulb+ede...@mail.gmail.com http://postgres.cz/wiki/Pretty_borders_in_psql This experiment fails, but there are some interesting tips in discuss. So I propose little bit different proposal - choose one predefined style for any table lines elements. These styles are active only when linestyle is unicode. So possible line elements are: * border, * header_separator, * row_separator, * column_separator, Possible styles (for each element) * none, * single, * double, * thick, It should to have enough variability to define all styles proposed early. I hope, so this proposal is secure and simple for usage. Styles should be persistently saved in .psqlrc file - and some examples can be in documentation. Usage: \pset linestyle_border double \pset linestyle_header_separator single \pset linestyle_row_separator single \pset linestyle_column_separator single \pset linestyle unicode ╔═══╤╤═══╗ ║ a │ b │ c ║ ╟───┼┼───╢ ║ 1 │ 2012-05-24 │ Hello ║ ╟───┼┼───╢ ║ 2 │ 2012-05-25 │ Hello ║ ║ ││ World ║ ╚═══╧╧═══╝ (2 rows) Comments, ideas ? Regards Pavel commit 8f0918a42b095df6a8e5fc981a2947cc54b14404 Author: Pavel Stehule pavel.steh...@gooddata.com Date: Sat Jun 28 21:25:45 2014 +0200 rebase for 9.5 and clean warnings diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index ee6ec3a..671259f 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -2281,6 +2281,42 @@ lo_import 152801 /para /listitem /varlistentry + + varlistentry + termliteralunicode_border_style/literal/term +
Re: [HACKERS] Array of composite types returned from python
Am I missing anything, (ie memory leak, undesirable behavior elsewhere)? -Ed I applied the patch and it looks like it is working well. As a longtime plpython user, I appreciate the fix. I have a few comments: 1) I would remove the error message from the PO files as well. 2) You removed the comment: - /* -* We don't support arrays of row types yet, so the first argument -* can be NULL. -*/ But didn't change the code there. I haven't delved deep enough into the code yet to understand the full meaning, but the comment would indicate that if arrays of row types are supported, the first argument cannot be null. 3) This is such a simple change with no new infrastructure code (PLyObject_ToComposite already exists). Can you think of a reason why this wasn't done until now? Was it a simple miss or purposefully excluded? -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [Fwd: Re: [HACKERS] proposal: new long psql parameter --on-error-stop]
From: Pavel Stehule pavel.steh...@gmail.com I modified description of setting system variables in dependency on O.S. Thank you, it's almost OK. As mentioned in my previous mail, I think determines should be determine to follow other messages. I'll mark this patch as ready for committer when this is fixed. + printf(_( COMP_KEYWORD_CASE determines which letter case to use when completing an SQL key word\n)); Personally, I don't think we have to describe how to set environment variables, because it's preliminary knowledge and not specific to PostgreSQL. However, I don't mind if you retain or remove the description. Regards MauMau -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
Re: [HACKERS] ALTER SYSTEM RESET?
On Sat, Jun 28, 2014 at 10:38 PM, Christoph Berg c...@df7cb.de wrote: Re: Vik Fearing 2014-06-27 53ad15f7.2060...@dalibo.com Amit, I added this to the next commitfest with your name as reviewer. https://commitfest.postgresql.org/action/patch_view?id=1495 Please update the status as you see fit. Isn't this 9.4 material? I think it's late for adding new feature/sub-feature/minor enhancement in 9.4, unless without that base feature won't work. Isn't your use case addressed by alternative suggested by me upthread? With Regards, Amit Kapila. EnterpriseDB: http://www.enterprisedb.com