Shared posts

18 May 23:03

O que fazer quando descubro que agi errado?

by noreply@blogger.com (Mario Persona)


https://youtu.be/0chXnqsBkLc

Volte ao ponto em que se desviou e procure se humilhar reconhecendo seu engano. Muitas vezes na vida somos obrigados a fazer isso se quisermos recuperar nossa comunhão com Deus e voltar a dar um testemunho coerente com a fé que professamos. Às vezes teremos de engolir ofensas, baixar a cabeça e deixar o Senhor nos restaurar do jeito dele, e eventualmente tratar com aqueles que podem ter até contribuído para nossa queda.

Esta passagem de 2 Reis sempre me foi de ajuda em momentos assim:

"E disseram os filhos dos profetas a Eliseu: Eis que o lugar em que habitamos diante da tua face, nos é estreito. Vamos, pois, até ao Jordão e tomemos de lá, cada um de nós, uma viga, e façamo-nos ali um lugar para habitar. E disse ele: Ide. E disse um: Serve-te de ires com os teus servos. E disse: Eu irei. E foi com eles; e, chegando eles ao Jordão, cortaram madeira. E sucedeu que, derrubando um deles uma viga, o ferro caiu na água; e clamou, e disse: Ai, meu senhor! ele era emprestado. E disse o homem de Deus: Onde caiu? E mostrando-lhe ele o lugar, cortou um pau, e o lançou ali, e fez flutuar o ferro. E disse: Levanta-o. Então ele estendeu a sua mão e o tomou." 2 Reis 6:1-7

Os "filhos dos profetas" aparentemente não estavam satisfeitos com o que tinham recebido de Deus. Esses deviam ser discípulos que seguiam e auxiliavam um profeta em suas necessidades, aprendendo a extrair do profeta o máximo de ensino que pudessem, como era o caso aqui com Eliseu. Mas havia neste um sentimento de insatisfação que os levou a desejar um lugar mais amplo.

Podemos às vezes ficar insatisfeitos com as limitações que o Senhor permitiu e querer buscar mais espaço, maior liberdade do que aquela que o Senhor nos concedeu. Você nunca desejou se livrar de pessoas e problemas que o cercam onde você está, seja em casa, no trabalho, na escola ou entre os irmãos? Eu também. É o desejo de um espaço mais amplo, como o de querer esticar os braços para os lados viajando horas em um carro pequeno.

Mas o que os "filhos dos profetas" não sabiam era que seriam incapazes de conseguir tal façanha, pois de si mesmos nada possuíam. Se tinham alguma coisa ou reputação era graças ao profeta que eles acompanhavam. Eliseu deixa que eles façam sua própria vontade e até vai junto com eles, como um pai que deseja ver até onde seu filho consegue chegar em sua busca por independência.

Você já deve ter feito isso quando seu filho pequeno teimou que iria conseguir pedalar sem as rodinhas de apoio. Você correu ao lado pronto para ampará-lo em seu tombo. E o tombo dos filhos dos profetas foi quando eles deixaram cair o machado emprestado num rio e ficaram desesperados. Correram pedir a ajuda do profeta.

O profeta pergunta: "Onde foi que caiu?". Eles são obrigados a admitir que o que tinham nem deles era, mas emprestado, e precisam voltar até onde perderam o ferro do machado, do mesmo modo como José e Maria foram obrigados um dia a voltarem até o lugar onde tinha perdido o menino Jesus. Levaram um dia para perder e três dias para reencontrar.

"E, tendo ele já doze anos, subiram a Jerusalém, segundo o costume do dia da festa. E, regressando eles, terminados aqueles dias, ficou o menino Jesus em Jerusalém, e não o soube José, nem sua mãe. Pensando, porém, eles que viria de companhia pelo caminho, andaram caminho de um dia, e procuravam-no entre os parentes e conhecidos; e, como o não encontrassem, voltaram a Jerusalém em busca dele. E aconteceu que, passados três dias, o acharam no templo, assentado no meio dos doutores, ouvindo-os, e interrogando-os." (Lc 2:42-46).

Um dia para perder e três para reencontrar. O reencontro é sempre mais demorado e custoso que a perda. Os filhos dos profetas levam Eliseu até o lugar onde tinham perdido o ferro do machado, ou seja, voltam ao ponto onde havia ocorrido o problema. Ali o profeta joga um pedaço de pau — um madeiro — na água, e o ferro do machado flutua. Aquilo era uma figura de Cristo, da aplicação da cruz de Cristo a uma situação de erro para sermos restaurados.

Devemos voltar ao problema, ao ponto onde nos desviamos por nos sentirmos confiantes de carregar nas mãos uma verdade que nem era nossa, mas emprestada. E depois de voltar a esse ponto em que perdemos a verdade emprestada, a solução é aplicar o madeiro, a cruz de Cristo, à situação. A cruz nos fala de humilhação e morte, e só conseguimos enxergar uma situação quando deixamos morrer nosso ego. Só então estamos prontos a ser restaurados.

por Mario Persona

Mario Persona é palestrante e consultor de comunicação, marketing e desenvolvimento profissional (www.mariopersona.com.br). Não possui formação ou título eclesiástico e nem está ligado a alguma denominação religiosa, estando congregado desde 1981 somente ao Nome do Senhor Jesus. Esta mensagem originalmente não contém propaganda. Alguns sistemas de envio de email ou RSS costumam adicionar mensagens publicitárias que podem não expressar a opinião do autor.)
16 May 21:09

Passei de fase

by noreply@blogger.com (Mario Persona)
Seria o aquecimento global que causava em mim aquela sensação de derretimento? Ou seria a redução do oxigênio no ar que me deixava tonto? Quem sabe eu deveria culpar a poluição da água pelos pés pesados, o pensamento distante e o olhar vidrado... Ou talvez aquela sensação fosse normal para quem acabava de se tornar avô?



Existe um ritual de passagem quando a gente se torna pai. É uma experiência que deixa você completamente bobo, como eu fiquei quando deixei minha esposa em uma maternidade de Brasília para ter nossa primeira filha e saí dirigindo pela cidade em plena madrugada. Vaguei quase uma hora pelas ruas e avenidas até perceber que não sabia o que estava fazendo. Eu deveria estar no hospital, aguardando o parto, ao invés de ter deixado minha esposa lá como quem deixa a filha na escola e vai para o trabalho.

Comprei uma maçã verde em uma banca de rua, a única coisa aberta àquela hora da madrugada, e voltei ao hospital com a desculpa de que tinha ido comprar uma fruta para ela.

Quase trinta anos se passaram desde o primeiro parto e eu voltava a experimentar esse passar de fase no game da vida. Minha filha, que nasceu em minha fase macrobiótica de bicho-grilo-avesso-a-tecnologia, havia dado à luz um garotão nos EUA — meu primeiro neto — a sete mil quilômetros daqui, mas eu podia ver e escutar seu choro quase diariamente via Skype. Na parte do choro, os sete mil quilômetros até que eram uma vantagem.

Quantas fases eu passei para chegar aqui? Não foram poucas. Quem passa dos quarenta — e eu já passei dos sessenta — deve saber que nada será como antes, e a visão da vida também deve mudar. Até certa idade você corre atrás de dinheiro, sucesso e poder, qualquer que seja sua carreira. Seu relógio anda pra frente. Então, um belo dia, você entra em modo de contagem regressiva. Aí é hora de olhar menos para o cifrão e mais para o significado da vida. E um neto ajuda demais nessa mudança de fase.

É claro que nem todos pensam assim. Muitos preferem mentir o processo natural da vida, numa desesperada tentativa de negar as mudanças de fase. Tinge aqui, estica ali, suga acolá, tentando recuperar os anos perdidos criando filhos, aturando o cônjuge e trabalhando sem parar. Mas, será que foram mesmo perdidos? Se fizer um balanço vai descobrir um saldo positivo. O melhor mesmo é aceitar o processo. Sem completar uma fase você não entra na seguinte.

Existe algo de belo na estação da vida chamada envelhecer. Ou será que você precisa provar que é tão forte, ágil e capaz quanto um adolescente? Eu, particularmente, prefiro observar a natureza dando livre curso ao seu processo. Acho que nada se compara à profusão de cores das folhas de outono no hemisfério norte. Sim, elas estão caindo, mas caem belas para dar lugar às mais novas.

Depois de ter tido filhos e plantado árvores, o seu vigor estará mais para escrever livros ou simplesmente narrar suas histórias ao lado do berço das novas gerações. Elas necessitam desse conhecimento transformado em sabedoria e envelhecido em tonéis de experiência. Isto se a sua meta na vida não for dirigir um carro vermelho, tomar pílulas azuis e ser o tiozão das baladas adolescentes.

Passar de fase é algo que deve ser acalentado, sorvido sem sofreguidão, como fazemos com vinhos caros. Afinal, para que a pressa quando se passou da metade do jogo? Passar de fase é coisa para ser anunciada com orgulho e paixão. Como contou um escritor na entrevista que ouvi no rádio do carro.

Acho que foi Ignácio Loyola Brandão, não tenho certeza. O que recordo bem foi que contou da palestra que fez para 400 pessoas. Antes de iniciar, pediu licença à plateia para manter seu celular ligado, pois esperava uma ligação importante. Na metade da palestra o celular tocou. Ele atendeu, desligou e, voltando-se para a plateia, curiosa por saber que assunto poderia ser mais importante do que sua palestra naquele momento. Então ele anunciou, com voz embargada:

— Meu neto nasceu!

Pela primeira vez na história 400 pessoas aplaudiram de pé a interrupção de uma palestra por um celular.


Mario Persona é palestrante de comunicação, marketing e desenvolvimento profissional. Seus serviços, livros, textos e entrevistas podem ser encontrados em www.mariopersona.com.br

© Mario Persona  - Quer publicar Mario Persona CAFE em seu blog? Não se esqueça de colocar um link apontando para www.mariopersona.com.br .
11 May 21:37

David Rader: Copy Records in Batches with Postgresql

When you want to copy all the records from one table to another – for example, to change the data model or my favorite migrate data from a foreign table to a local PostgreSQL, you want to use multiple batches to avoid a long running transaction or the need to restart from the beginning in case of failure. This is a common challenge if you are copying data from one server to another (for example PROD to dev) or migrating data from another database (like Oracle or MySQL) to Postgres via an FDW.

Common Table Expressions (CTE’s) and a small amount of pl/pgSQL make it easy to code up a loop that will grab a batch of records, start after the maximum id and keep copying.

Setup some sample data

Let’s create a couple sample tables and fill the source with a few sample records:

CREATE TABLE my_source (id int, field1 int, field2 varchar(50));
CREATE TABLE my_dest (id int, field1 int, field2 varchar(50));
INSERT INTO my_source (SELECT generate_series(1, 4000, 1), generate_series(2,8000,2), 'some made up text');
select * from my_source limit 5;
 id | field1 |      field2       
----+--------+-------------------
  1 |      2 | some made up text
  2 |      4 | some made up text
  3 |      6 | some made up text
  4 |      8 | some made up text
  5 |     10 | some made up text
(5 rows)

Simple SQL Statement

The naive approach to copy over from source to dest is to just use a single SQL statement to INSERT INTO … SELECT like this:

INSERT INTO my_dest SELECT id, field1, field2 from my_source; 
INSERT 0 4000 

Works fine on this small sample data, but not for the 100 million row Oracle table that you’re trying to copy over the network with a few data transformations in the middle. It is better to copy the records over in batches so that you can commit every few thousand or million records based on the size of your server and tables.

Better with Batches

Same sample tables. Start fresh for the example:

TRUNCATE TABLE my_dest;
TRUNCATE TABLE

Now, use a CTE that inserts a batch of 100 records and select the max(ID) to use for the next batch. Loop gently:

DO LANGUAGE plpgsql $$
DECLARE max_id INTEGER = 0;
BEGIN
    WHILE max_id > -1 LOOP
        WITH insertrows AS (
          INSERT INTO my_dest
          SELECT * from my_source
          WHERE id > max_id
          LIMIT 100
          RETURNING id
        )
        SELECT max(id) INTO max_id from insertrows;
        RAISE NOTICE '%', max_id;
    END LOOP;
END$$;
NOTICE:  100
NOTICE:  200
NOTICE:  300
...
NOTICE:  3900
NOTICE:  4000
NOTICE:  <NULL>
DO

Notes and Caveats

Getting the max_id and filtering the next batch is much better than using a fixed number of rows and trying to use OFFSET to skip to the next batch. OFFSET actually requires the database to retrieve and count the rows it is skipping rather than just “jumping” ahead.

The batching works best with a unique primary key as the field to filter on, since you know there are not duplicates and there is already an index available. If you are batching on some other field, make sure there is an index otherwise the filter will do a sequence scan on the source and be slower than you want.

If this process fails partway through, you will need to query the max(id) from the destination table to figure out where to restart from. If you expect failures (remote network link, etc), or if you want to show progress during a long run, you may want to store the max_id value to a table.

Don’t leave that Raise Notice in for your production code 🙂

Happy Batching!

10 May 17:50

As reunioes devem ser publicas ou reservadas?

by noreply@blogger.com (Mario Persona)


https://youtu.be/Mlg2ihmnEgs

Você perguntou se quando os irmãos estão reunidos em assembleia ou igreja (que é sinônimo), esss reuniões podem ser em salões abertos para a rua ou devem ser reservadas. Encontramos alguns princípios na Bíblia que pode nos dar uma direção, começando com os evangelhos, que são anteriores a formação da Igreja na terra.

O Senhor Jesus, quando ainda estava aqui, pediu aos seus discípulos que preparassem a Páscoa, que era uma festa do judaísmo que comemorava a libertação dos israelitas da escravidão do Egito. Mas a intenção do Senhor não estava em apenas celebrar a Páscoa, mas também instituir a ceia que seria depois revelada ao apóstolo Paulo como o ponto alto da celebração cristã. Em 1 Coríntios 11 o apóstolo conta como havia recebido do próprio Senhor, e não de algum outro apóstolo, essa instituição.

Mas voltando aos evangelhos, quando o Senhor pediu aos discípulos para prepararem a Páscoa, eles fizeram a pergunta que todo cristão deveria fazer quando pensa em congregar, e vale a pena transcrever a passagem toda aqui:

"E mandou a Pedro e a João, dizendo: Ide, preparai-nos a páscoa, para que a comamos. E eles lhe perguntaram: Onde queres que a preparemos? E ele lhes disse: Eis que, quando entrardes na cidade, encontrareis um homem, levando um cântaro de água; segui-o até à casa em que ele entrar. E direis ao pai de família da casa: O Mestre te diz: Onde está o aposento em que hei de comer a páscoa com os meus discípulos? Então ele vos mostrará um grande cenáculo mobilado; aí fazei preparativos. E, indo eles, acharam como lhes havia sido dito; e prepararam a páscoa. E, chegada a hora, pôs-se à mesa, e com ele os doze apóstolos." (Lc 22:8-14).

O Senhor deu instruções para que eles preparassem tudo em um cenáculo, que era o andar superior de uma casa. Não era para fazer aquilo ao nível da rua, mas em um lugar mais reservado porque não seria um evento aberto a todos, mas apenas a alguns poucos convidados. Vemos a mesma coisa acontecer em Atos 1:13, quando os discípulos se reuniram, não ainda como igreja, mas como discípulos judeus do Messias:

"E, entrando, subiram ao cenáculo, onde habitavam Pedro e Tiago, João e André, Filipe e Tomé, Bartolomeu e Mateus, Tiago, filho de Alfeu, Simão, o Zelote, e Judas, irmão de Tiago. Todos estes perseveravam unanimemente em oração e súplicas, com as mulheres, e Maria mãe de Jesus, e com seus irmãos." (At 1:13-14). Na versão Almeida Revista e Atualizada está assim: "Quando ali entraram, subiram para o cenáculo onde se reuniam Pedro, João, Tiago, etc.".

Todos estavam reunidos nesse mesmo cenáculo quando foi formada a Igreja com a descida do Espírito Santo que passaria a habitar em cada crente: "E, cumprindo-se o dia de Pentecostes, estavam todos concordemente no mesmo lugar; e de repente veio do céu um som, como de um vento veemente e impetuoso, e encheu toda a casa em que estavam assentados." (At 2:1-2).

Algum tempo depois já como igreja, nós os vemos também congregados no primeiro dia da semana, o domingo, para celebrar a ceia do Senhor em um cenáculo, ou seja, num andar superior de uma casa. "E no primeiro dia da semana, ajuntando-se os discípulos para partir o pão, Paulo, que havia de partir no dia seguinte, falava com eles; e prolongou a prática até à meia-noite. E havia muitas luzes no cenáculo onde estavam juntos." (At 20:7-8).

Não existe nenhuma ordenança no sentido de termos de congregar em um andar superior, mas estes exemplos bastam para a mente espiritual perceber que Deus pede algum grau de separação com o rés do chão. As reuniões da igreja são para a igreja, não para estranhos, portanto não devemos escolher um local que possa parecer uma vitrine para o mundo. Evidentemente incrédulos podem ter acesso ao local de reuniões dos irmãos, mas não um acesso escancarado de forma convidativa para todos participarem.

As reuniões da igreja são para os salvos, não para os perdidos, mesmo porque as atividades principais dessas reuniões são o ministério da Palavra para crentes, a ceia do Senhor e as orações. Ao menos era assim que os primeiros cristãos se reuniam. "E perseveravam na doutrina dos apóstolos, e na comunhão, e no partir do pão, e nas orações." (At 2:42). Nem preciso dizer que não se trata de uma reunião evangelística destinada a convidar pecadores para crerem em Cristo, embora algum incrédulo que entre ali poderá eventualmente ouvir o evangelho em meio ao ministério da Palavra para crentes.

Volto a insistir que, como irmãos salvos por Cristo, não estamos reunidos para o mundo, mas para o nome de Jesus. Não há nada de errado se os irmãos se reunirem a portas fechadas em locais onde exista o risco de entrar estranhos que causem distúrbios ou tirem a atenção daqueles que estão ali para o Senhor, não para o mundo e nem para os incrédulos.

Hoje existe tecnologia que permite manter portas fechadas e ter câmeras que permitam abri-las apenas a conhecidos, e quem congrega em locais com risco de assaltos ou em zonas de guerra sabe como algo assim pode ser útil. Os irmãos que congregam em casas no Egito costumam combinar a chegada separados e um de cada vez para não levantar suspeitas de radicais islâmicos. Lá até os templos de denominações cristãs (apenas as antigas, porque as novas são proibidas de se estabelecer) costumam ter guardas armados na porta.

Nada disso que estou dizendo aqui tem a ver com evangelismo, pois suponho que você saiba a diferença entre congregar e pregar o evangelho. A pregação do evangelho é uma atividade de responsabilidade de quem evangeliza, não da igreja. A pregação do evangelho deve ser pública, mas as atividades da igreja são destinadas a crentes somente. Onde congrego usamos um salão e visitantes podem entrar e assistir as reuniões. Mas depois da ceia do Senhor, quando temos assuntos sensíveis a tratar, como algum caso de disciplina ou excomunhão, pedimos que os visitantes saiam e fiquem somente os irmãos em comunhão.

http://www.respondi.com.br/2010/03/igreja-nao-evangeliza.html

por Mario Persona

Mario Persona é palestrante e consultor de comunicação, marketing e desenvolvimento profissional (www.mariopersona.com.br). Não possui formação ou título eclesiástico e nem está ligado a alguma denominação religiosa, estando congregado desde 1981 somente ao Nome do Senhor Jesus. Esta mensagem originalmente não contém propaganda. Alguns sistemas de envio de email ou RSS costumam adicionar mensagens publicitárias que podem não expressar a opinião do autor.)
08 May 21:12

Interview: Encrypted email must be easy too

by Tresorit

Secure cloud storage services like Tresorit help your company to share confidential business documents securely. But how can you also protect your internal email communication without overcomplicating it for your staff? We spoke about this with Arne Möhle, co-founder of the encrypted email provider Tutanota – via email, of course.

When was the first time you thought: ‘I’d rather not send this via email’?

In one of my previous jobs, we wanted to exchange highly sensitive project data with a client. Installing PGP was not feasible due to the tedious effort of doing so and its lack of compatibility. Back then, password-encrypted archives helped us, but even they weren’t the most convenient solution, since we were only able to encrypt the actual attachments, but not the content of the email itself.

Are there any better solutions now?

Tutanota, of course. 🙂 We apply end-to-end-encryption to everything, fully automatically. A lot of the time, this is biggest problem with most encrypted email solutions: the user has to do all the work – generating the key, sharing the key, etc. Most people shy away from this hassle. It is too complicated, and even if you understand the system, errors can creep in, e.g. when the wrong keys are being applied. Therefore it is so important for encrypted apps to automate these processes so that the user doesn’t need to worry about anything and also can’t make any mistakes.

The use of end-to-end-encryption is now quite common, especially on messenger services. How come that encrypted communication has been adapted in consumer apps before business solutions?

Because messenger services make it easy. End-to-end-encryption is a default feature for these services. The consumer uses it without being aware of it. And this is precisely how encrypted email apps should work.

Why is encryption also important for business emails?

It isn’t just important, it is critical! Employees handle confidential data on a daily basis: clients’ personal information, offers, acquisition projects. R&D is not the only department dealing with data that needs to be protected. This is why it is of utmost importance for businesses that all employees communicate in an end-to-end-encrypted form, especially internally. This is the only way to ensure that nobody can interfere with emails and search them for key words. Unfortunately, this is easier to do than most companies like to believe.

What should entrepreneurs bear in mind when switching to encrypted email? What are the obstacles?

They must make sure it is easy to apply. If it is too complicated, their employees won’t use it. In the worst-case scenario, they will switch to using their private email account with Gmail or Yahoo, which could be disastrous for the company.

What can businesses do to protect their other data?

Of course, there are many other areas of business communication that must be protected. Telephoning, messaging, cloud storage, mobile devices, etc. need to be considered in the IT security concept to the same extent as emails.

In the last few years, more and more European encrypted services entered the market – how come?

By now everyone knows that it was easy enough for the NSA to gather data from American providers. And who can guarantee the businesses that the secret services are not involved in industry espionage?

Europe is a great location for privacy-oriented online services. Data protection requirements are very high, and it is even obligatory for businesses to protect their clients’ data. This is why many companies choose a European provider – preferably one that applies data end-to-end-encryption. It is the only way to ensure that nobody apart from the user can access the data. And it is thus the only way for businesses to be sure that nobody is spying on them.

This is what makes solutions like Tutanota or Tresorit attractive for businesses: they enable companies to take advantage of the cloud without giving up their data sovereignty.

 

 

Arne Möhle on encrypted email About Arne Möhle:
Arne Möhle is one of the founders and a developer at Tutanota, the end-to-end-encrypted mailbox for businesses and individuals. He writes code to end mass surveillance and industry espionage – by automatically encrypting all emails. He regularly writes about data protection and encryption on the Tutanota-Blog – https://tutanota.com/.

 

The post Interview: Encrypted email must be easy too appeared first on Tresorit Blog.

06 May 00:21

Peter Eisentraut: PostgreSQL 10 identity columns explained

For PostgreSQL 10, I have worked on a feature called “identity columns”. Depesz already wrote a blog post about it and showed that it works pretty much like serial columns:

CREATE TABLE test_old (
    id serial PRIMARY KEY,
    payload text
);

INSERT INTO test_old (payload) VALUES ('a'), ('b'), ('c') RETURNING *;

and

CREATE TABLE test_new (
    id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    payload text
);

INSERT INTO test_new (payload) VALUES ('a'), ('b'), ('c') RETURNING *;

do pretty much the same thing, except that the new way is more verbose. ;-)

So why bother?

Compatibility

The new syntax conforms to the SQL standard. Creating auto-incrementing columns has been a notorious area of incompatibility between different SQL implementations. Some have lately been adopting the standard SQL syntax, however. So now you can move code around between, for example, PostgreSQL, DB2, and Oracle without any change (in this area).

Permissions

A general problem with the old way is that the system doesn’t actually remember that the user typed serial. It expands this at parse time into something like

CREATE SEQUENCE test_old_id_seq;

CREATE TABLE test_old (
    id int NOT NULL PRIMARY KEY,
    payload text
);

ALTER TABLE test_old
    ALTER COLUMN id SET DEFAULT nextval('test_old_id_seq');

ALTER SEQUENCE test_old_id_seq OWNED BY test_old.id;

The OWNED BY in the last command is an attempt to remember something about the serialness, but it is still insufficient in some cases.

The new way creates the sequence as a proper internal dependency of the table, so that various weird implementation details of the serial pseudotype are not exposed.

One common problem is that permissions for the sequence created by a serial column need to be managed separately:

CREATE USER foo;
GRANT INSERT ON test_old TO foo;
GRANT INSERT ON test_new TO foo;

SET SESSION AUTHORIZATION foo;

INSERT INTO test_old (payload) VALUES ('d');
ERROR:  permission denied for sequence test_old_id_seq

INSERT INTO test_new (payload) VALUES ('d');
-- OK

You can fix the error by also running

GRANT USAGE ON SEQUENCE test_old_id_seq;

If you have deployment scripts, this is annoying and problematic, because the name of the sequence is automatically generated. Here, of course, it appears in the error message, and it is easy to guess, but sometimes a slightly different name is chosen, and then your deployment scripts will fail.

Managing sequences

You also need to know the name of the sequence if you want to make some changes to the sequence:

ALTER SEQUENCE test_old_id_seq RESTART WITH 1000;

With an identity column, you don’t need to know the name of the sequence:

ALTER TABLE test_new ALTER COLUMN id RESTART WITH 1000;

Schema management

Since serial is not a real type, it can only be used in certain circumstances. You can specify serial as a column type when creating a table or when adding a column. But dropping serialness from an existing column or adding it to an existing column is not straightforward.

To drop serialness, you can drop the sequence (again, after ascertaining the name) with the CASCADE option, which cascades to remove the default value of the associated column:

DROP SEQUENCE test_old_id_seq CASCADE;

If you instead drop the default value like

ALTER TABLE test_old ALTER COLUMN id DROP DEFAULT;

it will drop the default but leave the sequence in place.

If you want to take an existing integer column and turn it into a serial column, there is no single command to do that. You will have to manually assemble the CREATE SEQUENCE and ALTER TABLE ... SET DEFAULT commands shown earlier.

Dropping the identity property of an existing column is easy:

ALTER TABLE test_new ALTER COLUMN id DROP IDENTITY;

You cannot accidentally make a mistake and drop a default, because there is none. But just in case, you get a nice error message:

=> ALTER TABLE test_new ALTER COLUMN id DROP DEFAULT;
ERROR:  column "id" of relation "test_new" is an identity column
HINT:  Use ALTER TABLE ... ALTER COLUMN ... DROP IDENTITY instead.

You can also turn an existing integer column into an identity column with one command:

ALTER TABLE test_new
    ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY;

Copying table structures

If you use the CREATE TABLE / LIKE functionality to copy the structure of a table, serial columns pose a problem:

CREATE TABLE test_old2 (LIKE test_old INCLUDING ALL);
INSERT INTO test_old2 (payload) VALUES ('e') RETURNING *;
 id | payload
----+---------
  4 | e

Note that even though the new table is a separate table, it keeps using the old sequence.

This gets even more confusing when you want to drop the first table:

=> DROP TABLE test_old;
ERROR:  cannot drop table test_old because other objects depend on it
DETAIL:  default for table test_old2 column id depends on sequence test_old_id_seq
HINT:  Use DROP ... CASCADE to drop the dependent objects too.

(You can use CASCADE as hinted, or drop test_old2 first. The latter works without CASCADE because the sequence is still linked to the first table.)

When you copy a table with an identity column in this way, you get a new sequence:

CREATE TABLE test_new2 (LIKE test_new INCLUDING ALL);
INSERT INTO test_new2 (payload) VALUES ('e') RETURNING *;
 id | payload
----+---------
  1 | e

Upgrading

Perhaps you are convinced and you want to “upgrade” all your messy serial columns to this new identity column thing. (Note that you don’t have to “upgrade”. You can keep using serial columns the same way as before.) Here is a PL/pgSQL function that you can use:

CREATE OR REPLACE FUNCTION upgrade_serial_to_identity(tbl regclass, col name)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
  colnum smallint;
  seqid oid;
  count int;
BEGIN
  -- find column number
  SELECT attnum INTO colnum FROM pg_attribute WHERE attrelid = tbl AND attname = col;
  IF NOT FOUND THEN
    RAISE EXCEPTION 'column does not exist';
  END IF;

  -- find sequence
  SELECT INTO seqid objid
    FROM pg_depend
    WHERE (refclassid, refobjid, refobjsubid) = ('pg_class'::regclass, tbl, colnum)
      AND classid = 'pg_class'::regclass AND objsubid = 0
      AND deptype = 'a';

  GET DIAGNOSTICS count = ROW_COUNT;
  IF count < 1 THEN
    RAISE EXCEPTION 'no linked sequence found';
  ELSIF count > 1 THEN
    RAISE EXCEPTION 'more than one linked sequence found';
  END IF;  

  -- drop the default
  EXECUTE 'ALTER TABLE ' || tbl || ' ALTER COLUMN ' || quote_ident(col) || ' DROP DEFAULT';

  -- change the dependency between column and sequence to internal
  UPDATE pg_depend
    SET deptype = 'i'
    WHERE (classid, objid, objsubid) = ('pg_class'::regclass, seqid, 0)
      AND deptype = 'a';

  -- mark the column as identity column
  UPDATE pg_attribute
    SET attidentity = 'd'
    WHERE attrelid = tbl
      AND attname = col;
END;
$$;

Call it like this:

SELECT upgrade_serial_to_identity('test_old', 'id');

If you are using schemas, it would look like this:

SELECT upgrade_serial_to_identity('public.test_old', 'id');

Check your table definition before and after:

=> \d test_old
                             Table "public.test_old"
 Column  |  Type   | Collation | Nullable |               Default
---------+---------+-----------+----------+--------------------------------------
 id      | integer |           | not null | nextval('test_old_id_seq'::regclass)
 payload | text    |           |          |
=> \d test_old
                           Table "public.test_old"
 Column  |  Type   | Collation | Nullable |             Default
---------+---------+-----------+----------+----------------------------------
 id      | integer |           | not null | generated by default as identity
 payload | text    |           |          |

Further reading

More information can be found in the PostgreSQL documentation, starting from the CREATE TABLE reference page.

28 Apr 18:53

How A Grumpy Programmer Secures Their Laptop

On the /dev/hell podcast episode I recorded with Ed last night, I got the chance to talk at length about my early experiences with my new laptop. According the 'About This Mac':

  • MacBook Pro (13-inch, 2016, Four Thunderbolt 3 Ports)
  • Processor 2.9 GHz Inetl Core i5
  • Memory 16 GB 2133 MHz LPDDR3
  • Startup Disk Macintosh HD
  • Graphics Intel Iris Graphics 550 1536 MB
  • Pretentious Level High

Thanks to a focus by Apple on People Not Like Me, I was able to get up and running really quickly on my new laptop. The Migration Assistant worked perfectly except for not copying over some saved game files for a Steam game that I play quite a bit (Football Manager 2016). Especially when I have a setup that requires the use of SSH keys and applications all configured to my liking, this was awesome.

My next thought turned to security. Clearly we are in a era where attempts to access people's computers is on the rise. Not that I am thinking I am the target of a shady cabal of l33t hax0rs being paid by shadowy security forces of governments that don't like my politics, but I want to at least make them work a bit. So I want to share what I decided to do.

I've been using FileVault for a long time (in fact, it was a requirement for me if I wished to use my own equipment while working for Mozilla).

After that, you have all sorts of options. After seeing a Tweet from someone mentioning a bunch of tools that can help increase the security of your laptop I decided to take the plunge.

First, I installed Little Snitch. It monitors all my network connections and provides me with a bunch of options to allow or deny the connection, forever or just for a limited time. Starting with this tool I had to (and still are, to a minor extent) acknowledge and decide what to do about a ridiculous number of connection attempts by all sorts of programs. For the older crowd, I feel like I am playing some new version of Everquest. So. Much. Furious. Clicking.

Not content to develop repetitive stress injuries to my right hand, I installed Little Flocker. It's a good complement to Little Snitch -- it watches for any interactions with files, looks for keystroke loggers, and checks for malware. More. Clicking.

Next up was to install Micro Snitch to tell me any time my webcamera and microphones were being used. More alerts to acknowledge but at least my microphone only turns on when I need it to. So far.

Finally I installed BlockBlock to let me know if something keeps trying to install malware in known locations. Just another layer of security for someone to overcome. They clearly indicate that the application is in beta, so keep that in mind.

With those apps installed and running and configured, I massaged my very sore wrist and started reading this awesome document at the suggestion of a kind soul on Twitter. Lots of great stuff in there that you can do and raises interesting points about deciding what type of threats you are looking to protect yourself from. Here's a list of the advice from it that I followed:

  • patch everything when updates are available
  • frequent system backups (shoutout to Backblaze)
  • full-volume encryption
  • third-party firewalls
  • Disable Spotlight Suggestions
  • Use Homebrew
  • use dnsmasq, DNSSEC and dnscrypt
  • turn off captive portal
  • use Privoxy as a local web proxy

I plan on implementing some of the other recommendations, but that's what I started with. For Mac users, please read through that document. So much good stuff along with explanations of why you should do it.

Hope that helps!

25 Apr 21:11

Usando a API da TotalVoice para enviar SMS em PHP

by Elton Minetto

Imagine a situação: você está no conforto da sua casa (ou no conforto do seu pub favorito) e algo importante acontece em seu site/produto/projeto. Algo como um erro no banco de dados ou um cliente que acaba de fazer uma compra de vários dígitos.

Em ambos os exemplos seria bem útil você receber algum tipo de aviso sobre o ocorrido, seja para resolver o problema ou para pagar uma nova rodada de cerveja no segundo caso.

Uma forma rápida de realizar isso é enviando um SMS para o responsável no momento que o evento ocorreu. Uma das formas mais simples de realizar isso é usar uma API, como a fornecida pelos meus amigos da TotalVoice.

A TotalVoice é uma startup de Santa Catarina e que está recebendo destaque no mercado. A API deles é bem fácil de entender e eles têm um exemplo de uso em PHP, no Github. Mas fica aqui a sugestão para a equipe da TotalVoice: o exemplo oficial é bem “old school”, então, fiz uma pesquisa no Packagist e encontrei um repositório extra-oficial, que tem uma versão mais “moderna”.

O primeiro passo é criar uma conta no site, colocar alguns reais em créditos e pegar o seu token de acesso para a API.

Para começar a testar sem tirar o escorpião do bolso, você pode enviar um e-mail para “sucesso@totalvoice.com.br”, informando sua conta e solicitando um crédito bônus de R$ 5,00.

Com essa informação basta instalar o pacote usando:

php composer.phar require minerva-framework/totalvoice-api

E criar um código similar a este:

<?php 

require 'vendor/autoload.php'; 

use Minerva\TotalVoice\TotalVoice; 
use Minerva\TotalVoice\SMS\SMS; 


$sms = new SMS(); 
$sms->setNumber(47999996666); 
$sms->setText("Venda bilionária feita! Pagar mais cervejas!!"); 

TotalVoice::$token = 'SEU_TOKEN'; 
$response = TotalVoice::sendSms($sms); 
var_dump($response->getContent());

Lendo a documentação da API, é possível ver que o envio de SMS é só uma das funcionalidades disponíveis. Fiquei particularmente interessado no recurso de Webhooks para poder controlar o status das ligações telefônicas e SMSs de forma automática. Dá para criar soluções interessantes com isso.

Bom, fica aqui a dica de uma solução nacional e fácil de usar que pode ser bem útil em vários cenários além dos que eu comentei aqui.

25 Apr 18:06

222

by Francisco Nunes

a Rafa e Tássia

sempre
presentes
em
forma
de
saudade

23 Apr 16:29

O descanso

by Francisco Nunes

Amados de nosso Senhor,

A primeira e tão bem-vinda palavra Dele para nós foi: “Vinde a Mim todos os que estais cansados” (Mt 11.28). Aquela labuta do fútil Adão estava sobre nós, tanto no pecado como na canseira das obras.

Deixamos isso na cruz do Senhor ou ainda o estamos suportando, em parte? Marta estava atarefada com muitas coisas, ainda que pensasse estar servindo seu Senhor! Estranho que tal serviço trouxesse tensão e irritação, ressoasse nos nervos e trouxesse um julgamento errado dos outros; contudo, essa dualidade que vemos em Betânia ainda não acabou; ainda a encontramos no serviço a Deus. E muitas “separações”, muitos afastamentos devem-se a isso, e muita é a perplexidade que vem desta outra palavra sobre o supremo serviço do Senhor: “Meu jugo é suave e Meu fardo é leve” (v. 30). Em face de algumas experiências [dos cristãos], essa frase soa irônica.

O Senhor não nos chama para tal labor, mas para o descanso. “Aqueles que crêem de fato entram no descanso” (cf. Hb 4.3) e: “Eu te darei descanso” (cf. Js 1.13). Ele promete descanso, não apenas do pecado, mas do trabalho inútil e desapontador. A maldição do trabalho de Adão em todas as suas formas gera nada além de um infrutífero cansaço, uma exaustão de esforço sem recompensa, e certamente “o suor da testa”. As energias da carne, a mera intensidade da alma, as chamas de uma paixão auto-criada, tudo isso causa febre, geralmente uma grande febre que nos torna desequilibrados para servir nosso Senhor quando Ele verdadeiramente necessita de nosso ministério.

Tão insistentemente o Salvador diz para a sinceridade e o impulso carnais: “Uma coisa é necessária: que você se aquiete e ouça Meu conselho, pois Eu sou seu Senhor”. Busque a quietude.

Pois as obras estão consumadas desde a fundação do mundo, e nada podemos fazer para torná-las mais perfeitas ou adicionar algo a elas. À parte Dele, nada há do que se fez.

E então? Há o lado bom, que é a boa parceria. Ele e nós devemos agora trabalhar juntos por meio de Seu Espírito que habita interiormente, assim como Ele e o Pai trabalharam juntos na terra mediante essa habitação. É o grande jugo, o eterno propósito de Deus; mas ele é fácil e leve, pois a carga está sobre o Espírito, dentro de nosso espírito, e não é uma pressão em algum lugar na alma: nem os nervos nem o cérebro são tentados por ele, nem a carne conhece seu peso. Porém o pilar interior de Sua força é o suporte, uma pressão de cima vinda do soberano amor.

Mas agora trabalhemos e nos alegremos em trabalhar. Existe labuta e talvez haja um feliz cansaço, mas não tensão.

Para concluir, eis aqui o segredo contido em uma experiência exultante: “Trabalhei muito mais do que todos eles; todavia, não eu, mas a graça de Deus que está comigo” (1Co 15.10). Paulo enfatizou grandemente estas últimas palavras, “a graça Deus que está comigo”, por toda a vida, pois o derradeiro toque sútil do “velho homem” que busca servir a Deus é dizer “eu” no templo de Sua glória. Como disse Andrew Murray: “Onde a carne busca servir a Deus há a força do pecado”.

“Levanta-Te, Senhor, ao Teu repouso, Tu e a arca da Tua força” (Sl 132.8).

Na fraqueza que permite o Triunfo Dele,

T. Austin-Sparks
T. Madoc-Jeffreys

20 Apr 17:40

Microsoft Authenticator: Acabaram-se as passwords na Microsoft

by Pedro Simões
A segurança e a privacidade são quase sempre garantidas pelas palavras-passe e pelos mecanismos adicionais. Por norma, quanto mais seguras são, mais complicadas são de usar. A Microsoft resolveu agora simplificar esses processos e...
19 Apr 18:48

Outras areias

by Francisco Nunes

– Acho que era principalmente por causa daquele seu jeito particuloso. Não havia o que lhe chamasse a atenção quando não queria, quando tava lá sumida naquele mundo seu só dela.
– Nem os amigos, próximos?
– Não, nem. Era uma mudeza, de olhos, que ninguém entrava, fazia parte. Mesmo que chamando o nome dela, não respondia se tava no lá longe dentro-de-si. Como podia? No início, todo mundo se incomodava, gritava até, xingava ela. Achavam que era desrespeitante, um modo… Então, com aquele seu sorriso branco, de frescor da tarde, de uma calma de coração que era tanta, tudo se acalmava. A gente não entendia, mas parecia entendê. Aceitava. Ficava tudo bem. Aos dispois, já nem mais perturbava mais ninguém já conhecido. Era o jeito dela, era ela assim. Desse modo, assinzinho. Então, não tinha razão de irritá. Mais era aprendê a aproveitá a companhia, a presença, a sabedoria, a doçura. Quando falava, ah!, ficava o povo tudo quieto! Daquela boca miúda, desenhadinha de pintura, brotava coisa que ninguém imaginava donde vinha! Ela desenrolava os problema mais enroscado, os causo de família, aqueles assunto que ficava no escondido do coração que nem a pessoa sabia que tinha. Os velho aceitava, as criança entendia, os mais ignorante não tinha dificuldade na compreensão das coisa. Ela falava na medida que se precisava, sem sobrança de palavra, sem enfeitamento de gramática. Só o exato. Como uma faca bem afiada, cortando e chegando no miolo, no tutano. Nunca carecia de erguer a voz, de exaltar no tom. Só mesmo a fala mansinha…
– Mas teve o sumiço?
– Ah! Foi uma comoção sem tamanho! Naquela manhã, parecia tê um… uma coisa ruim no ar. Alguém comentô que os passarinho não tava cantando. A estranheza que não se sabia o quê. Tinha um trem apertano o estômago de todo mundo, um desatino na cabeça. Mas só aos dispois é que a gente se apercebeu disso tudo. Quando viu que ela tinha sumido. Como? O quarto pequenino dela continuava fechado por dentro, e já passava umas hora que ela não aparecia – tiveram de arrombá a porta com pé-de-cabra e ombro. Lá dentro, tudo igual: ordeiro, perfumado, os lençol esticado, o vaso com flor do campo. Em cima da mesinha, uma folha de papel com um desenho lindo de uma paisagem, vista duma praia deserta que tinha uma moça sozinha caminhando. A moça do desenho era ela mesma! Pequeninha, mas dava pra sabê que era ela: os cabelo ruivo claro no vento, o vestido comprido branco que ela gostava muito, o jeito de segurá as sandália que tinha… Um assombro, porque ninguém nunca sabia que ela desenhava! Fazia muito bordado, crochê, costura, mas desenho?! E, num canto do papel, escrito com a pena que tava ao lado, ainda molhada de tinta, com a letra redonda de professora dela, umas palavra de oculto significado: Imaginei outras areias, ei-las, mas os passos vacilam.

– E depois?
– Procuremo ela por todo canto. A vila toda saiu na busca. Não tinha explicação, não tinha rastro nenhum, ninguém não tinha visto nada. Como era muito conhecida, não tinha como alguém não sabê que era ela. Mas sumiu. Assim. Dum quarto fechado, sem tê como. Era uma pessoa como que nunca tinha existido ali. A vida de tudo nós ficou uma tristeza que só. Não tinham vontade de comê, de estudá e cartilha, de ordenhá as vaca nem brincá no galpão. Até as moça que tinha inveja dela, por causa da beleza, se arrependia e sofria. Foi um fim. A vila toda ficou de luto, abatida na tristeza, silenciosa.
– Pra sempre?
– Cabo duns seis mês ou mais um pouco, era um domingo de manhã, invernoso, mas não tava frio, como era de costume por aqui. Ninguém ainda tinha notado isso, quando a gente ouviu. Primeiro, foi um passarinho que não canta nessa época. Depois… a mesma vozinha doce, amorosa, de embalá bebê, que cantava as beleza da terra, dos sonho do povo, dumas esperança de céu e paz, com umas palavra nova, nunca de ouvida… A mesma vozinha que acordava os dia, a fazenda. Era ela! Corremo pro quarto dela, donde vinha a voz, coração aflito, alegre, animado, se perguntano. Linda como sempre, o olhar de criança, o sorriso de gente que ama: ela tinha voltado! Tava saindo do quarto, nem ficou surpresa com nós tudo olhando prela com aquelas cara espantada. Pareceu não vê nada de diferente, pareceu que não tinha acontecido nada demais. Deu um beijo em cada um de nós e foi pra cozinha, prepará o café.
– E assim?
– Fiquemo sem sabê o que fazê. Se olhemo, fiquemo com medo de estragá a alegria dela tê voltado, não sabia o que dizê. Uns até se beliscô, se achando em sonho. E num era. Então, esperemo um outro momento do dia, outra hora mais no molde de fazê inquirição. Mas o dia foi se passando, os pessoal foi sabendo, veio visitá… e quando via ela, ninguém tinha de coragem de perguntá nada. As pergunta ensaiada morria na garganta, sumia num só. Se virava só na alegria dela tá ali, vivinha, de volta. Não sei. Parecia que a presença dela, ressurgida, já explicava tudo, já dizia que tava tudo bem, que o mais importante era aquilo dali, ela e nós de novo junto.
– Mas no depois?
– Nada. Nunca falemo no assunto. Nunca subemo onde que ela teve aqueles seis mês. Ele nunca falô nada, nunca se explicô. Parecia até que ela nem sabia que tinha se ido. A gente só sabia que tinha alguma coisa bem forte, misterienta.
– Por quê?
– Porque ela nunca mais teve aquele olhar particuloso, de se perder em pensamento, como se não tivesse com a gente. Seu olhar era… diferente, mais amplo, sossegado. Parecia tê achado uma resposta, o fim. Foi desse modo que minha filha, Sibele, sumiu e retornou.

Silenciou um instante, olhou para o lado como se buscasse uma lembrança que teimava em fugir.

– Sabe –, retomou falando devagar –, uma coisa… Na hora, a gente nem deu atenção, mas… outro mistério. Na sandália dela tinha uma areia muito fininha. No outro dia, ela tinha colocado a areia num vidrinho, de perfume vazio, que agora fica sobre a mesinha. Vez que outra, eu chego de mansinho no quarto e vejo ela olhando pro vidrinho, quieta, sem se mexer, sem saber que o resto do mundo existe ainda. Aquele antigo olhar…

(scs, 30714)

Salvar

Salvar

18 Apr 19:23

Alan Pope: My Ubuntu 16.04 GNOME Setup

My Ubuntu 16.04 GNOME Setup

This is a post for friends who saw my desktop screenshot and anyone else who likes Unity and is looking at alternatives. A big thanks to Stuart Langridge and Joey Sneddon whose linked posts inspired some of this.

The recent news that upcoming versions of Ubuntu will use GNOME as the default desktop rather than Unity, made me take another look at the GNOME desktop

If you're not interested in my opinion but just want to know what I did, then jump to "Migration from Unity to GNOME" below.

Why Unity?

I'm quite a Unity fan - yes, we exist! I've used it on my laptops and desktops my daily desktop pretty much since it came out, long before I worked at Canonical. I've tried a few other desktop environments, usually for no more than a week or so before getting frustrated and running back to Unity.

Here's what my typical desktop looks like on Ubuntu 16.04

Unity as I use it

At this point I'm sure there are a few people reading this and wondering why I like Unity, incredulous that anyone would. I get this from time to time. Some people seem to bizzarely think "I don't like Unity, therefore nobody does." which is ludicrous, but very obviously happening.

Anecdotally, I still see way more Unity screenshots than other desktops in random non-Linux videos on YouTube, on stranger's laptops on trains & on "millions of dollars" worth of laptops sold by Dell, System76 etc. I've also been told in person by people who like it, but don't like speaking up for fear of unwanted confrontation. ¯\_(ツ)_/¯

But it's a vocal minority of Linux users who tell me what desktop I (and everyone else) shouldn't use. Screw them, it's my PC, I'll run what I like. :)

However, that said, Unity is "dead", apparently, despite it having a few years of support left on the 16.04 LTS release. So I thought I'd take a fresh look at GNOME to see if I can switch to it easily and keep the parts of the Linux desktop I like, change the things I don't and tolerate the things I can't.

For me, it's not one single feature that made me come back to Unity time and time again, but a variety of reasons. Here's a non-exhaustive list of features I enjoy:-

  • Dash - Single button + search to launch apps and find files
  • HUD - Single button + search to find application features in menus
  • Launcher - Quick access via keyboard (or mouse) to top 10+ apps I use, always on screen
  • Window controls - Top left is their rightful place
  • Menus - In the titlebar or top bar (global)
  • App & Window switch behaviour via Alt+Tab & Alt+(key-above-tab)
  • App Spread - Super+S and Super+W to see all windows, or all windows of an app
  • Focus follows mouse - Initially global menu broke this but it was fixed

Much of this comes down to "is really well managed with just a keyboard" which is amusing given how many people tell me Unity (before Unity 8) is awful because it's designed for touch screens.

The things I think could be improved in Unity comprise a pretty short list, and if I thought really hard, I might expand this. If I did they'd probably only be papercut nit-picks rather than significant issues. So, I would have liked these things to have been fixed at some point, but that probably won't happen now :(

  • Memory footprint - It would be nice if the RAM usage of Unity was lower.
  • CPU/GPU overhead - Sometimes it can take a second or two to launch the dash, which should be near-instant all the time
  • Incompleteness - There were interesting designs & updates which never really got finished in Unity7
  • Cross distro support - It would have been nice to have Unity on other distros than just Ubuntu

So let's say a fond farewell to my primary desktop for over 6 years and make the switch.

Migration from Unity to GNOME

With that said, to move from Unity to GNOME on my ThinkPad T450 running Ubuntu 16.04 LTS I did the following:-

Install GNOME

I decided to go with the GNOME version shipping in the archive. People have suggested I try PPAs, but for my primary desktop I'd rather keep using the archive builds, unless there's some really compelling reason to upgrade.

So I backed up my laptop - well, I didn't - my laptop is backed up automatically every 6 hours, so I just figured if anything went belly-up I'd go back to the earlier backup. I then installed GNOME using this command:-

sudo apt install ubuntu-gnome-desktop^

Logout from Unity, choose GNOME at the login screen and we're in.

Default GNOME Desktop

Default GNOME Desktop

First impresssions

These are the things that jump out at me that I don't like and how they're fixed. One thing that's pretty neat about GNOME Shell is the ability to modify it via extensions. For most of the things I didn't like, there was an extension to change the behaviour.

Some are just plain extensions installed via GNOME Extensions, but some needed extra fiddling with Tweak Tool.

Activites hot corner

I find this too easily triggered, so I used No TopLeft Hot Corner. Later, I also discovered the Hide Activtes Button which helps even more by moving the window controls to the very top left, without the "Activities" in the way. I can still use the Super key to find things, with Activities hidden.

No Launcher

GNOME hides the launcher until you press Activites or the Super key. I fixed that with Dash to Dock.

In Tweak Tool, Dash to Dock settings -> Position and size -> tick "Panel mode: extend to the screen edge". I set "Intelligent Autohide" off, because I never liked that feature in Unity, although it had some vocal fans. Also I set the pixel size to 32px. In the Launchers tab I set "Move the applications button at the beginning of the dock".

Legacy indicators

Apparently developers are terrible people and haven't updated their indicators to some new spec, so they get relegated to the "Lower Left Corner of Shame". This is dumb. I used TopIcons Plus to put them where $DEITY intended, and where my eyes are already looking, the top right corner.

Volume control

In Unity I'm used to adjusting the master volume with the mouse wheel while the sound indicator is clicked. I fixed this with Better Volume Indicator

Giant titlebars

GNOME always feels to me like it's designed to waste vertical space with titlebars so I added Pixel Saver.

Missing Rubbish Bin

I like having the Trash / Rubbish Bin / Recycle Bin / Basket on screen. In Unity it's at the bottom of the launcher. I couldn't find an extension which did this so I used trash extension to move it to the top panel indicator area.

Slow animations

Some things felt a bit sluggish to me, so it was recommend that I install the Impatience extension, which seems to have helped my perception, if nothing else.

Remaining niggles

Things I haven't figured out yet. If you have any suggestions, do let me know in the comments below.

  • How to hide the clock completely
    • I frequently record screencasts of my laptop and the time jumping around in the recording can be distracting. So I just hide the clock. I don't see an easy way to do that yet.
  • Make accelerator keys work in alt+space window menu
    • For many years I have used the accelerators in the window controls menu accessed via Alt+space to do things like maximize the window. Alt+Space,x is welded in my muscle memory. I don't understand why they were disabled in GNOME Shell (they work in other desktops).
  • Alt-Tab behaviour is broken (by design (IMHO))
    • All windows of an application come to front when Alt+Tabbed to, even if I only want one window. I have to dance around with Alt+Tab & Alt+Grave.

Reader Suggestions

In the comments below, the following addtional extensions have been suggested.

Greg suggested the Alt Tab List First Window Extension which on initial play seems to fix the Alt-Tab issue listed above! Many thanks Greg!

Alif mentioned Status Area Horizontal Spacing which is great for compressing the gaps out of the indicator area in the top right, to use the space more efficiently. Thanks Alif!

Conclusion

So this is now my desktop, and I'm quite pleased with it! Massive thanks to the GNOME team, the Ubuntu GNOME flavour team, and all the extension authors who made this possible.

My new Ubuntu GNOME Desktop

My new Ubuntu GNOME Desktop

Initially I was a bit frustrated by the default behaviour of GNOME Shell. I've been pleasantly surprised by the extent and functionality of extensions available. Without them, there's no way I'd use this on a daily basis, as it's just too irritating. I'm sure somebody loves the default behaviour though, and that's great :)

I realise I'm running an 'old' version of GNOME Shell (3.18) coming directly from the Ubuntu 16.04 (LTS) archive. It may be there's additional features or fixes that are going to improve things further. I won't be upgrading to 16.10, 17.04 or 17.10 however, and likely won't use a GNOME PPA for my primary desktop. I'll stick with this until 18.04 (the next Ubuntu LTS) has baked for a while. I don't want to upgrade to 18.04 and find extensions break and put me backwards again.

I've had this setup for a few days now, and I'm pretty pleased with how it went. Did you try this? Any other changes you made? Let me know in a comment below! Thanks. :D

18 Apr 19:15

How to Internationalize Your AngularJS App

by MEHMET BAJIN, DEVELOPER @ TOPTAL
Internationalizing modern apps, where the front-end and the back-end are distinctly separate from one another, can be a little tricky. AngularJS, with the help of a few tools, makes internationalizing your app a breeze. In this article, Toptal Freelance Software Engineer Mehmet Bajin gives us a step-by-step tutorial to internationalizing and localizing AngularJS apps.
17 Apr 19:20

Replicação: o que mudou

by Euler Taveira
A mais de 6 anos atrás, eu escrevi o artigo Hot Standby e Streaming Replication que descreve uma das funcionalidades mais aguardadas na época: replicação nativa. De lá para cá houveram diversas melhorias nessa funcionalidade que a tornaram sólida para diversas arquiteturas de sistemas. Irei atualizar os passos descritos no post antigo (que por sinal ainda são válidos) com opções que melhoraram a implantação da replicação no PostgreSQL.
A versão 9.0 implementou a replicação nativa baseada no envio de registros (streaming replication). Um protocolo foi definido para o envio de registros do WAL do servidor principal para o servidor secundário. O servidor secundário tem a capacidade de aceitar consultas somente leitura (hot standby). Em resumo, foi adicionado suporte a um servidor principal e vários servidores secundários (aceitando ou não consultas).
Da versão 9.1 a 9.6 houveram várias melhorias que tornaram essa solução mais sólida e robusta a cada versão. Destaco o suporte a: replicação síncrona (9.1), replicação em cascata (9.2), possibilidade de seguir nova linha do tempo (9.3), slots de replicação (9.4), replicação com atraso (9.4), resincronizar servidor principal antigo com pg_rewind (9.5), múltiplos servidores síncronos ao mesmo tempo (9.6).
A Timbira contribui com duas funcionalidades nessa evolução: função pg_xlog_location_diff (calcular diferença entre posições do WAL -- útil para descobrir o lag de replicação) e recovery_min_apply_delay (atrasar a aplicação do WAL no servidor secundário -- útil para recuperar de desastres tais como remover um banco de dados em produção).
O cenário que utilizaremos é o mesmo do artigo anterior cuja ilustração está na figura abaixo.


O cenário

  • 2 servidores PostgreSQL: um servidor principal (aceita leitura e modificação de dados) e um servidor secundário (aceita ou não consultas somente leitura). Estes servidores devem ser preferencialmente (quase) idênticos pois a replicação é "binária", sendo incompatível em arquiteturas e/ou sistemas operacionais distintos. (Em soluções de alta disponibilidade, utilizar um servidor secundário muito inferior ao servidor principal pode ser inaceitável para negócio. Certifique-se que o servidor secundário tenha capacidade de substituir o servidor principal.);
  • versão do PostgreSQL: a mesma versão em ambos servidores. Com mesma versão quero dizer que os dois primeiros números devem ser iguais (por exemplo, 9.1.3 e 9.1.24, 9.3.10 e 9.3.15, 9.6.2 e 9.6.2). Se for usar versões corretivas diferentes (9.3.10 x 9.3.15), mesmo que momentâneo para alguma atualização, é recomendado manter os servidores secundários com versões corretivas mais recentes para evitar que alguma incompatibilidade (causada por um bug) seja replicada e não consiga ser aplicada em uma versão corretiva anterior;
  • rede: a replicação utiliza o protocolo do PostgreSQL e, portanto, todo o tráfego será através da porta do serviço (padrão é 5432). Certifique-se que o servidor secundário consiga acessar o servidor principal a partir da porta do serviço. Se utilizarmos o pg_basebackup para montar o servidor secundário, não há necessidade de configuração especial (ele transmite os dados do agrupamento através do próprio protocolo do PostgreSQL); no entanto, a utilização de outro método de cópia (ssh, rsync, etc) demandará ajuste no acesso para a(s) porta(s) utilizada(s);
  • acesso: o acesso root não é obrigatório se o local do diretório de dados do servidor secundário estiver com as devidas permissões para o usuário do serviço do PostgreSQL (comumente usuário postgres). A partir da versão 9.1, o usuário que replica os dados precisa ter a permissão REPLICATION ou ser superusuário; na 9.0, o usuário deve ser superusuário;
  • endereço de rede: para o servidor principal e o servidor secundário usaremos 10.1.1.1 e 10.1.1.2, respectivamente;
  • diretório de dados: para o servidor principal usaremos /bd/primario e o servidor secundário usaremos /bd/secundario;
  • usuário do serviço: o usuário do sistema operacional em ambos os servidores será o postgres.

No servidor principal


Começamos alterando a configuração do postgres (/bd/primario/postgresql.conf) no servidor principal:

listen_addresses = '*'
wal_level = replica               # hot_standby até 9.5
max_wal_senders = 3
max_replication_slots = 3    # parâmetro a partir da 9.4

O parâmetro listen_addresses permite que o servidor principal escute todos os endereços da rede (o pg_hba.conf faz restrição por endereço). O parâmetro wal_level determina a quantidade de informação vai para WAL (replica permitirá arquivamento do WAL e replicação). O parâmetro max_wal_senders indica o número máximo de servidores secundários ou aplicações para backup base (tais como pg_basebackup e pg_receivexlog). O parâmetro max_replication_slots especifica o número máximo de slots de replicação permitidos.

É possível prevenir a reciclagem do WAL (que ainda é útil para algum servidor secundário) utilizando o parâmetro wal_keep_segments ou arquivando o WAL com o parâmetro archive_command. O parâmetro wal_keep_segments especifica um número mínimo de arquivos de log de transação a serem mantidos no pg_xlog caso algum servidor secundário necessite obtê-los via replicação. O parâmetro archive_command especifica um comando utilizado para copiar o arquivo de log de transação (que foi recentemente preenchido) para algum local acessível pelos servidores secundários. Contudo, esses métodos podem reter mais arquivos do que o necessário enquanto o slot de replicação visa reter somente o WAL necessário para algum servidor secundário. Uma desvantagem do slot de replicação é que ele não limita a quantidade de arquivos do WAL armazenados no diretório pg_xlog. Isso quer dizer que se algum servidor secundário for desligado e o DBA esquecer de remover o slot de replicação dele, o pg_xlog vai crescer indefinidamente.

As modificações no arquivo /bd/primario/postgresql.conf necessitam de um reinício do serviço.

postgres@principal:~$ pg_ctl restart -D /bd/primario
esperando o servidor desligar.....feito
servidor está parado
servidor está iniciando

A replicação usará uma conexão do postgres. E para realizar essa conexão utilizaremos uma role específica para replicação. A versão 9.0 exigia um superusuário para tal mas a partir da 9.1 essa role pode ter simplesmente a permissão REPLICATION.

postgres@principal:~$ psql
psql (9.6.2)
Digite "help" para ajuda.

postgres=# CREATE ROLE replicacao REPLICATION LOGIN;
CREATE ROLE
postgres=# \q

Dependendo de sua política de segurança, você precisará definir uma senha para a role replicacao. A senha poderá ser informada na string de conexão no arquivo /bd/secundario/recovery.conf ou preferencialmente em um arquivo de senhas (~postgres/.pgpass ou %APPDATA%\postgresql\pgpass.conf no Windows) no servidor secundário.
postgres@principal:~$ psql
psql (9.6.2)
Digite "help" para ajuda.

postgres=# \password replicacao
Digite nova senha:
Digite-a novamente:
postgres=# \q

Precisamos ajustar o acesso no servidor principal. Isso porque a conexão é feita do servidor secundário para o servidor principal. O arquivo /bd/primario/pg_hba.conf controla esse acesso. Os acessos de replicação são identificados utlizando replication com nome do banco de dados (se você tiver um banco chamado replication, ele deve estar entre aspas duplas). Se você decidir utilizar autenticação por senha, o método de autenticação pode ser md5.

host    replication    replicacao    10.1.1.2/32    md5

A adição de uma nova regra de autenticação exige um reload do serviço.

postgres@principal:~$ pg_ctl reload -D /bd/primario
servidor foi sinalizado

No servidor secundário


O próximo passo é obter uma cópia base (base backup) para montar o servidor secundário. A cópia base é uma cópia de todo agrupamento de dados (PGDATA) incluindo os diretórios de todas as tablespaces. Ilustraremos três maneiras de realizar essa cópia dependendo da disponibilidade do serviço.

      1. Servidor principal parado


      Se o servidor puder ficar parado durante a cópia, podemos fazer:
      postgres@principal:~$ pg_ctl stop -D /bd/primario
      esperando o servidor desligar.....feito
      servidor está parado
      postgres@principal:~$ rsync -av --exclude postgresql.auto.conf.tmp --exclude postmaster.pid --exclude postmaster.opts --exclude pg_stat_tmp/* --exclude pg_replslot/* --exclude pg_dynshmem/* --exclude pg_notify/* --exclude pg_serial/* --exclude pg_snapshots/* --exclude pg_subtrans/* --exclude pg_xlog/* --exclude pg_log/* /bd/primario/ postgres@10.1.1.2:/bd/secundario
      sending incremental file list
      ./
      PG_VERSION
      pg_ident.conf
      postgresql.auto.conf
      .
      .
      .
      pg_tblspc/
      pg_twophase/
      pg_xlog/

      sent 364,684,662 bytes  received 96,744 bytes  9,234,972.30 bytes/sec
      total size is 364,298,395  speedup is 1.00
      postgres@principal:~$ pg_ctl start -D /bd/primario
      servidor está iniciando

      No comando rsync não esqueça da barra ao final do nome do diretório. Ele vai indicar que copiaremos somente o conteúdo de /bd/primario e não o diretório primario. Alguns arquivos e/ou diretórios excluídos (--exclude) podem não existir na sua versão, ignore-os. Os diretórios pg_stat_tmp e pg_log podem ser configurados pelo DBA, certifique-se que eles não foram alterados para outros valores.

      2. Servidor principal em atividade


      Caso você queira fazer a cópia base com o servidor em atividade, precisamos executar alguns passos além da cópia. O slot de replicação foi implementado na versão 9.4. Em versões anteriores, ignore o primeiro comando e utilize o arquivamento ou o parâmetro wal_keep_segments conforme explicado acima.
      postgres=# SELECT * FROM pg_create_physical_replication_slot('secundario', true);
       slot_name   | xlog_position
      -------------------+---------------------
       secundario  | 0/99005D50
      (1 registro)

      postgres=# SELECT pg_start_backup('replica', true);
       pg_start_backup
      --------------------------
       0/9A000060
      (1 registro)

      postgres=# \q
      postgres@principal:~$ rsync -av --exclude postgresql.auto.conf.tmp --exclude postmaster.pid --exclude postmaster.opts --exclude pg_stat_tmp/* --exclude pg_replslot/* --exclude pg_dynshmem/* --exclude pg_notify/* --exclude pg_serial/* --exclude pg_snapshots/* --exclude pg_subtrans/* --exclude pg_xlog/* --exclude pg_log/* /bd/primario/ postgres@10.1.1.2:/bd/secundario
      sending incremental file list
      ./
      PG_VERSION
      backup_label
      pg_ident.conf
      .
      .
      .
      pg_twophase/
      pg_xlog/

      sent 364,626,339 bytes  received 96,728 bytes  145,889,226.80 bytes/sec
      total size is 364,240,052  speedup is 1.00
      postgres@principal:~$ psql
      psql (9.6.2)
      Digite "help" para ajuda.

      euler=# SELECT pg_stop_backup();
      NOTA:  pg_stop_backup concluído, todos os segmentos do WAL foram arquivados
       pg_stop_backup
      -------------------------
       0/9BDD1B38
      (1 registro)

      euler=# \q

      Criamos um slot de replicação (com a função pg_create_physical_replication_slot) para limitar a reciclagem do WAL porque o servidor secundário precisará dele. O segundo parâmetro da função é importante porque a reserva é feita imediatamente ao invés de fazer somente na primeira conexão (sem a reserva imediata, uma cópia base que demora algumas horas poderia remover WAL necessário para montar a réplica). Em versões anteriores, faça arquivamento ou utilize o parâmetro wal_keep_segments.

      A função pg_start_backup prepara o servidor principal para iniciar uma cópia base. Após a sua execução podemos fazer a cópia mesmo que arquivos estejam sendo criados (tabelas/índices novos) e/ou excluídos. A cópia base exclui alguns arquivos que podem ser diferentes no servidor secundário (como postgresql.conf e pg_hba.conf) ou que não são necessários (vide parâmetros --exclude no comando rsync). Executamos a função pg_stop_backup para indicar o fim da cópia.

      3. pg_basebackup


      O comando pg_basebackup automatiza a geração de cópias base com servidores postgres em atividade. A cópia base é feita utilizando uma conexão do postgres e utiliza o protocolo de replicação. As configurações feitas no servidor principal e o usuário criado são os pré-requisitos para executar o pg_basebackup. O pg_basebackup deve ser executado a partir do servidor secundário.

      postgres@secundario:~$ pg_basebackup --format=plain --xlog-method=stream --checkpoint=fast --progress -D /bd/secundario -R -v -h 10.1.1.1 -p 5432 -U replicacao
      ponto de início do log de transação: 0/16001FD8 na linha do tempo 1
      pg_basebackup: iniciando receptor do WAL em segundo plano
      98860/98860 kB (100%), 1/1 tablespace                                        
      transaction log end point: 0/16076238
      pg_basebackup: esperando processo em segundo plano terminar o envio ...
      pg_basebackup: cópia base completa

      No exemplo acima, utilizamos o formato plain, que mantém o mesmo layout dos arquivos e diretórios do servidor principal. Se tiver tablespaces, elas vão para o mesmo caminho absoluto definido do servidor principal (certifique-se que os caminhos existam antes de executar o pg_basebackup). O parâmetro --xlog-method especifica que o pg_basebackup irá incluir todos os arquivos de log de transação necessários. O valor stream indica que irá copiar o WAL em paralelo com a cópia base, necessitando para isso de uma conexão extra com o servidor principal (o outro valor é fetch mas só copia o WAL ao final da cópia base, necessitando que não haja reciclagem do WAL -- vide wal_keep_segments). O parâmetro --checkpoint controla se o CHECKPOINT será espalhado (spread) ou rápido (fast) -- a opção fast pode causar um pico de IO; use-a somente em horários de baixa carga. A opção -D especifica o diretório que o agrupamento de dados do servidor secundário será armazenado. A opção -R gera o arquivo recovery.conf (com as opções informadas pelo pg_basebackup) no diretório de saída (-D) para facilitar a montagem do servidor secundário. As opções -h (host), -p (porta) e -U (usuário) são relativas a conexão com servidor principal.

      Iniciando a réplica


      No servidor secundário, o próximo passo é criar o arquivo /bd/secundario/recovery.conf. A presença desse arquivo indica para o postgres que ele deve iniciar em modo de recuperação (a replicação é uma recuperação contínua).
      standby_mode = 'on'
      primary_conninfo = 'host=10.1.1.1 port=5432 user=replicacao'
      O parâmetro standby_mode garante que o servidor secundário ficará em recuperação contínua indefinidamente. Para replicação por fluxo, é necessário informar o parâmetro primary_conninfo especificando como se conectar no servidor principal.

      Se o servidor secundário ficar muito atrasado em relação ao servidor principal, a conexão de replicação pode ser interrompida porque o arquivo de log de transação que contém o registro a ser replicado, já foi reciclado no servidor principal. É uma cenário que pode ocorrer ao realizar cargas de dados e/ou manutenções. As soluções, conforme detalhamos acima, são: wal_keep_segments, arquivamento ou slots. Para wal_keep_segments, basta ajustá-lo no servidor principal. O arquivamento deve ser feito no servidor principal e o local de armazenamento deve ser acessível pelo servidor secundário.

      No servidor principal, crie o diretório /bd/archives com permissão de escrita para usuário postgres e edite o arquivo /bd/primario/postgresql.conf:
      archive_mode = on
      archive_command = 'cp %p /bd/archives/%f'

      Um reinício do postgres no servidor principal é necessário para que o arquivamento seja ativado.

      E no servidor secundário, edite arquivo /bd/secundario/recovery.conf:
      restore_command = 'scp postgres@10.1.1.1:/bd/archives/%f %p'
      Nesse caso (scp), use um par de chaves para acesso via ssh sem solicitar senha.

      Por fim, se optar por utilizar slots (versão >= 9.4), crie o slot com a função pg_create_physical_replication_slot conforme detalhado acima e adicione o seguinte parâmetro no arquivo /bd/secundario/recovery.conf:
      primary_slot_name = 'secundario'

      O nome do slot é aquele que você informou no primeiro parâmetro da função. Para obter os slots, utilize a seguinte consulta:
      postgres=# SELECT slot_name, slot_type, active, restart_lsn FROM pg_replication_slots;
       slot_name   | slot_type | active | restart_lsn
      -------------------+--------------+---------+--------------------
       secundario  | physical  | f         | 0/1A272848
      (1 registro)

      Mais alguns ajustes no arquivo /bd/secundario/postgresql.conf.
      hot_standby = on
      hot_standby_feedback = on

      O parâmetro hot_standby permitirá consultas somente leitura no servidor secundário. O parâmetro hot_standby_feedback faz com que o servidor secundário envie informações ao servidor principal para impedir o cancelamento de consultas no servidor secundário. A desvantagem é o inchaço de tabelas no servidor principal porque algumas consultas longas no servidor secundário ainda utilizam registros que já foram removidos no servidor principal e não podem ser limpados porque provocariam o cancelamento da consulta no servidor secundário.

      Se o objetivo do servidor secundário é alta disponibilidade, é preferível não ajustar hot_standby_feedback e manter os valores de max_standby_archive_delay e max_standby_streaming_delay baixos, assim o servidor secundário não ficará tão distante do servidor principal por causa de atrasos provocados por consultas longas.

      Todavia, se o objetivo do servidor secundário é executar consultas longas habilite hot_standby_feedback e/ou defina os valores de max_standby_archive_delay e max_standby_streaming_delay altos ou mesmo -1 (infinito). Tenha em mente que manter um atraso grande fará com que outras conexões não vejam mudanças recentes no servidor principal (porque elas ainda não foram aplicadas).

      O último passo é iniciar o serviço no servidor secundário:
      postgres@secundario:~$ pg_ctl start -D /bd/secundario
      postgres@secundario:~$ cat postgresql-2017-02-20_213649.log
      LOG:  sistema de banco de dados foi interrompido; última execução em 2017-02-20 21:28:06 BRT
      LOG:  entrando no modo em espera
      LOG:  redo inicia em 0/1B000028
      LOG:  estado de recuperação consistente alcançado em 0/1B0000F8
      LOG:  sistema de banco de dados está pronto para aceitar conexões somente leitura
      LOG:  iniciado fluxo de WAL do principal em 0/1C000000 na linha do tempo 1

      Para monitorar a replicação, consulte a visão pg_stat_replication no servidor principal:
      postgres=# SELECT *, pg_xlog_location_diff(sent_location, replay_location) AS lag_replay FROM pg_stat_replication;
      -[ RECORD 1 ]----+------------------------------------------------
      pid                      | 18943
      usesysid             | 16384
      usename             | replicacao
      application_name | walreceiver
      client_addr          |
      client_hostname  |
      client_port           | -1
      backend_start     | 2017-02-20 21:36:49.788049-03
      backend_xmin     |
      state                   | streaming
      sent_location      | 0/1FE534C0
      write_location     | 0/1FE534C0
      flush_location     | 0/1FE4F4F0
      replay_location   | 0/1FE4F4F0
      sync_priority       | 0
      sync_state          | async
      lag_replay           | 16336
      Lembre-se de remover o slot (se estiver utilizando), após desativar algum servidor secundário. Um slot sem uso retém arquivos de log de transação indefinidamente (podendo encher a sua partição rapidamente se o espaço for reduzido). Para remover o slot, execute:
      postgres=# SELECT pg_drop_replication_slot('secundario');
       pg_drop_replication_slot
      -------------------------------------

      (1 registro)
      12 Apr 19:52

      Bruce Momjian: Inside the WAL

      The write-ahead log (WAL) does many things:

      It is great that a single facility is used for so much. Fortunately, it is possible to look inside of the WAL. This is particularly useful for setting recovery_target_xid in recovery.conf.

      The binary portion of the WAL can be viewed using pg_xlogdump. This is the output of transaction 558, which was an INSERT into a table with one index:

      Continue Reading »

      10 Apr 20:29

      Robert Haas: New Features Coming in PostgreSQL 10

      The list of new features coming in PostgreSQL 10 is extremely impressive.  I've been involved in the PostgreSQL project since the 8.4 release cycle (2008-2009), and I've never seen anything like this.  Many people have already blogged about these features elsewhere; my purpose here is just to bring together a list of the features that, in my opinion, are the biggest new things that we can expect to see in PostgreSQL 10.  [Disclaimers: (1) Other people may have different opinions.  (2) It is not impossible that some patches could be reverted prior to release.  (3) The list below represents the work of the entire PostgreSQL community, not specifically me or EnterpriseDB, and I have no intention of taking credit for anyone else's work.]
      Read more »
      03 Apr 15:49

      Ativando o Optimus NVIDIA GPU no Dell XPS 15 com Linux, mesmo na bateria

      by Fábio Akita

      Já se passou um bom tempo desde meu artigo sobre tuning Manjaro para o Dell XPS 15. Manjaro lançou uma versão mais recente (17) e o kernel lançou a 4.10. A atualização do Manjaro 16 e do kernel 4.9 se deu sem problemas.

      Estes são os pacotes específicos do kernel atualmente instalados:

      $ pacman -Ss 410 | grep installed
      core/linux410 4.10.1-1 [installed]
      core/linux410-headers 4.10.1-1 [installed]
      extra/linux410-acpi_call 1.1.0-0.7 (linux410-extramodules) [installed]
      extra/linux410-bbswitch 0.8-0.7 (linux410-extramodules) [installed]
      extra/linux410-ndiswrapper 1.61-0.7 (linux410-extramodules) [installed]
      extra/linux410-nvidia 1:375.39-0.7 (linux410-extramodules) [installed]

      E para ter certeza de que tudo está ok, eu removi os antigos pacotes relacionados à versão 4.9:

      sudo pacman -R linux49 linux49-headers linux49-acpi_call linux49-bbswitch linux49-ndiswrapper linux49-nvidia

      Eu também atualizei a BIOS para a mais recente, 1.2.19 (embora muitos tenham dito para ficar em 1.2.18 por enquanto, mas eu não reduzi). A atualização da BIOS é bastante fácil porque você só precisa ter uma unidade USB formatada FAT e copiar o arquivo “XPS_9550_1.2.19.exe”. Na inicialização, você pode pressionar F12 e escolher a opção para atualizar diretamente de lá.

      Uma coisa que parou de funcionar foram as teclas de função para controlar o brilho da tela. Eu não fui capaz de resolver isso de volta, mas eu ainda posso controlar o brilho manualmente a partir do Terminal usando comandos como este:

      xbacklight -inc 20 # to increment
      xbacklight -dec 20 # to decrement

      Então, a parte mais irritante: o cartão NVIDIA Optimus.

      Suspender o sistema operacional funciona perfeitamente na maioria das vezes. Eu posso apenas fechar a tampa, abrir no outro dia e a bateria permanece razoavelmente no mesmo nível. Kudos para a equipe do kernel por apoiar isso.

      Mas o sistema de gerenciamento de energia desliga a GPU NVIDIA e não posso reativá-la depois que a máquina voltar da suspensão, mesmo que eu a conecte novamente a uma fonte de alimentação. Sempre que eu tento executar algo através de optirun (o que força o processamento através da GPU NVIDIA em vez da GPU Intel integrado primário) ele dá erro com esta mensagem:

      Could not enable discrete graphics card

      E a única maneira de tê-lo em execução era conectar o cabo de alimentação e reiniciar a máquina. Então, eu poderia usar o NVIDIA GPU normalmente. Reiniciar o tempo todo não é lento (graças ao rápido SSD), mas ainda é chato ter que reabrir cada aplicativo toda vez.

      Finalmente, depois de muita pesquisa, eu descobri como ter o NVIDIA GPU habilitado mesmo na bateria e após suspender. Primeiro, você precisa saber o ID PCI para o cartão:

      $ lspci | grep "NVIDIA" | cut -b -8
      01:00.0

      Então, você precisa editar /etc/default/tlp e adicionar esse ID PCI para ser colocado na lista negra do gerenciamento de energia:

      # Exclude PCI(e) device adresses the following list from Runtime PM
      # (separate with spaces). Use lspci to get the adresses (1st column).
      #RUNTIME_PM_BLACKLIST="bb:dd.f 11:22.3 44:55.6"
      RUNTIME_PM_BLACKLIST="01:00.0"

      Reinicie e é isso! Agora eu posso executar aplicativos através do cartão NVIDIA mesmo sem estar conectado ao cabo de alimentação.

      Parece que há um conflito entre TLP e Bumblebee. A solução foi listada neste tópico do reddit de janeiro/2017  e neste tópico de fevereiro/2017 no fórum Manjaro se você estiver interessado na discussão sobre isso.

      A parte mais difícil de usar o NVIDIA no Linux é entender todas as muitas terminologias dele. Nem mesmo tenho certeza de que já compreendi tudo.

      Isso é o que eu descobri até agora:

      • Optimus é a tecnologia de cards gráficos híbridos, que permite que uma GPU Intel de baixa potência seja o card principal que você pode conectar à secundária GPU NVIDIA, exigente em termos de energia, exatamente quando você realmente precisa dele.
      • optirun é o comando que você usa para fazer essa conexão.
      • “NVIDIA” é o que chamamos de binários proprietários oficiais. No Arch está disponível no pacote “linux410-nvidia”.
      • “Nouveau” é o driver de código aberto, ele usa Primus para fazer a conexão em vez de optirun. Acredito que você deve evitar esse driver por enquanto se precisar de desempenho completo e conformidade total da GPU.
      • Bumblebee” é um daemon usado para ativar e desativar a NVIDIA GPU. Você não quer que ele esteja ativado o tempo todo, especialmente quando estiver sendo executado com bateria, para evitar drená-la muito rápido.
      • bbswitch” é o módulo do kernel que faz chamadas ACPI de baixo nível para controlar o estado de energia do cartão NVIDIA GPU.
      • TLP” é o sistema de gerenciamento de energia geral do Linux, que controla todos os aspectos do hardware da máquina, incluindo os dispositivos PCI (um dos quais é o cartão NVIDIA).

      Eu entendo que você não quer que TLP entre em cena e desligue o cartão, porque se ele o fizer, então Bumblebee não poderá ativá-lo novamente quando necessário (através de bbswitch). Então você tem que colocar na lista negra o dispositivo PCI em TLP e deixar Bumblebee fazer o seu trabalho.

      Se tudo estiver funcionando bem, então NVIDIA GPU estará desativada por padrão. Você pode verificar se ela está desligada através de bbswitch:

      $ cat /proc/acpi/bbswitch
      0000:01:00.0 OFF

      Agora, digamos que você queira forçar algo a usar o card, então você faz isso assim:

      $ optirun -vv glxgears
      [ 1817.200384] [DEBUG]Reading file: /etc/bumblebee/bumblebee.conf
      [ 1817.200519] [INFO]Configured driver: nvidia
      [ 1817.200579] [DEBUG]optirun version 3.2.1-2017-02-27-Format:%h$ starting...
      [ 1817.200584] [DEBUG]Active configuration:
      [ 1817.200588] [DEBUG] bumblebeed config file: /etc/bumblebee/bumblebee.conf
      [ 1817.200592] [DEBUG] X display: :8
      [ 1817.200595] [DEBUG] LD_LIBRARY_PATH: /usr/lib/nvidia:/usr/lib32/nvidia
      [ 1817.200599] [DEBUG] Socket path: /var/run/bumblebee.socket
      [ 1817.200603] [DEBUG] Accel/display bridge: auto
      [ 1817.200607] [DEBUG] VGL Compression: proxy
      [ 1817.200611] [DEBUG] VGLrun extra options: 
      [ 1817.200615] [DEBUG] Primus LD Path: /usr/lib/primus:/usr/lib32/primus
      [ 1817.200645] [DEBUG]Using auto-detected bridge virtualgl
      [ 1818.163747] [INFO]Response: Yes. X is active.
      
      [ 1818.163757] [INFO]Running application using virtualgl.
      [ 1818.163843] [DEBUG]Process vglrun started, PID 9770.
      10419 frames in 5.0 seconds = 2083.766 FPS
      10671 frames in 5.0 seconds = 2134.041 FPS

      Isto irá executar glxgears (um aplicativo simples para testar o card) através da conexão Optimus (em modo detalhado, é por isso que você tem todas essas informações extras). E se glxgears era capaz de usar a NVIDIA GPU, ele deve relatar FPS (frames per second) maior que 1.000.

      E você pode verificar com bbswitch como este:

      $ cat /proc/acpi/bbswitch
      0000:01:00.0 ON

      Quando você Ctrl-C fora de glxgears ele deve relatar como OFF novamente.

      Apenas para ter certeza, é importante garantir que o /etc/bumblebee/bumblebee.conf está personalizado como este (somente as chaves importantes são mostradas abaixo):

      [bumblebeed]
      Driver=nvidia
      ...
      [optirun]
      Bridge=auto
      ...
      [driver-nvidia]
      KernelDriver=nvidia
      PMMethod=bbswitch
      ...

      Até agora, as únicas pequenas questões que ainda tenho são as seguintes:

      • As teclas de função não alteram o brilho da tela
      • Fone de ouvido bluetooth Bose conecta perfeitamente, mas não se tornará saída de som primária sem manualmente mudar para tal nas configurações de Som (mas todas as teclas de função de hardware para controle de volume e mídia funcionam sem problemas).
      • Eu tive que instalar o Manjaro usando o boot antigo da BIOS e o esquema de partição MBR em vez de GPT sobre UEFI. Não sei com certeza como mover para GPT/UEFI agora (usando um esquema de partição cifrada LUKS)

      Depois de corrigir a NVIDIA GPU após uma suspensão ou desligamento de energia, os outros problemas são apenas pequenos aborrecimentos.

      Até agora, estou muito feliz por estar usando Manjaro no Dell XPS. Estou usando uma configuração de monitor duplo e tudo está funcionando perfeitamente. Se você quiser tentar isto, eu recomendo que você fique com a versão 9560 (versão mid 2016) Sandy Bridge. Não vá para as novas versões Kaby Lake ainda, pois você vai achar BIOS firmware bastante bugado e muitos aspectos do hardware não estarão ainda devidamente suportados ou documentados.

      E se você é novo no Arch, eu recomendo que você comece com o Manjaro GNOME. É de longe o melhor e mais útil desktop Linux que eu já tentei.

      ***

      Artigo traduzido com autorização do autor. Publicado originalmente em http://www.akitaonrails.com/2017/03/14/enabling-optimus-nvidia-gpu-on-the-dell-xps-15-with-linux-even-on-battery

      30 Mar 20:43

      Privacidade: módulo de segurança de internet banking solicita senha sudo de usuários linux

      by Augusto Campos
      Tenho uma conta no Banco do Brasil, como muitos outros brasileiros. Utilizo o Internet Banking do BB no meu computador. Sou usuário Ubuntu já há vários anos. Todavia, essa notícia é importante para outros usuários Linux.

      Em março de 2017 usuários do Internet Banking do Banco do Brasil começaram a receber a mensagem de que um novo módulo de segurança necessitava ser instalado. Para ver a mensagem de erro basta acessar o site do BB e clicar no botão "ACESSE SUA CONTA" (a mensagem de erro aparece caso você não tenha o módulo instalado. A mensagem aparece tanto em sistemas Windows quanto Linux, e em ambos navegadores, Firefox e IE.

      Se você quiser acessar o Internet Banking obrigatoriamente terá que instalar o módulo. As instruções de instalação estão disponíveis nos links da página com o erro.

      Eu fiz a instalação no meu sistema Ubuntu e qual não foi a minha surpresa quando percebi que o durante o processo de instalação do módulo foi solicitada a minha senha de administrador (senha sudo).

      Aparentemente o software "warsaw", desenvolvido pela GAS Tecnologia, da empresa Diebold, desenvolveu um módulo de segurança que discretamente solicita o usuário ubuntu/linux a sua senha de administrador. Isso fica claro nas próprias instruções para instalação do módulo que estão disponíveis na página de ajuda e tira-dúvidas do BB para o sistema Ubuntu/Mint. O walkthrough com as imagens mostra duas caixas de diálogo durante o processo de instalação: uma caixa apresentada pelo próprio sistema Ubuntu solicitando permissão para instalação de software (o que é um procedimento padrão); e uma segunda caixa de diálogo que é apresentada pelo instalador e que requisita novamente a senha de administrador com a mensagem "Você precisa ter permissões de administrador para instalar softwares. Pode ser inseguro instalar pacotes manualmente. Instale apenas programas de origem confiável."

      (...) Note que alguns usuários serão perspicazes o suficiente para perceberem que algo está errado com o instalador, e que ele não deveria solicitar a senha sudo. Porém, grande parte dos usuários não possui conhecimento suficiente para compreender o alcance do processo, e provavelmente digitarão a sua senha novamente nessa segunda caixa de diálogo, permitindo que a GAS Tecnologia tenha acesso ao seu computador de uma forma que não fosse tão séria, seria até banal.

      O usuário leigo, que não possui um maior conhecimento de sistemas de computação, não irá duvidar da validade da segunda solicitação por vários motivos. (1) A instalação do software é obrigatória - sem a instalação do módulo de segurança o cliente não tem acesso ao Internet Banking; (2) O software é utilizado por uma instituição financeira de renome e respeitável, além de ser uma das maiores no Brasil (o software também é utilizado por outras instituições financeiras, porém eu sou cliente apenas do BB); (3) a caixa de diálogo do instalador é apresentada de forma a assemelhar-se à caixa de diálogo do sistema Ubuntu, portanto não sendo honesta na sua apresentação e induzindo o usuário a digitar novamente a sua senha.

      A comunidade Linux deve levantar-se contra softwares que não respeitam o usuário e seu direito à privacidade. Milhões de usuários estão sendo obrigados a utilizar esse módulo de segurança que, no mínimo, pode ser considerado questionável no seu processo de instalação.

      Reclamações em relação à GAS Tecnologia não são raras com atestam as inúmeras reclamações enviadas para o site Reclame Aqui.

      Enviado por Daniel Montezano (tnlmontezanoΘgmail·com)

      O artigo "Privacidade: módulo de segurança de internet banking solicita senha sudo de usuários linux" foi originalmente publicado no site BR-Linux.org, de Augusto Campos.

      31 Jan 19:08

      PG Phriday: Everything in Common

      by Shaun

      Not a lot of people remember what Postgres was like before version 8.4. In many ways, this was the first “modern” release of the database engine. CTEs, Window Functions, column level permissions, in-place upgrade compatible with subsequent versions, collation support, continuous query statistic collection; it was just a smorgasbord of functionality.

      Of these, CTEs or Common Table Expressions, probably enjoy the most user-level exposure; for good reason. Before this, there was no way to perform a recursive query in Postgres, which really hurts in certain situations. Want to display all related child threads in an online discussion? How about fetching the components of an organization chart by following management assignments? Better get ready for a lot of queries in a loop.

      In addition to that, complicated queries were difficult to logically simplify. Reporting queries are especially prone to frequent sequences of aggregates and subqueries. It’s not uncommon to build a query that’s several pages long in this kind of context. Optimizing such an unwieldy beast is often difficult or even impossible simply due to all of the components and confusing nesting.

      CTEs changed these things for the better and in the eyes of many, finally brought Postgres to parity with Oracle and its long-established recursive query support. So let’s explore what CTEs really deliver, and how they can improve our Postgres experience—caveats and all.

      Let’s start with a trivial table and some data:

      CREATE TABLE employee 
      (
        employee_id  SERIAL PRIMARY KEY,
        full_name    VARCHAR NOT NULL,
        manager_id   INT REFERENCES employee
      );
      
      

      INSERT INTO employee (full_name, manager_id) VALUES ('King Randor', NULL), ('Prince Adam', 1), ('Teela', 2), ('Man-at-Arms', 2), ('Skeletor', NULL), ('Evil-Lyn', 5), ('Trap Jaw', 5), ('Clawful', 6);

      It’s easy enough to display the management relationships. Here’s how our cartoon cohorts look with a basic JOIN:

      SELECT m.full_name AS boss, e.full_name AS goon
        FROM employee e
        JOIN employee m ON (m.employee_id = e.manager_id)
       ORDER BY e.manager_id;
      
      
      boss     |    goon     
      

      -------------+------------- King Randor | Prince Adam Prince Adam | Teela Prince Adam | Man-at-Arms Skeletor | Evil-Lyn Skeletor | Trap Jaw Evil-Lyn | Clawful

      In this trivial example, we can visually follow the results and understand that Clawful is ultimately a minion of Skeletor. We could also leverage our knowledge that the organization chart is only three levels deep and employ a third join to fully represent all relationships. But such a shallow corporate hierarchy is exceedingly rare, so let’s use a CTE to flush out the table instead.

      WITH RECURSIVE org_tree AS (
          SELECT NULL::VARCHAR AS boss, , 0 AS level,
                 employee_id AS end_boss
            FROM employee
           WHERE manager_id IS NULL
          UNION ALL
          SELECT t.full_name AS boss, e., t.level + 1 AS level,
                 t.end_boss
            FROM employee e
            JOIN org_tree t ON (t.employee_id = e.manager_id)
      )
      SELECT repeat(' ', level * 5) || full_name AS relationship
        FROM org_tree
       ORDER BY end_boss, level;
      
      

      relationship

      King Randor Prince Adam Teela Man-at-Arms Skeletor Trap Jaw Evil-Lyn Clawful

      Well that’s quite an improvement! But how does it work?

      Our initial clue is the first query within the CTE. Other databases may do this differently, but Postgres creates a temporary in-memory table to act as a holding area to represent the CTE contents as they’re constructed. When we specify the RECURSIVE decorator, we gain the ability to bootstrap that temporary data with one query. The second query can then refer to the cumulative result in each iteration of the recursion.

      The result is one query that loops in on itself three times in our example. We took advantage of this by adding a new column to track how deep the recursion is so we can visualize this more easily. Here’s what the contents of the “tree” table look like for each phase:

      WITH RECURSIVE tree AS (
          SELECT NULL::VARCHAR AS boss, , 0 AS level
            FROM employee
           WHERE manager_id IS NULL
          UNION ALL
          SELECT t.full_name AS boss, e., t.level + 1 AS level
            FROM employee e
            JOIN tree t ON (t.employee_id = e.manager_id)
      )
      SELECT * FROM tree;
      
      
      boss     | employee_id |  full_name  | manager_id | level 
      

      -------------+-------------+-------------+------------+------- | 1 | King Randor | | 0 | 5 | Skeletor | | 0 King Randor | 2 | Prince Adam | 1 | 1 Skeletor | 6 | Evil-Lyn | 5 | 1 Skeletor | 7 | Trap Jaw | 5 | 1 Prince Adam | 3 | Teela | 2 | 2 Prince Adam | 4 | Man-at-Arms | 2 | 2 Evil-Lyn | 8 | Clawful | 6 | 2

      Each “level” here represents one dive into the employee table to fetch employees of the employees already listed. This loop naturally terminates once every boss is listed in the results. But there’s one flaw in this particular construction: what if we wanted to choose any grunt and see the whole chain of command from that point? To do that, we need to modify the CTE slightly to incorporate our desired predicate in the CTE portion itself so we can follow the relationship properly.

      Here’s how that looks:

      WITH RECURSIVE tree AS (
          SELECT , 0 AS level
            FROM employee
           WHERE full_name = 'Clawful'
          UNION ALL
          SELECT e., t.level + 1 AS level
            FROM tree t
            JOIN employee e ON (e.employee_id = t.manager_id)
      )
      SELECT full_name
        FROM tree
       ORDER BY level DESC;
      
      

      full_name

      Skeletor Evil-Lyn Clawful

      Not bad, eh? We had to flip the JOIN because we started with a specific minion instead of the list of all executives. Then we followed the chain backwards, adding one middle-management peon per iteration until we reached the End Boss. We could combine this kind of trickery by writing a CTE that refers to another CTE and produce a query that would output the entire organization given any member in the hierarchy. We won’t, because that’s a gigantic and rather ugly query, but the capability is there.

      What we can do, is demonstrate using CTEs to logically separate query fragments of a larger whole. In the past, a reporting query might consist of an imposing bulk of awkward subqueries to produce necessary aggregates and decode or label various summaries. In the worst cases, such queries might meander for dozens of pages. It’s often a miracle the end result executes at all, and debugging it is equally problematic.

      Here’s how we might use CTEs to solve that conundrum:

      WITH RECURSIVE org_tree AS (
          SELECT NULL::VARCHAR AS boss, , 0 AS level,
                 employee_id AS end_boss
            FROM employee
           WHERE manager_id IS NULL
          UNION ALL
          SELECT t.full_name AS boss, e., t.level + 1 AS level,
                 t.end_boss
            FROM employee e
            JOIN org_tree t ON (t.employee_id = e.manager_id)
      ),
      org_stats AS (
        SELECT m.full_name AS ceo, count()-1 AS minions,
               max(level) AS cruelty
          FROM org_tree org
          JOIN employee m ON (m.employee_id = org.end_boss)
         GROUP BY m.full_name
      ),
      org_attributes AS (
        SELECT m.full_name AS ceo,
               sum(1) FILTER (WHERE org.full_name ILIKE '%evil%') AS evil,
               sum(1) FILTER (WHERE org.full_name ILIKE '%prince%' OR
                                    org.full_name ILIKE '%king%') AS royalty
          FROM org_tree org
          JOIN employee m ON (m.employee_id = org.end_boss)
         GROUP BY m.full_name
      )
      SELECT st., atr.evil, atr.royalty
        FROM org_stats st
        JOIN org_attributes atr USING (ceo);
      
      
       ceo     | minions | cruelty | evil | royalty 
      

      -------------+---------+---------+------+--------- King Randor | 3 | 2 | | 2 Skeletor | 3 | 2 | 1 |

      The first portion of the query is just our previous recursive attempt to flatten the organization chart and see how everything is related. The second summarizes basic statistics like employee count and maximum abstraction through middle-management. The third is just a bunch of miscellaneous attributes that might be interesting in a report. All of our examples are trivial, but in a real report, each of these may reflect much more comprehensive aggregates and formulas. Yet despite query complexity, we can determine the end goal of a fragment at a glance. Combine this with SQL comments, and we have a very user-friendly report.

      Of course, CTEs are not all sunshine and roses. Remember when we said a CTE is built in a temporary memory location to facilitate recursive functionality and allow CTEs to reference each other? A consequence is that every CTE acts as what we call an optimization fence.

      Normally before a query is executed, it is broken down into its component parts and the planner translates those elements into execution instructions. This might mean collapsing certain conditionals, simplifying or substituting a subquery, pushing predicates down into a stack for better row elimination, and so on.

      When the planner encounters a CTE however, it can go no further. It will optimize the CTE query itself, but it does so as an encapsulated black box. Even if a WHERE clause from the referring query could greatly reduce matched rows during the CTE execution, that optimization cannot be applied. The CTE executes as written as if we had done this instead:

      CREATE TEMP TABLE my_cte_chunk AS
      SELECT ...
      

      This applies to every CTE in a query. It’s better to think of each CTE as a virtual temporary table. While that allows each CTE to refer to the entire contents of another CTE, it also means we may lose several opportunities to optimize a query. It’s not uncommon to unroll a CTE and receive a much faster query in return. Query planners are complex beasts, and like any software compiler, may simplify necessary instructions by eliminating entire branches from the execution tree due to redundancy or empty result paths. Using a CTE reduces the planner’s ability to do that.

      On the other hand, an experienced user can leverage this knowledge to their benefit. Since the query planner cannot penetrate optimization fences, it means we can override its decision tree. When the data or statistics indicate the planner will improperly prefer a highly inefficient plan, we can force it along an improved path. In these cases, we’re actively trading the potential for future planner improvements for immediate advantage.

      The primary argument here is that the planner improvements we need may not arrive for years, or at all. Can we justify suffering bad performance for an undetermined length of time until some nebulous future planner addresses our obscure data edge case? Often the answer to this question is ‘no’. In the rare instances where this justification applies, leveraging optimization fences is probably a safe bet. At least we have the option!

      In the end, Postgres improved its reputation among power users, and we gained a versatile tool that enabled the previously impossible. New recursion, simplification, and optimization options, all from a single feature? Yes, please!

      25 Nov 17:01

      David Rader: Holy Easy PostgreSQL deployment

      Holy Easy PostgreSQL deployment!

      In case you missed it, the BigSQL team released an awesome package manager for installing and configuring PostgreSQL and many related, useful components. The package manager can be found here: https://www.bigsql.org/package-manager.jsp.

      Playfully named pgc, for ‘pretty good command line’, pgc is a utility similar to yum or apt-get that allows you to install, configure, update and manage Postgres related components including foreign data wrappers, stored procedure languages, connectors, devops tools, HA tools and monitoring tools. Common uses:

      • Provision Postgres (9.2 through 9.6, including multiple versions on same server)
      • Installing pgBouncer, Backrest, and other community projects
      • Scripting configurations in chef or other devops tools

      PGC runs on Linux, Windows and OS X and supports the same exact cli so it is an ideal provisioning/management tool for multi OS environments.

      PGC not only allows you to get and install these components but you can use pgc to update each component as new updates become available.

      PGC’s syntax is very intuitive and easy to use:

      Use the help command to see the possible commands:

      $ ./pgc help
      Usage: pgc command [component1 component2 ...]
      Common commands:
      help - Show this help file
      info - Display OS or component information
      list - Display installed & available components
      status - Display status of installed server components
      start - Start server components
      stop - Stop server components
      enable - Enable a server component
      disable - Disable a server component from starting automatically
      update - Retrieve new list of available components
      upgrade - Upgrade installed components to newer (compatible) versions
      install - Install a component
      remove - Remove a component
      Advanced commands:
      init - Initialize a component
      download - Download a component
      config - Configure a component
      clean - Remove component files from download cache
      enable - Enable a server component
      disable - Disable a server component from starting automatically

      Example workflow:

      1) Checking to see what components are available

      The list command displays installed and available components. It confirms that the core 
Postgres 9.6 server component is installed.

      $ ./pgc list
      Category     | Component           | Version   | Stage | ReleaseDt  | Status         | Cur? | Updates
      PostgreSQL     pg92                  9.2.18-2a           2016-09-15                    1
      PostgreSQL     pg93                  9.3.14-2a           2016-09-15                    1
      PostgreSQL     pg94                  9.4.9-2a            2016-09-15                    1
      PostgreSQL     pg95                  9.5.4-2             2016-08-18                    1
      PostgreSQL     pg96                  9.6.0-1             2016-09-29   Installed        1
      Extensions     hadoop_fdw2-pg96      2.5.0-1             2016-09-01                    1
      Extensions     oracle_fdw1-pg96      1.5.0-1             2016-09-01                    1
      Extensions     orafce3-pg96          3.3.1-1             2016-09-23                    1
      Extensions     plprofiler3-pg96      3.0-1               2016-10-08                    1
      Extensions     plv814-pg96           1.4.8-1             2016-09-01                    1
      Extensions     postgis22-pg96        2.2.2-2             2016-09-01                    1
      Extensions     postgis23-pg96        2.3.0-1             2016-10-08                    1
      Extensions     slony22-pg96          2.2.5-2             2016-09-01                    1
      Servers        bam2                  1.6.2               2016-09-15                    1
      Servers        cassandra30           3.0.8               2016-09-01                    1
      Servers        hadoop26              2.6.4               2016-02-14                    1
      Servers        hive2                 2.0.1               2016-06-16                    1
      Servers        pgbouncer17           1.7.2-1a            2016-10-08                    1
      Servers        pgha2                 2.1b                2015-12-17                    1
      Servers        pgstudio2             2.0.1-2             2016-03-23                    1
      Servers        spark16               1.6.1               2016-03-16                    1
      Servers        tomcat8               8.5.4               2016-09-01                    1
      Servers        zookeeper34           3.4.8               2016-03-30                    1
      Applications   backrest              1.08                2016-09-23                    1
      Applications   birt                  4.5.0               2016-05-12                    1
      Applications   ora2pg                17.4                2016-05-12                    1
      Applications   pgbadger              9.0                 2016-09-03                    1
      Frameworks     java8                 8u92                2016-07-01                    1

      2) Installing a component

      Use the install command to provision a component

      $ ./pgc install pg96
      [‘pg96′]
      Get:1 http://s3.amazonaws.com/pgcentral pg96-9.6.0-1-linux64
      Unpacking pg96-9.6.0-1-linux64.tar.bz2

      3) Initialize PostgreSQL 9.6

      ./pgc init pg96
      ## Initializing pg96 #######################
      Superuser Password [password]:
      Confirm Password:
      Giving current user permission to data dir
      Initializing Postgres DB at:
      -D “/software/bigsql/data/pg96″
      Using PostgreSQL Port 5432
      Password securely remembered in the file: /home/oscgadmin/.pgpass
      to load this postgres into your environment, source the env file:
      /software/bigsql/pg96/pg96.env

      4) Add extensions, such as FDW’s, PostGIS, Slony replication, or the NEW plProfiler 3

      $ ./pgc list –extensions pg96
      Category   | Component        | Version | Stage | ReleaseDt  | Status | Cur? | Updates
      Extensions   hadoop_fdw2-pg96   2.5.0-1           2016-09-01            1
      Extensions   oracle_fdw1-pg96   1.5.0-1           2016-09-01            1
      Extensions   orafce3-pg96       3.3.1-1           2016-09-23            1
      Extensions   plprofiler3-pg96   3.0-1             2016-10-08            1
      Extensions   plv814-pg96        1.4.8-1           2016-09-01            1
      Extensions   postgis22-pg96     2.2.2-2           2016-09-01            1
      Extensions   postgis23-pg96     2.3.0-1           2016-10-08            1
      Extensions   slony22-pg96       2.2.5-2           2016-09-01            1
      $ ./pgc install plprofiler3-pg96
      [‘plprofiler3-pg96′]
      Get:1 http://s3.amazonaws.com/pgcentral plprofiler3-pg96-3.0-1-linux64
      Unpacking plprofiler3-pg96-3.0-1-linux64.tar.bz2

      5) Install and launch a GUI management and monitoring console – BigSQL Manager:

      $ ./pgc install bam2
      [‘bam2′]
      Get:1 http://s3.amazonaws.com/pgcentral bam2-1.6.2
      Unpacking bam2-1.6.2.tar.bz2
      oscgadmin@ubuntu:~/Downloads/bigsql$ ./pgc start bam2
      bam2 starting on port 8050
      bam2 started on port 8050.

      BigSQL Manager

      As you can see, pgc by BigSQL is an easy to use provisioning tool for Postgres and its related components. Anyone looking to use Postgres in their DevOps environment would benefit from using pgc so take a look at it today! https://www.bigsql.org/package-manager.jsp

      18 Nov 00:35

      Oração, sofrimento, Palavra e fé

      by Francisco Nunes
      Ore! Deus ouve!
      Ore! Deus ouve!

      Donizete, um amado irmão, é o marido de Maria de Luca, essa querida irmã que coopera com o Campos de Boaz como editora. Ela é que tem publicado os últimos Gotas de Orvalho. O Doni está há mais de um mês na UTI. Por causa de dores de cabeça, foi fazer uma tomografia, que revelou um tumor no cerebelo. Feita a cirurgia, teve meningite, trombose e outras complicações. Ele está bem, recuperando-se, mas ainda amarrado à cama, pois não deve se mover, com dificuldade para falar, cansado. Depois que tiver alta, terá um longo processo de recuperação pela frente.

      Doni e Maria têm um lindo casal de filhos.

      A situação não é apenas de expectativa e de sofrimento. Deus tem usado isso para operar algo novo, maravilhoso na família e em todos os que os conhecem (eu me incluo como um especial privilegiado pela amizade desse casal). Recentemente, Maria me enviou um texto pelo WhatsApp que, com a permissão dela, publico aqui.

      Sei que o apoio e as orações dos irmãos é que estão nos sustentando. Eu estou aqui, esperando no Senhor. Sei que Ele é poderoso. A mim, cabe apenas me humilhar na presença Dele e clamar por Sua misericórdia e compaixão até que se compadeça de nós.

      Eu tive uma conversa com as crianças essa semana. Eu lhes expliquei, usando o salmo 139, que todos os nossos dias foram escritos na presença de Deus. E que, se o Senhor não voltar antes, cada um de nós será chamado a Sua presença quando Ele determinar. E por isso nós poderíamos descansar. Porque o papai só pode morrer se for o momento em que o Senhor chamar. E, mesmo que alguém esteja com plena saúde, se Ele chamar, esse alguém morrerá.

      Então, um dia depois, meu filho foi disputar um campeonato com a equipe da escola. Foram bem colocados e ganharam até medalha. No dia seguinte, o pai de um de seus colegas trabalhou o dia todo normalmente. À noite, ao chegar em casa, sentiu-se mal. Teve um ataque fulminante do coração e morreu. Meu filho me disse que se lembrou do que eu havia falado.

      Olho para o Doni dormindo no hospital e penso em tantas coisas que o Senhor está me ensinando com tudo isso enquanto ele dorme. Ensinando a meus filhos e a toda nossa família. Vejo o quanto minha fé é vacilante e como gostamos de ter o controle sobre tudo o que nos acontece. Como somos relutantes em nos jogar nos braços do Pai e dizer-Lhe que faça Sua vontade! Como ainda tememos a morte! Como ainda nos falta a coragem e a bravura de irmãos do passado cuja única coisa que temiam era desagradar o Pai! Que o Senhor, em Sua misericórdia, me encontre vigilante.

      Eu respondi a ela:

      Maria, eu seria muito leviano se tentasse acrescentar qualquer coisa ao que você disse. Mesmo concordar com isso, eu sinto, é, de minha parte, superficial, pois só consigo imaginar o que seja esse tempo.

      O pouco que conheço do Senhor me faz saber que Ele é sempre bondoso, mesmo quando nos conduz pelo vale da sombra da morte. Fugimos tanto dela, e ela é tão real, precisa e inevitável. E nossos filhos precisam saber disso, pois, em Adão, somos todos perecíveis.

      Muito obrigado por partilhar isso comigo. Sinto-me honrado por vocês e agraciado pelo Senhor em poder ler isso. Se me permite, eu gostaria de publicar um artigo no Campos, pedindo oração dos leitores também e partilhando esse texto. Não o farei sem sua autorização.

      Li ontem num livro do Spurgeon: “É bom ficar sabendo que Deus não põe fardos pesados sobre ombros inexperientes. […] Não pense que, à medida que você cresce em graça, a vereda se tornará mais suave sob seus pés e os céus, mais serenos sobre sua cabeça. Ao contrário, reconheça que, conforme Deus lhe dá maior habilidade como soldado, Ele o mandará para empreitadas mais árduas ainda.” Que lhes sirva de consolo saber que Deus capacitou seus ombros para isso.

      Saibam que amamos imensamente vocês.

      Alguns dias depois, ela também me escreveu o seguinte:

      Eu estava terminando de ler um livro do Jerry Bridges quando tudo começou. O nome do livro é Confiando em Deus, mesmo quando a vida nos golpeia, aflige e fere. É um livro doce, resultado do estudo do autor sobre a soberania de Deus enquanto via o câncer consumir a saúde da esposa, até que o Senhor a tomou para Si. Foi uma leitura proveitosa, tanto para mim como para o Doni, que estava na metade do livro e terminou de lê-lo já no hospital, antes da cirurgia.

      O autor mostra tantos exemplos bíblicos de pessoas que sofreram dor e perda e, ainda assim, confiaram no Senhor. Dois apóstolos foram presos: Tiago e Pedro. A igreja orou pela libertação dos dois. Pedro foi liberto milagrosamente, enquanto Tiago foi decapitado. O que pensou a esposa de cada um deles?

      Tenho aprendido com estes e tantos outros exemplos que “nossa leve e momentânea tribulação produz para nós eterno peso de glória”. Os dias não têm sido fáceis. Um dia recebo uma boa notícia, no outro, uma ruim. Mas tenho comigo que nossa frágil vida está em mãos seguras. Como dizia Spurgeon, “a menos que Deus me chame, eu não posso morrer”. E o contrário é igualmente verdadeiro. Se Ele chamar você, não importa se goza de boa saúde ou tem prosperidade financeira que lhe garanta recursos mil, você irá se encontrar com Ele.

      Tenho vivido cada dia. Um de cada vez. Sem querer previsões, sem querer saber o que houve em casos como o dele. Confio apenas que Deus cuida dos Seus um a um. Ele escreve nossa história de maneira única. Embora os testemunhos sirvam sempre para nos dar alento, Hebreus nos alerta que, olhando para aqueles testemunhos, devemos imitar a fé que tiveram – e não os atos de fé.

      Conheço irmãos por quem oramos quando não havia mais esperança, e Deus os curou. Outros, igualmente piedosos, foram chamados a Sua presença. Então, aguardo em Deus o desfecho de tudo isso, sabendo que Ele é Deus e só Ele merece toda honra. Se Ele for glorificado com a cura do Doni, amém. Mas, se não, que Ele igualmente seja glorificado.

      Eu sou tão fraca e tenho uma fé tão vacilante! Mas tenho pedido a Deus que me fortaleça para que eu possa testemunhar sobre a paz de Jesus aos médicos com quem converso diariamente.

      Lembro-me sempre da paz que havia entre os irmãos morávios, a qual levou John Wesley a procurá-los, porque, mesmo em meio à grande tormenta, nem suas crianças temiam a morte. E aquilo o atraiu. Um irmão fez-lhe algumas perguntas que o levaram posteriormente a ter uma experiência real com Jesus, e ele se tornou o maior pregador da Inglaterra.

      Que o Senhor continue nos conduzindo, apesar de nossa fraqueza e grande debilidade. Ele é forte, capaz, bom e Todo-poderoso.

      Partilho tudo isso com você, prezado leitor do Campos de Boaz, em primeiro lugar para pedir suas orações por todos eles. Como costumo dizer, orações são sempre bem-vindas! Orações pela plena recuperação do Doni, sem nenhuma seqüela, por paciência e confiança para o tempo que ele ainda terá de passar no hospital. Oração pela Maria, para que o Senhor a capacite, dia após dia, a esperar, confiar e ajudar seus filhos a também confiarem e esperarem no Senhor. Pelos filhos, para que, apesar da pouca idade, conheçam o Senhor no meio desse sofrimento.

      Partilho também para que sirva de alerta: qualquer um de nós, e qualquer pessoa a quem amamos, a qualquer momento, pode ser chamado à presença do Senhor. Você está preparado? E seus filhos? Já conhecem o Senhor? São ajudados a confiar no Senhor? E seus amigos e parentes, a quem você muito ama, estão prontos para se encontrar com o Criador?

      Por fim, divido isso para que lhe sirva de encorajamento. Em toda situação, Deus quer apenas uma coisa: conformar-nos mais e mais à imagem de Seu Filho. Se O buscarmos, se nos submetermos a Sua vontade, por vezes misteriosa e cheia de dor, se exercitarmos nossa confiança e submissão a Ele, Deus obterá em nós o que deseja.

      Em Cristo, seu conservo

      Francisco Nunes

      12 Jun 12:10

      Andrew Dunstan: Indiscriminate use of CTEs considered harmful

      Common Table Expressions are a wonderful thing. Not only are they indespensible for creating recursive queries, but they can be a powerful tool in creating complex queries that are comprehensible. It's very easy to get lost in a fog of sub-sub-sub-queries, so using CTEs as a building block can make things a lot nicer.

      However, there is one aspect of the current implementation of CTEs that should make you pause. Currently CTEs are in effect materialized before they can be used. That is, Postgres runs the query and stashes the data in a temporary store before it can be used in the larger query. There are a number of consequences of this.

      First, this can be a good thing. I have on a number of occasions used this fact to good effect to get around problems with poorly performing query plans. It's more or less the same effect as putting "offset 0" on a subquery.

      However, it can also result in some very inefficient plans. In particular, if CTEs return a lot of rows they can result in some spectacularly poorly performing plans at the point where you come to use them. Note also that any indexes on the underlying tables will be of no help to you at all at this point, since you are no longer querying against those tables but against the intermediate result mentioned above, which has no indexes at all.

      This was brought home to me forcefully on Friday and Saturday when I was looking at a very poorly performing query. After some analysis and testing, the simple act of inlining two CTEs in the query in question resulted in the query running in 4% of the time it had previously taken. Indiscriminate use of CTEs had made the performance of this query 25 times worse.

      So the moral is: be careful in using CTEs. They are not just a convenient tool for abstracting away subqueries.

      There has been some discussion about removing this aspect of the implementation of CTEs. It's not something that is inherent in CTEs, it's simply a part of the way we have implemented them in PostgreSQL. However, for now, you need to be familiar with the optimization effects when using them, or you might face the same problem I was dealing with above.


      09 Jun 15:56

      Gotas de orvalho (51)

      by Francisco Nunes
      Orvalho dos céus para começar cada dia da semana

      A coroa de ferro do sofrimento precede a coroa de ouro da glória.

      (F. B. Meyer)

      Deus pediu a Abraão a coisa mais preciosa em sua vida. Não era Isaque que Deus queria, mas Abraão.

      (J. Oswald Sanders)

      Não se esqueça de que o mundo odeia a Palavra de Deus acima de tudo, mas precisa dela acima de tudo.

      (Henry Vögel)

      Desejo ardentemente o dia de Cristo. Quase posso chamar de cruel a Sua ausência. Oh!, quando O veremos?

      (Samuel Rutherford)

      Eu não quero nada para mim mesma; quero tudo para o Senhor.

      (Margaret Barber)

      Meus sentimentos estão tão presos ao céu que posso deixar a todos vocês sem remorsos. Não é que os ame menos, mas amo mais a Deus.

      (William Wilberforce)

      Existe algo de suave em ser podado por uma mão ferida.

      (Lady Powerscourt)

      06 Jun 14:41

      PG Phriday: Trusty Table Tiers

      by Shaun

      I always advocate breaking up large Postgres tables for a few reasons. Beyond query performance concerns, maintaining one monolithic structure is always more time consuming and consequentially more dangerous. The time required to create a dozen small indexes may be slightly longer than a single larger one, but we can treat the smaller indexes as incremental. If we want to rebuild, add more indexes, or fix any corruption, why advocate an all-or-nothing proposition? Deleting from one large table will be positively glacial compared to simply dropping an entire expired partition. The list just goes on and on.

      On the other hand, partitioning in Postgres can be pretty intimidating. There are so many manual steps involved, that it’s easy to just kick the can down the road and tackle the problem later, or not at all. Extensions like the excellent pg_partman remove much of the pain involved in wrangling an army of partitions, and we strongly suggest using some kind of tool-kit instead of reinventing the wheel.

      The main limitation with most existing partition management libraries is that they never deviate from the examples listed in the Postgres documentation. It’s always: create inherited tables, add redirection triggers, automate, rinse, repeat. In most cases, this is exactly the right approach. Unfortunately triggers are slow, and especially in an OLTP context, this can introduce sufficient overhead that partitions are avoided entirely.

      Well, there is another way to do partitioning that’s almost never mentioned. The idea is to actually utilize the base table as a storage target, and in lieu of triggers, schedule data movement during low-volume time periods. The primary benefit to this is that there’s no more trigger overhead. It also means we can poll the base table itself for recent data with the ONLY clause. This is a massive win for extremely active tables, and the reason tab_tier was born.

      Let’s create some data for testing this out:

      CREATE TABLE sensor_log (
        id            INT PRIMARY KEY,
        location      VARCHAR NOT NULL,
        reading       BIGINT NOT NULL,
        reading_date  TIMESTAMP NOT NULL
      );
       
      INSERT INTO sensor_log (id, location, reading, reading_date)
      SELECT s.id, s.id % 1000, s.id % 100,
             CURRENT_DATE - ((s.id * 10) || 's')::INTERVAL
        FROM generate_series(1, 5000000) s(id);
       
      CREATE INDEX idx_sensor_log_location ON sensor_log (location);
      CREATE INDEX idx_sensor_log_date ON sensor_log (reading_date);
       
      ANALYZE sensor_log;

      Now we have 5-million rows in a table with a defined date column that’s a perfect candidate for partitioning. The way this data is currently distributed, we have content going back to late 2014. Imagine in this scenario we don’t need this much live information at all times. So we decide to keep one week of logs for active use, and relegate everything else into some kind of monthly partition.

      This is how all of that would look in tab_tier:

      CREATE EXTENSION tab_tier;
       
      SELECT tab_tier.register_tier_root('public', 'sensor_log', 'reading_date');
       
      UPDATE tab_tier.tier_root
         SET root_retain = '1 week'::INTERVAL,
             part_period = '1 month'::INTERVAL
       WHERE root_schema = 'public'
         AND root_table = 'sensor_log';
       
      SELECT tab_tier.bootstrap_tier_parts('public', 'sensor_log');
       
      \dt
       
                       List OF relations
       Schema |          Name          | TYPE  |  Owner   
      --------+------------------------+-------+----------
       public | sensor_log             | TABLE | postgres
       public | sensor_log_part_201410 | TABLE | postgres
       public | sensor_log_part_201411 | TABLE | postgres
       public | sensor_log_part_201412 | TABLE | postgres
       public | sensor_log_part_201501 | TABLE | postgres
       public | sensor_log_part_201502 | TABLE | postgres
       public | sensor_log_part_201503 | TABLE | postgres
       public | sensor_log_part_201504 | TABLE | postgres
       public | sensor_log_part_201505 | TABLE | postgres
       public | sensor_log_part_201506 | TABLE | postgres
       public | sensor_log_part_201507 | TABLE | postgres
       public | sensor_log_part_201508 | TABLE | postgres
       public | sensor_log_part_201509 | TABLE | postgres
       public | sensor_log_part_201510 | TABLE | postgres
       public | sensor_log_part_201511 | TABLE | postgres
       public | sensor_log_part_201512 | TABLE | postgres
       public | sensor_log_part_201601 | TABLE | postgres
       public | sensor_log_part_201602 | TABLE | postgres
       public | sensor_log_part_201603 | TABLE | postgres
       public | sensor_log_part_201604 | TABLE | postgres
       public | sensor_log_part_201605 | TABLE | postgres

      Taking this piece by piece, the first thing we did after creating the extension itself, was to call the register_tier_root function. This officially tells tab_tier about the table, and creates a record with configuration elements we can tweak. And that’s exactly what we do by setting the primary retention window and the partition size. Creating all of the partitions manually is pointless, so we also invoke bootstrap_tier_parts. Its job is to check the range of dates currently represented in the table, and create all of the partitions necessary to store it.

      What did not happen here, is any data movement. This goes back to our original concern regarding maintenance. Some tables may be several GB or even TB in size, and moving all of that data as one gargantuan operation would be a really bad idea. Instead, tab_tier provides the migrate_tier_data function to relocate data for a specific partition.

      With a bit of clever SQL, we can even generate a script for it:

      COPY (
        SELECT 'SELECT tab_tier.migrate_tier_data(''public'', ''sensor_log'', ''' || 
               REPLACE(part_table, 'sensor_log_part_', '') || ''');' AS part_name
          FROM tab_tier.tier_part
          JOIN tab_tier.tier_root USING (tier_root_id)
         WHERE root_schema = 'public'
           AND root_table = 'sensor_log'
         ORDER BY part_table
      ) TO '/tmp/move_parts.sql';
       
      \i /tmp/move_parts.SQL
       
      SELECT COUNT(*) FROM ONLY sensor_log;
       
       COUNT 
      -------
       60480
       
      SELECT COUNT(*) FROM sensor_log_part_201504;
       
       COUNT  
      --------
       259200

      Following some debugging notices, all of our data has moved to the appropriate partition. We verified that by checking the base table and a randomly chosen partition for record counts. At this point, the table is now ready for regular maintenance. In this case “maintenance” means regularly calling the cap_tier_partitions and migrate_all_tiers functions. The first ensures target partitions always exist, and the second moves any pending data to a waiting partition for all tables we’ve registered.

      And that’s it. We’re completely done with this table. If we stopped here, we could be secure in the knowledge we no longer have to worry about some gigantic monolith ruining our day some time in the future. But that’s not how tab_tier got its name. One or two levels does not a tier make; the real “secret sauce” is its support for long term storage.

      One thing we didn’t really cover, and most partition systems never even consider, is that partitioning is only half of the story. On an extremely active system, having months or years of data just sitting around is relatively frowned upon. The mere presence of older data might encourage using it, transforming our finely tuned OLTP engine into a mixed workload wreck. One or two queries against those archives, and suddenly our cache is tainted and everything is considerably slower.

      We need to move that data off of the system, and there are quite a few ways to do that. Some might use ETL scripts or systems like talend to accomplish that goal. Or we can just use tab_tier and a Postgres foreign table. Let’s now dictate that only six months of archives should ever exist on the primary server. Given that constraint, this is how we could proceed:

      -- Do this on some kind of archive server
       
      CREATE USER arc_user PASSWORD 'PasswordsAreLame';
       
      CREATE TABLE sensor_log (
        id            INT PRIMARY KEY,
        location      VARCHAR NOT NULL,
        reading       BIGINT NOT NULL,
        reading_date  TIMESTAMP NOT NULL,
        snapshot_dt   TIMESTAMP WITHOUT TIME ZONE
      );
       
      GRANT ALL ON sensor_log TO arc_user;
       
      -- Back on the data source..,
       
      UPDATE tab_tier.tier_root
         SET lts_threshold = '6 months'::INTERVAL,
             lts_target = 'public.sensor_log_archive'
       WHERE root_schema = 'public'
         AND root_table = 'sensor_log';
       
      CREATE EXTENSION postgres_fdw;
       
      CREATE USER arc_user PASSWORD 'PasswordsAreLame';
      GRANT tab_tier_role TO arc_user;
      GRANT ALL ON ALL TABLES IN SCHEMA PUBLIC TO tab_tier_role;
       
      CREATE SERVER arc_srv 
        FOREIGN DATA WRAPPER postgres_fdw 
        OPTIONS (dbname 'postgres', host 'archive-host');
       
      CREATE USER MAPPING FOR arc_user 
        SERVER arc_srv 
        OPTIONS (USER 'arc_user', password 'PasswordsAreLame');
       
      CREATE FOREIGN TABLE sensor_log_archive (
        id            INT,
        location      VARCHAR NOT NULL,
        reading       BIGINT NOT NULL,
        reading_date  TIMESTAMP NOT NULL,
        snapshot_dt   TIMESTAMP WITHOUT TIME ZONE
       
      ) SERVER arc_srv OPTIONS (TABLE_NAME 'sensor_log');
       
      GRANT INSERT ON sensor_log_archive TO tab_tier_role;
       
      -- Connect as arc_user, then run this:
       
      SELECT tab_tier.archive_tier('public', 'sensor_log');
       
      SELECT COUNT(*) FROM sensor_log_archive;
       
        COUNT  
      ---------
       3263360

      Whew! That was a lot of work. Maybe a future version of tab_tier should provide a wrapper for that. In any case, all we did was set up a foreign table on a remote server, create a separate user to handle the data movement, and tell tab_tier about our six month threshold for long term storage, and the target table itself.

      Using a foreign table isn’t required here, since the target can be any kind of table, but isn’t that the whole point of this exercise? The cool thing about Postgres foreign data wrappers is that we could have used any of them. In this case we’re just moving data to another remote Postgres instance, but we could have dumped everything into Cassandra or Hadoop instead. Take that, subspace!

      For those who noticed all of the ridiculous GRANT statements, please remember this is only for demonstration purposes. A real system would probably use ALTER DEFAULT PRIVILEGES to give tab_tier_role more limited control over a specific schema and tables specifically designed for archival. The extension doesn’t add its own privileges—even to tables it creates—in case controls are tightly locked down. We don’t want to hijack any carefully laid down security. Instead tab_tier just propagates any ACLs it finds on root tables to new partitions.

      This is the same reason we ran the archive_tier (or archive_all_tiers) routine as a different user. Since we’re using a foreign user mapping, we want to limit data leak potential by isolating the movement process from the table owner or a superuser. We recommend using this approach for any foreign table usage whenever possible.

      With all of that out of the way, we still need to clean up. We archived all of the partition content, but the partitions themselves are still sitting around and gathering dust. Let’s fix that by running one final step as the owner of sensor_log or any superuser:

      SELECT part_table
        FROM tab_tier.tier_part
       WHERE is_archived;
       
             part_table       
      ------------------------
       sensor_log_part_201410
       sensor_log_part_201411
       sensor_log_part_201412
       sensor_log_part_201501
       sensor_log_part_201502
       sensor_log_part_201503
       sensor_log_part_201504
       sensor_log_part_201505
       sensor_log_part_201506
       sensor_log_part_201507
       sensor_log_part_201508
       sensor_log_part_201509
       sensor_log_part_201510
       
      SELECT tab_tier.drop_archived_tiers();
       
      SELECT COUNT(*) FROM sensor_log_archive;
       
        COUNT  
      ---------
       1736640

      During the archival process itself, tab_tier marks the related metadata so archived tables will no longer be used in any of the data movement functions. It also makes them an easy target for removal with a maintenance function. We can see that everything worked as a large portion of our data is no longer part of the sensor_log inheritance tree. Now the archived data is securely located on another system that’s probably geared more toward OLAP use, or some incomprehensible Hive we don’t have to worry about.

      I for one, welcome our incomprehensible Hive overlords.

      27 May 03:51

      Menos para os revisores…

      by Francisco Nunes

      Meditar é preciso. Revisar também.

      Facilmente se observa que o texto, lido hoje na Galileu online, não foi revisado.

      Primeira cochilada, mais do que evidente: professional. (Como essa é a forma em inglês, aumentam minhas suspeitas de que o texto foi traduzido e não mal revisado.) Em português, escreve-se profissional.

      Qua? A pressa na tradução e a falta de revisão uniram o que e o a. O correto seria “de que a meditação”. Mas no início da frase há um bom acerto: lembre-se de que. Quem se lembra, lembra-se de alguma coisa. Quem lembra, lembra alguma coisa.

      Não vou comentar o restante da frase, já que é um especialista que está dizendo. Mas acho difícil acreditar que a meditação vá fazer o sujeito ficar bombadão como os exercícios na academia.

      Crossfit é pros fracos. Eu tô meditando!

      Um gerente ou um engenheiro. Essa é uma construção típica do inglês, não usada, ou desnecessária, em português. Por aqui, dizemos e escrevemos apenas: Não importa se você é gerente ou engenheiro.

      Por fim, a forma correta é bem-estar. Mesmo com a lambança do Acordo Ortográfico, esse necessário hífen foi mantido. Bem-estar é substantivo; bem estar é o mesmo que estar bem. “Para ele bem estar, estamos cuidando de seu bem-estar.” “Sono de qualidade garante seu bem-estar o dia todo.” “Para eu bem estar, preciso dormir bem.”

      Aprendeu? Medite, mas não dispense a academia. E a revisão de seus textos.

      Abraço.

      O post Menos para os revisores… apareceu primeiro em Que falta faz um revisor!.

      27 May 03:39

      Utilizando o Optimize for ad-hoc workloads

      by Dennes Torres

      O servidor SQL Server possui a configuração Optimize for ad-hoc workloads, sobre a qual já escrevi uma dica antes.

      O SQL Server sempre cria um cache do plano de execução das queries que executamos, quer sejam stored procedures ou queries ad hoc. Porém, quando nossa atividade no servidor é demasiadamente focada em queries ad hoc – instruções SQL enviadas diretamente ao servidor, ao contrário do uso de procedures -, corremos o risco de que a criação dos planos de execução consuma memória de forma inadequada.

      Isso pode acontecer porque é possível que muitas das queries ad hoc que executamos no servidor jamais se repitam, por isso a armazenagem do plano de execução pode ser um desperdício de memória.

      Para resolver este problema, podemos utilizar a configuração ‘Optimize for Ad hoc queries’. Quando esta configuração está ativada, o servidor apenas guarda o plano de execução da query em cache na segunda vez que ela for executada, não da primeira.

      Na primeira execução é criado um stub em cache, contendo apenas uma contagem de execução da query. Na segunda execução, o stub é substituído pelo plano de execução real.

      Para ativar essa configuração, precisamos primeiro ativar a exibição de configurações avançadas:

      sp_configure 'show advanced options',1
      GO
      reconfigure
      GO

      Em seguida, ativar a configuração:

      sp_configure 'optimize for ad hoc workloads',1
      GO
      reconfigure
      go

      Para desativar, utilizamos as mesmas instruções, trocando “1” por “0”.

      Vamos fazer uma simulação para que você veja o efeito gerado. Utilizando o banco AdventureWorks, rode em um ambiente de teste as seguintes instruções:

      dbcc freeproccache
      go
      select * from person.person Where LastName='Raheem'
      go

      Agora vamos verificar o resultado dessa execução no cache:

      select usecounts,cacheobjtype,objtype,size_in_bytes,[text]
      from sys.dm_exec_cached_plans
          cross apply sys.dm_exec_sql_text(plan_handle)

      Observe na imagem abaixo o tamanho guardado no cache, indicando que o plano de execução está no cache.

      Screenshot-168_thumb1

      Agora ative o ‘optimize for ad hoc workloads’, conforme indiquei acima, e repita a execução dos mesmos trechos acima. Veja o resultado no cache:

      Screenshot-169_thumb2

      Desta vez, apenas um stub foi guardado no cache; não o plano inteiro. Com isso, temos uma economia de memória caso essa query não venha a ser utilizada novamente. Execute novamente a query (sem limpar o cache) e confira o resultado no cache:

      Screenshot-170_thumb1

      Agora o stub foi transformado em plano de execução realmente compilado. Ele não soma as contagens, que continua sendo um, afinal o plano compilado ainda não foi re-utilizado. Execute novamente a mesma query e confira o cache; assim poderá observar a contagem aumentando, como na imagem abaixo.

      Screenshot-171_thumb1

      Todo servidor sempre possui alguma quantidade de queries ad-hoc. Considero essa configuração uma boa prática na grande maioria dos servidores. São poucas as exceções.

      18 May 18:41

      Paginando dados com OffSet e Fetch

      by Dennes Torres

      Uma nova forma de realizar paginação na busca de informações no SQL Server é utilizando as cláusulas Offset/Fetch que foram criadas no SQL Server 2012. Veja como é a sintaxe:

      select firstname,lastname from person.person
      order by businessentityID
      offset 0 rows
      fetch next 10 rows only

      No exemplo acima, estamos buscando as primeiras 10 linhas da tabela person (banco adventureworks2012). Para buscar as próximas 10 linhas, basta alterar para que fique da seguinte forma:

      select firstname,lastname from person.person
      order by businessentityID
      offset 10 rows
      fetch next 10 rows only

      Porém nem tudo são flores. Para gerar o efeito da instrução offset, saltando linhas, o SQL Server utiliza um index scan. O total de linhas do scan é o total somando do offset mais o fetch, conforme mostra a figura abaixo.

      Screenshot-108_thumb1

      Dessa forma, existe uma perda gradual de performance conforme avançamos na paginação com offset/fetch, até atingir o pior cenário possível, na última página.

      Assim sendo, o uso de offset/fetch é muito prático, mas deve ser limitado a result sets não muito grandes, pois para result sets maiores a perda de performance ao longo das páginas pode ser considerável.

      06 May 14:00

      Tomas Vondra: On the usefulness of expression indexes

      When teaching PostgreSQL trainings, both on basics and advanced topics, I often find out the attendees have very little idea how powerful the expression indexes may be (if they are aware of them at all). So let me give you a brief overview.

      So, let’s say we have a table, with a range of timestamps (yes, we have generate_series function that can generate dates):

      CREATE TABLE t AS
      SELECT d, repeat(md5(d::text), 10) AS padding
        FROM generate_series(timestamp '1900-01-01',
                             timestamp '2100-01-01',
                             interval '1 day') s(d);
      VACUUM ANALYZE t;

      The table also includes a padding column, to make it a bit larger. Now, let’s do a simple range query, selecting just one month from the ~200 years included in the table. If you do explain on the query, you’ll see something like this:

      EXPLAIN SELECT * FROM t WHERE d BETWEEN '2001-01-01' AND '2001-02-01';
      
                                     QUERY PLAN
      ------------------------------------------------------------------------
       Seq Scan on t  (cost=0.00..4416.75 rows=32 width=332)
         Filter: ((d >= '2001-01-01 00:00:00'::timestamp without time zone)
              AND (d <= '2001-02-01 00:00:00'::timestamp without time zone))
      (2 rows)

      and on my laptop, this runs in ~20ms. Not bad, considering this has to walk through the whole table with ~75k rows.

      But let’s create an index on the timestamp column (all indexes here are the default type, i.e. btree, unless mentioned explicitly):

      CREATE INDEX idx_t_d ON t (d);

      And now let’s try to run the query again:

                                     QUERY PLAN
      ------------------------------------------------------------------------
       Index Scan using idx_t_d on t  (cost=0.29..9.97 rows=34 width=332)
         Index Cond: ((d >= '2001-01-01 00:00:00'::timestamp without time zone)
                  AND (d <= '2001-02-01 00:00:00'::timestamp without time zone))
      (2 rows)

      and this runs in 0.5ms, so roughly 40x faster. But that was of course a simple indexes, created directly on the column, not expression index. So let’s assume we instead need to select data from each 1st day of each month, doing a query like this

      SELECT * FROM t WHERE EXTRACT(day FROM d) = 1;

      which however can’t use the index, as it needs to evaluate an expression on the column while the index is built on the column itself, as shown on the EXPLAIN ANALYZE:

                                     QUERY PLAN
      ------------------------------------------------------------------------
       Seq Scan on t  (cost=0.00..4416.75 rows=365 width=332)
                      (actual time=0.045..40.601 rows=2401 loops=1)
         Filter: (date_part('day'::text, d) = '1'::double precision)
         Rows Removed by Filter: 70649
       Planning time: 0.209 ms
       Execution time: 43.018 ms
      (5 rows)

      So not only this has to do a sequential scan, it also has to do the evaluation, increasing the query duration to 43ms.

      The database is unable to use the index for multiple reasons. Indexes (at least btree indexes) rely on querying sorted data, provided by the tree-like structure, and while the range query can benefit from that, the second query (with `extract` call) can’t.

      Note: Another issue is that the set of operators supported by indexes (i.e. that can be evaluated on indexes directly) is very limited. And the “extract” function is not supported, so the query can’t work around the ordering issue by using a Bitmap Index Scan.

      In theory the database might try to transform the condition into range conditions, but that is extremely difficult and specific to expression. In this case we’d have to generate an infinite number of such “per-day” ranges, because the planner does not really know the min/max timestamps in the table. So the database does not even try.

      But while the database does not know how to transform the conditions, developers often do. For example with conditions like

      (column + 1) >= 1000

      it’s not difficult to rewrite it like this

      column >= (1000 - 1)

      which works just fine with the indexes.

      But what if such transformation is not possible, as for example for the example query

      SELECT * FROM t WHERE EXTRACT(day FROM d) = 1;

      In this case the developer would have to face the same issue with unknown min/max for the d column, and even then it would generate a lot of ranges.

      Well, this blog post is about expression indexes, and so far we have only used regular indexes, built on the column directly. So, let’s create the first expression index:

      CREATE INDEX idx_t_expr ON t ((extract(day FROM d)));
      ANALYZE t;

      which then gives us this explain plan

                                     QUERY PLAN
      ------------------------------------------------------------------------
       Bitmap Heap Scan on t  (cost=47.35..3305.25 rows=2459 width=332)
                              (actual time=2.400..12.539 rows=2401 loops=1)
         Recheck Cond: (date_part('day'::text, d) = '1'::double precision)
         Heap Blocks: exact=2401
         ->  Bitmap Index Scan on idx_t_expr  (cost=0.00..46.73 rows=2459 width=0)
                                      (actual time=1.243..1.243 rows=2401 loops=1)
               Index Cond: (date_part('day'::text, d) = '1'::double precision)
       Planning time: 0.374 ms
       Execution time: 17.136 ms
      (7 rows)

      So while this does not give us the same 40x speedup as the index in the first example, that’s kinda expected as this query returns far more tuples (2401 vs. 32). Moreover those are spread through the whole table and not as localized as in the first example. So it’s a nice 2x speedup, and in many real-world cases you’ll see much larger improvements.

      But the ability to use indexes for conditions with complex expressions is not the most interesting information here – that’s kinda the reason why people create expression indexes. But that’s not the only benefit.

      If you look at the two explain plans presented above (without and with the expression index), you might notice this:

                                     QUERY PLAN
      ------------------------------------------------------------------------
       Seq Scan on t  (cost=0.00..4416.75 rows=365 width=332)
                      (actual time=0.045..40.601 rows=2401 loops=1)
       ...
                                     QUERY PLAN
      ------------------------------------------------------------------------
       Bitmap Heap Scan on t  (cost=47.35..3305.25 rows=2459 width=332)
                              (actual time=2.400..12.539 rows=2401 loops=1)
       ...

      Right – creating the expression index significantly improved estimates. Without the index we only have statistics (MCV + histogram) for raw table columns, so the database does not know how to estimate the expression

      EXTRACT(day FROM d) = 1

      So it instead applies a default estimate for equality conditions, which is 0.5% of all rows – as the table has 73050 rows, we end up with an estimate of just 365 rows. It’s common to see much worse estimation errors in real-world applications.

      With the index, however, the database also collected statistics on columns of the index, and in this case the column contains results of the expression. And while planning, the optimizer notices this and produces much better estimate.

      This is a huge benefit, and may help with fixing some cases of poor query plans caused by inaccurate estimates. Yet most people are unaware of this handy tool.

      And the usefulness of this tool only increased with the introduction of JSONB data type in 9.4, because it’s about the only way to collect statistics about the contents of the JSONB documents.

      When indexing JSONB documents, two basic indexing strategies exist. You can either create a GIN/GiST index on the whole document, e.g. like this

      CREATE INDEX ON t USING GIN (jsonb_column);

      which allows you to query arbitrary paths in the JSONB column, use containment operator to match sub-documents, etc. That’s great, but you still have only the basic per-column statistics, which are
      not very useful as the documents are treated as scalar values (and no one matches whole documents or uses range of documents).

      Expression indexes, for example created like this:

      CREATE INDEX ON t ((jsonb_column->'id'));

      will only be useful for the particular expression, i.e. this newly created index will be useful for

      SELECT * FROM t WHERE jsonb_column ->> 'id' = 123;

      but not for queries accessing other JSON keys, like ‘value’ for example

      SELECT * FROM t WHERE jsonb_column ->> 'value' = 'xxxx';

      This is not to say that GIN/GiST indexes on the whole document are useless, but you have to choose. Either you create a focused expression index, useful when querying a particular key and with the added benefit of statistics on the expression. Or you create a GIN/GiST index on the whole document, able to handle queries on arbitrary keys, but without the statistics.

      However you can have a cake and eat it too, in this case, because you can create both indexes at the same time, and the database will choose which of them to use for individual queries. And you’ll have accurate statistics, thanks to the expression indexes.

      Sadly, you can’t eat the whole cake, because expression indexes and GIN/GiST indexes use different conditions

      -- expression (btree)
      SELECT * FROM t WHERE jsonb_column ->> 'id' = 123;
      
      -- GIN/GiST
      SELECT * FROM t WHERE jsonb_column @> '{"id" : 123}';

      so the planner can’t use them at the same time – expression indexes for estimation and GIN/GiST for execution.

      05 May 19:00

      How to Visualize DC/OS

      by Apurva Dave

      We’re excited to see that DC/OS platform has gone open source. What’s more we’re fortunate enough to have been invited along for the ride! This post will give you a short overview of what’s happening, why it matters, and how Sysdig is involved.

      What is DC/OS?

      DC/OS (Data Center Operating System) was originally created by Mesosphere. It takes two key open source projects, Mesos and Marathon, and enables you to abstract away distributed resources into one “pool” of memory, compute, and disk. DC/OS bundles additional services such as mesos-dns, tooling like a CLI, a GUI, a repository for the packages that you want to run, and frameworks like Marathon (a.k.a. distributed init), Chronos (a.k.a. distributed cron), and more. The end result is a simple, packaged way to run complex distributed applications with or without containers.

      DCOS Dashboard

      All the power of DC/OS, now open source!

      Why does it matter?

      As most of you know we’re currently amidst a major platform shift – the move from virtual machines to containers will allow organizations to deliver more functionality, faster. Projects like DC/OS matter because they simplify the process of getting an environment running that can effectively manage and enable containers in the first place. In short, containers are great, but only if you have something like DC/OS to take your containers into production.

      But you’ve still got to monitor it all!

      It was just a couple weeks back that Sysdig announced its formal partnership with Mesosphere, and more importantly, our technical integration with Mesos, Marathon, and DC/OS.

      And because the open sourced DC/OS is full-featured DC/OS, our integration works exactly the same across our open source and commercial products. The link above has an example of deep troubleshooting… instead of recreating that I’ll provide a “getting started” example.

      Visualizing DC/OS at Work

      Deploying applications with DC/OS is a totally new paradigm, so it can be challenging to wrap your head around what exactly the platform is doing. How is it allocating resources? Where is your application actually running?

      Let’s suppose you’re deploying a few applications on top of DC/OS and you’d like to understand:

      • What are the applications?
      • What resources are they using?
      • How are they performing?

      Enter Sysdig Cloud.It provides real-time topology mapping that allows you to automatically visualize the physical resources at work. You simply use our one-line command to deploy the Sysdig agent. No additional Sysdig Cloud agent configuration is required when the Mesos master is installed with default settings on the nodes where the Mesos API server runs (“Master” nodes). The Sysdig Cloud agent will look for the process named “mesos-master”. If the process is found at any time, our agent will automatically connect to the local Mesos and Marathon (if available) API servers, to collect cluster configuration and current state metadata in addition to host metrics.

      OK, so point-and-click, you’ve pushed out your applications on DC/OS.

      DCOS Dashboard

      Services view within DC/OS

      Assuming you’ve instrumented the hosts running DC/OS, you can get a view like this which tells you how the machines are doing from an infrastructure perspective:

      Sysdig Mesos Dashboard

      Nothing too unusual (or insightful) here… this is just straight infrastructure monitoring. But let’s start to look at relationships of these hosts in a topology:

      Sysdig Mesos Dashboard

      OK, so this is slightly more interesting. We can see communication between the hosts, request times, and resource usage of the machines themselves all in one place. But how does this relate to your app? And what is DC/OS doing as a part of this? Let’s drill down into these hosts…

      Sysdig Mesos Dashboard

      And we see small boxes that each represent a container running its own software… it’s spaghetti! And that’s a good thing, it means DC/OS is doing its job. DC/OS is distributing containers across machines in a way that makes the optimal use of underlying resources.

      As we mentioned, Sysdig also integrates with the master to collect metadata about your system. We use that data to take physical data, like what you’re seeing above, and create logical picture of what your apps are doing. When you apply the metadata, you get this:

      Sysdig Mesos Dashboard

      OK, now we’re cooking. We can see a few applications, as well as the relationships between their components, as well as the resources they are using. While the combination of physical and logical topology is especially useful for troubleshooting, it’s also a huge help in understanding the basics of how DC/OS works in the first place.

      Just the beginning…

      Deploying a containerized application is just a step in your overall process from conceptualizing an application all the way through running it in production. DC/OS makes it simple to get those apps running, and Sysdig is very happy to partner with the DC/OS team to make monitoring just as simple. While in this post we focused on visualizing how an application is deployed on DC/OS, our next post will focus on what your application is doing and how you can troubleshoot it more effectively. Stay tuned!

      The post How to Visualize DC/OS appeared first on Sysdig.