In the previous Translator 101 post, we looked at some of the dispatch tables and options processing in a translator. This time we’re going to cover the rest of the “shell” of a translator – i.e. the other global parts not specific to handling a particular request.
Let’s start by looking at the relationship between a translator and its shared library. At a first approximation, this is the relationship between an object and a class in just about any object-oriented programming language. The class defines behaviors, but has to be instantiated as an object to have any kind of existence. In our case the object is an xlator_t. Several of these might be created within the same daemon, sharing all of the same code through init/fini and dispatch tables, but sharing no data. You could implement shared data (as static variables in your shared libraries) but that’s strongly discouraged. Every function in your shared library will get an xlator_t as an argument, and should use it. This lack of class-level data is one of the points where the analogy to common OOP systems starts to break down. Another place is the complete lack of inheritance. Translators inherit behavior (code) from exactly one shared library – looked up and loaded using the “type” field in a volfile “volume . . . end-volume” block – and that’s it – not even single inheritance, no subclasses or superclasses, no mixins or prototypes, just the relationship between an object and its class. With that in mind, let’s turn to the init function that we just barely touched on last time.
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
int32_t init (xlator_t *this) { data_t *data = NULL; rot_13_private_t *priv = NULL; if (!this->children || this->children->next) { gf_log ("rot13", GF_LOG_ERROR, "FATAL: rot13 should have exactly one child"); return -1; } if (!this->parents) { gf_log (this->name, GF_LOG_WARNING, "dangling volume. check volfile "); } priv = GF_CALLOC (sizeof (rot_13_private_t), 1, 0); if (!priv) return -1; |
At the very top, we see the function signature – we get a pointer to the xlator_t object that we’re initializing, and we return an int32_t status. As with most functions in the translator API, this should be zero to indicate success. In this case it’s safe to return -1 for failure, but watch out: in dispatch-table functions, the return value means the status of the function call rather than the request. A request error should be reflected as a callback with a non-zero op_ret value, but the dispatch function itself should still return zero. In fact, the handling of a non-zero return from a dispatch function is not all that robust (we recently had a bug report in HekaFS related to this) so it’s something you should probably avoid altogether. This only underscores the difference between dispatch functions and init/fini functions, where non-zero returns are expected and handled logically by aborting the translator setup. We can see that down at the bottom, where we return -1 to indicate that we couldn’t allocate our private-data area (more about that later).
The first thing this init function does is check that the translator is being set up in the right kind of environment. Translators are called by parents and in turn call children. Some translators are “initial” translators that inject requests into the system from elsewhere – e.g. mount/fuse injecting requests from the kernel, protocol/server injecting requests from the network. Those translators don’t need parents, but rot-13 does and so we check for that. Similarly, some translators are “final” translators that (from the perspective of the current process) terminate requests instead of passing them on – e.g. protocol/client passing them to another node, storage/posix passing them to a local filesystem. Other translators “multiplex” between multiple children – passing each parent request on to one (cluster/dht), some (cluster/stripe), or all (cluster/afr) of those children. Rot-13 fits into none of those categories either, so it checks that it has exactly one child. It might be more convenient or robust if translator shared libraries had standard variables describing these requirements, to be checked in a consistent way by the translator-loading infrastructure itself instead of by each separate init function, but this is the way translators work today.
The last thing we see in this fragment is allocating our private data area. This can literally be anything we want; the infrastructure just provides the priv pointer as a convenience but takes no responsibility for how it’s used. In this case we’re using GF_CALLOC to allocate our own rot_13_private_t structure. This gets us all the benefits of GlusterFS’s memory-leak detection infrastructure, but the way we’re calling it is not quite ideal. For one thing, the first two arguments – from calloc(3) – are kind of reversed. For another, notice how the last argument is zero. That can actually be an enumerated value, to tell the GlusterFS allocator what type we’re allocating. This can be very useful information for memory profiling and leak detection, so it’s recommended that you follow the example of any xxx-mem-types.h file elsewhere in the source tree instead of just passing zero here (even though that works).
To finish our tour of standard initialization/termination, let’s look at the end of init and the beginning of fini
174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
this->private = priv; gf_log ("rot13", GF_LOG_DEBUG, "rot13 xlator loaded"); return 0; } void fini (xlator_t *this) { rot_13_private_t *priv = this->private; if (!priv) return; this->private = NULL; GF_FREE (priv); |
At the end of init we’re just storing our private-data pointer in the priv field of our xlator_t, then returning zero to indicate that initialization succeeded. As is usually the case, our fini is even simpler. All it really has to do is GF_FREE our private-data pointer, which we do in a slightly roundabout way here. Notice how we don’t even have a return value here, since there’s nothing obvious and useful that the infrastructure could do if fini failed.
That’s practically everything we need to know to get our translator through loading, initialization, options processing, and termination. If we had defined no dispatch functions, we could actually configure a daemon to use our translator and it would work as a basic pass-through from its parent to a single child. In the next post I’ll cover how to build the translator and configure a daemon to use it, so that we can actually step through it in a debugger and see how it all fits together before we actually start adding functionality.
Sobre o autor
Navegue por canal
Automação
Últimas novidades em automação de TI para empresas de tecnologia, equipes e ambientes
Inteligência artificial
Descubra as atualizações nas plataformas que proporcionam aos clientes executar suas cargas de trabalho de IA em qualquer ambiente
Nuvem híbrida aberta
Veja como construímos um futuro mais flexível com a nuvem híbrida
Segurança
Veja as últimas novidades sobre como reduzimos riscos em ambientes e tecnologias
Edge computing
Saiba quais são as atualizações nas plataformas que simplificam as operações na borda
Infraestrutura
Saiba o que há de mais recente na plataforma Linux empresarial líder mundial
Aplicações
Conheça nossas soluções desenvolvidas para ajudar você a superar os desafios mais complexos de aplicações
Programas originais
Veja as histórias divertidas de criadores e líderes em tecnologia empresarial
Produtos
- Red Hat Enterprise Linux
- Red Hat OpenShift
- Red Hat Ansible Automation Platform
- Red Hat Cloud Services
- Veja todos os produtos
Ferramentas
- Treinamento e certificação
- Minha conta
- Suporte ao cliente
- Recursos para desenvolvedores
- Encontre um parceiro
- Red Hat Ecosystem Catalog
- Calculadora de valor Red Hat
- Documentação
Experimente, compre, venda
Comunicação
- Contate o setor de vendas
- Fale com o Atendimento ao Cliente
- Contate o setor de treinamento
- Redes sociais
Sobre a Red Hat
A Red Hat é a líder mundial em soluções empresariais open source como Linux, nuvem, containers e Kubernetes. Fornecemos soluções robustas que facilitam o trabalho em diversas plataformas e ambientes, do datacenter principal até a borda da rede.
Selecione um idioma
Red Hat legal and privacy links
- Sobre a Red Hat
- Oportunidades de emprego
- Eventos
- Escritórios
- Fale com a Red Hat
- Blog da Red Hat
- Diversidade, equidade e inclusão
- Cool Stuff Store
- Red Hat Summit